More customize options are back

This commit is contained in:
LittleSheep 2025-05-30 01:23:24 +08:00
parent b0c1981c9a
commit afe1c700eb
9 changed files with 252 additions and 47 deletions

View File

@ -279,6 +279,10 @@
"settingsSoundEffects": "Sound Effects", "settingsSoundEffects": "Sound Effects",
"settingsAprilFoolFeatures": "April Fool Features", "settingsAprilFoolFeatures": "April Fool Features",
"settingsEnterToSend": "Enter to Send", "settingsEnterToSend": "Enter to Send",
"settingsTransparentAppBar": "Transparent App Bar",
"settingsCustomFonts": "Custom Fonts",
"settingsCustomFontsHint": "Custom fonts will be used for all text in the app. Make sure it is installed on your device.",
"settingsColorScheme": "Color Scheme",
"postTitle": "Title", "postTitle": "Title",
"postDescription": "Description", "postDescription": "Description",
"call": "Call", "call": "Call",

View File

@ -137,6 +137,8 @@ PODS:
- OrderedSet (6.0.3) - OrderedSet (6.0.3)
- package_info_plus (0.4.5): - package_info_plus (0.4.5):
- Flutter - Flutter
- pasteboard (0.0.1):
- Flutter
- path_provider_foundation (0.0.1): - path_provider_foundation (0.0.1):
- Flutter - Flutter
- FlutterMacOS - FlutterMacOS
@ -204,6 +206,7 @@ DEPENDENCIES:
- media_kit_libs_ios_video (from `.symlinks/plugins/media_kit_libs_ios_video/ios`) - media_kit_libs_ios_video (from `.symlinks/plugins/media_kit_libs_ios_video/ios`)
- media_kit_video (from `.symlinks/plugins/media_kit_video/ios`) - media_kit_video (from `.symlinks/plugins/media_kit_video/ios`)
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`) - package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
- pasteboard (from `.symlinks/plugins/pasteboard/ios`)
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`) - path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`) - shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
- sqflite_darwin (from `.symlinks/plugins/sqflite_darwin/darwin`) - sqflite_darwin (from `.symlinks/plugins/sqflite_darwin/darwin`)
@ -271,6 +274,8 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/media_kit_video/ios" :path: ".symlinks/plugins/media_kit_video/ios"
package_info_plus: package_info_plus:
:path: ".symlinks/plugins/package_info_plus/ios" :path: ".symlinks/plugins/package_info_plus/ios"
pasteboard:
:path: ".symlinks/plugins/pasteboard/ios"
path_provider_foundation: path_provider_foundation:
:path: ".symlinks/plugins/path_provider_foundation/darwin" :path: ".symlinks/plugins/path_provider_foundation/darwin"
shared_preferences_foundation: shared_preferences_foundation:
@ -319,6 +324,7 @@ SPEC CHECKSUMS:
nanopb: fad817b59e0457d11a5dfbde799381cd727c1275 nanopb: fad817b59e0457d11a5dfbde799381cd727c1275
OrderedSet: e539b66b644ff081c73a262d24ad552a69be3a94 OrderedSet: e539b66b644ff081c73a262d24ad552a69be3a94
package_info_plus: af8e2ca6888548050f16fa2f1938db7b5a5df499 package_info_plus: af8e2ca6888548050f16fa2f1938db7b5a5df499
pasteboard: 49088aeb6119d51f976a421db60d8e1ab079b63c
path_provider_foundation: 080d55be775b7414fd5a5ef3ac137b97b097e564 path_provider_foundation: 080d55be775b7414fd5a5ef3ac137b97b097e564
PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47 PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47
SAMKeychain: 483e1c9f32984d50ca961e26818a534283b4cd5c SAMKeychain: 483e1c9f32984d50ca961e26818a534283b4cd5c

View File

@ -1,9 +1,12 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:island/pods/theme.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
part 'config.freezed.dart'; part 'config.freezed.dart';
part 'config.g.dart';
const kTokenPairStoreKey = 'dyn_user_tk'; const kTokenPairStoreKey = 'dyn_user_tk';
@ -14,13 +17,8 @@ const kAppbarTransparentStoreKey = 'app_bar_transparent';
const kAppBackgroundStoreKey = 'app_has_background'; const kAppBackgroundStoreKey = 'app_has_background';
const kAppColorSchemeStoreKey = 'app_color_scheme'; const kAppColorSchemeStoreKey = 'app_color_scheme';
const kAppNotifyWithHaptic = 'app_notify_with_haptic'; const kAppNotifyWithHaptic = 'app_notify_with_haptic';
const kAppExpandPostLink = 'app_expand_post_link';
const kAppExpandChatLink = 'app_expand_chat_link';
const kAppRealmCompactView = 'app_realm_compact_view';
const kAppCustomFonts = 'app_custom_fonts'; const kAppCustomFonts = 'app_custom_fonts';
const kAppMixedFeed = 'app_mixed_feed';
const kAppAutoTranslate = 'app_auto_translate'; const kAppAutoTranslate = 'app_auto_translate';
const kAppHideBottomNav = 'app_hide_bottom_nav';
const kAppSoundEffects = 'app_sound_effects'; const kAppSoundEffects = 'app_sound_effects';
const kAppAprilFoolFeatures = 'app_april_fool_features'; const kAppAprilFoolFeatures = 'app_april_fool_features';
const kAppWindowSize = 'app_window_size'; const kAppWindowSize = 'app_window_size';
@ -57,48 +55,73 @@ sealed class AppSettings with _$AppSettings {
required bool soundEffects, required bool soundEffects,
required bool aprilFoolFeatures, required bool aprilFoolFeatures,
required bool enterToSend, required bool enterToSend,
required bool appBarTransparent,
required String? customFonts,
required int? appColorScheme, // The color stored via the int type
}) = _AppSettings; }) = _AppSettings;
} }
class AppSettingsNotifier extends StateNotifier<AppSettings> { @riverpod
final SharedPreferences prefs; class AppSettingsNotifier extends _$AppSettingsNotifier {
@override
AppSettingsNotifier(this.prefs) AppSettings build() {
: super( final prefs = ref.watch(sharedPreferencesProvider);
AppSettings( return AppSettings(
autoTranslate: prefs.getBool(kAppAutoTranslate) ?? false, autoTranslate: prefs.getBool(kAppAutoTranslate) ?? false,
soundEffects: prefs.getBool(kAppSoundEffects) ?? true, soundEffects: prefs.getBool(kAppSoundEffects) ?? true,
aprilFoolFeatures: prefs.getBool(kAppAprilFoolFeatures) ?? true, aprilFoolFeatures: prefs.getBool(kAppAprilFoolFeatures) ?? true,
enterToSend: prefs.getBool(kAppEnterToSend) ?? true, enterToSend: prefs.getBool(kAppEnterToSend) ?? true,
), appBarTransparent: prefs.getBool(kAppbarTransparentStoreKey) ?? false,
); customFonts: prefs.getString(kAppCustomFonts),
appColorScheme: prefs.getInt(kAppColorSchemeStoreKey),
);
}
void setAutoTranslate(bool value) { void setAutoTranslate(bool value) {
final prefs = ref.read(sharedPreferencesProvider);
prefs.setBool(kAppAutoTranslate, value); prefs.setBool(kAppAutoTranslate, value);
state = state.copyWith(autoTranslate: value); state = state.copyWith(autoTranslate: value);
} }
void setSoundEffects(bool value) { void setSoundEffects(bool value) {
final prefs = ref.read(sharedPreferencesProvider);
prefs.setBool(kAppSoundEffects, value); prefs.setBool(kAppSoundEffects, value);
state = state.copyWith(soundEffects: value); state = state.copyWith(soundEffects: value);
} }
void setAprilFoolFeatures(bool value) { void setAprilFoolFeatures(bool value) {
final prefs = ref.read(sharedPreferencesProvider);
prefs.setBool(kAppAprilFoolFeatures, value); prefs.setBool(kAppAprilFoolFeatures, value);
state = state.copyWith(aprilFoolFeatures: value); state = state.copyWith(aprilFoolFeatures: value);
} }
void setEnterToSend(bool value) { void setEnterToSend(bool value) {
final prefs = ref.read(sharedPreferencesProvider);
prefs.setBool(kAppEnterToSend, value); prefs.setBool(kAppEnterToSend, value);
state = state.copyWith(enterToSend: value); state = state.copyWith(enterToSend: value);
} }
}
final appSettingsProvider = void setAppBarTransparent(bool value) {
StateNotifierProvider<AppSettingsNotifier, AppSettings>((ref) { final prefs = ref.read(sharedPreferencesProvider);
final prefs = ref.watch(sharedPreferencesProvider); prefs.setBool(kAppbarTransparentStoreKey, value);
return AppSettingsNotifier(prefs); state = state.copyWith(appBarTransparent: value);
}); ref.read(themeProvider.notifier).reloadTheme();
}
void setCustomFonts(String? value) {
final prefs = ref.read(sharedPreferencesProvider);
prefs.setString(kAppCustomFonts, value ?? '');
state = state.copyWith(customFonts: value);
ref.read(themeProvider.notifier).reloadTheme();
}
void setAppColorScheme(int? value) {
final prefs = ref.read(sharedPreferencesProvider);
prefs.setInt(kAppColorSchemeStoreKey, value ?? 0);
state = state.copyWith(appColorScheme: value);
ref.read(themeProvider.notifier).reloadTheme();
}
}
final updateInfoProvider = final updateInfoProvider =
StateNotifierProvider<UpdateInfoNotifier, (String?, String?)>((ref) { StateNotifierProvider<UpdateInfoNotifier, (String?, String?)>((ref) {

View File

@ -15,7 +15,7 @@ T _$identity<T>(T value) => value;
/// @nodoc /// @nodoc
mixin _$AppSettings { mixin _$AppSettings {
bool get autoTranslate; bool get soundEffects; bool get aprilFoolFeatures; bool get enterToSend; bool get autoTranslate; bool get soundEffects; bool get aprilFoolFeatures; bool get enterToSend; bool get appBarTransparent; String? get customFonts; int? get appColorScheme;
/// Create a copy of AppSettings /// Create a copy of AppSettings
/// with the given fields replaced by the non-null parameter values. /// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false) @JsonKey(includeFromJson: false, includeToJson: false)
@ -26,16 +26,16 @@ $AppSettingsCopyWith<AppSettings> get copyWith => _$AppSettingsCopyWithImpl<AppS
@override @override
bool operator ==(Object other) { bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is AppSettings&&(identical(other.autoTranslate, autoTranslate) || other.autoTranslate == autoTranslate)&&(identical(other.soundEffects, soundEffects) || other.soundEffects == soundEffects)&&(identical(other.aprilFoolFeatures, aprilFoolFeatures) || other.aprilFoolFeatures == aprilFoolFeatures)&&(identical(other.enterToSend, enterToSend) || other.enterToSend == enterToSend)); return identical(this, other) || (other.runtimeType == runtimeType&&other is AppSettings&&(identical(other.autoTranslate, autoTranslate) || other.autoTranslate == autoTranslate)&&(identical(other.soundEffects, soundEffects) || other.soundEffects == soundEffects)&&(identical(other.aprilFoolFeatures, aprilFoolFeatures) || other.aprilFoolFeatures == aprilFoolFeatures)&&(identical(other.enterToSend, enterToSend) || other.enterToSend == enterToSend)&&(identical(other.appBarTransparent, appBarTransparent) || other.appBarTransparent == appBarTransparent)&&(identical(other.customFonts, customFonts) || other.customFonts == customFonts)&&(identical(other.appColorScheme, appColorScheme) || other.appColorScheme == appColorScheme));
} }
@override @override
int get hashCode => Object.hash(runtimeType,autoTranslate,soundEffects,aprilFoolFeatures,enterToSend); int get hashCode => Object.hash(runtimeType,autoTranslate,soundEffects,aprilFoolFeatures,enterToSend,appBarTransparent,customFonts,appColorScheme);
@override @override
String toString() { String toString() {
return 'AppSettings(autoTranslate: $autoTranslate, soundEffects: $soundEffects, aprilFoolFeatures: $aprilFoolFeatures, enterToSend: $enterToSend)'; return 'AppSettings(autoTranslate: $autoTranslate, soundEffects: $soundEffects, aprilFoolFeatures: $aprilFoolFeatures, enterToSend: $enterToSend, appBarTransparent: $appBarTransparent, customFonts: $customFonts, appColorScheme: $appColorScheme)';
} }
@ -46,7 +46,7 @@ abstract mixin class $AppSettingsCopyWith<$Res> {
factory $AppSettingsCopyWith(AppSettings value, $Res Function(AppSettings) _then) = _$AppSettingsCopyWithImpl; factory $AppSettingsCopyWith(AppSettings value, $Res Function(AppSettings) _then) = _$AppSettingsCopyWithImpl;
@useResult @useResult
$Res call({ $Res call({
bool autoTranslate, bool soundEffects, bool aprilFoolFeatures, bool enterToSend bool autoTranslate, bool soundEffects, bool aprilFoolFeatures, bool enterToSend, bool appBarTransparent, String? customFonts, int? appColorScheme
}); });
@ -63,13 +63,16 @@ class _$AppSettingsCopyWithImpl<$Res>
/// Create a copy of AppSettings /// Create a copy of AppSettings
/// with the given fields replaced by the non-null parameter values. /// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline') @override $Res call({Object? autoTranslate = null,Object? soundEffects = null,Object? aprilFoolFeatures = null,Object? enterToSend = null,}) { @pragma('vm:prefer-inline') @override $Res call({Object? autoTranslate = null,Object? soundEffects = null,Object? aprilFoolFeatures = null,Object? enterToSend = null,Object? appBarTransparent = null,Object? customFonts = freezed,Object? appColorScheme = freezed,}) {
return _then(_self.copyWith( return _then(_self.copyWith(
autoTranslate: null == autoTranslate ? _self.autoTranslate : autoTranslate // ignore: cast_nullable_to_non_nullable autoTranslate: null == autoTranslate ? _self.autoTranslate : autoTranslate // ignore: cast_nullable_to_non_nullable
as bool,soundEffects: null == soundEffects ? _self.soundEffects : soundEffects // ignore: cast_nullable_to_non_nullable as bool,soundEffects: null == soundEffects ? _self.soundEffects : soundEffects // ignore: cast_nullable_to_non_nullable
as bool,aprilFoolFeatures: null == aprilFoolFeatures ? _self.aprilFoolFeatures : aprilFoolFeatures // ignore: cast_nullable_to_non_nullable as bool,aprilFoolFeatures: null == aprilFoolFeatures ? _self.aprilFoolFeatures : aprilFoolFeatures // ignore: cast_nullable_to_non_nullable
as bool,enterToSend: null == enterToSend ? _self.enterToSend : enterToSend // ignore: cast_nullable_to_non_nullable as bool,enterToSend: null == enterToSend ? _self.enterToSend : enterToSend // ignore: cast_nullable_to_non_nullable
as bool, as bool,appBarTransparent: null == appBarTransparent ? _self.appBarTransparent : appBarTransparent // ignore: cast_nullable_to_non_nullable
as bool,customFonts: freezed == customFonts ? _self.customFonts : customFonts // ignore: cast_nullable_to_non_nullable
as String?,appColorScheme: freezed == appColorScheme ? _self.appColorScheme : appColorScheme // ignore: cast_nullable_to_non_nullable
as int?,
)); ));
} }
@ -80,13 +83,16 @@ as bool,
class _AppSettings implements AppSettings { class _AppSettings implements AppSettings {
const _AppSettings({required this.autoTranslate, required this.soundEffects, required this.aprilFoolFeatures, required this.enterToSend}); const _AppSettings({required this.autoTranslate, required this.soundEffects, required this.aprilFoolFeatures, required this.enterToSend, required this.appBarTransparent, required this.customFonts, required this.appColorScheme});
@override final bool autoTranslate; @override final bool autoTranslate;
@override final bool soundEffects; @override final bool soundEffects;
@override final bool aprilFoolFeatures; @override final bool aprilFoolFeatures;
@override final bool enterToSend; @override final bool enterToSend;
@override final bool appBarTransparent;
@override final String? customFonts;
@override final int? appColorScheme;
/// Create a copy of AppSettings /// Create a copy of AppSettings
/// with the given fields replaced by the non-null parameter values. /// with the given fields replaced by the non-null parameter values.
@ -98,16 +104,16 @@ _$AppSettingsCopyWith<_AppSettings> get copyWith => __$AppSettingsCopyWithImpl<_
@override @override
bool operator ==(Object other) { bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is _AppSettings&&(identical(other.autoTranslate, autoTranslate) || other.autoTranslate == autoTranslate)&&(identical(other.soundEffects, soundEffects) || other.soundEffects == soundEffects)&&(identical(other.aprilFoolFeatures, aprilFoolFeatures) || other.aprilFoolFeatures == aprilFoolFeatures)&&(identical(other.enterToSend, enterToSend) || other.enterToSend == enterToSend)); return identical(this, other) || (other.runtimeType == runtimeType&&other is _AppSettings&&(identical(other.autoTranslate, autoTranslate) || other.autoTranslate == autoTranslate)&&(identical(other.soundEffects, soundEffects) || other.soundEffects == soundEffects)&&(identical(other.aprilFoolFeatures, aprilFoolFeatures) || other.aprilFoolFeatures == aprilFoolFeatures)&&(identical(other.enterToSend, enterToSend) || other.enterToSend == enterToSend)&&(identical(other.appBarTransparent, appBarTransparent) || other.appBarTransparent == appBarTransparent)&&(identical(other.customFonts, customFonts) || other.customFonts == customFonts)&&(identical(other.appColorScheme, appColorScheme) || other.appColorScheme == appColorScheme));
} }
@override @override
int get hashCode => Object.hash(runtimeType,autoTranslate,soundEffects,aprilFoolFeatures,enterToSend); int get hashCode => Object.hash(runtimeType,autoTranslate,soundEffects,aprilFoolFeatures,enterToSend,appBarTransparent,customFonts,appColorScheme);
@override @override
String toString() { String toString() {
return 'AppSettings(autoTranslate: $autoTranslate, soundEffects: $soundEffects, aprilFoolFeatures: $aprilFoolFeatures, enterToSend: $enterToSend)'; return 'AppSettings(autoTranslate: $autoTranslate, soundEffects: $soundEffects, aprilFoolFeatures: $aprilFoolFeatures, enterToSend: $enterToSend, appBarTransparent: $appBarTransparent, customFonts: $customFonts, appColorScheme: $appColorScheme)';
} }
@ -118,7 +124,7 @@ abstract mixin class _$AppSettingsCopyWith<$Res> implements $AppSettingsCopyWith
factory _$AppSettingsCopyWith(_AppSettings value, $Res Function(_AppSettings) _then) = __$AppSettingsCopyWithImpl; factory _$AppSettingsCopyWith(_AppSettings value, $Res Function(_AppSettings) _then) = __$AppSettingsCopyWithImpl;
@override @useResult @override @useResult
$Res call({ $Res call({
bool autoTranslate, bool soundEffects, bool aprilFoolFeatures, bool enterToSend bool autoTranslate, bool soundEffects, bool aprilFoolFeatures, bool enterToSend, bool appBarTransparent, String? customFonts, int? appColorScheme
}); });
@ -135,13 +141,16 @@ class __$AppSettingsCopyWithImpl<$Res>
/// Create a copy of AppSettings /// Create a copy of AppSettings
/// with the given fields replaced by the non-null parameter values. /// with the given fields replaced by the non-null parameter values.
@override @pragma('vm:prefer-inline') $Res call({Object? autoTranslate = null,Object? soundEffects = null,Object? aprilFoolFeatures = null,Object? enterToSend = null,}) { @override @pragma('vm:prefer-inline') $Res call({Object? autoTranslate = null,Object? soundEffects = null,Object? aprilFoolFeatures = null,Object? enterToSend = null,Object? appBarTransparent = null,Object? customFonts = freezed,Object? appColorScheme = freezed,}) {
return _then(_AppSettings( return _then(_AppSettings(
autoTranslate: null == autoTranslate ? _self.autoTranslate : autoTranslate // ignore: cast_nullable_to_non_nullable autoTranslate: null == autoTranslate ? _self.autoTranslate : autoTranslate // ignore: cast_nullable_to_non_nullable
as bool,soundEffects: null == soundEffects ? _self.soundEffects : soundEffects // ignore: cast_nullable_to_non_nullable as bool,soundEffects: null == soundEffects ? _self.soundEffects : soundEffects // ignore: cast_nullable_to_non_nullable
as bool,aprilFoolFeatures: null == aprilFoolFeatures ? _self.aprilFoolFeatures : aprilFoolFeatures // ignore: cast_nullable_to_non_nullable as bool,aprilFoolFeatures: null == aprilFoolFeatures ? _self.aprilFoolFeatures : aprilFoolFeatures // ignore: cast_nullable_to_non_nullable
as bool,enterToSend: null == enterToSend ? _self.enterToSend : enterToSend // ignore: cast_nullable_to_non_nullable as bool,enterToSend: null == enterToSend ? _self.enterToSend : enterToSend // ignore: cast_nullable_to_non_nullable
as bool, as bool,appBarTransparent: null == appBarTransparent ? _self.appBarTransparent : appBarTransparent // ignore: cast_nullable_to_non_nullable
as bool,customFonts: freezed == customFonts ? _self.customFonts : customFonts // ignore: cast_nullable_to_non_nullable
as String?,appColorScheme: freezed == appColorScheme ? _self.appColorScheme : appColorScheme // ignore: cast_nullable_to_non_nullable
as int?,
)); ));
} }

28
lib/pods/config.g.dart Normal file
View File

@ -0,0 +1,28 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'config.dart';
// **************************************************************************
// RiverpodGenerator
// **************************************************************************
String _$appSettingsNotifierHash() =>
r'049447d982114220771702146a08b9b4626c31e5';
/// See also [AppSettingsNotifier].
@ProviderFor(AppSettingsNotifier)
final appSettingsNotifierProvider =
AutoDisposeNotifierProvider<AppSettingsNotifier, AppSettings>.internal(
AppSettingsNotifier.new,
name: r'appSettingsNotifierProvider',
debugGetCreateSourceHash:
const bool.fromEnvironment('dart.vm.product')
? null
: _$appSettingsNotifierHash,
dependencies: null,
allTransitiveDependencies: null,
);
typedef _$AppSettingsNotifier = AutoDisposeNotifier<AppSettings>;
// ignore_for_file: type=lint
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package

View File

@ -1,9 +1,7 @@
import 'dart:async'; import 'dart:async';
import 'dart:convert'; import 'dart:convert';
import 'dart:io';
import 'package:auto_route/auto_route.dart'; import 'package:auto_route/auto_route.dart';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:flutter_hooks/flutter_hooks.dart';
@ -733,7 +731,7 @@ class _ChatInput extends ConsumerWidget {
return; return;
} }
final enterToSend = ref.read(appSettingsProvider).enterToSend; final enterToSend = ref.read(appSettingsNotifierProvider).enterToSend;
final isEnter = event.logicalKey == LogicalKeyboardKey.enter; final isEnter = event.logicalKey == LogicalKeyboardKey.enter;
if (isEnter) { if (isEnter) {
@ -760,7 +758,7 @@ class _ChatInput extends ConsumerWidget {
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
final enterToSend = ref.watch(appSettingsProvider).enterToSend; final enterToSend = ref.watch(appSettingsNotifierProvider).enterToSend;
return Material( return Material(
elevation: 8, elevation: 8,

View File

@ -7,6 +7,7 @@ import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_colorpicker/flutter_colorpicker.dart';
import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:image_picker/image_picker.dart'; import 'package:image_picker/image_picker.dart';
@ -28,7 +29,7 @@ class SettingsScreen extends HookConsumerWidget {
final serverUrl = ref.watch(serverUrlProvider); final serverUrl = ref.watch(serverUrlProvider);
final prefs = ref.watch(sharedPreferencesProvider); final prefs = ref.watch(sharedPreferencesProvider);
final controller = TextEditingController(text: serverUrl); final controller = TextEditingController(text: serverUrl);
final settings = ref.watch(appSettingsProvider); final settings = ref.watch(appSettingsNotifierProvider);
final isDesktop = final isDesktop =
!kIsWeb && (Platform.isWindows || Platform.isMacOS || Platform.isLinux); !kIsWeb && (Platform.isWindows || Platform.isMacOS || Platform.isLinux);
final isWide = isWideScreen(context); final isWide = isWideScreen(context);
@ -88,6 +89,107 @@ class SettingsScreen extends HookConsumerWidget {
), ),
), ),
// Custom fonts settings
ListTile(
isThreeLine: true,
minLeadingWidth: 48,
title: Text('settingsCustomFonts').tr(),
contentPadding: const EdgeInsets.only(left: 24, right: 17),
leading: const Icon(Symbols.font_download),
subtitle: Padding(
padding: const EdgeInsets.only(top: 6),
child: TextField(
controller: TextEditingController(text: settings.customFonts),
decoration: InputDecoration(
hintText: 'Nunito, Arial, sans-serif',
helperText: 'settingsCustomFontsHelper'.tr(),
suffixIcon: IconButton(
icon: const Icon(Symbols.restart_alt),
onPressed: () {
ref
.read(appSettingsNotifierProvider.notifier)
.setCustomFonts(null);
showSnackBar(context, 'settingsApplied'.tr());
},
),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
),
isDense: true,
),
onSubmitted: (value) {
ref
.read(appSettingsNotifierProvider.notifier)
.setCustomFonts(value.isEmpty ? null : value);
showSnackBar(context, 'settingsApplied'.tr());
},
),
),
),
// Color scheme settings
ListTile(
minLeadingWidth: 48,
title: Text('settingsColorScheme').tr(),
contentPadding: const EdgeInsets.only(left: 24, right: 17),
leading: const Icon(Symbols.palette),
trailing: GestureDetector(
onTap: () {
showDialog(
context: context,
builder: (context) {
Color selectedColor =
settings.appColorScheme != null
? Color(settings.appColorScheme!)
: Colors.indigo;
return AlertDialog(
title: Text('settingsColorScheme').tr(),
content: SingleChildScrollView(
child: ColorPicker(
pickerColor: selectedColor,
onColorChanged: (color) {
selectedColor = color;
},
),
),
actions: [
TextButton(
onPressed: () => Navigator.of(context).pop(),
child: Text('Cancel').tr(),
),
TextButton(
onPressed: () {
ref
.read(appSettingsNotifierProvider.notifier)
.setAppColorScheme(selectedColor.value);
Navigator.of(context).pop();
},
child: Text('Confirm').tr(),
),
],
);
},
);
},
child: Container(
width: 40,
height: 40,
decoration: BoxDecoration(
color:
settings.appColorScheme != null
? Color(settings.appColorScheme!)
: Colors.indigo,
shape: BoxShape.circle,
border: Border.all(
color: Theme.of(context).colorScheme.outline.withOpacity(0.5),
width: 2,
),
),
),
),
),
// Background image settings (only for non-web platforms) // Background image settings (only for non-web platforms)
if (!kIsWeb && docBasepath.value != null) if (!kIsWeb && docBasepath.value != null)
ListTile( ListTile(
@ -128,13 +230,15 @@ class SettingsScreen extends HookConsumerWidget {
// Clear background image option // Clear background image option
if (!kIsWeb && docBasepath.value != null) if (!kIsWeb && docBasepath.value != null)
FutureBuilder<bool>( FutureBuilder<bool>(
future: File('${docBasepath.value}/app_background_image').exists(), future:
File('${docBasepath.value}/$kAppBackgroundImagePath').exists(),
builder: (context, snapshot) { builder: (context, snapshot) {
if (!snapshot.hasData || !snapshot.data!) { if (!snapshot.hasData || !snapshot.data!) {
return const SizedBox.shrink(); return const SizedBox.shrink();
} }
return ListTile( return ListTile(
minLeadingWidth: 48,
title: Text('settingsBackgroundImageClear').tr(), title: Text('settingsBackgroundImageClear').tr(),
contentPadding: const EdgeInsets.symmetric(horizontal: 24), contentPadding: const EdgeInsets.symmetric(horizontal: 24),
leading: const Icon(Symbols.texture), leading: const Icon(Symbols.texture),
@ -207,7 +311,9 @@ class SettingsScreen extends HookConsumerWidget {
trailing: Switch( trailing: Switch(
value: settings.autoTranslate, value: settings.autoTranslate,
onChanged: (value) { onChanged: (value) {
ref.read(appSettingsProvider.notifier).setAutoTranslate(value); ref
.read(appSettingsNotifierProvider.notifier)
.setAutoTranslate(value);
}, },
), ),
), ),
@ -221,7 +327,9 @@ class SettingsScreen extends HookConsumerWidget {
trailing: Switch( trailing: Switch(
value: settings.soundEffects, value: settings.soundEffects,
onChanged: (value) { onChanged: (value) {
ref.read(appSettingsProvider.notifier).setSoundEffects(value); ref
.read(appSettingsNotifierProvider.notifier)
.setSoundEffects(value);
}, },
), ),
), ),
@ -235,7 +343,9 @@ class SettingsScreen extends HookConsumerWidget {
trailing: Switch( trailing: Switch(
value: settings.aprilFoolFeatures, value: settings.aprilFoolFeatures,
onChanged: (value) { onChanged: (value) {
ref.read(appSettingsProvider.notifier).setAprilFoolFeatures(value); ref
.read(appSettingsNotifierProvider.notifier)
.setAprilFoolFeatures(value);
}, },
), ),
), ),
@ -253,7 +363,25 @@ class SettingsScreen extends HookConsumerWidget {
trailing: Switch( trailing: Switch(
value: settings.enterToSend, value: settings.enterToSend,
onChanged: (value) { onChanged: (value) {
ref.read(appSettingsProvider.notifier).setEnterToSend(value); ref
.read(appSettingsNotifierProvider.notifier)
.setEnterToSend(value);
},
),
),
// Transparent app bar settings
ListTile(
minLeadingWidth: 48,
title: Text('settingsTransparentAppBar').tr(),
contentPadding: const EdgeInsets.only(left: 24, right: 17),
leading: const Icon(Symbols.blur_on),
trailing: Switch(
value: settings.appBarTransparent,
onChanged: (value) {
ref
.read(appSettingsNotifierProvider.notifier)
.setAppBarTransparent(value);
}, },
), ),
), ),

View File

@ -686,6 +686,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.4.1" version: "3.4.1"
flutter_colorpicker:
dependency: "direct main"
description:
name: flutter_colorpicker
sha256: "969de5f6f9e2a570ac660fb7b501551451ea2a1ab9e2097e89475f60e07816ea"
url: "https://pub.dev"
source: hosted
version: "1.1.0"
flutter_highlight: flutter_highlight:
dependency: "direct main" dependency: "direct main"
description: description:

View File

@ -103,6 +103,7 @@ dependencies:
flutter_webrtc: ^0.14.1 flutter_webrtc: ^0.14.1
livekit_client: ^2.4.7 livekit_client: ^2.4.7
pasteboard: ^0.4.0 pasteboard: ^0.4.0
flutter_colorpicker: ^1.1.0
dev_dependencies: dev_dependencies:
flutter_test: flutter_test: