Account leveling

This commit is contained in:
LittleSheep 2025-05-17 02:31:10 +08:00
parent a059e38aac
commit db2c67ddeb
9 changed files with 239 additions and 41 deletions

View File

@ -230,5 +230,8 @@
"friendSentRequestHint": { "friendSentRequestHint": {
"one": "{} friend request sent", "one": "{} friend request sent",
"other": "{} friend requests sent" "other": "{} friend requests sent"
} },
"levelingProgress": "Leveling Progress",
"levelingProgressExperience": "{} EXP",
"levelingProgressLevel": "Level {}"
} }

View File

@ -32,6 +32,9 @@ abstract class SnAccountProfile with _$SnAccountProfile {
required String? lastName, required String? lastName,
required String? bio, required String? bio,
required String? pictureId, required String? pictureId,
required int experience,
required int level,
required double levelingProgress,
required SnCloudFile? picture, required SnCloudFile? picture,
required String? backgroundId, required String? backgroundId,
required SnCloudFile? background, required SnCloudFile? background,

View File

@ -200,7 +200,7 @@ $SnAccountProfileCopyWith<$Res> get profile {
/// @nodoc /// @nodoc
mixin _$SnAccountProfile { mixin _$SnAccountProfile {
String get id; String? get firstName; String? get middleName; String? get lastName; String? get bio; String? get pictureId; SnCloudFile? get picture; String? get backgroundId; SnCloudFile? get background; DateTime get createdAt; DateTime get updatedAt; DateTime? get deletedAt; String get id; String? get firstName; String? get middleName; String? get lastName; String? get bio; String? get pictureId; int get experience; int get level; double get levelingProgress; SnCloudFile? get picture; String? get backgroundId; SnCloudFile? get background; DateTime get createdAt; DateTime get updatedAt; DateTime? get deletedAt;
/// Create a copy of SnAccountProfile /// Create a copy of SnAccountProfile
/// with the given fields replaced by the non-null parameter values. /// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false) @JsonKey(includeFromJson: false, includeToJson: false)
@ -213,16 +213,16 @@ $SnAccountProfileCopyWith<SnAccountProfile> get copyWith => _$SnAccountProfileCo
@override @override
bool operator ==(Object other) { bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is SnAccountProfile&&(identical(other.id, id) || other.id == id)&&(identical(other.firstName, firstName) || other.firstName == firstName)&&(identical(other.middleName, middleName) || other.middleName == middleName)&&(identical(other.lastName, lastName) || other.lastName == lastName)&&(identical(other.bio, bio) || other.bio == bio)&&(identical(other.pictureId, pictureId) || other.pictureId == pictureId)&&(identical(other.picture, picture) || other.picture == picture)&&(identical(other.backgroundId, backgroundId) || other.backgroundId == backgroundId)&&(identical(other.background, background) || other.background == background)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)); return identical(this, other) || (other.runtimeType == runtimeType&&other is SnAccountProfile&&(identical(other.id, id) || other.id == id)&&(identical(other.firstName, firstName) || other.firstName == firstName)&&(identical(other.middleName, middleName) || other.middleName == middleName)&&(identical(other.lastName, lastName) || other.lastName == lastName)&&(identical(other.bio, bio) || other.bio == bio)&&(identical(other.pictureId, pictureId) || other.pictureId == pictureId)&&(identical(other.experience, experience) || other.experience == experience)&&(identical(other.level, level) || other.level == level)&&(identical(other.levelingProgress, levelingProgress) || other.levelingProgress == levelingProgress)&&(identical(other.picture, picture) || other.picture == picture)&&(identical(other.backgroundId, backgroundId) || other.backgroundId == backgroundId)&&(identical(other.background, background) || other.background == background)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt));
} }
@JsonKey(includeFromJson: false, includeToJson: false) @JsonKey(includeFromJson: false, includeToJson: false)
@override @override
int get hashCode => Object.hash(runtimeType,id,firstName,middleName,lastName,bio,pictureId,picture,backgroundId,background,createdAt,updatedAt,deletedAt); int get hashCode => Object.hash(runtimeType,id,firstName,middleName,lastName,bio,pictureId,experience,level,levelingProgress,picture,backgroundId,background,createdAt,updatedAt,deletedAt);
@override @override
String toString() { String toString() {
return 'SnAccountProfile(id: $id, firstName: $firstName, middleName: $middleName, lastName: $lastName, bio: $bio, pictureId: $pictureId, picture: $picture, backgroundId: $backgroundId, background: $background, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)'; return 'SnAccountProfile(id: $id, firstName: $firstName, middleName: $middleName, lastName: $lastName, bio: $bio, pictureId: $pictureId, experience: $experience, level: $level, levelingProgress: $levelingProgress, picture: $picture, backgroundId: $backgroundId, background: $background, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)';
} }
@ -233,7 +233,7 @@ abstract mixin class $SnAccountProfileCopyWith<$Res> {
factory $SnAccountProfileCopyWith(SnAccountProfile value, $Res Function(SnAccountProfile) _then) = _$SnAccountProfileCopyWithImpl; factory $SnAccountProfileCopyWith(SnAccountProfile value, $Res Function(SnAccountProfile) _then) = _$SnAccountProfileCopyWithImpl;
@useResult @useResult
$Res call({ $Res call({
String id, String? firstName, String? middleName, String? lastName, String? bio, String? pictureId, SnCloudFile? picture, String? backgroundId, SnCloudFile? background, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt String id, String? firstName, String? middleName, String? lastName, String? bio, String? pictureId, int experience, int level, double levelingProgress, SnCloudFile? picture, String? backgroundId, SnCloudFile? background, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt
}); });
@ -250,7 +250,7 @@ class _$SnAccountProfileCopyWithImpl<$Res>
/// Create a copy of SnAccountProfile /// Create a copy of SnAccountProfile
/// with the given fields replaced by the non-null parameter values. /// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? firstName = freezed,Object? middleName = freezed,Object? lastName = freezed,Object? bio = freezed,Object? pictureId = freezed,Object? picture = freezed,Object? backgroundId = freezed,Object? background = freezed,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,}) { @pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? firstName = freezed,Object? middleName = freezed,Object? lastName = freezed,Object? bio = freezed,Object? pictureId = freezed,Object? experience = null,Object? level = null,Object? levelingProgress = null,Object? picture = freezed,Object? backgroundId = freezed,Object? background = freezed,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,}) {
return _then(_self.copyWith( return _then(_self.copyWith(
id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
as String,firstName: freezed == firstName ? _self.firstName : firstName // ignore: cast_nullable_to_non_nullable as String,firstName: freezed == firstName ? _self.firstName : firstName // ignore: cast_nullable_to_non_nullable
@ -258,7 +258,10 @@ as String?,middleName: freezed == middleName ? _self.middleName : middleName //
as String?,lastName: freezed == lastName ? _self.lastName : lastName // ignore: cast_nullable_to_non_nullable as String?,lastName: freezed == lastName ? _self.lastName : lastName // ignore: cast_nullable_to_non_nullable
as String?,bio: freezed == bio ? _self.bio : bio // ignore: cast_nullable_to_non_nullable as String?,bio: freezed == bio ? _self.bio : bio // ignore: cast_nullable_to_non_nullable
as String?,pictureId: freezed == pictureId ? _self.pictureId : pictureId // ignore: cast_nullable_to_non_nullable as String?,pictureId: freezed == pictureId ? _self.pictureId : pictureId // ignore: cast_nullable_to_non_nullable
as String?,picture: freezed == picture ? _self.picture : picture // ignore: cast_nullable_to_non_nullable as String?,experience: null == experience ? _self.experience : experience // ignore: cast_nullable_to_non_nullable
as int,level: null == level ? _self.level : level // ignore: cast_nullable_to_non_nullable
as int,levelingProgress: null == levelingProgress ? _self.levelingProgress : levelingProgress // ignore: cast_nullable_to_non_nullable
as double,picture: freezed == picture ? _self.picture : picture // ignore: cast_nullable_to_non_nullable
as SnCloudFile?,backgroundId: freezed == backgroundId ? _self.backgroundId : backgroundId // ignore: cast_nullable_to_non_nullable as SnCloudFile?,backgroundId: freezed == backgroundId ? _self.backgroundId : backgroundId // ignore: cast_nullable_to_non_nullable
as String?,background: freezed == background ? _self.background : background // ignore: cast_nullable_to_non_nullable as String?,background: freezed == background ? _self.background : background // ignore: cast_nullable_to_non_nullable
as SnCloudFile?,createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable as SnCloudFile?,createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable
@ -299,7 +302,7 @@ $SnCloudFileCopyWith<$Res>? get background {
@JsonSerializable() @JsonSerializable()
class _SnAccountProfile implements SnAccountProfile { class _SnAccountProfile implements SnAccountProfile {
const _SnAccountProfile({required this.id, required this.firstName, required this.middleName, required this.lastName, required this.bio, required this.pictureId, required this.picture, required this.backgroundId, required this.background, required this.createdAt, required this.updatedAt, required this.deletedAt}); const _SnAccountProfile({required this.id, required this.firstName, required this.middleName, required this.lastName, required this.bio, required this.pictureId, required this.experience, required this.level, required this.levelingProgress, required this.picture, required this.backgroundId, required this.background, required this.createdAt, required this.updatedAt, required this.deletedAt});
factory _SnAccountProfile.fromJson(Map<String, dynamic> json) => _$SnAccountProfileFromJson(json); factory _SnAccountProfile.fromJson(Map<String, dynamic> json) => _$SnAccountProfileFromJson(json);
@override final String id; @override final String id;
@ -308,6 +311,9 @@ class _SnAccountProfile implements SnAccountProfile {
@override final String? lastName; @override final String? lastName;
@override final String? bio; @override final String? bio;
@override final String? pictureId; @override final String? pictureId;
@override final int experience;
@override final int level;
@override final double levelingProgress;
@override final SnCloudFile? picture; @override final SnCloudFile? picture;
@override final String? backgroundId; @override final String? backgroundId;
@override final SnCloudFile? background; @override final SnCloudFile? background;
@ -328,16 +334,16 @@ Map<String, dynamic> toJson() {
@override @override
bool operator ==(Object other) { bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnAccountProfile&&(identical(other.id, id) || other.id == id)&&(identical(other.firstName, firstName) || other.firstName == firstName)&&(identical(other.middleName, middleName) || other.middleName == middleName)&&(identical(other.lastName, lastName) || other.lastName == lastName)&&(identical(other.bio, bio) || other.bio == bio)&&(identical(other.pictureId, pictureId) || other.pictureId == pictureId)&&(identical(other.picture, picture) || other.picture == picture)&&(identical(other.backgroundId, backgroundId) || other.backgroundId == backgroundId)&&(identical(other.background, background) || other.background == background)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)); return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnAccountProfile&&(identical(other.id, id) || other.id == id)&&(identical(other.firstName, firstName) || other.firstName == firstName)&&(identical(other.middleName, middleName) || other.middleName == middleName)&&(identical(other.lastName, lastName) || other.lastName == lastName)&&(identical(other.bio, bio) || other.bio == bio)&&(identical(other.pictureId, pictureId) || other.pictureId == pictureId)&&(identical(other.experience, experience) || other.experience == experience)&&(identical(other.level, level) || other.level == level)&&(identical(other.levelingProgress, levelingProgress) || other.levelingProgress == levelingProgress)&&(identical(other.picture, picture) || other.picture == picture)&&(identical(other.backgroundId, backgroundId) || other.backgroundId == backgroundId)&&(identical(other.background, background) || other.background == background)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt));
} }
@JsonKey(includeFromJson: false, includeToJson: false) @JsonKey(includeFromJson: false, includeToJson: false)
@override @override
int get hashCode => Object.hash(runtimeType,id,firstName,middleName,lastName,bio,pictureId,picture,backgroundId,background,createdAt,updatedAt,deletedAt); int get hashCode => Object.hash(runtimeType,id,firstName,middleName,lastName,bio,pictureId,experience,level,levelingProgress,picture,backgroundId,background,createdAt,updatedAt,deletedAt);
@override @override
String toString() { String toString() {
return 'SnAccountProfile(id: $id, firstName: $firstName, middleName: $middleName, lastName: $lastName, bio: $bio, pictureId: $pictureId, picture: $picture, backgroundId: $backgroundId, background: $background, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)'; return 'SnAccountProfile(id: $id, firstName: $firstName, middleName: $middleName, lastName: $lastName, bio: $bio, pictureId: $pictureId, experience: $experience, level: $level, levelingProgress: $levelingProgress, picture: $picture, backgroundId: $backgroundId, background: $background, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)';
} }
@ -348,7 +354,7 @@ abstract mixin class _$SnAccountProfileCopyWith<$Res> implements $SnAccountProfi
factory _$SnAccountProfileCopyWith(_SnAccountProfile value, $Res Function(_SnAccountProfile) _then) = __$SnAccountProfileCopyWithImpl; factory _$SnAccountProfileCopyWith(_SnAccountProfile value, $Res Function(_SnAccountProfile) _then) = __$SnAccountProfileCopyWithImpl;
@override @useResult @override @useResult
$Res call({ $Res call({
String id, String? firstName, String? middleName, String? lastName, String? bio, String? pictureId, SnCloudFile? picture, String? backgroundId, SnCloudFile? background, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt String id, String? firstName, String? middleName, String? lastName, String? bio, String? pictureId, int experience, int level, double levelingProgress, SnCloudFile? picture, String? backgroundId, SnCloudFile? background, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt
}); });
@ -365,7 +371,7 @@ class __$SnAccountProfileCopyWithImpl<$Res>
/// Create a copy of SnAccountProfile /// Create a copy of SnAccountProfile
/// with the given fields replaced by the non-null parameter values. /// with the given fields replaced by the non-null parameter values.
@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? firstName = freezed,Object? middleName = freezed,Object? lastName = freezed,Object? bio = freezed,Object? pictureId = freezed,Object? picture = freezed,Object? backgroundId = freezed,Object? background = freezed,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,}) { @override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? firstName = freezed,Object? middleName = freezed,Object? lastName = freezed,Object? bio = freezed,Object? pictureId = freezed,Object? experience = null,Object? level = null,Object? levelingProgress = null,Object? picture = freezed,Object? backgroundId = freezed,Object? background = freezed,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,}) {
return _then(_SnAccountProfile( return _then(_SnAccountProfile(
id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
as String,firstName: freezed == firstName ? _self.firstName : firstName // ignore: cast_nullable_to_non_nullable as String,firstName: freezed == firstName ? _self.firstName : firstName // ignore: cast_nullable_to_non_nullable
@ -373,7 +379,10 @@ as String?,middleName: freezed == middleName ? _self.middleName : middleName //
as String?,lastName: freezed == lastName ? _self.lastName : lastName // ignore: cast_nullable_to_non_nullable as String?,lastName: freezed == lastName ? _self.lastName : lastName // ignore: cast_nullable_to_non_nullable
as String?,bio: freezed == bio ? _self.bio : bio // ignore: cast_nullable_to_non_nullable as String?,bio: freezed == bio ? _self.bio : bio // ignore: cast_nullable_to_non_nullable
as String?,pictureId: freezed == pictureId ? _self.pictureId : pictureId // ignore: cast_nullable_to_non_nullable as String?,pictureId: freezed == pictureId ? _self.pictureId : pictureId // ignore: cast_nullable_to_non_nullable
as String?,picture: freezed == picture ? _self.picture : picture // ignore: cast_nullable_to_non_nullable as String?,experience: null == experience ? _self.experience : experience // ignore: cast_nullable_to_non_nullable
as int,level: null == level ? _self.level : level // ignore: cast_nullable_to_non_nullable
as int,levelingProgress: null == levelingProgress ? _self.levelingProgress : levelingProgress // ignore: cast_nullable_to_non_nullable
as double,picture: freezed == picture ? _self.picture : picture // ignore: cast_nullable_to_non_nullable
as SnCloudFile?,backgroundId: freezed == backgroundId ? _self.backgroundId : backgroundId // ignore: cast_nullable_to_non_nullable as SnCloudFile?,backgroundId: freezed == backgroundId ? _self.backgroundId : backgroundId // ignore: cast_nullable_to_non_nullable
as String?,background: freezed == background ? _self.background : background // ignore: cast_nullable_to_non_nullable as String?,background: freezed == background ? _self.background : background // ignore: cast_nullable_to_non_nullable
as SnCloudFile?,createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable as SnCloudFile?,createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable

View File

@ -48,6 +48,9 @@ _SnAccountProfile _$SnAccountProfileFromJson(Map<String, dynamic> json) =>
lastName: json['last_name'] as String?, lastName: json['last_name'] as String?,
bio: json['bio'] as String?, bio: json['bio'] as String?,
pictureId: json['picture_id'] as String?, pictureId: json['picture_id'] as String?,
experience: (json['experience'] as num).toInt(),
level: (json['level'] as num).toInt(),
levelingProgress: (json['leveling_progress'] as num).toDouble(),
picture: picture:
json['picture'] == null json['picture'] == null
? null ? null
@ -75,6 +78,9 @@ Map<String, dynamic> _$SnAccountProfileToJson(_SnAccountProfile instance) =>
'last_name': instance.lastName, 'last_name': instance.lastName,
'bio': instance.bio, 'bio': instance.bio,
'picture_id': instance.pictureId, 'picture_id': instance.pictureId,
'experience': instance.experience,
'level': instance.level,
'leveling_progress': instance.levelingProgress,
'picture': instance.picture?.toJson(), 'picture': instance.picture?.toJson(),
'background_id': instance.backgroundId, 'background_id': instance.backgroundId,
'background': instance.background?.toJson(), 'background': instance.background?.toJson(),

View File

@ -10,6 +10,7 @@ import 'package:island/pods/network.dart';
import 'package:island/pods/userinfo.dart'; import 'package:island/pods/userinfo.dart';
import 'package:island/route.gr.dart'; import 'package:island/route.gr.dart';
import 'package:island/widgets/account/status.dart'; import 'package:island/widgets/account/status.dart';
import 'package:island/widgets/account/leveling_progress.dart';
import 'package:island/widgets/app_scaffold.dart'; import 'package:island/widgets/app_scaffold.dart';
import 'package:island/widgets/content/cloud_files.dart'; import 'package:island/widgets/content/cloud_files.dart';
import 'package:material_symbols_icons/symbols.dart'; import 'package:material_symbols_icons/symbols.dart';
@ -92,6 +93,11 @@ class AccountScreen extends HookConsumerWidget {
], ],
), ),
).padding(horizontal: 8), ).padding(horizontal: 8),
LevelingProgressCard(
level: user.value!.profile.level,
experience: user.value!.profile.experience,
progress: user.value!.profile.levelingProgress,
).padding(horizontal: 8),
Row( Row(
children: [ children: [
Expanded( Expanded(

View File

@ -6,6 +6,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:island/models/user.dart'; import 'package:island/models/user.dart';
import 'package:island/pods/network.dart'; import 'package:island/pods/network.dart';
import 'package:island/widgets/account/badge.dart'; import 'package:island/widgets/account/badge.dart';
import 'package:island/widgets/account/leveling_progress.dart';
import 'package:island/widgets/account/status.dart'; import 'package:island/widgets/account/status.dart';
import 'package:island/widgets/app_scaffold.dart'; import 'package:island/widgets/app_scaffold.dart';
import 'package:island/widgets/content/cloud_files.dart'; import 'package:island/widgets/content/cloud_files.dart';
@ -115,7 +116,14 @@ class AccountProfileScreen extends HookConsumerWidget {
).padding(horizontal: 24, bottom: 24), ).padding(horizontal: 24, bottom: 24),
) )
else else
const Gap(16), const SliverGap(4),
SliverToBoxAdapter(
child: LevelingProgressCard(
level: data.profile.level,
experience: data.profile.experience,
progress: data.profile.levelingProgress,
).padding(horizontal: 20, bottom: 24),
),
SliverToBoxAdapter( SliverToBoxAdapter(
child: const Divider(height: 1).padding(bottom: 24), child: const Divider(height: 1).padding(bottom: 24),
), ),

View File

@ -6,7 +6,7 @@ part of 'relationship.dart';
// RiverpodGenerator // RiverpodGenerator
// ************************************************************************** // **************************************************************************
String _$sentFriendRequestHash() => r'cb134439280d361af585c3108fdd12543ac84130'; String _$sentFriendRequestHash() => r'2efa72835b1740e0fe96bd347bce0f98b6ae80d6';
/// See also [sentFriendRequest]. /// See also [sentFriendRequest].
@ProviderFor(sentFriendRequest) @ProviderFor(sentFriendRequest)
@ -27,7 +27,7 @@ final sentFriendRequestProvider =
typedef SentFriendRequestRef = typedef SentFriendRequestRef =
AutoDisposeFutureProviderRef<List<SnRelationship>>; AutoDisposeFutureProviderRef<List<SnRelationship>>;
String _$relationshipListNotifierHash() => String _$relationshipListNotifierHash() =>
r'ad352e8b10641820d5acac27b26ad1bb0b59b67f'; r'560410cba6e4c26affd91aa86b3666319bd31f24';
/// See also [RelationshipListNotifier]. /// See also [RelationshipListNotifier].
@ProviderFor(RelationshipListNotifier) @ProviderFor(RelationshipListNotifier)

View File

@ -0,0 +1,57 @@
import 'package:flutter/material.dart';
import 'package:gap/gap.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:styled_widget/styled_widget.dart';
class LevelingProgressCard extends StatelessWidget {
final int level;
final int experience;
final double progress;
const LevelingProgressCard({
super.key,
required this.level,
required this.experience,
required this.progress,
});
@override
Widget build(BuildContext context) {
return Card(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Text('levelingProgress').tr().fontSize(16).bold(),
Row(
spacing: 8,
crossAxisAlignment: CrossAxisAlignment.baseline,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
textBaseline: TextBaseline.alphabetic,
children: [
Text(
'levelingProgressLevel'.tr(args: [level.toString()]),
style: GoogleFonts.robotoMono(),
).fontSize(13).bold(),
Text(
'levelingProgressExperience'.tr(args: [experience.toString()]),
style: GoogleFonts.robotoMono(),
).fontSize(13),
],
),
const Gap(8),
Tooltip(
message: '${(progress).toStringAsFixed(1)}%',
child: LinearProgressIndicator(
minHeight: 4,
value: progress / 100,
color: Theme.of(context).colorScheme.primary,
backgroundColor:
Theme.of(context).colorScheme.surfaceContainerHigh,
),
),
],
).padding(horizontal: 16, vertical: 12),
);
}
}

View File

@ -1,7 +1,7 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<!-- <!--
If you are serving your web app in a path other than the root, change the If you are serving your web app in a path other than the root, change the
href value below to reflect the base path you are serving from. href value below to reflect the base path you are serving from.
@ -14,29 +14,135 @@
This is a placeholder for base href that will be replaced by the value of This is a placeholder for base href that will be replaced by the value of
the `--base-href` argument provided to `flutter build`. the `--base-href` argument provided to `flutter build`.
--> -->
<base href="$FLUTTER_BASE_HREF"> <base href="$FLUTTER_BASE_HREF" />
<meta charset="UTF-8"> <meta charset="UTF-8" />
<meta content="IE=Edge" http-equiv="X-UA-Compatible"> <meta content="IE=Edge" http-equiv="X-UA-Compatible" />
<meta name="description" content="A new Flutter project."> <meta name="description" content="A new Flutter project." />
<!-- iOS meta tags & icons --> <!-- iOS meta tags & icons -->
<meta name="mobile-web-app-capable" content="yes"> <meta name="mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black"> <meta name="apple-mobile-web-app-status-bar-style" content="black" />
<meta name="apple-mobile-web-app-title" content="island"> <meta name="apple-mobile-web-app-title" content="island" />
<link rel="apple-touch-icon" href="icons/Icon-192.png"> <link rel="apple-touch-icon" href="icons/Icon-192.png" />
<!-- Favicon --> <!-- Favicon -->
<link rel="icon" type="image/png" href="favicon.png"/> <link rel="icon" type="image/png" href="favicon.png" />
<title>island</title> <title>island</title>
<link rel="manifest" href="manifest.json"> <link rel="manifest" href="manifest.json" />
</head>
<body> <style>
<script src="https://unpkg.com/sweetalert@2.1.2/dist/sweetalert.min.js" async></script> @import url("https://fonts.googleapis.com/css2?family=Rubik:ital,wght@0,300..900;1,300..900&display=swap");
<script src="flutter_bootstrap.js" async></script>
<script> html,
document.oncontextmenu = (evt) => evt.preventDefault(); body {
</script> font-family: "Rubik", sans-serif;
</body> }
.swal-overlay {
background-color: rgba(0, 0, 0, 0.4);
}
.swal-modal {
background-color: #1a1a1a;
border-radius: 28px;
padding: 24px;
box-shadow: 0 8px 12px rgba(0, 0, 0, 0.2);
}
.swal-title {
color: #ffffff;
font-size: 24px;
font-weight: 500;
margin: 0 0 8px 0;
}
.swal-text {
color: rgba(255, 255, 255, 0.87);
font-size: 16px;
line-height: 1.5;
text-align: center;
margin: 12px 0;
}
.swal-button {
padding: 10px 24px;
border-radius: 20px;
font-size: 14px;
font-weight: 500;
text-transform: uppercase;
transition: background-color 0.2s;
margin: 0 8px;
border: none;
outline: none;
}
.swal-button--confirm {
background-color: #6750A4;
color: #ffffff;
}
.swal-button--confirm:hover {
background-color: #7c65b5;
}
.swal-button--cancel {
background-color: transparent;
color: #6750A4;
}
.swal-button--cancel:hover {
background-color: rgba(103, 80, 164, 0.08);
}
.swal-icon {
border-color: #6750A4;
margin: 12px auto;
}
.swal-icon--success__line {
background-color: #6750A4;
}
.swal-icon--success__ring {
border-color: #6750A4;
}
.swal-icon--warning {
border-color: #F2B824;
}
.swal-icon--warning__body,
.swal-icon--warning__dot {
background-color: #F2B824;
}
.swal-icon--error {
border-color: #DC362E;
}
.swal-icon--error__line {
background-color: #DC362E;
}
.swal-footer {
margin-top: 16px;
padding: 0;
border: none;
text-align: right;
}
</style>
</head>
<body>
<script
src="https://unpkg.com/sweetalert@2.1.2/dist/sweetalert.min.js"
async
></script>
<script src="flutter_bootstrap.js" async></script>
<script>
document.oncontextmenu = (evt) => evt.preventDefault();
</script>
</body>
</html> </html>