chore: show visibility toggle loading, standardize level calculation (#2631)

This commit is contained in:
ggurdin 2025-05-02 14:50:45 -04:00 committed by GitHub
parent 20a14969e7
commit b6053230c5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 104 additions and 48 deletions

View file

@ -36,6 +36,10 @@ class ConstructListModel {
/// A list of unique grammar lemmas
List<String> grammarLemmasList = [];
/// [D] is the "compression factor". It determines how quickly
/// or slowly the level grows relative to XP
final double D = 1500;
List<ConstructIdentifier> 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) {

View file

@ -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<void> Function(matrix.Visibility) setVisibility;
final Future<void> 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<VisibilityToggle> createState() => VisibilityToggleState();
}
class VisibilityToggleState extends State<VisibilityToggle> {
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<void> _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<void> _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,
),
);
},
),
],
);