feat: show unlocked constructs snackbar (#2193)
This commit is contained in:
parent
b104069d31
commit
269af9f4e6
7 changed files with 133 additions and 16 deletions
|
|
@ -4827,5 +4827,6 @@
|
|||
"startChatting": "Start chatting",
|
||||
"referFriends": "Refer friends",
|
||||
"referFriendDialogTitle": "Invite a friend to your conversation",
|
||||
"referFriendDialogDesc": "Do you have a friend who is excited to learn a new language with you? Then copy and send this invitation link to join and start chatting with you today."
|
||||
"referFriendDialogDesc": "Do you have a friend who is excited to learn a new language with you? Then copy and send this invitation link to join and start chatting with you today.",
|
||||
"youUnlocked": "You've unlocked"
|
||||
}
|
||||
|
|
@ -30,6 +30,7 @@ import 'package:fluffychat/pages/chat_details/chat_details.dart';
|
|||
import 'package:fluffychat/pangea/analytics_misc/constructs_model.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/level_up.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';
|
||||
import 'package:fluffychat/pangea/choreographer/controllers/choreographer.dart';
|
||||
import 'package:fluffychat/pangea/choreographer/enums/edit_type.dart';
|
||||
|
|
@ -365,7 +366,9 @@ class ChatController extends State<ChatPageWithRoom>
|
|||
|
||||
_levelSubscription = pangeaController.getAnalytics.stateStream
|
||||
.where(
|
||||
(update) => update is Map<String, dynamic> && update['level_up'] != null,
|
||||
(update) =>
|
||||
update is Map<String, dynamic> &&
|
||||
(update['level_up'] != null || update['unlocked_constructs'] != null),
|
||||
)
|
||||
// .listen(
|
||||
// (update) => Future.delayed(
|
||||
|
|
@ -380,13 +383,20 @@ class ChatController extends State<ChatPageWithRoom>
|
|||
// remove delay now that GetAnalyticsController._onLevelUp
|
||||
// is async is should take roughly 500ms to make requests anyway
|
||||
(update) {
|
||||
LevelUpUtil.showLevelUpDialog(
|
||||
update['level_up'],
|
||||
update['analytics_room_id'],
|
||||
update["construct_summary_state_event_id"],
|
||||
update['construct_summary'],
|
||||
context,
|
||||
);
|
||||
if (update['level_up'] != null) {
|
||||
LevelUpUtil.showLevelUpDialog(
|
||||
update['level_up'],
|
||||
update['analytics_room_id'],
|
||||
update["construct_summary_state_event_id"],
|
||||
update['construct_summary'],
|
||||
context,
|
||||
);
|
||||
} else if (update['unlocked_constructs'] != null) {
|
||||
showUnlockedMorphsSnackbar(
|
||||
update['unlocked_constructs'],
|
||||
context,
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
// Pangea#
|
||||
|
|
|
|||
|
|
@ -158,7 +158,7 @@ class MorphFeatureBox extends StatelessWidget {
|
|||
morphFeature: morphFeature,
|
||||
morphTag: morphTag,
|
||||
constructAnalytics: analytics,
|
||||
onTap: analytics.points > 0
|
||||
onTap: analytics.points > 10
|
||||
? () => onConstructZoom(id)
|
||||
: null,
|
||||
);
|
||||
|
|
@ -196,16 +196,17 @@ class MorphTagChip extends StatelessWidget {
|
|||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
final unlocked = constructAnalytics.points > 10;
|
||||
|
||||
return InkWell(
|
||||
borderRadius: BorderRadius.circular(32.0),
|
||||
onTap: onTap,
|
||||
child: Opacity(
|
||||
opacity: constructAnalytics.points > 0 ? 1.0 : 0.3,
|
||||
opacity: unlocked ? 1.0 : 0.3,
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(32.0),
|
||||
gradient: constructAnalytics.points > 0
|
||||
gradient: unlocked
|
||||
? LinearGradient(
|
||||
begin: Alignment.centerLeft,
|
||||
end: Alignment.centerRight,
|
||||
|
|
@ -215,7 +216,7 @@ class MorphTagChip extends StatelessWidget {
|
|||
],
|
||||
)
|
||||
: null,
|
||||
color: constructAnalytics.points > 0 ? null : theme.disabledColor,
|
||||
color: unlocked ? null : theme.disabledColor,
|
||||
),
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: 4.0,
|
||||
|
|
@ -228,8 +229,7 @@ class MorphTagChip extends StatelessWidget {
|
|||
SizedBox(
|
||||
width: 28.0,
|
||||
height: 28.0,
|
||||
child: constructAnalytics.points > 0 ||
|
||||
Matrix.of(context).client.isSupportAccount
|
||||
child: unlocked || Matrix.of(context).client.isSupportAccount
|
||||
? MorphIcon(
|
||||
morphFeature: morphFeature,
|
||||
morphTag: morphTag,
|
||||
|
|
|
|||
|
|
@ -36,6 +36,22 @@ class ConstructListModel {
|
|||
/// A list of unique grammar lemmas
|
||||
List<String> grammarLemmasList = [];
|
||||
|
||||
List<ConstructIdentifier> get unlockedGrammarLemmas {
|
||||
final morphs = constructList(type: ConstructTypeEnum.morph);
|
||||
final List<ConstructIdentifier> unlocked = [];
|
||||
for (final morph in grammarLemmasList) {
|
||||
final matches = morphs.where((m) => m.lemma == morph);
|
||||
final totalPoints = matches.fold<int>(
|
||||
0,
|
||||
(total, match) => total + match.points,
|
||||
);
|
||||
if (totalPoints > 10) {
|
||||
unlocked.add(matches.first.id);
|
||||
}
|
||||
}
|
||||
return unlocked;
|
||||
}
|
||||
|
||||
/// Analytics data consumed by widgets. Updated each time new analytics come in.
|
||||
int prevXP = 0;
|
||||
int totalXP = 0;
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ import 'package:fluffychat/pangea/common/constants/local.key.dart';
|
|||
import 'package:fluffychat/pangea/common/controllers/base_controller.dart';
|
||||
import 'package:fluffychat/pangea/common/controllers/pangea_controller.dart';
|
||||
import 'package:fluffychat/pangea/common/utils/error_handler.dart';
|
||||
import 'package:fluffychat/pangea/constructs/construct_identifier.dart';
|
||||
import 'package:fluffychat/pangea/constructs/construct_repo.dart';
|
||||
import 'package:fluffychat/pangea/events/constants/pangea_event_types.dart';
|
||||
import 'package:fluffychat/pangea/extensions/pangea_room_extension.dart';
|
||||
|
|
@ -139,7 +140,12 @@ class GetAnalyticsController extends BaseController {
|
|||
|
||||
final offset =
|
||||
_pangeaController.userController.publicProfile?.xpOffset ?? 0;
|
||||
final prevUnlockedMorphs = constructListModel.unlockedGrammarLemmas.toSet();
|
||||
constructListModel.updateConstructs(analyticsUpdate.newConstructs, offset);
|
||||
final newUnlockedMorphs = constructListModel.unlockedGrammarLemmas
|
||||
.toSet()
|
||||
.difference(prevUnlockedMorphs);
|
||||
|
||||
if (analyticsUpdate.type == AnalyticsUpdateType.server) {
|
||||
await _getConstructs(forceUpdate: true);
|
||||
}
|
||||
|
|
@ -149,6 +155,9 @@ class GetAnalyticsController extends BaseController {
|
|||
if (oldLevel > constructListModel.level) {
|
||||
await _onLevelDown(constructListModel.level, oldLevel);
|
||||
}
|
||||
if (newUnlockedMorphs.isNotEmpty) {
|
||||
_onUnlockMorphLemmas(newUnlockedMorphs);
|
||||
}
|
||||
_updateAnalyticsStream(origin: analyticsUpdate.origin);
|
||||
// Update public profile each time that new analytics are added.
|
||||
// If the level hasn't changed, this will not send an update to the server.
|
||||
|
|
@ -187,6 +196,10 @@ class GetAnalyticsController extends BaseController {
|
|||
);
|
||||
}
|
||||
|
||||
void _onUnlockMorphLemmas(Set<ConstructIdentifier> unlocked) {
|
||||
setState({'unlocked_constructs': unlocked});
|
||||
}
|
||||
|
||||
/// A local cache of eventIds and construct uses for messages sent since the last update.
|
||||
/// It's a map of eventIDs to a list of OneConstructUses. Not just a list of OneConstructUses
|
||||
/// because, with practice activity constructs, we might need to add to the list for a given
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ class LearningProgressIndicatorsState
|
|||
int uniqueLemmas(ProgressIndicatorEnum indicator) {
|
||||
switch (indicator) {
|
||||
case ProgressIndicatorEnum.morphsUsed:
|
||||
return _constructsModel.grammarLemmas;
|
||||
return _constructsModel.unlockedGrammarLemmas.length;
|
||||
case ProgressIndicatorEnum.wordsUsed:
|
||||
return _constructsModel.vocabLemmas;
|
||||
default:
|
||||
|
|
|
|||
77
lib/pangea/chat/utils/unlocked_morphs_snackbar.dart
Normal file
77
lib/pangea/chat/utils/unlocked_morphs_snackbar.dart
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
// ignore_for_file: depend_on_referenced_packages, implementation_imports
|
||||
|
||||
import 'package:flutter/material.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/constructs/construct_identifier.dart';
|
||||
import 'package:fluffychat/pangea/morphs/get_grammar_copy.dart';
|
||||
import 'package:fluffychat/pangea/morphs/morph_icon.dart';
|
||||
|
||||
void showUnlockedMorphsSnackbar(
|
||||
Set<ConstructIdentifier> unlockedConstructs,
|
||||
BuildContext context,
|
||||
) {
|
||||
for (final construct in unlockedConstructs) {
|
||||
final copy = getGrammarCopy(
|
||||
category: construct.category,
|
||||
lemma: construct.lemma,
|
||||
context: context,
|
||||
);
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
behavior: FluffyThemes.isColumnMode(context)
|
||||
? SnackBarBehavior.floating
|
||||
: SnackBarBehavior.fixed,
|
||||
width: FluffyThemes.isColumnMode(context)
|
||||
? MediaQuery.of(context).size.width
|
||||
: null,
|
||||
showCloseIcon: true,
|
||||
duration: const Duration(seconds: 5),
|
||||
dismissDirection: DismissDirection.none,
|
||||
backgroundColor: Theme.of(context).colorScheme.surface,
|
||||
content: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Wrap(
|
||||
spacing: 16.0,
|
||||
alignment: WrapAlignment.center,
|
||||
children: [
|
||||
Text(
|
||||
L10n.of(context).youUnlocked,
|
||||
style: TextStyle(
|
||||
fontSize: FluffyThemes.isColumnMode(context) ? 32.0 : 16.0,
|
||||
color: Theme.of(context).colorScheme.onSurface,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
spacing: 16.0,
|
||||
children: [
|
||||
Flexible(
|
||||
child: Text(
|
||||
copy ?? construct.lemma,
|
||||
style: TextStyle(
|
||||
fontSize:
|
||||
FluffyThemes.isColumnMode(context) ? 32.0 : 16.0,
|
||||
color: AppConfig.gold,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
MorphIcon(
|
||||
morphFeature: construct.category,
|
||||
morphTag: construct.lemma,
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue