Added material you

This commit is contained in:
JHubi1 2024-06-13 20:51:22 +02:00
parent baf654be40
commit 6697346628
No known key found for this signature in database
GPG Key ID: 7BF82570CBBBD050
13 changed files with 347 additions and 143 deletions

View File

@ -368,6 +368,36 @@
"description": "Text displayed for cancel button, should be capitalized",
"context": "Visible in the settings view"
},
"settingsThemeDevice": "Gerät",
"@settingsThemeDevice": {
"description": "Text displayed as description for device theme option",
"context": "Visible in the settings view"
},
"settingsThemeOllama": "Ollama",
"@settingsThemeOllama": {
"description": "Text displayed as description for Ollama theme option",
"context": "Visible in the settings view"
},
"settingsThemeRestartTitle": "Neustart Erforderlich",
"@settingsThemeRestartTitle": {
"description": "Title of the restart required dialog",
"context": "Visible in the settings view"
},
"settingsThemeRestartDescription": "Das Ändern des Themas erfordert einen Neustart.\nMöchtest du jetzt neu starten oder die Aktion abbrechen?",
"@settingsThemeRestartDescription": {
"description": "Description of the restart required dialog",
"context": "Visible in the settings view"
},
"settingsThemeRestartRestart": "Neustarten",
"@settingsThemeRestartRestart": {
"description": "Text displayed for restart button, should be capitalized",
"context": "Visible in the settings view"
},
"settingsThemeRestartCancel": "Abbrechen",
"@settingsThemeRestartCancel": {
"description": "Text displayed for cancel button, should be capitalized",
"context": "Visible in the settings view"
},
"settingsVoicePermissionLoading": "Lade Sprachberechtigungen ...",
"@settingsVoicePermissionLoading": {
"description": "Text displayed while loading voice permissions",

View File

@ -368,6 +368,36 @@
"description": "Text displayed for cancel button, should be capitalized",
"context": "Visible in the settings view"
},
"settingsThemeDevice": "Device",
"@settingsThemeDevice": {
"description": "Text displayed as description for device theme option",
"context": "Visible in the settings view"
},
"settingsThemeOllama": "Ollama",
"@settingsThemeOllama": {
"description": "Text displayed as description for Ollama theme option",
"context": "Visible in the settings view"
},
"settingsThemeRestartTitle": "Restart Required",
"@settingsThemeRestartTitle": {
"description": "Title of the restart required dialog",
"context": "Visible in the settings view"
},
"settingsThemeRestartDescription": "Changing the theme requires a restart.\nDo you want to restart now or cancel the action?",
"@settingsThemeRestartDescription": {
"description": "Description of the restart required dialog",
"context": "Visible in the settings view"
},
"settingsThemeRestartRestart": "Restart",
"@settingsThemeRestartRestart": {
"description": "Text displayed for restart button, should be capitalized",
"context": "Visible in the settings view"
},
"settingsThemeRestartCancel": "Cancel",
"@settingsThemeRestartCancel": {
"description": "Text displayed for cancel button, should be capitalized",
"context": "Visible in the settings view"
},
"settingsVoicePermissionLoading": "Loading voice permissions ...",
"@settingsVoicePermissionLoading": {
"description": "Text displayed while loading voice permissions",

View File

@ -32,6 +32,7 @@ import 'package:flutter_displaymode/flutter_displaymode.dart';
import 'package:speech_to_text/speech_to_text.dart';
import 'package:flutter_tts/flutter_tts.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:dynamic_color/dynamic_color.dart';
// client configuration
@ -127,10 +128,18 @@ class _AppState extends State<App> {
}
load();
}
WidgetsBinding.instance.addPostFrameCallback(
(timeStamp) {
if (!(prefs?.getBool("useDeviceTheme") ?? false)) {
@override
Widget build(BuildContext context) {
return DynamicColorBuilder(
builder: (ColorScheme? lightDynamic, ColorScheme? darkDynamic) {
if ((prefs?.getBool("useDeviceTheme") ?? false) &&
lightDynamic != null &&
darkDynamic != null) {
theme = ThemeData.from(colorScheme: lightDynamic);
themeDark = ThemeData.from(colorScheme: darkDynamic);
} else {
theme = ThemeData.from(
colorScheme: const ColorScheme(
brightness: Brightness.light,
@ -153,14 +162,51 @@ class _AppState extends State<App> {
onError: Colors.black,
surface: Colors.black,
onSurface: Colors.white));
setState(() {});
}
},
);
}
@override
Widget build(BuildContext context) {
WidgetsBinding.instance.addPostFrameCallback((_) {
WidgetsBinding.instance.platformDispatcher.onPlatformBrightnessChanged =
() {
// invert colors used, because brightness not updated yet
SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle(
systemNavigationBarColor:
(prefs?.getString("brightness") ?? "system") == "system"
? ((MediaQuery.of(context).platformBrightness ==
Brightness.light)
? (themeDark ?? ThemeData.dark()).colorScheme.surface
: (theme ?? ThemeData()).colorScheme.surface)
: (prefs?.getString("brightness") == "dark"
? (themeDark ?? ThemeData()).colorScheme.surface
: (theme ?? ThemeData.dark()).colorScheme.surface),
systemNavigationBarIconBrightness:
(((prefs?.getString("brightness") ?? "system") == "system" &&
MediaQuery.of(context).platformBrightness ==
Brightness.dark) ||
prefs?.getString("brightness") == "light")
? Brightness.dark
: Brightness.light));
};
// brightness changed function not run at first startup
SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle(
systemNavigationBarColor:
(prefs?.getString("brightness") ?? "system") == "system"
? ((MediaQuery.of(context).platformBrightness ==
Brightness.light)
? (theme ?? ThemeData.dark()).colorScheme.surface
: (themeDark ?? ThemeData()).colorScheme.surface)
: (prefs?.getString("brightness") == "dark"
? (themeDark ?? ThemeData()).colorScheme.surface
: (theme ?? ThemeData.dark()).colorScheme.surface),
systemNavigationBarIconBrightness:
(((prefs?.getString("brightness") ?? "system") == "system" &&
MediaQuery.of(context).platformBrightness ==
Brightness.light) ||
prefs?.getString("brightness") == "light")
? Brightness.dark
: Brightness.light));
});
return MaterialApp(
localizationsDelegates: AppLocalizations.localizationsDelegates,
supportedLocales: AppLocalizations.supportedLocales,
@ -184,6 +230,7 @@ class _AppState extends State<App> {
? ThemeMode.dark
: ThemeMode.light),
home: const MainApp());
});
}
}
@ -541,54 +588,6 @@ class _MainAppState extends State<MainApp> {
}));
}
void setBrightness() {
WidgetsBinding
.instance.platformDispatcher.onPlatformBrightnessChanged = () {
// invert colors used, because brightness not updated yet
SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle(
systemNavigationBarColor:
(prefs!.getString("brightness") ?? "system") == "system"
? ((MediaQuery.of(context).platformBrightness ==
Brightness.light)
? (themeDark ?? ThemeData.dark())
.colorScheme
.surface
: (theme ?? ThemeData()).colorScheme.surface)
: (prefs!.getString("brightness") == "dark"
? (themeDark ?? ThemeData()).colorScheme.surface
: (theme ?? ThemeData.dark()).colorScheme.surface),
systemNavigationBarIconBrightness:
(((prefs!.getString("brightness") ?? "system") ==
"system" &&
MediaQuery.of(context).platformBrightness ==
Brightness.dark) ||
prefs!.getString("brightness") == "light")
? Brightness.dark
: Brightness.light));
};
// brightness changed function not run at first startup
SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle(
systemNavigationBarColor:
(prefs!.getString("brightness") ?? "system") == "system"
? ((MediaQuery.of(context).platformBrightness ==
Brightness.light)
? (theme ?? ThemeData.dark()).colorScheme.surface
: (themeDark ?? ThemeData()).colorScheme.surface)
: (prefs!.getString("brightness") == "dark"
? (themeDark ?? ThemeData()).colorScheme.surface
: (theme ?? ThemeData.dark()).colorScheme.surface),
systemNavigationBarIconBrightness:
(((prefs!.getString("brightness") ?? "system") == "system" &&
MediaQuery.of(context).platformBrightness ==
Brightness.light) ||
prefs!.getString("brightness") == "light")
? Brightness.dark
: Brightness.light));
}
setBrightness();
// prefs!.remove("welcomeFinished");
if (!(prefs!.getBool("welcomeFinished") ?? false) && allowSettings) {
// ignore: use_build_context_synchronously
@ -761,14 +760,16 @@ class _MainAppState extends State<MainApp> {
]),
actions: [
TextButton(
onPressed: () {selectionHaptic();
onPressed: () {
selectionHaptic();
Navigator.of(context).pop();
},
child: Text(AppLocalizations.of(
context)!
.deleteDialogCancel)),
TextButton(
onPressed: () {selectionHaptic();
onPressed: () {
selectionHaptic();
Navigator.of(context).pop();
for (var i = 0;
@ -1227,7 +1228,8 @@ class _MainAppState extends State<MainApp> {
SizedBox(
width: double.infinity,
child: OutlinedButton.icon(
onPressed: () async {selectionHaptic();
onPressed: () async {
selectionHaptic();
Navigator.of(context)
.pop();
setMainState = setState;
@ -1248,7 +1250,8 @@ class _MainAppState extends State<MainApp> {
SizedBox(
width: double.infinity,
child: OutlinedButton.icon(
onPressed: () async {selectionHaptic();
onPressed: () async {
selectionHaptic();
Navigator.of(context)
.pop();
@ -1300,7 +1303,8 @@ class _MainAppState extends State<MainApp> {
SizedBox(
width: double.infinity,
child: OutlinedButton.icon(
onPressed: () async {selectionHaptic();
onPressed: () async {
selectionHaptic();
Navigator.of(context)
.pop();
@ -1379,17 +1383,26 @@ class _MainAppState extends State<MainApp> {
attachmentButtonIcon: !multimodal
? (prefs?.getBool("voiceModeEnabled") ??
false)
? const Icon(Icons.headphones_rounded)
? Icon(Icons.headphones_rounded,
color:
Theme.of(context).iconTheme.color)
: null
: const Icon(Icons.add_a_photo_rounded),
: Icon(Icons.add_a_photo_rounded,
color: Theme.of(context).iconTheme.color),
sendButtonIcon: SizedBox(
height: 24,
child: CircleAvatar(
backgroundColor:
Theme.of(context).colorScheme.primary,
Theme.of(context).iconTheme.color,
radius: 12,
child:
const Icon(Icons.arrow_upward_rounded)),
child: Icon(Icons.arrow_upward_rounded,
color:
(prefs?.getBool("useDeviceTheme") ??
false)
? Theme.of(context)
.colorScheme
.surface
: null)),
),
sendButtonMargin: EdgeInsets.zero,
attachmentButtonMargin: EdgeInsets.zero,
@ -1414,8 +1427,7 @@ class _MainAppState extends State<MainApp> {
Platform.isMacOS))
? 0
: 8),
messageMaxWidth: (MediaQuery.of(context).size.width >=
1000)
messageMaxWidth: (MediaQuery.of(context).size.width >= 1000)
? (MediaQuery.of(context).size.width >= 1600)
? (MediaQuery.of(context).size.width >= 2200)
? 1900
@ -1428,17 +1440,23 @@ class _MainAppState extends State<MainApp> {
secondaryColor: (themeDark ?? ThemeData.dark()).colorScheme.primary.withAlpha(20),
attachmentButtonIcon: !multimodal
? (prefs?.getBool("voiceModeEnabled") ?? false)
? const Icon(Icons.headphones_rounded)
? Icon(Icons.headphones_rounded, color: Theme.of(context).iconTheme.color)
: null
: const Icon(Icons.add_a_photo_rounded),
: Icon(Icons.add_a_photo_rounded, color: Theme.of(context).iconTheme.color),
sendButtonIcon: SizedBox(
height: 24,
child: CircleAvatar(
backgroundColor:
Theme.of(context).colorScheme.primary,
Theme.of(context).iconTheme.color,
radius: 12,
child:
const Icon(Icons.arrow_upward_rounded)),
child: Icon(Icons.arrow_upward_rounded,
color:
(prefs?.getBool("useDeviceTheme") ??
false)
? Theme.of(context)
.colorScheme
.surface
: null)),
),
sendButtonMargin: EdgeInsets.zero,
attachmentButtonMargin: EdgeInsets.zero,

View File

@ -17,6 +17,7 @@ import 'settings/about.dart';
import 'package:dartx/dartx.dart';
import 'package:http/http.dart' as http;
import 'package:bitsdojo_window/bitsdojo_window.dart';
import 'package:dynamic_color/dynamic_color.dart';
Widget toggle(BuildContext context, String text, bool value,
Function(bool value) onChanged,
@ -81,11 +82,22 @@ Widget toggle(BuildContext context, String text, bool value,
}
}
: onChanged,
activeTrackColor: disabled
? Theme.of(context).colorScheme.primary.withAlpha(50)
: null,
trackOutlineColor: disabled
? const WidgetStatePropertyAll(Colors.grey)
? WidgetStatePropertyAll(Theme.of(context)
.colorScheme
.primary
.withAlpha(150)
.harmonizeWith(
Theme.of(context).colorScheme.primary))
: null,
thumbColor: disabled
? const WidgetStatePropertyAll(Colors.grey)
? WidgetStatePropertyAll(Theme.of(context)
.colorScheme
.primary
.withAlpha(150))
: null)))
]),
]),
@ -364,8 +376,12 @@ class _ScreenSettingsState extends State<ScreenSettings> {
splashFactory: NoSplash.splashFactory,
child: Row(
children: [
const Icon(Icons.error_rounded,
color: Colors.red),
Icon(Icons.error_rounded,
color: Colors.red
.harmonizeWith(
Theme.of(context)
.colorScheme
.primary)),
const SizedBox(width: 8),
Text(
AppLocalizations.of(context)!
@ -373,8 +389,12 @@ class _ScreenSettingsState extends State<ScreenSettings> {
hostInvalidHost
? "host"
: "url"),
style: const TextStyle(
color: Colors.red))
style: TextStyle(
color: Colors.red
.harmonizeWith(
Theme.of(context)
.colorScheme
.primary)))
],
))
: null,
@ -402,15 +422,24 @@ class _ScreenSettingsState extends State<ScreenSettings> {
)
: Row(
children: [
const Icon(Icons.check_rounded,
color: Colors.green),
Icon(Icons.check_rounded,
color: Colors.green
.harmonizeWith(
Theme.of(context)
.colorScheme
.primary)),
const SizedBox(width: 8),
Text(
AppLocalizations.of(
context)!
.settingsHostValid,
style: const TextStyle(
color: Colors.green,
style: TextStyle(
color: Colors.green
.harmonizeWith(
Theme.of(
context)
.colorScheme
.primary),
fontFamily:
"monospace"))
],
@ -481,7 +510,8 @@ class _ScreenSettingsState extends State<ScreenSettings> {
.settingsSavedAutomatically,
Icons.info_rounded,
null,
color: Colors.grey)
color: Colors.grey.harmonizeWith(
Theme.of(context).colorScheme.primary))
])))));
}
}

View File

@ -8,6 +8,7 @@ import '../screen_settings.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:bitsdojo_window/bitsdojo_window.dart';
import 'package:dynamic_color/dynamic_color.dart';
class ScreenSettingsBehavior extends StatefulWidget {
const ScreenSettingsBehavior({super.key});
@ -116,7 +117,8 @@ class _ScreenSettingsBehaviorState extends State<ScreenSettingsBehavior> {
.settingsBehaviorNotUpdatedForOlderChats,
Icons.info_rounded,
null,
color: Colors.grey)
color: Colors.grey
.harmonizeWith(Theme.of(context).colorScheme.primary))
]))),
);
}

View File

@ -11,6 +11,7 @@ import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:bitsdojo_window/bitsdojo_window.dart';
import 'package:file_picker/file_picker.dart';
import 'package:intl/intl.dart';
import 'package:dynamic_color/dynamic_color.dart';
class ScreenSettingsExport extends StatefulWidget {
const ScreenSettingsExport({super.key});
@ -169,10 +170,12 @@ class _ScreenSettingsExportState extends State<ScreenSettingsExport> {
const SizedBox(height: 16),
button(AppLocalizations.of(context)!.settingsExportInfo,
Icons.info_rounded, null,
color: Colors.grey),
color: Colors.grey
.harmonizeWith(Theme.of(context).colorScheme.primary)),
button(AppLocalizations.of(context)!.settingsExportWarning,
Icons.warning_rounded, null,
color: Colors.orange)
color: Colors.orange
.harmonizeWith(Theme.of(context).colorScheme.primary))
]))),
);
}

View File

@ -1,7 +1,6 @@
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import '../main.dart';
import '../worker/haptic.dart';
@ -367,6 +366,72 @@ class _ScreenSettingsInterfaceState extends State<ScreenSettingsInterface> {
});
});
}),
const SizedBox(height: 8),
SegmentedButton(
segments: [
ButtonSegment(
value: "device",
label: Text(AppLocalizations.of(context)!
.settingsThemeDevice),
icon: const Icon(Icons.devices_rounded)),
ButtonSegment(
value: "ollama",
label: Text(AppLocalizations.of(context)!
.settingsThemeOllama),
icon: const ImageIcon(
AssetImage("assets/logo512.png")))
],
selected: {
(prefs?.getBool("useDeviceTheme") ?? false)
? "device"
: "ollama"
},
onSelectionChanged: (p0) {
selectionHaptic();
showDialog(
context: context,
builder: (context) {
return StatefulBuilder(
builder: (context, setLocalState) {
return AlertDialog(
title: Text(AppLocalizations.of(context)!
.settingsThemeRestartTitle),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(AppLocalizations.of(context)!
.settingsThemeRestartDescription),
]),
actions: [
TextButton(
onPressed: () {
selectionHaptic();
Navigator.of(context).pop();
},
child: Text(AppLocalizations.of(
context)!
.settingsThemeRestartCancel)),
TextButton(
onPressed: () async {
selectionHaptic();
await prefs!.setBool(
"useDeviceTheme",
p0.elementAt(0) == "device");
if (Platform.isWindows ||
Platform.isLinux ||
Platform.isMacOS) {
exit(0);
} else {
Restart.restartApp();
}
},
child: Text(AppLocalizations.of(
context)!
.settingsThemeRestartRestart))
]);
});
});
}),
const SizedBox(height: 16)
]),
)

View File

@ -10,6 +10,7 @@ import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:bitsdojo_window/bitsdojo_window.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:dynamic_color/dynamic_color.dart';
class ScreenSettingsVoice extends StatefulWidget {
const ScreenSettingsVoice({super.key});
@ -329,7 +330,9 @@ class _ScreenSettingsVoiceState extends State<ScreenSettingsVoice> {
.settingsExperimentalBetaFeature,
Icons.warning_rounded,
null,
color: Colors.orange, onLongTap: () {
color: Colors.orange
.harmonizeWith(Theme.of(context).colorScheme.primary),
onLongTap: () {
selectionHaptic();
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text(AppLocalizations.of(context)!

View File

@ -164,7 +164,10 @@ void setModel(BuildContext context, Function setState) {
? const Icon(Icons
.collections_rounded)
: null)),
checkmarkColor: (usedIndex == index)
checkmarkColor: (usedIndex == index &&
!(prefs?.getBool(
"useDeviceTheme") ??
false))
? ((MediaQuery.of(context)
.platformBrightness ==
Brightness.light)
@ -175,7 +178,10 @@ void setModel(BuildContext context, Function setState) {
.colorScheme
.secondary)
: null,
labelStyle: (usedIndex == index)
labelStyle: (usedIndex == index &&
!(prefs?.getBool(
"useDeviceTheme") ??
false))
? TextStyle(
color: (MediaQuery.of(context)
.platformBrightness ==
@ -188,7 +194,11 @@ void setModel(BuildContext context, Function setState) {
.colorScheme
.secondary)
: null,
selectedColor: (MediaQuery.of(context)
selectedColor: (prefs
?.getBool("useDeviceTheme") ??
false)
? null
: (MediaQuery.of(context)
.platformBrightness ==
Brightness.light)
? (theme ?? ThemeData())

View File

@ -153,6 +153,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.2.0"
dynamic_color:
dependency: "direct main"
description:
name: dynamic_color
sha256: eae98052fa6e2826bdac3dd2e921c6ce2903be15c6b7f8b6d8a5d49b5086298d
url: "https://pub.dev"
source: hosted
version: "1.7.0"
equatable:
dependency: transitive
description:

View File

@ -42,6 +42,7 @@ dependencies:
flutter_tts: ^4.0.2
permission_handler: ^11.3.1
datetime_loop: ^1.2.0
dynamic_color: ^1.7.0
dev_dependencies:
flutter_test:

View File

@ -7,6 +7,7 @@
#include "generated_plugin_registrant.h"
#include <bitsdojo_window_windows/bitsdojo_window_plugin.h>
#include <dynamic_color/dynamic_color_plugin_c_api.h>
#include <file_selector_windows/file_selector_windows.h>
#include <flutter_tts/flutter_tts_plugin.h>
#include <permission_handler_windows/permission_handler_windows_plugin.h>
@ -15,6 +16,8 @@
void RegisterPlugins(flutter::PluginRegistry* registry) {
BitsdojoWindowPluginRegisterWithRegistrar(
registry->GetRegistrarForPlugin("BitsdojoWindowPlugin"));
DynamicColorPluginCApiRegisterWithRegistrar(
registry->GetRegistrarForPlugin("DynamicColorPluginCApi"));
FileSelectorWindowsRegisterWithRegistrar(
registry->GetRegistrarForPlugin("FileSelectorWindows"));
FlutterTtsPluginRegisterWithRegistrar(

View File

@ -4,6 +4,7 @@
list(APPEND FLUTTER_PLUGIN_LIST
bitsdojo_window_windows
dynamic_color
file_selector_windows
flutter_tts
permission_handler_windows