diff --git a/assets/i18n/en-US.json b/assets/i18n/en-US.json index 5cc23d4..3ce7fda 100644 --- a/assets/i18n/en-US.json +++ b/assets/i18n/en-US.json @@ -279,6 +279,10 @@ "settingsSoundEffects": "Sound Effects", "settingsAprilFoolFeatures": "April Fool Features", "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", "postDescription": "Description", "call": "Call", diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 2b11f74..823f4a2 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -137,6 +137,8 @@ PODS: - OrderedSet (6.0.3) - package_info_plus (0.4.5): - Flutter + - pasteboard (0.0.1): + - Flutter - path_provider_foundation (0.0.1): - Flutter - FlutterMacOS @@ -204,6 +206,7 @@ DEPENDENCIES: - media_kit_libs_ios_video (from `.symlinks/plugins/media_kit_libs_ios_video/ios`) - media_kit_video (from `.symlinks/plugins/media_kit_video/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`) - shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`) - sqflite_darwin (from `.symlinks/plugins/sqflite_darwin/darwin`) @@ -271,6 +274,8 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/media_kit_video/ios" package_info_plus: :path: ".symlinks/plugins/package_info_plus/ios" + pasteboard: + :path: ".symlinks/plugins/pasteboard/ios" path_provider_foundation: :path: ".symlinks/plugins/path_provider_foundation/darwin" shared_preferences_foundation: @@ -319,6 +324,7 @@ SPEC CHECKSUMS: nanopb: fad817b59e0457d11a5dfbde799381cd727c1275 OrderedSet: e539b66b644ff081c73a262d24ad552a69be3a94 package_info_plus: af8e2ca6888548050f16fa2f1938db7b5a5df499 + pasteboard: 49088aeb6119d51f976a421db60d8e1ab079b63c path_provider_foundation: 080d55be775b7414fd5a5ef3ac137b97b097e564 PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47 SAMKeychain: 483e1c9f32984d50ca961e26818a534283b4cd5c diff --git a/lib/pods/config.dart b/lib/pods/config.dart index eae1466..23b6630 100644 --- a/lib/pods/config.dart +++ b/lib/pods/config.dart @@ -1,9 +1,12 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.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'; part 'config.freezed.dart'; +part 'config.g.dart'; const kTokenPairStoreKey = 'dyn_user_tk'; @@ -14,13 +17,8 @@ const kAppbarTransparentStoreKey = 'app_bar_transparent'; const kAppBackgroundStoreKey = 'app_has_background'; const kAppColorSchemeStoreKey = 'app_color_scheme'; 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 kAppMixedFeed = 'app_mixed_feed'; const kAppAutoTranslate = 'app_auto_translate'; -const kAppHideBottomNav = 'app_hide_bottom_nav'; const kAppSoundEffects = 'app_sound_effects'; const kAppAprilFoolFeatures = 'app_april_fool_features'; const kAppWindowSize = 'app_window_size'; @@ -57,48 +55,73 @@ sealed class AppSettings with _$AppSettings { required bool soundEffects, required bool aprilFoolFeatures, required bool enterToSend, + required bool appBarTransparent, + required String? customFonts, + required int? appColorScheme, // The color stored via the int type }) = _AppSettings; } -class AppSettingsNotifier extends StateNotifier { - final SharedPreferences prefs; - - AppSettingsNotifier(this.prefs) - : super( - AppSettings( - autoTranslate: prefs.getBool(kAppAutoTranslate) ?? false, - soundEffects: prefs.getBool(kAppSoundEffects) ?? true, - aprilFoolFeatures: prefs.getBool(kAppAprilFoolFeatures) ?? true, - enterToSend: prefs.getBool(kAppEnterToSend) ?? true, - ), - ); +@riverpod +class AppSettingsNotifier extends _$AppSettingsNotifier { + @override + AppSettings build() { + final prefs = ref.watch(sharedPreferencesProvider); + return AppSettings( + autoTranslate: prefs.getBool(kAppAutoTranslate) ?? false, + soundEffects: prefs.getBool(kAppSoundEffects) ?? true, + aprilFoolFeatures: prefs.getBool(kAppAprilFoolFeatures) ?? true, + enterToSend: prefs.getBool(kAppEnterToSend) ?? true, + appBarTransparent: prefs.getBool(kAppbarTransparentStoreKey) ?? false, + customFonts: prefs.getString(kAppCustomFonts), + appColorScheme: prefs.getInt(kAppColorSchemeStoreKey), + ); + } void setAutoTranslate(bool value) { + final prefs = ref.read(sharedPreferencesProvider); prefs.setBool(kAppAutoTranslate, value); state = state.copyWith(autoTranslate: value); } void setSoundEffects(bool value) { + final prefs = ref.read(sharedPreferencesProvider); prefs.setBool(kAppSoundEffects, value); state = state.copyWith(soundEffects: value); } void setAprilFoolFeatures(bool value) { + final prefs = ref.read(sharedPreferencesProvider); prefs.setBool(kAppAprilFoolFeatures, value); state = state.copyWith(aprilFoolFeatures: value); } void setEnterToSend(bool value) { + final prefs = ref.read(sharedPreferencesProvider); prefs.setBool(kAppEnterToSend, value); state = state.copyWith(enterToSend: value); } -} -final appSettingsProvider = - StateNotifierProvider((ref) { - final prefs = ref.watch(sharedPreferencesProvider); - return AppSettingsNotifier(prefs); - }); + void setAppBarTransparent(bool value) { + final prefs = ref.read(sharedPreferencesProvider); + prefs.setBool(kAppbarTransparentStoreKey, value); + 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 = StateNotifierProvider((ref) { diff --git a/lib/pods/config.freezed.dart b/lib/pods/config.freezed.dart index afb0848..248183f 100644 --- a/lib/pods/config.freezed.dart +++ b/lib/pods/config.freezed.dart @@ -15,7 +15,7 @@ T _$identity(T value) => value; /// @nodoc 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 /// with the given fields replaced by the non-null parameter values. @JsonKey(includeFromJson: false, includeToJson: false) @@ -26,16 +26,16 @@ $AppSettingsCopyWith get copyWith => _$AppSettingsCopyWithImpl Object.hash(runtimeType,autoTranslate,soundEffects,aprilFoolFeatures,enterToSend); +int get hashCode => Object.hash(runtimeType,autoTranslate,soundEffects,aprilFoolFeatures,enterToSend,appBarTransparent,customFonts,appColorScheme); @override 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; @useResult $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 /// 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( 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,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, +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 { - 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 soundEffects; @override final bool aprilFoolFeatures; @override final bool enterToSend; +@override final bool appBarTransparent; +@override final String? customFonts; +@override final int? appColorScheme; /// Create a copy of AppSettings /// with the given fields replaced by the non-null parameter values. @@ -98,16 +104,16 @@ _$AppSettingsCopyWith<_AppSettings> get copyWith => __$AppSettingsCopyWithImpl<_ @override 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 -int get hashCode => Object.hash(runtimeType,autoTranslate,soundEffects,aprilFoolFeatures,enterToSend); +int get hashCode => Object.hash(runtimeType,autoTranslate,soundEffects,aprilFoolFeatures,enterToSend,appBarTransparent,customFonts,appColorScheme); @override 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; @override @useResult $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 /// 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( 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,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, +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?, )); } diff --git a/lib/pods/config.g.dart b/lib/pods/config.g.dart new file mode 100644 index 0000000..5ea6dba --- /dev/null +++ b/lib/pods/config.g.dart @@ -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.internal( + AppSettingsNotifier.new, + name: r'appSettingsNotifierProvider', + debugGetCreateSourceHash: + const bool.fromEnvironment('dart.vm.product') + ? null + : _$appSettingsNotifierHash, + dependencies: null, + allTransitiveDependencies: null, + ); + +typedef _$AppSettingsNotifier = AutoDisposeNotifier; +// 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 diff --git a/lib/screens/chat/room.dart b/lib/screens/chat/room.dart index c9a67f1..469cf04 100644 --- a/lib/screens/chat/room.dart +++ b/lib/screens/chat/room.dart @@ -1,9 +1,7 @@ import 'dart:async'; import 'dart:convert'; -import 'dart:io'; import 'package:auto_route/auto_route.dart'; import 'package:easy_localization/easy_localization.dart'; -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; @@ -733,7 +731,7 @@ class _ChatInput extends ConsumerWidget { return; } - final enterToSend = ref.read(appSettingsProvider).enterToSend; + final enterToSend = ref.read(appSettingsNotifierProvider).enterToSend; final isEnter = event.logicalKey == LogicalKeyboardKey.enter; if (isEnter) { @@ -760,7 +758,7 @@ class _ChatInput extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { - final enterToSend = ref.watch(appSettingsProvider).enterToSend; + final enterToSend = ref.watch(appSettingsNotifierProvider).enterToSend; return Material( elevation: 8, diff --git a/lib/screens/settings.dart b/lib/screens/settings.dart index a83f934..0eec43d 100644 --- a/lib/screens/settings.dart +++ b/lib/screens/settings.dart @@ -7,6 +7,7 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; +import 'package:flutter_colorpicker/flutter_colorpicker.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:image_picker/image_picker.dart'; @@ -28,7 +29,7 @@ class SettingsScreen extends HookConsumerWidget { final serverUrl = ref.watch(serverUrlProvider); final prefs = ref.watch(sharedPreferencesProvider); final controller = TextEditingController(text: serverUrl); - final settings = ref.watch(appSettingsProvider); + final settings = ref.watch(appSettingsNotifierProvider); final isDesktop = !kIsWeb && (Platform.isWindows || Platform.isMacOS || Platform.isLinux); 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) if (!kIsWeb && docBasepath.value != null) ListTile( @@ -128,13 +230,15 @@ class SettingsScreen extends HookConsumerWidget { // Clear background image option if (!kIsWeb && docBasepath.value != null) FutureBuilder( - future: File('${docBasepath.value}/app_background_image').exists(), + future: + File('${docBasepath.value}/$kAppBackgroundImagePath').exists(), builder: (context, snapshot) { if (!snapshot.hasData || !snapshot.data!) { return const SizedBox.shrink(); } return ListTile( + minLeadingWidth: 48, title: Text('settingsBackgroundImageClear').tr(), contentPadding: const EdgeInsets.symmetric(horizontal: 24), leading: const Icon(Symbols.texture), @@ -207,7 +311,9 @@ class SettingsScreen extends HookConsumerWidget { trailing: Switch( value: settings.autoTranslate, onChanged: (value) { - ref.read(appSettingsProvider.notifier).setAutoTranslate(value); + ref + .read(appSettingsNotifierProvider.notifier) + .setAutoTranslate(value); }, ), ), @@ -221,7 +327,9 @@ class SettingsScreen extends HookConsumerWidget { trailing: Switch( value: settings.soundEffects, onChanged: (value) { - ref.read(appSettingsProvider.notifier).setSoundEffects(value); + ref + .read(appSettingsNotifierProvider.notifier) + .setSoundEffects(value); }, ), ), @@ -235,7 +343,9 @@ class SettingsScreen extends HookConsumerWidget { trailing: Switch( value: settings.aprilFoolFeatures, onChanged: (value) { - ref.read(appSettingsProvider.notifier).setAprilFoolFeatures(value); + ref + .read(appSettingsNotifierProvider.notifier) + .setAprilFoolFeatures(value); }, ), ), @@ -253,7 +363,25 @@ class SettingsScreen extends HookConsumerWidget { trailing: Switch( value: settings.enterToSend, 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); }, ), ), diff --git a/pubspec.lock b/pubspec.lock index cf3181d..b2be000 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -686,6 +686,14 @@ packages: url: "https://pub.dev" source: hosted 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: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index 8fcb792..d1cdb8e 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -103,6 +103,7 @@ dependencies: flutter_webrtc: ^0.14.1 livekit_client: ^2.4.7 pasteboard: ^0.4.0 + flutter_colorpicker: ^1.1.0 dev_dependencies: flutter_test: