Not functional, committing for code review
This commit is contained in:
parent
eaf13337a5
commit
d49d08f67b
5 changed files with 382 additions and 319 deletions
|
|
@ -4,22 +4,9 @@ import 'dart:async';
|
|||
import 'dart:developer';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:device_info_plus/device_info_plus.dart';
|
||||
import 'package:emoji_picker_flutter/emoji_picker_flutter.dart';
|
||||
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:image_picker/image_picker.dart';
|
||||
import 'package:matrix/matrix.dart';
|
||||
import 'package:scroll_to_index/scroll_to_index.dart';
|
||||
import 'package:sentry_flutter/sentry_flutter.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import 'package:universal_html/html.dart' as html;
|
||||
|
||||
import 'package:fluffychat/config/app_config.dart';
|
||||
import 'package:fluffychat/config/setting_keys.dart';
|
||||
import 'package:fluffychat/config/themes.dart';
|
||||
|
|
@ -30,7 +17,7 @@ import 'package:fluffychat/pages/chat_details/chat_details.dart';
|
|||
import 'package:fluffychat/pangea/analytics_misc/construct_type_enum.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/constructs_model.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/gain_points_animation.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/level_up.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/level_up/level_up_banner.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/put_analytics_controller.dart';
|
||||
import 'package:fluffychat/pangea/chat/utils/unlocked_morphs_snackbar.dart';
|
||||
import 'package:fluffychat/pangea/chat/widgets/event_too_large_dialog.dart';
|
||||
|
|
@ -66,6 +53,18 @@ import 'package:fluffychat/widgets/adaptive_dialogs/show_text_input_dialog.dart'
|
|||
import 'package:fluffychat/widgets/future_loading_dialog.dart';
|
||||
import 'package:fluffychat/widgets/matrix.dart';
|
||||
import 'package:fluffychat/widgets/share_scaffold_dialog.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:image_picker/image_picker.dart';
|
||||
import 'package:matrix/matrix.dart';
|
||||
import 'package:scroll_to_index/scroll_to_index.dart';
|
||||
import 'package:sentry_flutter/sentry_flutter.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import 'package:universal_html/html.dart' as html;
|
||||
|
||||
import '../../utils/account_bundles.dart';
|
||||
import '../../utils/localized_exception_extension.dart';
|
||||
import 'send_file_dialog.dart';
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import 'package:flutter/material.dart';
|
|||
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
||||
|
||||
//import for testing level up
|
||||
import '../../pangea/analytics_misc/level_up.dart';
|
||||
import '../../pangea/analytics_misc/level_up/level_up_banner.dart';
|
||||
import 'settings_chat.dart';
|
||||
|
||||
class SettingsChatView extends StatelessWidget {
|
||||
|
|
@ -34,8 +34,8 @@ class SettingsChatView extends StatelessWidget {
|
|||
// Test button for leveling up
|
||||
onPressed: () {
|
||||
LevelUpUtil.showLevelUpDialog(
|
||||
5,
|
||||
4,
|
||||
3,
|
||||
context,
|
||||
);
|
||||
},
|
||||
|
|
|
|||
267
lib/pangea/analytics_misc/level_up/level_up_banner.dart
Normal file
267
lib/pangea/analytics_misc/level_up/level_up_banner.dart
Normal file
|
|
@ -0,0 +1,267 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:audioplayers/audioplayers.dart';
|
||||
import 'package:cached_network_image/cached_network_image.dart';
|
||||
import 'package:fluffychat/config/app_config.dart';
|
||||
import 'package:fluffychat/config/themes.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/analytics_constants.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/level_up/level_up_manager.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/level_up/level_up_popup.dart';
|
||||
import 'package:fluffychat/pangea/common/config/environment.dart';
|
||||
import 'package:fluffychat/pangea/common/utils/overlay.dart';
|
||||
import 'package:fluffychat/widgets/matrix.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class LevelUpConstants {
|
||||
static const String starFileName = "star.png";
|
||||
static const String dinoLevelUPFileName = "DinoBot-Congratulate.png";
|
||||
}
|
||||
|
||||
class LevelUpUtil {
|
||||
static Future<void> showLevelUpDialog(
|
||||
int level,
|
||||
int prevLevel,
|
||||
BuildContext context,
|
||||
) async {
|
||||
final player = AudioPlayer();
|
||||
|
||||
final snackbarRegex = RegExp(r'_snackbar$');
|
||||
|
||||
while (MatrixState.pAnyState.activeOverlays
|
||||
.any((overlayId) => snackbarRegex.hasMatch(overlayId))) {
|
||||
await Future.delayed(const Duration(milliseconds: 100));
|
||||
}
|
||||
|
||||
player
|
||||
.play(
|
||||
UrlSource(
|
||||
"${AppConfig.assetsBaseURL}/${AnalyticsConstants.levelUpAudioFileName}",
|
||||
),
|
||||
)
|
||||
.then(
|
||||
(_) => Future.delayed(
|
||||
const Duration(seconds: 2),
|
||||
() => player.dispose(),
|
||||
),
|
||||
);
|
||||
|
||||
OverlayUtil.showOverlay(
|
||||
overlayKey: "level_up_notification",
|
||||
context: context,
|
||||
child: LevelUpBanner(
|
||||
level: level,
|
||||
prevLevel: prevLevel,
|
||||
backButtonOverride: IconButton(
|
||||
icon: const Icon(Icons.close),
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
),
|
||||
),
|
||||
transformTargetId: '',
|
||||
position: OverlayPositionEnum.top,
|
||||
backDropToDismiss: false,
|
||||
closePrevOverlay: false,
|
||||
canPop: false,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class LevelUpBanner extends StatefulWidget {
|
||||
final int level;
|
||||
final int prevLevel;
|
||||
final Widget? backButtonOverride;
|
||||
|
||||
const LevelUpBanner({
|
||||
required this.level,
|
||||
required this.prevLevel,
|
||||
required this.backButtonOverride,
|
||||
super.key,
|
||||
});
|
||||
|
||||
@override
|
||||
LevelUpBannerState createState() => LevelUpBannerState();
|
||||
}
|
||||
|
||||
class LevelUpBannerState extends State<LevelUpBanner>
|
||||
with TickerProviderStateMixin {
|
||||
late AnimationController _slideController;
|
||||
late Animation<Offset> _slideAnimation;
|
||||
|
||||
bool _showedDetails = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
||||
LevelUpManager().preloadAnalytics(
|
||||
context,
|
||||
widget.level,
|
||||
widget.prevLevel,
|
||||
);
|
||||
|
||||
LevelUpManager().shouldAutoPopup = true;
|
||||
|
||||
LevelUpManager().printAnalytics();
|
||||
|
||||
_slideController = AnimationController(
|
||||
vsync: this,
|
||||
duration: FluffyThemes.animationDuration,
|
||||
);
|
||||
|
||||
_slideAnimation = Tween<Offset>(
|
||||
begin: const Offset(0, -1),
|
||||
end: Offset.zero,
|
||||
).animate(
|
||||
CurvedAnimation(
|
||||
parent: _slideController,
|
||||
curve: Curves.easeOut,
|
||||
),
|
||||
);
|
||||
|
||||
_slideController.forward();
|
||||
|
||||
Future.delayed(const Duration(seconds: 10), () async {
|
||||
if (mounted && !_showedDetails) {}
|
||||
_close();
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> _close() async {
|
||||
await _slideController.reverse();
|
||||
MatrixState.pAnyState.closeOverlay("level_up_notification");
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_slideController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
Future<void> _toggleDetails() async {
|
||||
await _close();
|
||||
LevelUpManager().markPopupSeen();
|
||||
_showedDetails = true;
|
||||
|
||||
await showDialog(
|
||||
context: context,
|
||||
builder: (context) => LevelUpPopup(widget: widget),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final isColumnMode = FluffyThemes.isColumnMode(context);
|
||||
|
||||
final style = isColumnMode
|
||||
? Theme.of(context).textTheme.titleLarge?.copyWith(
|
||||
color: AppConfig.gold,
|
||||
fontWeight: FontWeight.bold,
|
||||
letterSpacing: 0.5,
|
||||
)
|
||||
: Theme.of(context).textTheme.bodyLarge?.copyWith(
|
||||
color: AppConfig.gold,
|
||||
fontWeight: FontWeight.bold,
|
||||
letterSpacing: 0.5,
|
||||
);
|
||||
|
||||
return SafeArea(
|
||||
child: Material(
|
||||
type: MaterialType.transparency,
|
||||
child: SlideTransition(
|
||||
position: _slideAnimation,
|
||||
child: LayoutBuilder(
|
||||
builder: (context, constraints) {
|
||||
return GestureDetector(
|
||||
onPanUpdate: (details) {
|
||||
if (details.delta.dy < -10) _close();
|
||||
},
|
||||
onTap: _toggleDetails,
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: 16.0,
|
||||
horizontal: 4.0,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).colorScheme.surface,
|
||||
border: Border(
|
||||
bottom: BorderSide(
|
||||
color: AppConfig.gold.withAlpha(200),
|
||||
width: 2.0,
|
||||
),
|
||||
),
|
||||
borderRadius: const BorderRadius.only(
|
||||
bottomLeft: Radius.circular(AppConfig.borderRadius),
|
||||
bottomRight: Radius.circular(AppConfig.borderRadius),
|
||||
),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
// Spacer for symmetry
|
||||
SizedBox(
|
||||
width: constraints.maxWidth >= 600 ? 120.0 : 65.0,
|
||||
),
|
||||
// Centered content
|
||||
Expanded(
|
||||
child: Padding(
|
||||
padding: EdgeInsets.symmetric(
|
||||
horizontal: isColumnMode ? 16.0 : 8.0,
|
||||
),
|
||||
child: Wrap(
|
||||
spacing: 16.0,
|
||||
alignment: WrapAlignment.center,
|
||||
crossAxisAlignment: WrapCrossAlignment.center,
|
||||
children: [
|
||||
Text(
|
||||
"Level up",
|
||||
style: style,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
CachedNetworkImage(
|
||||
imageUrl:
|
||||
"${AppConfig.assetsBaseURL}/${LevelUpConstants.starFileName}",
|
||||
height: 24,
|
||||
width: 24,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
// Optional staging-only dropdown icon
|
||||
SizedBox(
|
||||
width: constraints.maxWidth >= 600 ? 120.0 : 65.0,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
if (Environment.isStagingEnvironment)
|
||||
SizedBox(
|
||||
width: 32.0,
|
||||
height: 32.0,
|
||||
child: Center(
|
||||
child: IconButton(
|
||||
icon: const Icon(Icons.arrow_drop_down),
|
||||
style: IconButton.styleFrom(
|
||||
padding: const EdgeInsets.all(4.0),
|
||||
),
|
||||
onPressed: _toggleDetails,
|
||||
constraints: const BoxConstraints(),
|
||||
color:
|
||||
Theme.of(context).colorScheme.onSurface,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
95
lib/pangea/analytics_misc/level_up/level_up_manager.dart
Normal file
95
lib/pangea/analytics_misc/level_up/level_up_manager.dart
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
import 'package:fluffychat/pangea/analytics_misc/construct_type_enum.dart';
|
||||
import 'package:fluffychat/pangea/constructs/construct_repo.dart';
|
||||
import 'package:fluffychat/widgets/matrix.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class LevelUpManager {
|
||||
LevelUpManager._internal();
|
||||
factory LevelUpManager() {
|
||||
return _instance;
|
||||
}
|
||||
static final LevelUpManager _instance = LevelUpManager._internal();
|
||||
|
||||
int? prevLevel;
|
||||
int? level;
|
||||
|
||||
int? prevGrammar;
|
||||
int? nextGrammar;
|
||||
int? prevVocab;
|
||||
int? nextVocab;
|
||||
|
||||
ConstructSummary? constructSummary;
|
||||
|
||||
bool hasSeenPopup = false;
|
||||
bool shouldAutoPopup = false;
|
||||
String? error;
|
||||
|
||||
Future<void> preloadAnalytics(
|
||||
BuildContext context,
|
||||
int level,
|
||||
int prevLevel,
|
||||
) async {
|
||||
this.level = level;
|
||||
this.prevLevel = prevLevel;
|
||||
|
||||
//grammar and vocab
|
||||
nextGrammar = MatrixState.pangeaController.getAnalytics.constructListModel
|
||||
.unlockedLemmas(
|
||||
ConstructTypeEnum.morph,
|
||||
)
|
||||
.length;
|
||||
|
||||
nextVocab = MatrixState.pangeaController.getAnalytics.constructListModel
|
||||
.unlockedLemmas(
|
||||
ConstructTypeEnum.vocab,
|
||||
)
|
||||
.length;
|
||||
|
||||
//for now idk how to get these
|
||||
prevGrammar = 0;
|
||||
prevVocab = 0;
|
||||
|
||||
//fetch construct summary
|
||||
try {
|
||||
constructSummary = await MatrixState.pangeaController.getAnalytics
|
||||
.generateLevelUpAnalytics(
|
||||
level,
|
||||
prevLevel,
|
||||
);
|
||||
} catch (e) {
|
||||
error = e.toString();
|
||||
}
|
||||
}
|
||||
|
||||
void markPopupSeen() {
|
||||
hasSeenPopup = true;
|
||||
shouldAutoPopup = false;
|
||||
}
|
||||
|
||||
void printAnalytics() {
|
||||
print('Level Up Analytics:');
|
||||
print('Current Level: $level');
|
||||
print('Previous Level: $prevLevel');
|
||||
print('Next Grammar: $nextGrammar');
|
||||
print('Next Vocab: $nextVocab');
|
||||
if (constructSummary != null) {
|
||||
print('Construct Summary: ${constructSummary!.toJson()}');
|
||||
} else {
|
||||
print('Construct Summary: Not available');
|
||||
}
|
||||
}
|
||||
|
||||
void reset() {
|
||||
hasSeenPopup = false;
|
||||
shouldAutoPopup = false;
|
||||
prevLevel = null;
|
||||
level = null;
|
||||
prevGrammar = null;
|
||||
nextGrammar = null;
|
||||
prevVocab = null;
|
||||
nextVocab = null;
|
||||
constructSummary = null;
|
||||
error = null;
|
||||
// Reset any other state if necessary
|
||||
}
|
||||
}
|
||||
|
|
@ -1,18 +1,14 @@
|
|||
import 'dart:async';
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:audioplayers/audioplayers.dart';
|
||||
import 'package:cached_network_image/cached_network_image.dart';
|
||||
import 'package:confetti/confetti.dart';
|
||||
import 'package:fluffychat/config/app_config.dart';
|
||||
import 'package:fluffychat/config/themes.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/analytics_constants.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/construct_type_enum.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/learning_skills_enum.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/level_up/level_up_banner.dart';
|
||||
import 'package:fluffychat/pangea/analytics_summary/progress_bar/progress_bar.dart';
|
||||
import 'package:fluffychat/pangea/analytics_summary/progress_bar/progress_bar_details.dart';
|
||||
import 'package:fluffychat/pangea/common/config/environment.dart';
|
||||
import 'package:fluffychat/pangea/common/utils/overlay.dart';
|
||||
import 'package:fluffychat/pangea/common/widgets/full_width_dialog.dart';
|
||||
import 'package:fluffychat/pangea/constructs/construct_repo.dart';
|
||||
import 'package:fluffychat/widgets/matrix.dart';
|
||||
|
|
@ -23,257 +19,6 @@ import 'package:flutter_gen/gen_l10n/l10n.dart';
|
|||
import 'package:material_symbols_icons/symbols.dart';
|
||||
import 'package:matrix/matrix_api_lite/generated/model.dart';
|
||||
|
||||
class LevelUpConstants {
|
||||
static const String starFileName = "star.png";
|
||||
static const String dinoLevelUPFileName = "DinoBot-Congratulate.png";
|
||||
}
|
||||
|
||||
class LevelUpUtil {
|
||||
static Future<void> showLevelUpDialog(
|
||||
int level,
|
||||
int prevLevel,
|
||||
BuildContext context,
|
||||
) async {
|
||||
final player = AudioPlayer();
|
||||
|
||||
final snackbarRegex = RegExp(r'_snackbar$');
|
||||
|
||||
while (MatrixState.pAnyState.activeOverlays
|
||||
.any((overlayId) => snackbarRegex.hasMatch(overlayId))) {
|
||||
await Future.delayed(const Duration(milliseconds: 100));
|
||||
}
|
||||
|
||||
player
|
||||
.play(
|
||||
UrlSource(
|
||||
"${AppConfig.assetsBaseURL}/${AnalyticsConstants.levelUpAudioFileName}",
|
||||
),
|
||||
)
|
||||
.then(
|
||||
(_) => Future.delayed(
|
||||
const Duration(seconds: 2),
|
||||
() => player.dispose(),
|
||||
),
|
||||
);
|
||||
|
||||
OverlayUtil.showOverlay(
|
||||
overlayKey: "level_up_notification",
|
||||
context: context,
|
||||
child: LevelUpBanner(
|
||||
level: level,
|
||||
prevLevel: prevLevel,
|
||||
backButtonOverride: IconButton(
|
||||
icon: const Icon(Icons.close),
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
),
|
||||
),
|
||||
transformTargetId: '',
|
||||
position: OverlayPositionEnum.top,
|
||||
backDropToDismiss: false,
|
||||
closePrevOverlay: false,
|
||||
canPop: false,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class LevelUpBanner extends StatefulWidget {
|
||||
final int level;
|
||||
final int prevLevel;
|
||||
final Widget? backButtonOverride;
|
||||
|
||||
const LevelUpBanner({
|
||||
required this.level,
|
||||
required this.prevLevel,
|
||||
required this.backButtonOverride,
|
||||
super.key,
|
||||
});
|
||||
|
||||
@override
|
||||
LevelUpBannerState createState() => LevelUpBannerState();
|
||||
}
|
||||
|
||||
class LevelUpBannerState extends State<LevelUpBanner>
|
||||
with TickerProviderStateMixin {
|
||||
late AnimationController _slideController;
|
||||
late Animation<Offset> _slideAnimation;
|
||||
|
||||
late AnimationController _sizeController;
|
||||
|
||||
final bool _showedDetails = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
||||
_slideController = AnimationController(
|
||||
vsync: this,
|
||||
duration: FluffyThemes.animationDuration,
|
||||
);
|
||||
|
||||
_slideAnimation = Tween<Offset>(
|
||||
begin: const Offset(0, -1),
|
||||
end: Offset.zero,
|
||||
).animate(
|
||||
CurvedAnimation(
|
||||
parent: _slideController,
|
||||
curve: Curves.easeOut,
|
||||
),
|
||||
);
|
||||
|
||||
_sizeController = AnimationController(
|
||||
vsync: this,
|
||||
duration: FluffyThemes.animationDuration,
|
||||
);
|
||||
|
||||
_slideController.forward();
|
||||
|
||||
Future.delayed(const Duration(seconds: 10), () async {
|
||||
if (mounted && !_showedDetails) _close();
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> _close() async {
|
||||
await _slideController.reverse();
|
||||
MatrixState.pAnyState.closeOverlay("level_up_notification");
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_slideController.dispose();
|
||||
_sizeController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
Future<void> _toggleDetails() async {
|
||||
await _close();
|
||||
|
||||
//if (!mounted) return;
|
||||
|
||||
await showDialog(
|
||||
context: context,
|
||||
builder: (context) => LevelUpPopup(widget: widget),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final isColumnMode = FluffyThemes.isColumnMode(context);
|
||||
|
||||
final style = isColumnMode
|
||||
? Theme.of(context).textTheme.titleLarge?.copyWith(
|
||||
color: AppConfig.gold,
|
||||
fontWeight: FontWeight.bold,
|
||||
letterSpacing: 0.5,
|
||||
)
|
||||
: Theme.of(context).textTheme.bodyLarge?.copyWith(
|
||||
color: AppConfig.gold,
|
||||
fontWeight: FontWeight.bold,
|
||||
letterSpacing: 0.5,
|
||||
);
|
||||
|
||||
return SafeArea(
|
||||
child: Material(
|
||||
type: MaterialType.transparency,
|
||||
child: SlideTransition(
|
||||
position: _slideAnimation,
|
||||
child: LayoutBuilder(
|
||||
builder: (context, constraints) {
|
||||
return GestureDetector(
|
||||
onPanUpdate: (details) {
|
||||
if (details.delta.dy < -10) _close();
|
||||
},
|
||||
onTap: _toggleDetails,
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: 16.0,
|
||||
horizontal: 4.0,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).colorScheme.surface,
|
||||
border: Border(
|
||||
bottom: BorderSide(
|
||||
color: AppConfig.gold.withAlpha(200),
|
||||
width: 2.0,
|
||||
),
|
||||
),
|
||||
borderRadius: const BorderRadius.only(
|
||||
bottomLeft: Radius.circular(AppConfig.borderRadius),
|
||||
bottomRight: Radius.circular(AppConfig.borderRadius),
|
||||
),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
// Spacer for symmetry
|
||||
SizedBox(
|
||||
width: constraints.maxWidth >= 600 ? 120.0 : 65.0,
|
||||
),
|
||||
// Centered content
|
||||
Expanded(
|
||||
child: Padding(
|
||||
padding: EdgeInsets.symmetric(
|
||||
horizontal: isColumnMode ? 16.0 : 8.0,
|
||||
),
|
||||
child: Wrap(
|
||||
spacing: 16.0,
|
||||
alignment: WrapAlignment.center,
|
||||
crossAxisAlignment: WrapCrossAlignment.center,
|
||||
children: [
|
||||
Text(
|
||||
"Level up",
|
||||
style: style,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
CachedNetworkImage(
|
||||
imageUrl:
|
||||
"${AppConfig.assetsBaseURL}/${LevelUpConstants.starFileName}",
|
||||
height: 24,
|
||||
width: 24,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
// Optional staging-only dropdown icon
|
||||
SizedBox(
|
||||
width: constraints.maxWidth >= 600 ? 120.0 : 65.0,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
if (Environment.isStagingEnvironment)
|
||||
SizedBox(
|
||||
width: 32.0,
|
||||
height: 32.0,
|
||||
child: Center(
|
||||
child: IconButton(
|
||||
icon: const Icon(Icons.arrow_drop_down),
|
||||
style: IconButton.styleFrom(
|
||||
padding: const EdgeInsets.all(4.0),
|
||||
),
|
||||
onPressed: _toggleDetails,
|
||||
constraints: const BoxConstraints(),
|
||||
color:
|
||||
Theme.of(context).colorScheme.onSurface,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class LevelUpPopup extends StatelessWidget {
|
||||
const LevelUpPopup({
|
||||
super.key,
|
||||
|
|
@ -334,7 +79,7 @@ class _LevelUpBarAnimationState extends State<LevelUpBarAnimation>
|
|||
late final Animation<int> _grammarAnimation;
|
||||
late final Animation<double> _skillsOpacity;
|
||||
late final Animation<double> _shrinkMultiplier;
|
||||
late final Uri? avatarUrl;
|
||||
Uri? avatarUrl;
|
||||
late final Future<Profile> profile;
|
||||
|
||||
late final ConfettiController _confettiController;
|
||||
|
|
@ -423,7 +168,9 @@ class _LevelUpBarAnimationState extends State<LevelUpBarAnimation>
|
|||
),
|
||||
);
|
||||
|
||||
_controller.forward();
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
_controller.forward(); // or start your animation
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> _setConstructSummary() async {
|
||||
|
|
@ -515,51 +262,6 @@ class _LevelUpBarAnimationState extends State<LevelUpBarAnimation>
|
|||
],
|
||||
),
|
||||
),
|
||||
// Avatar and language
|
||||
/*AnimatedBuilder(
|
||||
animation: _progressAnimation,
|
||||
builder: (_, __) => Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
FutureBuilder<Profile>(
|
||||
future: client.fetchOwnProfile(),
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.connectionState != ConnectionState.done) {
|
||||
return const CircularProgressIndicator(); // Or a skeleton
|
||||
}
|
||||
if (snapshot.hasError) {
|
||||
print("Profile fetch error: ${snapshot.error}");
|
||||
return const Text("Error loading profile");
|
||||
}
|
||||
|
||||
if (!snapshot.hasData || snapshot.data == null) {
|
||||
print("No profile data!");
|
||||
return const Text("No data");
|
||||
}
|
||||
|
||||
|
||||
return ListTile(
|
||||
leading: Avatar(
|
||||
mxContent: snapshot.data?.avatarUrl,
|
||||
size: 20,
|
||||
),
|
||||
title: Text(profile?.displayName ?? client.userID!),
|
||||
contentPadding: EdgeInsets.zero,
|
||||
);
|
||||
},
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
Text(
|
||||
language,
|
||||
style: TextStyle(
|
||||
fontSize: 24 * _skillsOpacity.value,
|
||||
color: AppConfig.goldLight,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),*/
|
||||
// Progress bar + Level
|
||||
AnimatedBuilder(
|
||||
animation: _progressAnimation,
|
||||
Loading…
Add table
Reference in a new issue