feat: change UI of level up slightly and add animated bar before details summary
WIP: add a level up bar animation that plays before details screen when level up banner is clicked on. Also changed banner icon and background color
This commit is contained in:
parent
01d797e53f
commit
c13a316a31
1 changed files with 240 additions and 157 deletions
|
|
@ -1,19 +1,19 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:audioplayers/audioplayers.dart';
|
||||
import 'package:cached_network_image/cached_network_image.dart';
|
||||
import 'package:flutter_gen/gen_l10n/l10n.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/learning_skills_enum.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/constructs/construct_repo.dart';
|
||||
import 'package:fluffychat/widgets/matrix.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
||||
|
||||
class LevelUpConstants {
|
||||
static const String starFileName = "star.png";
|
||||
|
|
@ -88,6 +88,7 @@ class LevelUpBannerState extends State<LevelUpBanner>
|
|||
|
||||
bool _showDetails = false;
|
||||
bool _showedDetails = false;
|
||||
bool _showingLevelingAnimation = false;
|
||||
|
||||
ConstructSummary? _constructSummary;
|
||||
String? _error;
|
||||
|
|
@ -177,9 +178,15 @@ class LevelUpBannerState extends State<LevelUpBanner>
|
|||
if (!Environment.isStagingEnvironment) return;
|
||||
|
||||
if (mounted) {
|
||||
if (!_showedDetails) {
|
||||
setState(() {
|
||||
_showingLevelingAnimation = true;
|
||||
});
|
||||
}
|
||||
|
||||
setState(() {
|
||||
_showDetails = !_showDetails;
|
||||
if (_showDetails && !_showedDetails) {
|
||||
if (_showDetails && _showedDetails) {
|
||||
_showedDetails = true;
|
||||
}
|
||||
});
|
||||
|
|
@ -188,6 +195,14 @@ class LevelUpBannerState extends State<LevelUpBanner>
|
|||
? _sizeController.forward()
|
||||
: _sizeController.reverse());
|
||||
|
||||
if (_showDetails && _showingLevelingAnimation) {
|
||||
await Future.delayed(const Duration(seconds: 2));
|
||||
if (!mounted) return;
|
||||
setState(() {
|
||||
_showingLevelingAnimation = false;
|
||||
});
|
||||
}
|
||||
|
||||
if (!_showDetails) {
|
||||
await Future.delayed(
|
||||
const Duration(milliseconds: 300),
|
||||
|
|
@ -240,9 +255,10 @@ class LevelUpBannerState extends State<LevelUpBanner>
|
|||
top: 16,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.secondaryContainer,
|
||||
color:
|
||||
Theme.of(context).brightness == Brightness.dark
|
||||
? Colors.black
|
||||
: Colors.white,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
padding: const EdgeInsets.symmetric(
|
||||
|
|
@ -258,10 +274,8 @@ class LevelUpBannerState extends State<LevelUpBanner>
|
|||
text: TextSpan(
|
||||
children: [
|
||||
TextSpan(
|
||||
text: L10n.of(context)
|
||||
.congratulationsOnReaching(
|
||||
widget.level,
|
||||
),
|
||||
//Hardcoded for now, put in translations later
|
||||
text: "Level up",
|
||||
style: style,
|
||||
),
|
||||
TextSpan(
|
||||
|
|
@ -287,7 +301,7 @@ class LevelUpBannerState extends State<LevelUpBanner>
|
|||
duration: FluffyThemes.animationDuration,
|
||||
child: _error == null
|
||||
? FluffyThemes.isColumnMode(context)
|
||||
? ElevatedButton(
|
||||
? IconButton(
|
||||
style: IconButton.styleFrom(
|
||||
padding: const EdgeInsets
|
||||
.symmetric(
|
||||
|
|
@ -296,8 +310,11 @@ class LevelUpBannerState extends State<LevelUpBanner>
|
|||
),
|
||||
),
|
||||
onPressed: _toggleDetails,
|
||||
child: Text(
|
||||
L10n.of(context).details,
|
||||
icon: Icon(
|
||||
Icons.arrow_drop_down,
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.onSurface,
|
||||
),
|
||||
)
|
||||
: SizedBox(
|
||||
|
|
@ -337,10 +354,6 @@ class LevelUpBannerState extends State<LevelUpBanner>
|
|||
],
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
icon: const Icon(Icons.close),
|
||||
onPressed: _close,
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
|
|
@ -350,156 +363,168 @@ class LevelUpBannerState extends State<LevelUpBanner>
|
|||
SizeTransition(
|
||||
sizeFactor: _sizeAnimation,
|
||||
child: Container(
|
||||
constraints: BoxConstraints(
|
||||
maxHeight:
|
||||
MediaQuery.of(context).size.height * 0.75,
|
||||
),
|
||||
height: MediaQuery.of(context).size.height * 0.75,
|
||||
width: MediaQuery.of(context).size.width * .5,
|
||||
margin: const EdgeInsets.only(
|
||||
top: 4.0,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.black,
|
||||
color:
|
||||
Theme.of(context).brightness == Brightness.dark
|
||||
? Colors.black
|
||||
: Colors.white,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
spacing: 24.0,
|
||||
children: [
|
||||
Table(
|
||||
columnWidths: const {
|
||||
0: IntrinsicColumnWidth(),
|
||||
1: FlexColumnWidth(),
|
||||
2: IntrinsicColumnWidth(),
|
||||
},
|
||||
defaultVerticalAlignment:
|
||||
TableCellVerticalAlignment.middle,
|
||||
children: [
|
||||
...LearningSkillsEnum.values
|
||||
.where(
|
||||
(v) =>
|
||||
v.isVisible && _skillsPoints(v) > -1,
|
||||
)
|
||||
.map((skill) {
|
||||
return TableRow(
|
||||
child: _showingLevelingAnimation
|
||||
? const Expanded(
|
||||
child: LevelUpBarAnimation(),
|
||||
)
|
||||
: SingleChildScrollView(
|
||||
child: Column(
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.center,
|
||||
spacing: 24.0,
|
||||
children: [
|
||||
Table(
|
||||
columnWidths: const {
|
||||
0: IntrinsicColumnWidth(),
|
||||
1: FlexColumnWidth(),
|
||||
2: IntrinsicColumnWidth(),
|
||||
},
|
||||
defaultVerticalAlignment:
|
||||
TableCellVerticalAlignment.middle,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: 9.0,
|
||||
horizontal: 18.0,
|
||||
),
|
||||
child: Icon(
|
||||
skill.icon,
|
||||
size: 25,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: 9.0,
|
||||
horizontal: 18.0,
|
||||
),
|
||||
child: Text(
|
||||
skill.tooltip(context),
|
||||
style: const TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Colors.white,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: 9.0,
|
||||
horizontal: 18.0,
|
||||
),
|
||||
child: Text(
|
||||
"+ ${_skillsPoints(skill)} XP",
|
||||
style: const TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Colors.white,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
...LearningSkillsEnum.values
|
||||
.where(
|
||||
(v) =>
|
||||
v.isVisible &&
|
||||
_skillsPoints(v) > -1,
|
||||
)
|
||||
.map((skill) {
|
||||
return TableRow(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets
|
||||
.symmetric(
|
||||
vertical: 9.0,
|
||||
horizontal: 18.0,
|
||||
),
|
||||
child: Icon(
|
||||
skill.icon,
|
||||
size: 25,
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.onSurface,
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets
|
||||
.symmetric(
|
||||
vertical: 9.0,
|
||||
horizontal: 18.0,
|
||||
),
|
||||
child: Text(
|
||||
skill.tooltip(context),
|
||||
style: const TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight:
|
||||
FontWeight.w600,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets
|
||||
.symmetric(
|
||||
vertical: 9.0,
|
||||
horizontal: 18.0,
|
||||
),
|
||||
child: Text(
|
||||
"+ ${_skillsPoints(skill)} XP",
|
||||
style: const TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight:
|
||||
FontWeight.w600,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}),
|
||||
],
|
||||
);
|
||||
}),
|
||||
],
|
||||
),
|
||||
CachedNetworkImage(
|
||||
imageUrl:
|
||||
"${AppConfig.assetsBaseURL}/${LevelUpConstants.dinoLevelUPFileName}",
|
||||
width: 400,
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
if (_constructSummary?.textSummary != null)
|
||||
Container(
|
||||
padding: const EdgeInsets.all(12),
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.secondaryContainer,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
child: Text(
|
||||
_constructSummary!.textSummary,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.onSecondaryContainer,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
CachedNetworkImage(
|
||||
imageUrl:
|
||||
"${AppConfig.assetsBaseURL}/${LevelUpConstants.dinoLevelUPFileName}",
|
||||
width: 400,
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
if (_constructSummary?.textSummary !=
|
||||
null)
|
||||
Container(
|
||||
padding: const EdgeInsets.all(12),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.transparent,
|
||||
borderRadius:
|
||||
BorderRadius.circular(8),
|
||||
),
|
||||
child: Text(
|
||||
_constructSummary!.textSummary,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w400,
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.onSecondaryContainer,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 24,
|
||||
),
|
||||
// Share button, currently no functionality
|
||||
// ElevatedButton(
|
||||
// onPressed: () {
|
||||
// // Add share functionality
|
||||
// },
|
||||
// style: ElevatedButton.styleFrom(
|
||||
// backgroundColor: Colors.white,
|
||||
// foregroundColor: Colors.black,
|
||||
// padding: const EdgeInsets.symmetric(
|
||||
// vertical: 12,
|
||||
// horizontal: 24,
|
||||
// ),
|
||||
// shape: RoundedRectangleBorder(
|
||||
// borderRadius: BorderRadius.circular(8),
|
||||
// ),
|
||||
// ),
|
||||
// child: const Row(
|
||||
// mainAxisSize: MainAxisSize
|
||||
// .min,
|
||||
// children: [
|
||||
// Text(
|
||||
// "Share with Friends",
|
||||
// style: TextStyle(
|
||||
// fontSize: 16,
|
||||
// fontWeight: FontWeight.bold,
|
||||
// ),
|
||||
// ),
|
||||
// SizedBox(
|
||||
// width: 8,
|
||||
// ),
|
||||
// Icon(
|
||||
// Icons.ios_share,
|
||||
// size: 20,
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
],
|
||||
),
|
||||
const SizedBox(
|
||||
height: 24,
|
||||
),
|
||||
// Share button, currently no functionality
|
||||
// ElevatedButton(
|
||||
// onPressed: () {
|
||||
// // Add share functionality
|
||||
// },
|
||||
// style: ElevatedButton.styleFrom(
|
||||
// backgroundColor: Colors.white,
|
||||
// foregroundColor: Colors.black,
|
||||
// padding: const EdgeInsets.symmetric(
|
||||
// vertical: 12,
|
||||
// horizontal: 24,
|
||||
// ),
|
||||
// shape: RoundedRectangleBorder(
|
||||
// borderRadius: BorderRadius.circular(8),
|
||||
// ),
|
||||
// ),
|
||||
// child: const Row(
|
||||
// mainAxisSize: MainAxisSize
|
||||
// .min,
|
||||
// children: [
|
||||
// Text(
|
||||
// "Share with Friends",
|
||||
// style: TextStyle(
|
||||
// fontSize: 16,
|
||||
// fontWeight: FontWeight.bold,
|
||||
// ),
|
||||
// ),
|
||||
// SizedBox(
|
||||
// width: 8,
|
||||
// ),
|
||||
// Icon(
|
||||
// Icons.ios_share,
|
||||
// size: 20,
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
|
|
@ -513,3 +538,61 @@ class LevelUpBannerState extends State<LevelUpBanner>
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
//animated progress bar -- move to own file later
|
||||
class LevelUpBarAnimation extends StatefulWidget {
|
||||
const LevelUpBarAnimation({super.key});
|
||||
|
||||
@override
|
||||
State<LevelUpBarAnimation> createState() => _LevelUpBarAnimationState();
|
||||
}
|
||||
|
||||
class _LevelUpBarAnimationState extends State<LevelUpBarAnimation>
|
||||
with SingleTickerProviderStateMixin {
|
||||
late AnimationController _controller;
|
||||
late Animation<double> _animation;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
||||
_controller = AnimationController(
|
||||
duration: const Duration(milliseconds: 1500),
|
||||
vsync: this,
|
||||
);
|
||||
|
||||
_animation = Tween<double>(begin: 0, end: 1).animate(
|
||||
CurvedAnimation(parent: _controller, curve: Curves.easeInOut),
|
||||
);
|
||||
|
||||
_controller.forward();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AnimatedBuilder(
|
||||
animation: _animation,
|
||||
builder: (context, _) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(24),
|
||||
child: ProgressBar(
|
||||
levelBars: [
|
||||
LevelBarDetails(
|
||||
widthMultiplier: _animation.value,
|
||||
currentPoints: 0,
|
||||
fillColor: AppConfig.goldLight,
|
||||
),
|
||||
],
|
||||
height: 20,
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue