Skip to content

Commit

Permalink
Implement custom theme
Browse files Browse the repository at this point in the history
  • Loading branch information
veloce committed Dec 10, 2024
1 parent fb4be68 commit 52c1ded
Show file tree
Hide file tree
Showing 9 changed files with 155 additions and 81 deletions.
29 changes: 22 additions & 7 deletions lib/src/app.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import 'package:lichess_mobile/src/navigation.dart';
import 'package:lichess_mobile/src/network/connectivity.dart';
import 'package:lichess_mobile/src/network/http.dart';
import 'package:lichess_mobile/src/network/socket.dart';
import 'package:lichess_mobile/src/styles/lichess_colors.dart';
import 'package:lichess_mobile/src/styles/styles.dart';
import 'package:lichess_mobile/src/utils/screen.dart';

Expand Down Expand Up @@ -147,13 +148,27 @@ class _AppState extends ConsumerState<Application> {
final dynamicColorScheme =
brightness == Brightness.light ? fixedLightScheme : fixedDarkScheme;

final colorScheme =
generalPrefs.systemColors && dynamicColorScheme != null
? dynamicColorScheme
: ColorScheme.fromSeed(
seedColor: boardTheme.colors.darkSquare,
brightness: brightness,
);
ColorScheme colorScheme;
if (generalPrefs.customThemeEnabled) {
if (generalPrefs.customThemeSeed != null) {
colorScheme = ColorScheme.fromSeed(
seedColor: generalPrefs.customThemeSeed!,
brightness: brightness,
);
} else if (dynamicColorScheme != null) {
colorScheme = dynamicColorScheme;
} else {
colorScheme = ColorScheme.fromSeed(
seedColor: LichessColors.primary[500]!,
brightness: brightness,
);
}
} else {
colorScheme = ColorScheme.fromSeed(
seedColor: boardTheme.colors.darkSquare,
brightness: brightness,
);
}

final cupertinoThemeData = CupertinoThemeData(
primaryColor: colorScheme.primary,
Expand Down
26 changes: 18 additions & 8 deletions lib/src/init.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import 'package:lichess_mobile/src/db/secure_storage.dart';
import 'package:lichess_mobile/src/model/notifications/notification_service.dart';
import 'package:lichess_mobile/src/model/notifications/notifications.dart';
import 'package:lichess_mobile/src/model/settings/board_preferences.dart';
import 'package:lichess_mobile/src/model/settings/general_preferences.dart';
import 'package:lichess_mobile/src/model/settings/preferences_storage.dart';
import 'package:lichess_mobile/src/utils/chessboard.dart';
import 'package:lichess_mobile/src/utils/color_palette.dart';
Expand Down Expand Up @@ -95,14 +96,23 @@ Future<void> androidDisplayInitialization(WidgetsBinding widgetsBinding) async {
await DynamicColorPlugin.getCorePalette().then((value) {
setCorePalette(value);

if (getCorePalette() != null &&
prefs.getString(PrefCategory.board.storageKey) == null) {
prefs.setString(
PrefCategory.board.storageKey,
jsonEncode(
BoardPrefs.defaults.copyWith(boardTheme: BoardTheme.system),
),
);
if (getCorePalette() != null) {
if (prefs.getString(PrefCategory.general.storageKey) == null) {
prefs.setString(
PrefCategory.general.storageKey,
jsonEncode(
GeneralPrefs.defaults.copyWith(customThemeEnabled: true),
),
);
}
if (prefs.getString(PrefCategory.board.storageKey) == null) {
prefs.setString(
PrefCategory.board.storageKey,
jsonEncode(
BoardPrefs.defaults.copyWith(boardTheme: BoardTheme.system),
),
);
}
}
});
} catch (e) {
Expand Down
24 changes: 8 additions & 16 deletions lib/src/model/settings/general_preferences.dart
Original file line number Diff line number Diff line change
Expand Up @@ -49,17 +49,9 @@ class GeneralPreferences extends _$GeneralPreferences
return save(state.copyWith(masterVolume: volume));
}

Future<void> toggleCustomTheme() {
return save(state.copyWith(customThemeEnabled: !state.customThemeEnabled));
}

Future<void> setCustomThemeSeed(Color? color) {
return save(state.copyWith(customThemeSeed: color));
}

Future<void> toggleSystemColors() async {
await save(state.copyWith(systemColors: !state.systemColors));
if (state.systemColors == false) {
Future<void> toggleCustomTheme() async {
await save(state.copyWith(customThemeEnabled: !state.customThemeEnabled));
if (state.customThemeEnabled == false) {
final boardTheme = ref.read(boardPreferencesProvider).boardTheme;
if (boardTheme == BoardTheme.system) {
await ref
Expand All @@ -72,6 +64,10 @@ class GeneralPreferences extends _$GeneralPreferences
.setBoardTheme(BoardTheme.system);
}
}

Future<void> setCustomThemeSeed(Color? color) {
return save(state.copyWith(customThemeSeed: color));
}
}

@Freezed(fromJson: true, toJson: true)
Expand All @@ -87,9 +83,6 @@ class GeneralPrefs with _$GeneralPrefs implements Serializable {
required SoundTheme soundTheme,
@JsonKey(defaultValue: 0.8) required double masterVolume,

/// Should enable system color palette (android 12+ only)
required bool systemColors,

/// Should enable custom theme
@JsonKey(defaultValue: false) required bool customThemeEnabled,

Expand All @@ -105,8 +98,7 @@ class GeneralPrefs with _$GeneralPrefs implements Serializable {
isSoundEnabled: true,
soundTheme: SoundTheme.standard,
masterVolume: 0.8,
systemColors: true,
customThemeEnabled: false,
customThemeEnabled: true,
);

factory GeneralPrefs.fromJson(Map<String, dynamic> json) {
Expand Down
6 changes: 6 additions & 0 deletions lib/src/utils/color_palette.dart
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,12 @@ void setCorePalette(CorePalette? palette) {
}
}

Color? getCorePalettePrimary() {
return _corePalette?.primary != null
? Color(_corePalette!.primary.get(50))
: null;
}

/// Get the core palette if available (android 12+ only).
CorePalette? getCorePalette() {
return _corePalette;
Expand Down
3 changes: 0 additions & 3 deletions lib/src/view/puzzle/puzzle_tab_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -423,9 +423,6 @@ class _PuzzleMenuListTile extends StatelessWidget {
leading: Icon(
icon,
size: Styles.mainListTileIconSize,
color: Theme.of(context).platform == TargetPlatform.iOS
? CupertinoTheme.of(context).primaryColor
: Theme.of(context).colorScheme.primary,
),
title: Text(title, style: Styles.mainListTileTitle),
subtitle: Text(subtitle, maxLines: 3),
Expand Down
1 change: 0 additions & 1 deletion lib/src/view/settings/account_preferences_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,6 @@ class _AccountPreferencesScreenState
subtitle: Text(
context.l10n.preferencesExplainShowPlayerRatings,
maxLines: 5,
textAlign: TextAlign.justify,
),
value: data.showRatings.value,
onChanged: isLoading
Expand Down
16 changes: 3 additions & 13 deletions lib/src/view/settings/board_theme_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@ import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:lichess_mobile/src/model/settings/board_preferences.dart';
import 'package:lichess_mobile/src/model/settings/general_preferences.dart';
import 'package:lichess_mobile/src/utils/color_palette.dart';
import 'package:lichess_mobile/src/utils/l10n_context.dart';
import 'package:lichess_mobile/src/utils/system.dart';
import 'package:lichess_mobile/src/widgets/list.dart';
import 'package:lichess_mobile/src/widgets/platform.dart';

Expand Down Expand Up @@ -40,20 +39,11 @@ class _Body extends ConsumerWidget {
final boardTheme =
ref.watch(boardPreferencesProvider.select((p) => p.boardTheme));

final hasSystemColors =
ref.watch(generalPreferencesProvider.select((p) => p.systemColors));

final androidVersion = ref.watch(androidVersionProvider).whenOrNull(
data: (v) => v,
);
final hasSystemColors = getCorePalette() != null;

final choices = BoardTheme.values
.where(
(t) =>
t != BoardTheme.system ||
(hasSystemColors &&
androidVersion != null &&
androidVersion.sdkInt >= 31),
(t) => t != BoardTheme.system || hasSystemColors,
)
.toList();

Expand Down
128 changes: 95 additions & 33 deletions lib/src/view/settings/theme_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,13 @@ import 'package:lichess_mobile/src/model/settings/board_preferences.dart';
import 'package:lichess_mobile/src/model/settings/general_preferences.dart';
import 'package:lichess_mobile/src/styles/lichess_colors.dart';
import 'package:lichess_mobile/src/styles/lichess_icons.dart';
import 'package:lichess_mobile/src/utils/color_palette.dart';
import 'package:lichess_mobile/src/utils/l10n_context.dart';
import 'package:lichess_mobile/src/utils/navigation.dart';
import 'package:lichess_mobile/src/utils/system.dart';
import 'package:lichess_mobile/src/view/settings/board_theme_screen.dart';
import 'package:lichess_mobile/src/view/settings/piece_set_screen.dart';
import 'package:lichess_mobile/src/widgets/adaptive_choice_picker.dart';
import 'package:lichess_mobile/src/widgets/buttons.dart';
import 'package:lichess_mobile/src/widgets/list.dart';
import 'package:lichess_mobile/src/widgets/platform_alert_dialog.dart';
import 'package:lichess_mobile/src/widgets/platform_scaffold.dart';
Expand Down Expand Up @@ -50,7 +51,6 @@ class _Body extends ConsumerWidget {
Widget build(BuildContext context, WidgetRef ref) {
final generalPrefs = ref.watch(generalPreferencesProvider);
final boardPrefs = ref.watch(boardPreferencesProvider);
final androidVersionAsync = ref.watch(androidVersionProvider);

const horizontalPadding = 16.0;

Expand Down Expand Up @@ -98,25 +98,17 @@ class _Body extends ConsumerWidget {
ListSection(
hasLeading: true,
children: [
if (Theme.of(context).platform == TargetPlatform.android)
androidVersionAsync.maybeWhen(
data: (version) => version != null && version.sdkInt >= 31
? SwitchSettingTile(
leading: const Icon(Icons.colorize_outlined),
title: Text(context.l10n.mobileSystemColors),
value: generalPrefs.systemColors,
onChanged: (value) {
ref
.read(generalPreferencesProvider.notifier)
.toggleSystemColors();
},
)
: const SizedBox.shrink(),
orElse: () => const SizedBox.shrink(),
),
SwitchSettingTile(
leading: const Icon(Icons.colorize_outlined),
padding: Theme.of(context).platform == TargetPlatform.iOS
? const EdgeInsets.symmetric(horizontal: 14, vertical: 8)
: null,
title: const Text('Custom theme'),
// TODO translate
subtitle: const Text(
'Configure your own app theme using a seed color. Disable to use the chessboard theme.',
maxLines: 3,
),
value: generalPrefs.customThemeEnabled,
onChanged: (value) {
ref
Expand All @@ -137,34 +129,104 @@ class _Body extends ConsumerWidget {
children: [
PlatformListTile(
leading: const Icon(Icons.color_lens),
title: const Text('Custom theme color'),
title: const Text('Seed color'),
trailing: generalPrefs.customThemeSeed != null
? Container(
width: 20,
height: 20,
decoration: BoxDecoration(
color: generalPrefs.customThemeSeed ??
LichessColors.primary,
color: generalPrefs.customThemeSeed,
shape: BoxShape.circle,
),
)
: null,
: getCorePalette() != null
? Text(context.l10n.mobileSystemColors)
: Container(
width: 20,
height: 20,
decoration: BoxDecoration(
color: LichessColors.primary[500],
shape: BoxShape.circle,
),
),
onTap: () {
showAdaptiveDialog<void>(
showAdaptiveDialog<Object>(
context: context,
barrierDismissible: true,
barrierDismissible: false,
builder: (context) {
return PlatformAlertDialog(
content: SingleChildScrollView(
child: ColorPicker(
pickerColor: generalPrefs.customThemeSeed ??
LichessColors.primary,
onColorChanged: (color) {},
),
),
final defaultColor = getCorePalettePrimary() ??
LichessColors.primary[500]!;
bool useDefault =
generalPrefs.customThemeSeed == null;
Color color =
generalPrefs.customThemeSeed ?? defaultColor;
return StatefulBuilder(
builder: (context, setState) {
return PlatformAlertDialog(
content: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
ColorPicker(
enableAlpha: false,
pickerColor: color,
onColorChanged: (c) {
setState(() {
useDefault = false;
color = c;
});
},
),
SecondaryButton(
semanticsLabel: getCorePalette() != null
? context.l10n.mobileSystemColors
: 'Default color',
onPressed: !useDefault
? () {
setState(() {
useDefault = true;
color = defaultColor;
});
}
: null,
child: Text(
getCorePalette() != null
? context.l10n.mobileSystemColors
: 'Default color',
),
),
SecondaryButton(
semanticsLabel: context.l10n.cancel,
onPressed: () {
Navigator.of(context).pop(false);
},
child: Text(context.l10n.cancel),
),
SecondaryButton(
semanticsLabel: context.l10n.ok,
onPressed: () {
if (useDefault) {
Navigator.of(context).pop(null);
} else {
Navigator.of(context).pop(color);
}
},
child: Text(context.l10n.ok),
),
],
),
),
);
},
);
},
);
).then((color) {
if (color != false) {
ref
.read(generalPreferencesProvider.notifier)
.setCustomThemeSeed(color as Color?);
}
});
},
),
],
Expand Down
3 changes: 3 additions & 0 deletions lib/src/widgets/settings.dart
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ class SwitchSettingTile extends StatelessWidget {
required this.value,
this.onChanged,
this.leading,
this.padding,
super.key,
});

Expand All @@ -82,10 +83,12 @@ class SwitchSettingTile extends StatelessWidget {
final bool value;
final void Function(bool value)? onChanged;
final Widget? leading;
final EdgeInsetsGeometry? padding;

@override
Widget build(BuildContext context) {
return PlatformListTile(
padding: padding,
leading: leading,
title: _SettingsTitle(title: title),
subtitle: subtitle,
Expand Down

0 comments on commit 52c1ded

Please sign in to comment.