diff --git a/lib/pangea/analytics_misc/construct_list_model.dart b/lib/pangea/analytics_misc/construct_list_model.dart index 468db7ac7..1eb845154 100644 --- a/lib/pangea/analytics_misc/construct_list_model.dart +++ b/lib/pangea/analytics_misc/construct_list_model.dart @@ -36,6 +36,10 @@ class ConstructListModel { /// A list of unique grammar lemmas List grammarLemmasList = []; + /// [D] is the "compression factor". It determines how quickly + /// or slowly the level grows relative to XP + final double D = 1500; + List unlockedLemmas( ConstructTypeEnum type, { int threshold = 0, @@ -187,9 +191,6 @@ class ConstructListModel { } int calculateLevelWithXp(int totalXP) { - // [D] is the "compression factor". It determines how quickly - /// or slowly the level grows relative to XP - const double D = 1500; final doubleScore = (1 + sqrt((1 + (8.0 * totalXP / D)) / 2.0)); if (!doubleScore.isNaN && doubleScore.isFinite) { return doubleScore.floor(); @@ -207,9 +208,6 @@ class ConstructListModel { } int calculateXpWithLevel(int level) { - // [D] is the same "compression factor" as in calculateLevelWithXp. - const double D = 2500.0; - // If level <= 1, XP should be 0 or negative by this math. // In practice, you might clamp it to 0: if (level <= 1) { diff --git a/lib/pangea/chat_settings/widgets/visibility_toggle.dart b/lib/pangea/chat_settings/widgets/visibility_toggle.dart index 57180fcfc..fdbbe8a25 100644 --- a/lib/pangea/chat_settings/widgets/visibility_toggle.dart +++ b/lib/pangea/chat_settings/widgets/visibility_toggle.dart @@ -5,34 +5,69 @@ import 'package:matrix/matrix.dart' as matrix; import 'package:matrix/matrix.dart'; import 'package:fluffychat/config/app_config.dart'; +import 'package:fluffychat/widgets/future_loading_dialog.dart'; import 'package:fluffychat/widgets/matrix.dart'; -class VisibilityToggle extends StatelessWidget { - final Room? room; +class VisibilityToggle extends StatefulWidget { + final Room room; final Color? iconColor; final Future Function(matrix.Visibility) setVisibility; final Future Function(JoinRules) setJoinRules; - final bool spaceMode; - final matrix.Visibility visibility; - final JoinRules joinRules; - - final bool showSearchToggle; const VisibilityToggle({ required this.setVisibility, required this.setJoinRules, - this.room, + required this.room, this.iconColor, - this.spaceMode = false, - this.visibility = matrix.Visibility.private, - this.joinRules = JoinRules.knock, - this.showSearchToggle = true, super.key, }); - bool get _isPublic => room != null - ? room!.joinRules == matrix.JoinRules.public - : joinRules == matrix.JoinRules.public; + @override + State createState() => VisibilityToggleState(); +} + +class VisibilityToggleState extends State { + Room get room => widget.room; + + bool get _isPublic => room.joinRules == matrix.JoinRules.public; + + matrix.Visibility? _visibility; + bool _loading = true; + String? _error; + + @override + void initState() { + super.initState(); + _getVisibility(); + } + + Future _getVisibility() async { + try { + final resp = await Matrix.of(context).client.getRoomVisibilityOnDirectory( + room.id, + ); + _visibility = resp ?? matrix.Visibility.private; + } catch (e) { + _error = e.toString(); + } finally { + setState(() { + _loading = false; + }); + } + } + + Future _setVisibility(matrix.Visibility visibility) async { + try { + await widget.setVisibility(visibility); + _visibility = visibility; + } catch (e) { + _error = e.toString(); + } finally { + if (mounted) { + setState(() {}); + } + } + } @override Widget build(BuildContext context) { @@ -50,40 +85,63 @@ class VisibilityToggle extends StatelessWidget { ), secondary: CircleAvatar( backgroundColor: Theme.of(context).scaffoldBackgroundColor, - foregroundColor: iconColor, + foregroundColor: widget.iconColor, child: const Icon(Icons.key_outlined), ), value: !_isPublic, onChanged: (value) => - setJoinRules(value ? JoinRules.knock : JoinRules.public), + widget.setJoinRules(value ? JoinRules.knock : JoinRules.public), ), - FutureBuilder( - future: room != null - ? Matrix.of(context).client.getRoomVisibilityOnDirectory(room!.id) + ListTile( + title: Text( + L10n.of(context).canFindInSearch, + style: TextStyle( + color: Theme.of(context).colorScheme.secondary, + fontWeight: FontWeight.bold, + ), + ), + leading: CircleAvatar( + backgroundColor: Theme.of(context).scaffoldBackgroundColor, + foregroundColor: widget.iconColor, + child: const Icon(Icons.search_outlined), + ), + onTap: _visibility != null + ? () => showFutureLoadingDialog( + future: () async { + _setVisibility( + _visibility == matrix.Visibility.public + ? matrix.Visibility.private + : matrix.Visibility.public, + ); + }, + context: context, + ) : null, - builder: (context, snapshot) { - return SwitchListTile.adaptive( - activeColor: AppConfig.activeToggleColor, - title: Text( - L10n.of(context).canFindInSearch, - style: TextStyle( - color: Theme.of(context).colorScheme.secondary, - fontWeight: FontWeight.bold, + trailing: _loading || _error != null + ? SizedBox( + height: 24.0, + width: 24.0, + child: _error != null + ? Icon( + Icons.error, + color: Theme.of(context).colorScheme.error, + ) + : const CircularProgressIndicator.adaptive(), + ) + : Switch.adaptive( + activeColor: AppConfig.activeToggleColor, + value: _visibility == matrix.Visibility.public, + onChanged: (value) => showFutureLoadingDialog( + future: () async { + _setVisibility( + value + ? matrix.Visibility.public + : matrix.Visibility.private, + ); + }, + context: context, + ), ), - ), - secondary: CircleAvatar( - backgroundColor: Theme.of(context).scaffoldBackgroundColor, - foregroundColor: iconColor, - child: const Icon(Icons.search_outlined), - ), - value: room != null - ? snapshot.data == matrix.Visibility.public - : visibility == matrix.Visibility.public, - onChanged: (value) => setVisibility( - value ? matrix.Visibility.public : matrix.Visibility.private, - ), - ); - }, ), ], );