Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions lib/src/model/account/account_preferences.dart
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ typedef AccountPrefState = ({
BooleanPref clockSound,
// privacy
BooleanPref follow,
Challenge challenge,
});

/// A provider that tells if the user wants to see ratings in the app.
Expand Down Expand Up @@ -71,6 +72,7 @@ final defaultAccountPreferences = (
SubmitMoveChoice.correspondence,
}),
follow: const BooleanPref(true),
challenge: Challenge.registered,
);

/// Get the account preferences for the current user.
Expand Down Expand Up @@ -116,6 +118,7 @@ class AccountPreferences extends _$AccountPreferences {
_setPref('confirmResign', value);
Future<void> setSubmitMove(SubmitMove value) => _setPref('submitMove', value);
Future<void> setFollow(BooleanPref value) => _setPref('follow', value);
Future<void> setChallenge(Challenge value) => _setPref('challenge', value);

Future<void> _setPref<T>(String key, AccountPref<T> value) async {
await Future<void>.delayed(const Duration(milliseconds: 200));
Expand Down Expand Up @@ -375,6 +378,54 @@ enum Moretime implements AccountPref<int> {
}
}

enum Challenge implements AccountPref<int> {
never(1),
rating(2),
friends(3),
registered(4),
always(5);

const Challenge(this.value);

@override
final int value;

@override
String get toFormData => value.toString();

String label(BuildContext context) {
switch (this) {
case Challenge.never:
return context.l10n.never;
case Challenge.rating:
return context.l10n.ifRatingIsPlusMinusX('300');
case Challenge.friends:
return context.l10n.onlyFriends;
case Challenge.registered:
return context.l10n.ifRegistered;
case Challenge.always:
return context.l10n.always;
}
}

static Challenge fromInt(int value) {
switch (value) {
case 1:
return Challenge.never;
case 2:
return Challenge.rating;
case 3:
return Challenge.friends;
case 4:
return Challenge.registered;
case 5:
return Challenge.always;
default:
throw Exception('Invalid value for Challenge');
}
}
}

class SubmitMove implements AccountPref<int> {
SubmitMove(Iterable<SubmitMoveChoice> choices)
: choices = ISet(choices.toSet());
Expand Down
1 change: 1 addition & 0 deletions lib/src/model/account/account_repository.dart
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@ AccountPrefState _accountPreferencesFromPick(RequiredPick pick) {
pick('submitMove').asIntOrThrow(),
),
follow: BooleanPref(pick('follow').asBoolOrThrow()),
challenge: Challenge.fromInt(pick('challenge').asIntOrThrow()),
);
}

Expand Down
99 changes: 99 additions & 0 deletions lib/src/view/settings/account_preferences_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,41 @@ class _AccountPreferencesScreenState
);
},
),
SettingsListTile(
settingsLabel: Text(
context.l10n.letOtherPlayersChallengeYou,
),
settingsValue: data.challenge.label(context),
showCupertinoTrailingValue: false,
onTap: () {
if (Theme.of(context).platform ==
TargetPlatform.android) {
showChoicePicker(
context,
choices: Challenge.values,
selectedItem: data.challenge,
labelBuilder: (t) => Text(t.label(context)),
onSelectedItemChanged: isLoading
? null
: (Challenge? value) {
_setPref(
() => ref
.read(
accountPreferencesProvider.notifier,
)
.setChallenge(value ?? data.challenge),
);
},
);
} else {
pushPlatformRoute(
context,
title: context.l10n.letOtherPlayersChallengeYou,
builder: (context) => const AutoQueenSettingsScreen(),
);
}
},
),
],
),
],
Expand Down Expand Up @@ -800,3 +835,67 @@ class _MoretimeSettingsScreenState
);
}
}

class ChallengeSettingsScreen extends ConsumerStatefulWidget {
const ChallengeSettingsScreen({super.key});

@override
ConsumerState<ChallengeSettingsScreen> createState() =>
_ChallengeSettingsScreenState();
}

class _ChallengeSettingsScreenState
extends ConsumerState<ChallengeSettingsScreen> {
Future<void>? _pendingSetChallenge;

@override
Widget build(BuildContext context) {
final accountPrefs = ref.watch(accountPreferencesProvider);
return accountPrefs.when(
data: (data) {
if (data == null) {
return Center(
child: Text(context.l10n.mobileMustBeLoggedIn),
);
}

return FutureBuilder(
future: _pendingSetChallenge,
builder: (context, snapshot) {
return CupertinoPageScaffold(
navigationBar: CupertinoNavigationBar(
trailing: snapshot.connectionState == ConnectionState.waiting
? const CircularProgressIndicator.adaptive()
: null,
),
child: SafeArea(
child: ListView(
children: [
ChoicePicker(
choices: Challenge.values,
selectedItem: data.challenge,
titleBuilder: (t) => Text(t.label(context)),
onSelectedItemChanged:
snapshot.connectionState == ConnectionState.waiting
? null
: (Challenge? v) {
final future = ref
.read(accountPreferencesProvider.notifier)
.setChallenge(v ?? data.challenge);
setState(() {
_pendingSetChallenge = future;
});
},
),
],
),
),
);
},
);
},
loading: () => const Center(child: CircularProgressIndicator()),
error: (err, stack) => Center(child: Text(err.toString())),
);
}
}