From c48ce31bc652979e7215033f88c68c7b8b6a75fe Mon Sep 17 00:00:00 2001 From: otsmr Date: Sun, 5 Apr 2026 16:21:58 +0200 Subject: [PATCH] add view for reduce flames --- .../settings/developer/developer.view.dart | 25 ++++ .../developer/reduce_flames.view.dart | 130 ++++++++++++++++++ .../views/settings/settings_main.view.dart | 7 +- 3 files changed, 161 insertions(+), 1 deletion(-) create mode 100644 lib/src/views/settings/developer/reduce_flames.view.dart diff --git a/lib/src/views/settings/developer/developer.view.dart b/lib/src/views/settings/developer/developer.view.dart index 581bc85..a9d3ca5 100644 --- a/lib/src/views/settings/developer/developer.view.dart +++ b/lib/src/views/settings/developer/developer.view.dart @@ -3,6 +3,7 @@ import 'package:clock/clock.dart'; import 'package:drift/drift.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'package:go_router/go_router.dart'; import 'package:restart_app/restart_app.dart'; import 'package:twonly/globals.dart'; @@ -32,6 +33,14 @@ class _DeveloperSettingsViewState extends State { setState(() {}); } + Future toggleVideoStabilization() async { + await updateUserdata((u) { + u.videoStabilizationEnabled = !u.videoStabilizationEnabled; + return u; + }); + setState(() {}); + } + @override Widget build(BuildContext context) { return Scaffold( @@ -53,6 +62,14 @@ class _DeveloperSettingsViewState extends State { onTap: () => context.push(Routes.settingsDeveloperRetransmissionDatabase), ), + ListTile( + title: const Text('Toggle Video Stabilization'), + onTap: toggleVideoStabilization, + trailing: Switch( + value: gUser.videoStabilizationEnabled, + onChanged: (a) => toggleVideoStabilization(), + ), + ), ListTile( title: const Text('Delete all (!) app data'), onTap: () async { @@ -71,6 +88,10 @@ class _DeveloperSettingsViewState extends State { } }, ), + ListTile( + title: const Text('Reduce flames'), + onTap: () => context.push(Routes.settingsDeveloperReduceFlames), + ), if (!kReleaseMode) ListTile( title: const Text('Make it possible to reset flames'), @@ -84,9 +105,13 @@ class _DeveloperSettingsViewState extends State { flameCounter: const Value(0), maxFlameCounter: const Value(365), lastFlameCounterChange: Value(clock.now()), + maxFlameCounterFrom: Value( + clock.now().subtract(const Duration(days: 1)), + ), ), ); } + await HapticFeedback.heavyImpact(); }, ), if (!kReleaseMode) diff --git a/lib/src/views/settings/developer/reduce_flames.view.dart b/lib/src/views/settings/developer/reduce_flames.view.dart new file mode 100644 index 0000000..a762dff --- /dev/null +++ b/lib/src/views/settings/developer/reduce_flames.view.dart @@ -0,0 +1,130 @@ +import 'dart:async'; +import 'dart:collection'; +import 'package:drift/drift.dart' show Value; +import 'package:flutter/material.dart'; +import 'package:twonly/globals.dart'; +import 'package:twonly/src/database/twonly.db.dart'; +import 'package:twonly/src/views/components/avatar_icon.component.dart'; +import 'package:twonly/src/views/components/flame.dart'; + +class ReduceFlamesView extends StatefulWidget { + const ReduceFlamesView({super.key}); + + @override + State createState() => _ReduceFlamesViewState(); +} + +class _ReduceFlamesViewState extends State { + List allGroups = []; + List backupFlames = []; + HashSet changedGroupIds = HashSet(); + late StreamSubscription> groupSub; + + @override + void initState() { + super.initState(); + + final stream = twonlyDB.groupsDao.watchGroupsForChatList(); + + groupSub = stream.listen((update) async { + if (backupFlames.isEmpty) { + backupFlames = update; + } + update.sort( + (a, b) => a.flameCounter.compareTo(b.flameCounter), + ); + setState(() { + allGroups = update.where((g) => g.flameCounter > 1).toList(); + }); + }); + } + + @override + void dispose() { + unawaited(groupSub.cancel()); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: () => FocusScope.of(context).unfocus(), + child: Scaffold( + appBar: AppBar( + title: const Text('Reduce Flames'), + ), + body: SafeArea( + child: Padding( + padding: const EdgeInsets.only( + bottom: 40, + left: 10, + top: 20, + right: 10, + ), + child: Column( + children: [ + const Text( + 'There was a bug that caused the flames in direct messages to be replaced by group flames. Here, you can reduce the flames again. If you reduce the flames, the other person MUST do the same; otherwise, they will be resynchronized to the higher value.', + textAlign: TextAlign.center, + ), + const SizedBox(height: 10), + OutlinedButton( + onPressed: () async { + for (final backupGroup in backupFlames) { + if (changedGroupIds.contains(backupGroup.groupId)) { + await twonlyDB.groupsDao.updateGroup( + backupGroup.groupId, + GroupsCompanion( + flameCounter: Value(backupGroup.flameCounter), + ), + ); + } + } + }, + child: const Text('Undo changes'), + ), + const SizedBox(height: 10), + Expanded( + child: ListView.builder( + restorationId: 'new_message_users_list', + itemCount: allGroups.length, + itemBuilder: (context, i) { + final group = allGroups[i]; + return ListTile( + title: Row( + children: [ + Text(group.groupName), + FlameCounterWidget( + groupId: group.groupId, + prefix: true, + ), + ], + ), + leading: AvatarIcon( + group: group, + fontSize: 13, + ), + trailing: OutlinedButton( + onPressed: () { + changedGroupIds.add(group.groupId); + twonlyDB.groupsDao.updateGroup( + group.groupId, + GroupsCompanion( + flameCounter: Value(group.flameCounter - 1), + ), + ); + }, + child: const Text('-1'), + ), + ); + }, + ), + ), + ], + ), + ), + ), + ), + ); + } +} diff --git a/lib/src/views/settings/settings_main.view.dart b/lib/src/views/settings/settings_main.view.dart index a8b353f..47a11a4 100644 --- a/lib/src/views/settings/settings_main.view.dart +++ b/lib/src/views/settings/settings_main.view.dart @@ -121,7 +121,12 @@ class _SettingsMainViewState extends State { BetterListTile( icon: FontAwesomeIcons.circleQuestion, text: context.lang.settingsHelp, - onTap: () => context.push(Routes.settingsHelp), + onTap: () async { + await context.push(Routes.settingsHelp); + setState(() { + // gUser could have been changed + }); + }, ), if (gUser.isDeveloper) BetterListTile(