rough draft of navigation menu design updates (#947)
This commit is contained in:
parent
f9488cae01
commit
5f547deb58
12 changed files with 252 additions and 125 deletions
|
|
@ -4498,6 +4498,13 @@
|
|||
"selectBotChatMode": "Select chat mode",
|
||||
"messageNotInTargetLang": "Message not in target language",
|
||||
"other": "Other",
|
||||
"levelShort": "LVL {level}",
|
||||
"@levelShort": {
|
||||
"type": "text",
|
||||
"placeholders": {
|
||||
"level": {}
|
||||
}
|
||||
},
|
||||
"botModeValidation": "Please select a chat mode",
|
||||
"clickBestOption": "Choose the best options to translate your message!",
|
||||
"unlockedLanguageTools": "You’ve unlocked the language tools for this message. Try them out by clicking below!",
|
||||
|
|
|
|||
|
|
@ -35,6 +35,8 @@ abstract class AppConfig {
|
|||
static const Color activeToggleColor = Color(0xFF33D057);
|
||||
static const Color success = Color(0xFF33D057);
|
||||
static const Color warning = Color.fromARGB(255, 210, 124, 12);
|
||||
static const Color gold = Color.fromARGB(255, 253, 191, 1);
|
||||
static const Color goldLight = Color.fromARGB(255, 254, 223, 73);
|
||||
static const int overlayAnimationDuration = 250;
|
||||
// static String _privacyUrl =
|
||||
// 'https://gitlab.com/famedly/fluffychat/-/blob/main/PRIVACY.md';
|
||||
|
|
|
|||
|
|
@ -275,26 +275,44 @@ class ClientChooserButton extends StatelessWidget {
|
|||
color: Colors.transparent,
|
||||
borderRadius: BorderRadius.circular(99),
|
||||
child:
|
||||
// #Pangea
|
||||
Stack(
|
||||
alignment: Alignment.bottomRight,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(4),
|
||||
child:
|
||||
// Pangea#
|
||||
Avatar(
|
||||
mxContent: snapshot.data?.avatarUrl,
|
||||
name: snapshot.data?.displayName ??
|
||||
matrix.client.userID!.localpart,
|
||||
size: 50,
|
||||
// // #Pangea
|
||||
// Stack(
|
||||
// alignment: Alignment.bottomRight,
|
||||
// children: [
|
||||
// Padding(
|
||||
// padding: const EdgeInsets.all(4),
|
||||
// child:
|
||||
// // Pangea#
|
||||
Container(
|
||||
decoration: BoxDecoration(
|
||||
// borderRadius: BorderRadius.circular(15),
|
||||
// color: Theme.of(context).colorScheme.surfaceBright,
|
||||
borderRadius: BorderRadius.circular(30),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
spreadRadius: 1,
|
||||
blurRadius: 1,
|
||||
offset: const Offset(
|
||||
0,
|
||||
1,
|
||||
), // changes position of shadow
|
||||
),
|
||||
// #Pangea
|
||||
),
|
||||
const Icon(Icons.settings_outlined, size: 20),
|
||||
],
|
||||
],
|
||||
),
|
||||
child: Avatar(
|
||||
mxContent: snapshot.data?.avatarUrl,
|
||||
name: snapshot.data?.displayName ??
|
||||
matrix.client.userID!.localpart,
|
||||
size: 60,
|
||||
),
|
||||
),
|
||||
// Pangea#
|
||||
// // #Pangea
|
||||
// ),
|
||||
// const Icon(Icons.settings_outlined, size: 20),
|
||||
// ],
|
||||
// ),
|
||||
// // Pangea#
|
||||
),
|
||||
),
|
||||
],
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ extension ProgressIndicatorsExtension on ProgressIndicatorEnum {
|
|||
IconData get icon {
|
||||
switch (this) {
|
||||
case ProgressIndicatorEnum.wordsUsed:
|
||||
return Icons.text_fields_outlined;
|
||||
return Symbols.dictionary;
|
||||
case ProgressIndicatorEnum.morphsUsed:
|
||||
return Symbols.toys_and_games;
|
||||
case ProgressIndicatorEnum.level:
|
||||
|
|
@ -25,24 +25,7 @@ extension ProgressIndicatorsExtension on ProgressIndicatorEnum {
|
|||
Theme.of(context).brightness == Brightness.dark;
|
||||
|
||||
Color color(BuildContext context) {
|
||||
switch (this) {
|
||||
case ProgressIndicatorEnum.wordsUsed:
|
||||
return Theme.of(context).brightness == Brightness.dark
|
||||
? const Color.fromARGB(255, 169, 183, 237)
|
||||
: const Color.fromARGB(255, 38, 59, 141);
|
||||
// case ProgressIndicatorEnum.errorTypes:
|
||||
// return Theme.of(context).brightness == Brightness.dark
|
||||
// ? const Color.fromARGB(255, 212, 144, 216)
|
||||
// : const Color.fromARGB(255, 163, 39, 169);
|
||||
case ProgressIndicatorEnum.level:
|
||||
return Theme.of(context).brightness == Brightness.dark
|
||||
? const Color.fromARGB(255, 250, 220, 129)
|
||||
: const Color.fromARGB(255, 255, 208, 67);
|
||||
case ProgressIndicatorEnum.morphsUsed:
|
||||
return Theme.of(context).brightness == Brightness.dark
|
||||
? const Color.fromARGB(255, 169, 183, 237)
|
||||
: const Color.fromARGB(255, 38, 59, 141);
|
||||
}
|
||||
return Theme.of(context).colorScheme.primary;
|
||||
}
|
||||
|
||||
String tooltip(BuildContext context) {
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
import 'package:fluffychat/config/app_config.dart';
|
||||
import 'package:fluffychat/config/themes.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
|
|
@ -5,14 +6,16 @@ class AnimatedLevelBar extends StatefulWidget {
|
|||
final double height;
|
||||
final double beginWidth;
|
||||
final double endWidth;
|
||||
final BoxDecoration? decoration;
|
||||
final Color primaryColor;
|
||||
final Color highlightColor;
|
||||
|
||||
const AnimatedLevelBar({
|
||||
super.key,
|
||||
required this.height,
|
||||
required this.beginWidth,
|
||||
required this.endWidth,
|
||||
this.decoration,
|
||||
required this.primaryColor,
|
||||
required this.highlightColor,
|
||||
});
|
||||
|
||||
@override
|
||||
|
|
@ -76,10 +79,40 @@ class AnimatedLevelBarState extends State<AnimatedLevelBar>
|
|||
return AnimatedBuilder(
|
||||
animation: _animation,
|
||||
builder: (context, child) {
|
||||
return Container(
|
||||
height: widget.height,
|
||||
width: _animation.value,
|
||||
decoration: widget.decoration,
|
||||
return Stack(
|
||||
children: [
|
||||
Container(
|
||||
height: widget.height,
|
||||
width: _animation.value,
|
||||
decoration: BoxDecoration(
|
||||
color: widget.primaryColor,
|
||||
borderRadius: const BorderRadius.all(
|
||||
Radius.circular(AppConfig.borderRadius),
|
||||
),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withOpacity(0.2),
|
||||
spreadRadius: 0,
|
||||
blurRadius: 5,
|
||||
offset: const Offset(5, 0),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
top: 2,
|
||||
child: Container(
|
||||
height: 6,
|
||||
width: _animation.value >= 8 ? _animation.value - 8 : 0,
|
||||
decoration: BoxDecoration(
|
||||
color: widget.highlightColor,
|
||||
borderRadius: const BorderRadius.all(
|
||||
Radius.circular(AppConfig.borderRadius),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
|
|
|
|||
|
|
@ -36,19 +36,8 @@ class LevelBarState extends State<LevelBar> {
|
|||
height: widget.progressBarDetails.height,
|
||||
beginWidth: prevWidth,
|
||||
endWidth: width,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: const BorderRadius.all(
|
||||
Radius.circular(AppConfig.borderRadius),
|
||||
),
|
||||
color: widget.details.fillColor,
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withOpacity(0.2),
|
||||
blurRadius: 5,
|
||||
offset: const Offset(5, 0),
|
||||
),
|
||||
],
|
||||
),
|
||||
primaryColor: AppConfig.gold,
|
||||
highlightColor: AppConfig.goldLight,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,13 +13,9 @@ class ProgressBarBackground extends StatelessWidget {
|
|||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
height: details.height + 4,
|
||||
width: details.totalWidth + 4,
|
||||
height: details.height,
|
||||
width: details.totalWidth,
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(
|
||||
color: details.borderColor.withOpacity(0.5),
|
||||
width: 2,
|
||||
),
|
||||
borderRadius: const BorderRadius.all(
|
||||
Radius.circular(AppConfig.borderRadius),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -20,6 +20,6 @@ class ProgressBarDetails {
|
|||
const ProgressBarDetails({
|
||||
required this.totalWidth,
|
||||
required this.borderColor,
|
||||
this.height = 16,
|
||||
this.height = 14,
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,11 +7,12 @@ import 'package:fluffychat/pangea/models/analytics/construct_list_model.dart';
|
|||
import 'package:fluffychat/pangea/pages/settings_learning/settings_learning.dart';
|
||||
import 'package:fluffychat/pangea/widgets/chat_list/analytics_summary/analytics_popup/analytics_popup.dart';
|
||||
import 'package:fluffychat/pangea/widgets/chat_list/analytics_summary/learning_progress_bar.dart';
|
||||
import 'package:fluffychat/pangea/widgets/chat_list/analytics_summary/learning_settings_button.dart';
|
||||
import 'package:fluffychat/pangea/widgets/chat_list/analytics_summary/level_badge.dart';
|
||||
import 'package:fluffychat/pangea/widgets/chat_list/analytics_summary/progress_indicator.dart';
|
||||
import 'package:fluffychat/pangea/widgets/flag.dart';
|
||||
import 'package:fluffychat/widgets/matrix.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
||||
|
||||
/// A summary of "My Analytics" shown at the top of the chat list
|
||||
/// It shows a variety of progress indicators such as
|
||||
|
|
@ -76,22 +77,40 @@ class LearningProgressIndicatorsState
|
|||
return const SizedBox();
|
||||
}
|
||||
|
||||
final userL2 = MatrixState.pangeaController.languageController.userL2;
|
||||
|
||||
return Row(
|
||||
children: [
|
||||
const ClientChooserButton(),
|
||||
const SizedBox(width: 6),
|
||||
const SizedBox(width: 10),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
Matrix.of(context).client.userID ?? L10n.of(context)!.user,
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
fontSize: 12,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 6),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
LearningSettingsButton(
|
||||
onTap: () => showDialog(
|
||||
context: context,
|
||||
builder: (c) => const SettingsLearning(),
|
||||
),
|
||||
l2: userL2!.getDisplayName(context) ?? userL2.langCode,
|
||||
),
|
||||
Row(
|
||||
children: ProgressIndicatorEnum.values
|
||||
.where((i) => i != ProgressIndicatorEnum.level)
|
||||
.map(
|
||||
(indicator) => Padding(
|
||||
padding: const EdgeInsets.only(right: 10),
|
||||
padding: const EdgeInsets.only(left: 6),
|
||||
child: ProgressIndicatorBadge(
|
||||
points: uniqueLemmas(indicator),
|
||||
loading: _loading,
|
||||
|
|
@ -111,22 +130,11 @@ class LearningProgressIndicatorsState
|
|||
)
|
||||
.toList(),
|
||||
),
|
||||
InkWell(
|
||||
onTap: () => showDialog(
|
||||
context: context,
|
||||
builder: (c) => const SettingsLearning(),
|
||||
),
|
||||
child: LanguageFlag(
|
||||
language: MatrixState
|
||||
.pangeaController.languageController.userL2,
|
||||
size: 24,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 6),
|
||||
SizedBox(
|
||||
height: 36,
|
||||
height: 22,
|
||||
child: Stack(
|
||||
alignment: Alignment.center,
|
||||
children: [
|
||||
|
|
|
|||
|
|
@ -0,0 +1,62 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
||||
|
||||
/// A badge that represents one learning progress indicator (i.e., construct uses)
|
||||
class LearningSettingsButton extends StatelessWidget {
|
||||
final String l2;
|
||||
final VoidCallback onTap;
|
||||
|
||||
const LearningSettingsButton({
|
||||
super.key,
|
||||
required this.l2,
|
||||
required this.onTap,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Tooltip(
|
||||
message: L10n.of(context)!.learningSettings,
|
||||
child: InkWell(
|
||||
customBorder: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(15),
|
||||
),
|
||||
onTap: onTap,
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(15),
|
||||
color: Theme.of(context).colorScheme.surfaceBright,
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
spreadRadius: 1,
|
||||
blurRadius: 1,
|
||||
offset: const Offset(1, 1), // changes position of shadow
|
||||
),
|
||||
],
|
||||
),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Icon(
|
||||
size: 14,
|
||||
Icons.language,
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
weight: 1000,
|
||||
),
|
||||
const SizedBox(width: 5),
|
||||
Text(
|
||||
l2,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,6 @@
|
|||
import 'package:fluffychat/config/app_config.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
||||
|
||||
class LevelBadge extends StatelessWidget {
|
||||
final int level;
|
||||
|
|
@ -7,39 +9,45 @@ class LevelBadge extends StatelessWidget {
|
|||
super.key,
|
||||
});
|
||||
|
||||
Color levelColor(int level) {
|
||||
final colors = [
|
||||
const Color.fromARGB(255, 33, 97, 140), // Dark blue
|
||||
const Color.fromARGB(255, 186, 104, 200), // Soft purple
|
||||
const Color.fromARGB(255, 123, 31, 162), // Deep purple
|
||||
const Color.fromARGB(255, 0, 150, 136), // Teal
|
||||
const Color.fromARGB(255, 247, 143, 143), // Light pink
|
||||
const Color.fromARGB(255, 220, 20, 60), // Crimson red
|
||||
];
|
||||
return colors[level % colors.length];
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
width: 32,
|
||||
height: 32,
|
||||
decoration: BoxDecoration(
|
||||
color: levelColor(level),
|
||||
borderRadius: BorderRadius.circular(32),
|
||||
borderRadius: BorderRadius.circular(15),
|
||||
color: Theme.of(context).colorScheme.surfaceBright,
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withOpacity(0.2),
|
||||
blurRadius: 5,
|
||||
offset: const Offset(5, 0),
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
spreadRadius: 1,
|
||||
blurRadius: 1,
|
||||
offset: const Offset(1, 1), // changes position of shadow
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Center(
|
||||
child: Text(
|
||||
"$level",
|
||||
style: const TextStyle(color: Colors.white, fontSize: 16),
|
||||
),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 4, vertical: 2),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
CircleAvatar(
|
||||
backgroundColor: AppConfig.gold,
|
||||
radius: 8,
|
||||
child: Icon(
|
||||
size: 12,
|
||||
Icons.star,
|
||||
color: Theme.of(context).colorScheme.surfaceBright,
|
||||
weight: 1000,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 4),
|
||||
Text(
|
||||
L10n.of(context)!.levelShort(level),
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,31 +21,52 @@ class ProgressIndicatorBadge extends StatelessWidget {
|
|||
return Tooltip(
|
||||
message: indicator.tooltip(context),
|
||||
child: InkWell(
|
||||
customBorder: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(15),
|
||||
),
|
||||
onTap: onTap,
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Icon(
|
||||
indicator.icon,
|
||||
color: indicator.color(context),
|
||||
),
|
||||
const SizedBox(width: 5),
|
||||
!loading
|
||||
? Text(
|
||||
points.toString(),
|
||||
style: const TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold,
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(15),
|
||||
color: Theme.of(context).colorScheme.surfaceBright,
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
spreadRadius: 1,
|
||||
blurRadius: 1,
|
||||
offset: const Offset(-1, 1), // changes position of shadow
|
||||
),
|
||||
],
|
||||
),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Icon(
|
||||
size: 14,
|
||||
indicator.icon,
|
||||
color: indicator.color(context),
|
||||
weight: 1000,
|
||||
),
|
||||
const SizedBox(width: 5),
|
||||
!loading
|
||||
? Text(
|
||||
points.toString(),
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: indicator.color(context),
|
||||
),
|
||||
)
|
||||
: const SizedBox(
|
||||
height: 8,
|
||||
width: 8,
|
||||
child: CircularProgressIndicator.adaptive(
|
||||
strokeWidth: 2,
|
||||
),
|
||||
),
|
||||
)
|
||||
: const SizedBox(
|
||||
height: 8,
|
||||
width: 8,
|
||||
child: CircularProgressIndicator.adaptive(
|
||||
strokeWidth: 2,
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue