Improved desktop mode

This commit is contained in:
JHubi1 2024-06-26 16:07:02 +02:00
parent 4cc9e7d4c3
commit 34044e74bb
No known key found for this signature in database
GPG Key ID: 7BF82570CBBBD050
6 changed files with 442 additions and 253 deletions

View File

@ -165,26 +165,51 @@
"description": "Title of the behavior settings section", "description": "Title of the behavior settings section",
"context": "Visible in the settings view" "context": "Visible in the settings view"
}, },
"settingsDescriptionBehavior": "Change the behavior of the AI to your liking.",
"@settingsDescriptionBehavior": {
"description": "Description of the behavior settings section",
"context": "Visible in the settings view"
},
"settingsTitleInterface": "Interface", "settingsTitleInterface": "Interface",
"@settingsTitleInterface": { "@settingsTitleInterface": {
"description": "Title of the interface settings section", "description": "Title of the interface settings section",
"context": "Visible in the settings view" "context": "Visible in the settings view"
}, },
"settingsDescriptionInterface": "Edit how Ollama App looks and behaves.",
"@settingsDescriptionInterface": {
"description": "Description of the interface settings section",
"context": "Visible in the settings view"
},
"settingsTitleVoice": "Voice", "settingsTitleVoice": "Voice",
"@settingsTitleVoice": { "@settingsTitleVoice": {
"description": "Title of the voice settings section. Do not translate if not required!", "description": "Title of the voice settings section. Do not translate if not required!",
"context": "Visible in the settings view" "context": "Visible in the settings view"
}, },
"settingsDescriptionVoice": "Enable voice mode and configure voice settings.",
"@settingsDescriptionVoice": {
"description": "Description of the voice settings section",
"context": "Visible in the settings view"
},
"settingsTitleExport": "Export", "settingsTitleExport": "Export",
"@settingsTitleExport": { "@settingsTitleExport": {
"description": "Title of the export settings section", "description": "Title of the export settings section",
"context": "Visible in the settings view" "context": "Visible in the settings view"
}, },
"settingsDescriptionExport": "Export and import your chat history.",
"@settingsDescriptionExport": {
"description": "Description of the export settings section",
"context": "Visible in the settings view"
},
"settingsTitleAbout": "About", "settingsTitleAbout": "About",
"@settingsTitleAbout": { "@settingsTitleAbout": {
"description": "Title of the about settings section", "description": "Title of the about settings section",
"context": "Visible in the settings view" "context": "Visible in the settings view"
}, },
"settingsDescriptionAbout": "Check for updates and learn more about Ollama App.",
"@settingsDescriptionAbout": {
"description": "Description of the about settings section",
"context": "Visible in the settings view"
},
"settingsSavedAutomatically": "Settings are saved automatically", "settingsSavedAutomatically": "Settings are saved automatically",
"@settingsSavedAutomatically": { "@settingsSavedAutomatically": {
"description": "Text displayed when settings are saved automatically", "description": "Text displayed when settings are saved automatically",

View File

@ -259,7 +259,8 @@ class _MainAppState extends State<MainApp> {
left: desktopLayoutRequired(context) ? 17 : 12, left: desktopLayoutRequired(context) ? 17 : 12,
right: desktopLayoutRequired(context) ? 17 : 12); right: desktopLayoutRequired(context) ? 17 : 12);
return List.from([ return List.from([
desktopLayout(context) desktopFeature() ? const SizedBox(height: 8) : const SizedBox.shrink(),
desktopLayoutNotRequired(context)
? const SizedBox.shrink() ? const SizedBox.shrink()
: (Padding( : (Padding(
padding: padding, padding: padding,
@ -282,11 +283,14 @@ class _MainAppState extends State<MainApp> {
), ),
const SizedBox(width: 16), const SizedBox(width: 16),
]))))), ]))))),
desktopLayout(context) desktopLayoutNotRequired(context)
? const SizedBox.shrink() ? const SizedBox.shrink()
: (!allowMultipleChats && !allowSettings) : (!allowMultipleChats && !allowSettings)
? const SizedBox.shrink() ? const SizedBox.shrink()
: const Divider(), : Divider(
color: desktopLayout(context)
? Theme.of(context).colorScheme.onSurface.withAlpha(20)
: null),
(allowMultipleChats) (allowMultipleChats)
? (Padding( ? (Padding(
padding: padding, padding: padding,
@ -1513,7 +1517,7 @@ class _MainAppState extends State<MainApp> {
drawerEdgeDragWidth: drawerEdgeDragWidth:
desktopLayout(context) ? null : MediaQuery.of(context).size.width, desktopLayout(context) ? null : MediaQuery.of(context).size.width,
drawer: Builder(builder: (context) { drawer: Builder(builder: (context) {
if (desktopLayoutRequired(context)) { if (desktopLayoutRequired(context) && !settingsOpen) {
WidgetsBinding.instance.addPostFrameCallback((_) { WidgetsBinding.instance.addPostFrameCallback((_) {
if (Navigator.of(context).canPop()) { if (Navigator.of(context).canPop()) {
Navigator.of(context).pop(); Navigator.of(context).pop();

View File

@ -19,6 +19,7 @@ import 'package:dartx/dartx.dart';
import 'package:http/http.dart' as http; import 'package:http/http.dart' as http;
import 'package:bitsdojo_window/bitsdojo_window.dart'; import 'package:bitsdojo_window/bitsdojo_window.dart';
import 'package:dynamic_color/dynamic_color.dart'; import 'package:dynamic_color/dynamic_color.dart';
import 'package:transparent_image/transparent_image.dart';
Widget toggle(BuildContext context, String text, bool value, Widget toggle(BuildContext context, String text, bool value,
Function(bool value) onChanged, Function(bool value) onChanged,
@ -120,49 +121,99 @@ Widget title(String text, {double top = 16, double bottom = 16}) {
])); ]));
} }
Widget titleDivider({double top = 16, double bottom = 16}) { Widget titleDivider({double? top, double? bottom, BuildContext? context}) {
top ??= (context != null && desktopLayoutNotRequired(context)) ? 32 : 16;
bottom ??= (context != null && desktopLayoutNotRequired(context)) ? 32 : 16;
return Padding( return Padding(
padding: EdgeInsets.only(left: 8, right: 8, top: top, bottom: bottom), padding: EdgeInsets.only(left: 8, right: 8, top: top, bottom: bottom),
child: const Row( child: const Row(
mainAxisSize: MainAxisSize.max, mainAxisSize: MainAxisSize.max,
children: [ children: [Expanded(child: Divider())]));
Expanded(child: Divider()), }
],
)); Widget verticalTitleDivider(
{double? left, double? right, BuildContext? context}) {
left ??= (context != null && desktopLayoutNotRequired(context)) ? 32 : 16;
right ??= (context != null && desktopLayoutNotRequired(context)) ? 32 : 16;
return Padding(
padding: EdgeInsets.only(left: left, right: right, top: 8, bottom: 8),
child: const Row(mainAxisSize: MainAxisSize.max, children: [
// Expanded(child:
VerticalDivider()
// ),
]));
} }
Widget button(String text, IconData? icon, void Function()? onPressed, Widget button(String text, IconData? icon, void Function()? onPressed,
{Color? color, {BuildContext? context,
Color? color,
bool disabled = false, bool disabled = false,
bool replaceIconIfNull = false,
String? description,
void Function()? onDisabledTap, void Function()? onDisabledTap,
void Function()? onLongTap, void Function()? onLongTap,
void Function()? onDoubleTap}) { void Function()? onDoubleTap}) {
return InkWell( if (description != null &&
onTap: disabled (context != null && desktopLayoutNotRequired(context)) &&
? () { !description.startsWith("\n")) {
selectionHaptic(); description = "$description";
if (onDisabledTap != null) { }
onDisabledTap(); return Padding(
padding: (context != null && desktopLayoutNotRequired(context))
? const EdgeInsets.only(top: 8, bottom: 8)
: EdgeInsets.zero,
child: InkWell(
onTap: disabled
? () {
selectionHaptic();
if (onDisabledTap != null) {
onDisabledTap();
}
} }
} : onPressed,
: onPressed, onLongPress: (description != null && context != null)
onLongPress: onLongTap, ? desktopLayoutNotRequired(context)
onDoubleTap: onDoubleTap, ? null
borderRadius: BorderRadius.circular(8), : () {
child: Padding( ScaffoldMessenger.of(context).showSnackBar(SnackBar(
padding: const EdgeInsets.all(8), content: Text(description!.trim()),
child: Row(children: [ showCloseIcon: true));
(icon != null) }
? Icon(icon, color: disabled ? Colors.grey : color) : onLongTap,
: const SizedBox.shrink(), onDoubleTap: onDoubleTap,
(icon != null) borderRadius: BorderRadius.circular(8),
? const SizedBox(width: 16, height: 42) child: Padding(
: const SizedBox.shrink(), padding: const EdgeInsets.all(8),
Expanded( child: Row(children: [
child: Text(text, (icon != null || replaceIconIfNull)
style: TextStyle(color: disabled ? Colors.grey : color))) ? replaceIconIfNull
]), ? ImageIcon(MemoryImage(kTransparentImage))
)); : Icon(icon, color: disabled ? Colors.grey : color)
: const SizedBox.shrink(),
(icon != null || replaceIconIfNull)
? const SizedBox(width: 16, height: 42)
: const SizedBox.shrink(),
Expanded(
child: (context != null)
? RichText(
text: TextSpan(
text: text,
style: DefaultTextStyle.of(context).style.copyWith(
color: disabled ? Colors.grey : color),
children: [
(description != null &&
desktopLayoutNotRequired(context))
? TextSpan(
text: description,
style: const TextStyle(color: Colors.grey))
: const TextSpan()
]))
: Text(text,
style:
TextStyle(color: disabled ? Colors.grey : color)))
]),
)),
);
} }
class ScreenSettings extends StatefulWidget { class ScreenSettings extends StatefulWidget {
@ -233,6 +284,10 @@ class _ScreenSettingsState extends State<ScreenSettings> {
selectionHaptic(); selectionHaptic();
} }
double iconSize = 1;
bool animatedInitialized = false;
bool animatedDesktop = false;
@override @override
void initState() { void initState() {
super.initState(); super.initState();
@ -249,6 +304,10 @@ class _ScreenSettingsState extends State<ScreenSettings> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
if (!animatedInitialized) {
animatedInitialized = true;
animatedDesktop = desktopLayoutNotRequired(context);
}
return PopScope( return PopScope(
canPop: !hostLoading, canPop: !hostLoading,
onPopInvoked: (didPop) { onPopInvoked: (didPop) {
@ -267,222 +326,323 @@ class _ScreenSettingsState extends State<ScreenSettings> {
actions: desktopControlsActions(context)), actions: desktopControlsActions(context)),
body: Padding( body: Padding(
padding: const EdgeInsets.only(left: 16, right: 16), padding: const EdgeInsets.only(left: 16, right: 16),
child: Column(children: [ child: LayoutBuilder(builder: (context, constraints) {
Expanded( var column1 =
child: ListView(children: [ Column(mainAxisSize: MainAxisSize.min, children: [
const SizedBox(height: 8), AnimatedContainer(
TextField( duration: const Duration(milliseconds: 200),
controller: hostInputController, height: animatedDesktop ? 8 : 0,
keyboardType: TextInputType.url, child: const SizedBox.shrink()),
readOnly: useHost, const SizedBox(height: 8),
onSubmitted: (value) { TextField(
selectionHaptic(); controller: hostInputController,
checkHost(); keyboardType: TextInputType.url,
}, readOnly: useHost,
decoration: InputDecoration( onSubmitted: (value) {
labelText: AppLocalizations.of(context)! selectionHaptic();
.settingsHost, checkHost();
hintText: "http://localhost:11434", },
prefixIcon: IconButton( decoration: InputDecoration(
tooltip: AppLocalizations.of(context)! labelText:
.tooltipAddHostHeaders, AppLocalizations.of(context)!.settingsHost,
onPressed: () async { hintText: "http://localhost:11434",
selectionHaptic(); prefixIcon: IconButton(
String tmp = await prompt(context, tooltip: AppLocalizations.of(context)!
placeholder: .tooltipAddHostHeaders,
"{\"Authorization\": \"Bearer ...\"}", onPressed: () async {
title: AppLocalizations.of(context)! selectionHaptic();
.settingsHostHeaderTitle, String tmp = await prompt(context,
value: (prefs! placeholder:
.getString("hostHeaders") ?? "{\"Authorization\": \"Bearer ...\"}",
""), title: AppLocalizations.of(context)!
valueIfCanceled: "{}", .settingsHostHeaderTitle,
validator: (content) async { value: (prefs!
try { .getString("hostHeaders") ??
var tmp = jsonDecode(content); ""),
tmp as Map<String, dynamic>; valueIfCanceled: "{}",
return true; validator: (content) async {
} catch (_) { try {
return false; var tmp = jsonDecode(content);
} tmp as Map<String, dynamic>;
}, return true;
validatorError: } catch (_) {
AppLocalizations.of(context)! return false;
.settingsHostHeaderInvalid, }
prefill: !((prefs!.getString(
"hostHeaders") ??
{}) ==
"{}"));
prefs!.setString("hostHeaders", tmp);
}, },
icon: const Icon(Icons.add_rounded)), validatorError:
suffixIcon: useHost AppLocalizations.of(context)!
? const SizedBox.shrink() .settingsHostHeaderInvalid,
: (hostLoading prefill: !((prefs!.getString(
? Transform.scale( "hostHeaders") ??
scale: 0.5, {}) ==
child: "{}"));
const CircularProgressIndicator()) prefs!.setString("hostHeaders", tmp);
: IconButton( },
tooltip: icon: const Icon(Icons.add_rounded)),
AppLocalizations.of(context)! suffixIcon: useHost
.tooltipSave, ? const SizedBox.shrink()
onPressed: () { : (hostLoading
selectionHaptic(); ? Transform.scale(
checkHost(); scale: 0.5,
}, child:
icon: const Icon( const CircularProgressIndicator())
Icons.save_rounded), : IconButton(
)), tooltip:
border: const OutlineInputBorder(), AppLocalizations.of(context)!
error: (hostInvalidHost || hostInvalidUrl) .tooltipSave,
? InkWell( onPressed: () {
onTap: () { selectionHaptic();
selectionHaptic(); checkHost();
ScaffoldMessenger.of(context) },
.showSnackBar(SnackBar( icon:
content: Text(AppLocalizations const Icon(Icons.save_rounded),
.of(context)! )),
.settingsHostInvalidDetailed( border: const OutlineInputBorder(),
hostInvalidHost error: (hostInvalidHost || hostInvalidUrl)
? "host" ? InkWell(
: "url")), onTap: () {
showCloseIcon: true)); selectionHaptic();
}, ScaffoldMessenger.of(context)
highlightColor: Colors.transparent, .showSnackBar(SnackBar(
splashFactory: NoSplash.splashFactory, content: Text(AppLocalizations
child: Row( .of(context)!
.settingsHostInvalidDetailed(
hostInvalidHost
? "host"
: "url")),
showCloseIcon: true));
},
splashFactory: NoSplash.splashFactory,
highlightColor: Colors.transparent,
hoverColor: Colors.transparent,
child: Row(
children: [
Icon(Icons.error_rounded,
color: Theme.of(context)
.colorScheme
.error),
const SizedBox(width: 8),
Text(
AppLocalizations.of(context)!
.settingsHostInvalid(
hostInvalidHost
? "host"
: "url"),
style: TextStyle(
color: Theme.of(context)
.colorScheme
.error))
],
))
: null,
helper: InkWell(
onTap: () {
selectionHaptic();
},
splashFactory: NoSplash.splashFactory,
highlightColor: Colors.transparent,
hoverColor: Colors.transparent,
child: hostLoading
? Row(
children: [ children: [
Icon(Icons.error_rounded, const Icon(Icons.search_rounded,
color: Theme.of(context) color: Colors.grey),
.colorScheme
.error),
const SizedBox(width: 8), const SizedBox(width: 8),
Text( Text(
AppLocalizations.of(context)! AppLocalizations.of(context)!
.settingsHostInvalid( .settingsHostChecking,
hostInvalidHost style: const TextStyle(
? "host" color: Colors.grey,
: "url"), fontFamily: "monospace"))
style: TextStyle(
color: Theme.of(context)
.colorScheme
.error))
], ],
)) )
: null, : Row(
helper: InkWell( children: [
onTap: () { Icon(Icons.check_rounded,
selectionHaptic(); color: Colors.green
}, .harmonizeWith(
highlightColor: Colors.transparent, Theme.of(context)
splashFactory: NoSplash.splashFactory, .colorScheme
child: hostLoading .primary)),
? Row( const SizedBox(width: 8),
children: [ Text(
const Icon(Icons.search_rounded, AppLocalizations.of(context)!
color: Colors.grey), .settingsHostValid,
const SizedBox(width: 8), style: TextStyle(
Text( color: Colors.green
.harmonizeWith(
Theme.of(context)
.colorScheme
.primary),
fontFamily: "monospace"))
],
))))
]);
var column2 =
Column(mainAxisSize: MainAxisSize.min, children: [
button(
AppLocalizations.of(context)!.settingsTitleBehavior,
Icons.psychology_rounded, () {
selectionHaptic();
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
const ScreenSettingsBehavior()));
},
context: context,
description:
"\n${AppLocalizations.of(context)!.settingsDescriptionBehavior}"),
button(
AppLocalizations.of(context)!
.settingsTitleInterface,
Icons.web_asset_rounded, () {
selectionHaptic();
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
const ScreenSettingsInterface()));
},
context: context,
description:
"\n${AppLocalizations.of(context)!.settingsDescriptionInterface}"),
(!desktopFeature())
? button(
AppLocalizations.of(context)!
.settingsTitleVoice,
Icons.headphones_rounded, () {
selectionHaptic();
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
const ScreenSettingsVoice()));
},
context: context,
description:
"\n${AppLocalizations.of(context)!.settingsDescriptionVoice}")
: const SizedBox.shrink(),
button(
AppLocalizations.of(context)!.settingsTitleExport,
Icons.share_rounded, () {
selectionHaptic();
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
const ScreenSettingsExport()));
},
context: context,
description:
"\n${AppLocalizations.of(context)!.settingsDescriptionExport}"),
button(AppLocalizations.of(context)!.settingsTitleAbout,
Icons.help_rounded, () {
selectionHaptic();
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
const ScreenSettingsAbout()));
},
context: context,
description:
"\n${AppLocalizations.of(context)!.settingsDescriptionAbout}")
]);
animatedDesktop = desktopLayoutNotRequired(context);
return Column(children: [
Expanded(
child: desktopLayoutNotRequired(context)
? Row(
mainAxisSize: MainAxisSize.max,
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Expanded(
child: Column(
mainAxisSize: MainAxisSize.max,
children: [
column1,
Expanded(
child: Center(
child: InkWell(
splashFactory:
NoSplash.splashFactory,
highlightColor:
Colors.transparent,
enableFeedback: false,
hoverColor: Colors.transparent,
onTap: () async {
if (iconSize != 1) return;
heavyHaptic();
setState(() {
iconSize = 0.8;
});
await Future.delayed(
const Duration(
milliseconds: 200));
setState(() {
iconSize = 1.2;
});
await Future.delayed(
const Duration(
milliseconds: 200));
setState(() {
iconSize = 1;
});
},
child: AnimatedScale(
scale: iconSize,
duration: const Duration(
milliseconds: 400),
child: const ImageIcon(
AssetImage(
"assets/logo512.png"),
size: 44),
),
))),
Transform.translate(
offset: const Offset(0, 8),
child: button(
AppLocalizations.of( AppLocalizations.of(
context)! context)!
.settingsHostChecking, .settingsSavedAutomatically,
style: const TextStyle( Icons.info_rounded,
color: Colors.grey, null,
fontFamily: color: Colors.grey
"monospace"))
],
)
: Row(
children: [
Icon(Icons.check_rounded,
color: Colors.green
.harmonizeWith( .harmonizeWith(
Theme.of(context) Theme.of(context)
.colorScheme .colorScheme
.primary)), .primary)),
const SizedBox(width: 8), )
Text( ])),
AppLocalizations.of( verticalTitleDivider(context: context),
context)! Expanded(child: column2)
.settingsHostValid, ])
style: TextStyle( : ListView(children: [
color: Colors.green column1,
.harmonizeWith( AnimatedOpacity(
Theme.of( opacity: animatedDesktop ? 0 : 1,
context) duration:
.colorScheme const Duration(milliseconds: 200),
.primary), child: titleDivider(bottom: 4)),
fontFamily: AnimatedOpacity(
"monospace")) opacity: animatedDesktop ? 0 : 1,
], duration:
)))), const Duration(milliseconds: 200),
titleDivider(bottom: 4), child: column2)
button( ])),
AppLocalizations.of(context)! const SizedBox(height: 8),
.settingsTitleBehavior, desktopLayoutNotRequired(context)
Icons.psychology_rounded, () { ? const SizedBox.shrink()
selectionHaptic(); : button(
Navigator.push( AppLocalizations.of(context)!
context, .settingsSavedAutomatically,
MaterialPageRoute( Icons.info_rounded,
builder: (context) => null,
const ScreenSettingsBehavior())); color: Colors.grey.harmonizeWith(
}), Theme.of(context).colorScheme.primary))
button( ]);
AppLocalizations.of(context)! })))));
.settingsTitleInterface,
Icons.web_asset_rounded, () {
selectionHaptic();
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
const ScreenSettingsInterface()));
}),
(!desktopFeature())
? button(
AppLocalizations.of(context)!
.settingsTitleVoice,
Icons.headphones_rounded, () {
selectionHaptic();
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
const ScreenSettingsVoice()));
})
: const SizedBox.shrink(),
button(
AppLocalizations.of(context)!.settingsTitleExport,
Icons.share_rounded, () {
selectionHaptic();
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
const ScreenSettingsExport()));
}),
button(
AppLocalizations.of(context)!.settingsTitleAbout,
Icons.help_rounded, () {
selectionHaptic();
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
const ScreenSettingsAbout()));
})
]),
),
const SizedBox(height: 8),
button(
AppLocalizations.of(context)!
.settingsSavedAutomatically,
Icons.info_rounded,
null,
color: Colors.grey.harmonizeWith(
Theme.of(context).colorScheme.primary))
])))));
} }
} }

View File

@ -37,13 +37,11 @@ class _ScreenSettingsAboutState extends State<ScreenSettingsAbout> {
color: Theme.of(context).colorScheme.surface, color: Theme.of(context).colorScheme.surface,
child: Scaffold( child: Scaffold(
appBar: AppBar( appBar: AppBar(
title: Row(children: [ title: Row(children: [
Text(AppLocalizations.of(context)!.settingsTitleAbout), Text(AppLocalizations.of(context)!.settingsTitleAbout),
Expanded(child: SizedBox(height: 200, child: MoveWindow())) Expanded(child: SizedBox(height: 200, child: MoveWindow()))
]), ]),
actions: actions: desktopControlsActions(context)),
desktopControlsActions(context)
),
body: Padding( body: Padding(
padding: const EdgeInsets.only(left: 16, right: 16), padding: const EdgeInsets.only(left: 16, right: 16),
child: Column(children: [ child: Column(children: [
@ -110,7 +108,7 @@ class _ScreenSettingsAboutState extends State<ScreenSettingsAbout> {
prefs!.setBool("checkUpdateOnSettingsOpen", value); prefs!.setBool("checkUpdateOnSettingsOpen", value);
setState(() {}); setState(() {});
}), }),
titleDivider(), titleDivider(context: context),
button(AppLocalizations.of(context)!.settingsGithub, button(AppLocalizations.of(context)!.settingsGithub,
SimpleIcons.github, () { SimpleIcons.github, () {
selectionHaptic(); selectionHaptic();

View File

@ -46,7 +46,7 @@ class _ScreenSettingsBehaviorState extends State<ScreenSettingsBehavior> {
TextField( TextField(
controller: systemInputController, controller: systemInputController,
keyboardType: TextInputType.multiline, keyboardType: TextInputType.multiline,
maxLines: 2, maxLines: desktopLayoutNotRequired(context) ? 5 : 2,
decoration: InputDecoration( decoration: InputDecoration(
labelText: AppLocalizations.of(context)! labelText: AppLocalizations.of(context)!
.settingsSystemMessage, .settingsSystemMessage,

View File

@ -64,7 +64,9 @@ class _ScreenSettingsInterfaceState extends State<ScreenSettingsInterface> {
prefs!.setBool("resetOnModelSelect", value); prefs!.setBool("resetOnModelSelect", value);
setState(() {}); setState(() {});
}), }),
titleDivider(bottom: 20), titleDivider(
bottom: desktopLayoutNotRequired(context) ? 38 : 20,
context: context),
SegmentedButton( SegmentedButton(
segments: [ segments: [
ButtonSegment( ButtonSegment(
@ -121,7 +123,7 @@ class _ScreenSettingsInterfaceState extends State<ScreenSettingsInterface> {
prefs!.setBool("tips", value); prefs!.setBool("tips", value);
setState(() {}); setState(() {});
}), }),
titleDivider(), titleDivider(context: context),
toggle( toggle(
context, context,
AppLocalizations.of(context)! AppLocalizations.of(context)!
@ -240,7 +242,7 @@ class _ScreenSettingsInterfaceState extends State<ScreenSettingsInterface> {
})); }));
}); });
}), }),
titleDivider(), titleDivider(context: context),
toggle( toggle(
context, context,
AppLocalizations.of(context)! AppLocalizations.of(context)!