exit confirmation and practice session reloads on leaving
This commit is contained in:
parent
c05666cad8
commit
a2901d2949
5 changed files with 76 additions and 48 deletions
|
|
@ -9,6 +9,7 @@ import 'package:matrix/matrix_api_lite/generated/model.dart';
|
|||
|
||||
import 'package:fluffychat/config/app_config.dart';
|
||||
import 'package:fluffychat/config/themes.dart';
|
||||
import 'package:fluffychat/l10n/l10n.dart';
|
||||
import 'package:fluffychat/pages/archive/archive.dart';
|
||||
import 'package:fluffychat/pages/chat/chat.dart';
|
||||
import 'package:fluffychat/pages/chat_access_settings/chat_access_settings_controller.dart';
|
||||
|
|
@ -583,6 +584,67 @@ abstract class AppRoutes {
|
|||
const VocabPractice(),
|
||||
);
|
||||
},
|
||||
onExit: (context, state) async {
|
||||
// Check if bypass flag was set before navigation
|
||||
if (VocabPractice.bypassExitConfirmation) {
|
||||
VocabPractice.bypassExitConfirmation = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
final bool confirm = await showDialog<bool>(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return Center(
|
||||
child: ConstrainedBox(
|
||||
constraints: const BoxConstraints(
|
||||
maxWidth: 400,
|
||||
),
|
||||
child: Dialog(
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(24.0),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
Center(
|
||||
child: Text(
|
||||
L10n.of(context).exitPractice,
|
||||
style: const TextStyle(
|
||||
fontSize: 28,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop(true);
|
||||
},
|
||||
child: Text(L10n.of(context).yes),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
Navigator.of(context)
|
||||
.pop(false);
|
||||
},
|
||||
child: Text(L10n.of(context).no),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
) ??
|
||||
false;
|
||||
|
||||
return confirm;
|
||||
},
|
||||
),
|
||||
GoRoute(
|
||||
path: ':construct',
|
||||
|
|
|
|||
|
|
@ -5046,5 +5046,6 @@
|
|||
"voice": "Voice",
|
||||
"youLeftTheChat": "🚪 You left the chat",
|
||||
"downloadInitiated": "Download initiated",
|
||||
"webDownloadPermissionMessage": "If your browser blocks downloads, please enable downloads for this site."
|
||||
"webDownloadPermissionMessage": "If your browser blocks downloads, please enable downloads for this site.",
|
||||
"exitPractice": "Exit practice? Your progress will be lost."
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:go_router/go_router.dart';
|
||||
|
||||
import 'package:fluffychat/config/app_config.dart';
|
||||
import 'package:fluffychat/l10n/l10n.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/level_up/star_rain_widget.dart';
|
||||
|
|
@ -162,7 +164,12 @@ class CompletedActivitySessionView extends StatelessWidget {
|
|||
vertical: 8.0,
|
||||
),
|
||||
),
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
onPressed: () {
|
||||
VocabPractice.bypassExitConfirmation = true;
|
||||
debugPrint(
|
||||
"VocabPractice.bypassExitConfirmation set to ${VocabPractice.bypassExitConfirmation}");
|
||||
context.go('/rooms/analytics/vocab');
|
||||
},
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
|
|
|
|||
|
|
@ -46,6 +46,8 @@ class SessionLoader extends AsyncLoader<VocabPracticeSessionModel> {
|
|||
}
|
||||
|
||||
class VocabPractice extends StatefulWidget {
|
||||
static bool bypassExitConfirmation = false;
|
||||
|
||||
const VocabPractice({super.key});
|
||||
|
||||
@override
|
||||
|
|
@ -83,11 +85,7 @@ class VocabPracticeState extends State<VocabPractice> with AnalyticsUpdater {
|
|||
@override
|
||||
void dispose() {
|
||||
_languageStreamSubscription?.cancel();
|
||||
if (_isComplete) {
|
||||
VocabPracticeSessionRepo.clear();
|
||||
} else {
|
||||
_saveSession();
|
||||
}
|
||||
VocabPracticeSessionRepo.clear();
|
||||
_sessionLoader.dispose();
|
||||
activityState.dispose();
|
||||
activityConstructId.dispose();
|
||||
|
|
@ -185,12 +183,6 @@ class VocabPracticeState extends State<VocabPractice> with AnalyticsUpdater {
|
|||
}
|
||||
}
|
||||
|
||||
Future<void> _saveSession() async {
|
||||
if (_sessionLoader.isLoaded) {
|
||||
await VocabPracticeSessionRepo.update(_sessionLoader.value!);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _waitForAnalytics() async {
|
||||
if (!_analyticsService.initCompleter.isCompleted) {
|
||||
MatrixState.pangeaController.initControllers();
|
||||
|
|
@ -225,7 +217,7 @@ class VocabPracticeState extends State<VocabPractice> with AnalyticsUpdater {
|
|||
Future<void> reloadSession() async {
|
||||
_resetActivityState();
|
||||
_resetSessionState();
|
||||
await VocabPracticeSessionRepo.clear();
|
||||
|
||||
_sessionLoader.reset();
|
||||
await _startSession();
|
||||
}
|
||||
|
|
@ -240,7 +232,6 @@ class VocabPracticeState extends State<VocabPractice> with AnalyticsUpdater {
|
|||
bonus,
|
||||
forceUpdate: true,
|
||||
);
|
||||
await _saveSession();
|
||||
}
|
||||
|
||||
bool _continuing = false;
|
||||
|
|
@ -394,7 +385,6 @@ class VocabPracticeState extends State<VocabPractice> with AnalyticsUpdater {
|
|||
await _analyticsService.updateService
|
||||
.addAnalytics(choiceTargetId(choiceContent), [use]);
|
||||
|
||||
await _saveSession();
|
||||
if (!correct) return;
|
||||
|
||||
// Display the fact that the choice was correct before loading the next activity
|
||||
|
|
@ -403,7 +393,6 @@ class VocabPracticeState extends State<VocabPractice> with AnalyticsUpdater {
|
|||
// Then mark this activity as completed, and either load the next or complete the session
|
||||
_sessionLoader.value!.completeActivity();
|
||||
progressNotifier.value = _sessionLoader.value!.progress;
|
||||
await _saveSession();
|
||||
|
||||
_isComplete ? await _completeSession() : await _continueSession();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,11 +14,6 @@ class VocabPracticeSessionRepo {
|
|||
static final GetStorage _storage = GetStorage('vocab_practice_session');
|
||||
|
||||
static Future<VocabPracticeSessionModel> get() async {
|
||||
final cached = _getCached();
|
||||
if (cached != null) {
|
||||
return cached;
|
||||
}
|
||||
|
||||
final r = Random();
|
||||
final activityTypes = [
|
||||
ActivityTypeEnum.lemmaMeaning,
|
||||
|
|
@ -46,15 +41,9 @@ class VocabPracticeSessionRepo {
|
|||
startedAt: DateTime.now(),
|
||||
practiceTargets: targets,
|
||||
);
|
||||
await _setCached(session);
|
||||
return session;
|
||||
}
|
||||
|
||||
static Future<void> update(
|
||||
VocabPracticeSessionModel session,
|
||||
) =>
|
||||
_setCached(session);
|
||||
|
||||
static Future<void> clear() => _storage.erase();
|
||||
|
||||
static Future<List<ConstructIdentifier>> _fetch() async {
|
||||
|
|
@ -85,24 +74,4 @@ class VocabPracticeSessionRepo {
|
|||
}
|
||||
return targets;
|
||||
}
|
||||
|
||||
static VocabPracticeSessionModel? _getCached() {
|
||||
final keys = List<String>.from(_storage.getKeys());
|
||||
if (keys.isEmpty) return null;
|
||||
try {
|
||||
final json = _storage.read(keys.first) as Map<String, dynamic>;
|
||||
return VocabPracticeSessionModel.fromJson(json);
|
||||
} catch (e) {
|
||||
_storage.remove(keys.first);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
static Future<void> _setCached(VocabPracticeSessionModel session) async {
|
||||
await _storage.erase();
|
||||
await _storage.write(
|
||||
session.startedAt.toIso8601String(),
|
||||
session.toJson(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue