chore: simplify progress bar widget
This commit is contained in:
parent
be0ed2fa1a
commit
43014b3207
9 changed files with 118 additions and 304 deletions
|
|
@ -0,0 +1,43 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:fluffychat/config/app_config.dart';
|
||||
import 'package:fluffychat/pangea/analytics_summary/progress_bar/animated_progress_bar.dart';
|
||||
|
||||
class LevelPopupProgressBar extends StatefulWidget {
|
||||
final double height;
|
||||
final Duration duration;
|
||||
|
||||
const LevelPopupProgressBar({
|
||||
required this.height,
|
||||
required this.duration,
|
||||
super.key,
|
||||
});
|
||||
|
||||
@override
|
||||
LevelPopupProgressBarState createState() => LevelPopupProgressBarState();
|
||||
}
|
||||
|
||||
class LevelPopupProgressBarState extends State<LevelPopupProgressBar> {
|
||||
double width = 0.0;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
setState(() {
|
||||
width = 1.0;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AnimatedProgressBar(
|
||||
height: widget.height,
|
||||
widthPercent: width,
|
||||
barColor: AppConfig.goldLight,
|
||||
backgroundColor: Theme.of(context).colorScheme.secondaryContainer,
|
||||
duration: widget.duration,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -12,11 +12,10 @@ import 'package:matrix/matrix_api_lite/generated/model.dart';
|
|||
import 'package:fluffychat/config/app_config.dart';
|
||||
import 'package:fluffychat/l10n/l10n.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/learning_skills_enum.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/level_up/level_popup_progess_bar.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/level_up/level_up_banner.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/level_up/level_up_manager.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/level_up/star_rain_widget.dart';
|
||||
import 'package:fluffychat/pangea/analytics_summary/progress_bar/level_bar.dart';
|
||||
import 'package:fluffychat/pangea/analytics_summary/progress_bar/progress_bar_details.dart';
|
||||
import 'package:fluffychat/pangea/common/widgets/error_indicator.dart';
|
||||
import 'package:fluffychat/pangea/common/widgets/full_width_dialog.dart';
|
||||
import 'package:fluffychat/pangea/constructs/construct_repo.dart';
|
||||
|
|
@ -193,11 +192,6 @@ class _LevelUpPopupContentState extends State<LevelUpPopupContent>
|
|||
@override
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final Animation<double> progressAnimation =
|
||||
Tween<double>(begin: 0, end: 1).animate(
|
||||
CurvedAnimation(parent: _controller, curve: const Interval(0.0, 0.5)),
|
||||
);
|
||||
|
||||
final Animation<int> vocabAnimation =
|
||||
IntTween(begin: _startVocab, end: _endVocab).animate(
|
||||
CurvedAnimation(
|
||||
|
|
@ -282,23 +276,10 @@ class _LevelUpPopupContentState extends State<LevelUpPopupContent>
|
|||
animation: _controller,
|
||||
builder: (_, __) => Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: LayoutBuilder(
|
||||
builder: (context, constraints) {
|
||||
return LevelBar(
|
||||
details: const LevelBarDetails(
|
||||
fillColor: AppConfig.goldLight,
|
||||
currentPoints: 0,
|
||||
widthMultiplier: 1,
|
||||
),
|
||||
progressBarDetails: ProgressBarDetails(
|
||||
totalWidth: constraints.maxWidth *
|
||||
progressAnimation.value,
|
||||
height: 20,
|
||||
borderColor: colorScheme.primary,
|
||||
),
|
||||
);
|
||||
},
|
||||
const Expanded(
|
||||
child: LevelPopupProgressBar(
|
||||
height: 20,
|
||||
duration: Duration(milliseconds: 1000),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
|
|
|
|||
|
|
@ -1,21 +1,20 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:fluffychat/config/app_config.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/analytics_summary/progress_bar/animated_progress_bar.dart';
|
||||
import 'package:fluffychat/widgets/matrix.dart';
|
||||
|
||||
class LearningProgressBar extends StatelessWidget {
|
||||
final int level;
|
||||
final int totalXP;
|
||||
final double? height;
|
||||
final double height;
|
||||
final bool loading;
|
||||
|
||||
const LearningProgressBar({
|
||||
required this.level,
|
||||
required this.totalXP,
|
||||
required this.loading,
|
||||
this.height,
|
||||
required this.height,
|
||||
super.key,
|
||||
});
|
||||
|
||||
|
|
@ -30,16 +29,12 @@ class LearningProgressBar extends StatelessWidget {
|
|||
),
|
||||
);
|
||||
}
|
||||
return ProgressBar(
|
||||
|
||||
return AnimatedProgressBar(
|
||||
height: height,
|
||||
levelBars: [
|
||||
LevelBarDetails(
|
||||
fillColor: Theme.of(context).colorScheme.primary,
|
||||
currentPoints: totalXP,
|
||||
widthMultiplier:
|
||||
MatrixState.pangeaController.getAnalytics.levelProgress,
|
||||
),
|
||||
],
|
||||
widthPercent: MatrixState.pangeaController.getAnalytics.levelProgress,
|
||||
barColor: AppConfig.goldLight,
|
||||
backgroundColor: Theme.of(context).colorScheme.secondaryContainer,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,105 +0,0 @@
|
|||
import 'dart:math';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:fluffychat/config/app_config.dart';
|
||||
import 'package:fluffychat/config/themes.dart';
|
||||
|
||||
class AnimatedLevelBar extends StatefulWidget {
|
||||
final double height;
|
||||
final double beginWidth;
|
||||
final double endWidth;
|
||||
final Color primaryColor;
|
||||
|
||||
const AnimatedLevelBar({
|
||||
super.key,
|
||||
required this.height,
|
||||
required this.beginWidth,
|
||||
required this.endWidth,
|
||||
required this.primaryColor,
|
||||
});
|
||||
|
||||
@override
|
||||
AnimatedLevelBarState createState() => AnimatedLevelBarState();
|
||||
}
|
||||
|
||||
class AnimatedLevelBarState extends State<AnimatedLevelBar>
|
||||
with SingleTickerProviderStateMixin {
|
||||
late AnimationController _controller;
|
||||
|
||||
double get _beginWidth =>
|
||||
widget.beginWidth == 0 ? 0 : max(20, widget.beginWidth);
|
||||
double get _endWidth => widget.endWidth == 0 ? 0 : max(20, widget.endWidth);
|
||||
|
||||
/// Whether the animation has run for the first time during initState. Don't
|
||||
/// want the animation to run when the widget mounts, only when points are gained.
|
||||
bool _init = true;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_controller = AnimationController(
|
||||
vsync: this,
|
||||
duration: FluffyThemes.animationDuration,
|
||||
);
|
||||
|
||||
_controller.forward().then((_) => _init = false);
|
||||
}
|
||||
|
||||
@override
|
||||
void didUpdateWidget(covariant AnimatedLevelBar oldWidget) {
|
||||
super.didUpdateWidget(oldWidget);
|
||||
if ((oldWidget.endWidth == 0 ? 0 : max(20, oldWidget.endWidth)) !=
|
||||
(widget.endWidth == 0 ? 0 : max(20, widget.endWidth))) {
|
||||
_controller.reset();
|
||||
_controller.forward();
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
Animation<double> get _animation {
|
||||
// If this is the first run of the animation, don't animate. This is just the widget mounting,
|
||||
// not a points gain. This could instead be 'if going from 0 to a non-zero value', but that
|
||||
// would remove the animation for first points gained. It would remove the need for a flag though.
|
||||
if (_init) {
|
||||
return Tween<double>(
|
||||
begin: _endWidth,
|
||||
end: _endWidth,
|
||||
).animate(_controller);
|
||||
}
|
||||
|
||||
// animate the width of the bar
|
||||
return Tween<double>(
|
||||
begin: _beginWidth,
|
||||
end: _endWidth,
|
||||
).animate(_controller);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AnimatedBuilder(
|
||||
animation: _animation,
|
||||
builder: (context, child) {
|
||||
return Stack(
|
||||
children: [
|
||||
Container(
|
||||
height: widget.height,
|
||||
width: _animation.value,
|
||||
decoration: BoxDecoration(
|
||||
color: widget.primaryColor,
|
||||
borderRadius: const BorderRadius.all(
|
||||
Radius.circular(AppConfig.borderRadius),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:fluffychat/config/app_config.dart';
|
||||
import 'package:fluffychat/config/themes.dart';
|
||||
|
||||
class AnimatedProgressBar extends StatelessWidget {
|
||||
final double height;
|
||||
final double widthPercent;
|
||||
|
||||
final Color barColor;
|
||||
final Color backgroundColor;
|
||||
final Duration? duration;
|
||||
|
||||
const AnimatedProgressBar({
|
||||
required this.height,
|
||||
required this.widthPercent,
|
||||
required this.barColor,
|
||||
required this.backgroundColor,
|
||||
this.duration,
|
||||
super.key,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return LayoutBuilder(
|
||||
builder: (context, constraints) {
|
||||
return Stack(
|
||||
alignment: Alignment.centerLeft,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 2),
|
||||
child: Container(
|
||||
height: height,
|
||||
width: constraints.maxWidth,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: const BorderRadius.all(
|
||||
Radius.circular(AppConfig.borderRadius),
|
||||
),
|
||||
color: backgroundColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 2),
|
||||
child: AnimatedContainer(
|
||||
duration: duration ?? FluffyThemes.animationDuration,
|
||||
height: height,
|
||||
width: constraints.maxWidth * widthPercent,
|
||||
decoration: BoxDecoration(
|
||||
color: barColor,
|
||||
borderRadius: const BorderRadius.all(
|
||||
Radius.circular(AppConfig.borderRadius),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,43 +0,0 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:fluffychat/config/app_config.dart';
|
||||
import 'package:fluffychat/pangea/analytics_summary/progress_bar/animated_level_dart.dart';
|
||||
import 'package:fluffychat/pangea/analytics_summary/progress_bar/progress_bar_details.dart';
|
||||
|
||||
class LevelBar extends StatefulWidget {
|
||||
final LevelBarDetails details;
|
||||
final ProgressBarDetails progressBarDetails;
|
||||
|
||||
const LevelBar({
|
||||
super.key,
|
||||
required this.details,
|
||||
required this.progressBarDetails,
|
||||
});
|
||||
|
||||
@override
|
||||
LevelBarState createState() => LevelBarState();
|
||||
}
|
||||
|
||||
class LevelBarState extends State<LevelBar> {
|
||||
double prevWidth = 0;
|
||||
double get width =>
|
||||
widget.progressBarDetails.totalWidth * widget.details.widthMultiplier;
|
||||
|
||||
@override
|
||||
void didUpdateWidget(covariant LevelBar oldWidget) {
|
||||
super.didUpdateWidget(oldWidget);
|
||||
if (oldWidget.details.currentPoints != widget.details.currentPoints) {
|
||||
setState(() => prevWidth = width);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AnimatedLevelBar(
|
||||
height: widget.progressBarDetails.height,
|
||||
beginWidth: prevWidth,
|
||||
endWidth: width,
|
||||
primaryColor: AppConfig.goldLight,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,64 +0,0 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:fluffychat/pangea/analytics_summary/progress_bar/level_bar.dart';
|
||||
import 'package:fluffychat/pangea/analytics_summary/progress_bar/progress_bar_background.dart';
|
||||
import 'package:fluffychat/pangea/analytics_summary/progress_bar/progress_bar_details.dart';
|
||||
|
||||
// Provide an order list of level indicators, each with it's color
|
||||
// and stream. Also provide an overall width and pointsPerLevel.
|
||||
|
||||
class ProgressBar extends StatefulWidget {
|
||||
final List<LevelBarDetails> levelBars;
|
||||
final double? height;
|
||||
|
||||
const ProgressBar({
|
||||
super.key,
|
||||
required this.levelBars,
|
||||
this.height,
|
||||
});
|
||||
|
||||
@override
|
||||
ProgressBarState createState() => ProgressBarState();
|
||||
}
|
||||
|
||||
class ProgressBarState extends State<ProgressBar> {
|
||||
double width = 0;
|
||||
void setWidth(double newWidth) {
|
||||
if (width != newWidth) {
|
||||
setState(() => width = newWidth);
|
||||
}
|
||||
}
|
||||
|
||||
get progressBarDetails => ProgressBarDetails(
|
||||
totalWidth: width,
|
||||
borderColor: Theme.of(context).colorScheme.secondaryContainer,
|
||||
height: widget.height ?? 14,
|
||||
);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return LayoutBuilder(
|
||||
builder: (context, constraints) {
|
||||
if (width != constraints.maxWidth) {
|
||||
WidgetsBinding.instance.addPostFrameCallback(
|
||||
(_) => setWidth(constraints.maxWidth),
|
||||
);
|
||||
}
|
||||
return Stack(
|
||||
alignment: Alignment.centerLeft,
|
||||
children: [
|
||||
ProgressBarBackground(details: progressBarDetails),
|
||||
for (final levelBar in widget.levelBars)
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 2),
|
||||
child: LevelBar(
|
||||
details: levelBar,
|
||||
progressBarDetails: progressBarDetails,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:fluffychat/config/app_config.dart';
|
||||
import 'package:fluffychat/pangea/analytics_summary/progress_bar/progress_bar_details.dart';
|
||||
|
||||
class ProgressBarBackground extends StatelessWidget {
|
||||
final ProgressBarDetails details;
|
||||
|
||||
const ProgressBarBackground({
|
||||
super.key,
|
||||
required this.details,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 2),
|
||||
child: Container(
|
||||
height: details.height,
|
||||
width: details.totalWidth,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: const BorderRadius.all(
|
||||
Radius.circular(AppConfig.borderRadius),
|
||||
),
|
||||
color: details.borderColor,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,25 +0,0 @@
|
|||
import 'dart:ui';
|
||||
|
||||
class LevelBarDetails {
|
||||
final Color fillColor;
|
||||
final int currentPoints;
|
||||
final double widthMultiplier;
|
||||
|
||||
const LevelBarDetails({
|
||||
required this.fillColor,
|
||||
required this.currentPoints,
|
||||
required this.widthMultiplier,
|
||||
});
|
||||
}
|
||||
|
||||
class ProgressBarDetails {
|
||||
final double totalWidth;
|
||||
final Color borderColor;
|
||||
final double height;
|
||||
|
||||
const ProgressBarDetails({
|
||||
required this.totalWidth,
|
||||
required this.borderColor,
|
||||
this.height = 14,
|
||||
});
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue