Restrict desktop settings width, centralized delete dialog, allow changing titles and deleting non current chats

This commit is contained in:
JHubi1 2024-08-21 00:58:13 +02:00
parent 8813571b65
commit efcca113c8
No known key found for this signature in database
GPG Key ID: 7BF82570CBBBD050
10 changed files with 1210 additions and 1302 deletions

View File

@ -424,7 +424,8 @@ class _MainAppState extends State<MainApp> {
? null
: () async {
selectionHaptic();
if (!chatAllowed) return;
if (!chatAllowed &&
chatUuid == jsonDecode(item)["uuid"]) return;
if (!allowSettings) return;
String oldTitle = jsonDecode(item)["title"];
var newTitle = await prompt(context,
@ -480,6 +481,10 @@ class _MainAppState extends State<MainApp> {
width: 24,
child: IconButton(
onPressed: () {
if (!chatAllowed &&
chatUuid ==
jsonDecode(item)["uuid"])
return;
if (!allowMultipleChats) {
for (var i = 0;
i <
@ -511,124 +516,14 @@ class _MainAppState extends State<MainApp> {
return;
}
if (!allowSettings) {
if (prefs!.getBool(
"askBeforeDeletion") ??
false) {
showDialog(
context: context,
builder: (context) {
return StatefulBuilder(
builder: (context,
setLocalState) {
return AlertDialog(
title: Text(
AppLocalizations.of(
context)!
.deleteDialogTitle),
content: Column(
mainAxisSize:
MainAxisSize
.min,
children: [
Text(AppLocalizations.of(
context)!
.deleteDialogDescription),
]),
actions: [
TextButton(
onPressed:
() {
Navigator.of(
context)
.pop();
},
child: Text(AppLocalizations.of(
context)!
.deleteDialogCancel)),
TextButton(
onPressed:
() {
Navigator.of(
context)
.pop();
for (var i =
0;
i < (prefs!.getStringList("chats") ?? []).length;
i++) {
if (jsonDecode((prefs!.getStringList("chats") ?? [])[i])[
"uuid"] ==
jsonDecode(
item)["uuid"]) {
List<String>
tmp =
prefs!.getStringList("chats")!;
tmp.removeAt(
i);
prefs!.setStringList(
"chats",
tmp);
break;
}
}
if (chatUuid ==
jsonDecode(
item)["uuid"]) {
messages =
[];
chatUuid =
null;
if (!desktopLayoutRequired(
context)) {
Navigator.of(context)
.pop();
}
}
setState(
() {});
},
child: Text(AppLocalizations.of(
context)!
.deleteDialogDelete))
]);
});
});
} else {
for (var i = 0;
i <
(prefs!.getStringList(
"chats") ??
[])
.length;
i++) {
if (jsonDecode((prefs!
.getStringList(
"chats") ??
[])[i])["uuid"] ==
jsonDecode(
item)["uuid"]) {
List<String> tmp = prefs!
.getStringList(
"chats")!;
tmp.removeAt(i);
prefs!.setStringList(
"chats", tmp);
break;
}
}
if (chatUuid ==
jsonDecode(item)["uuid"]) {
messages = [];
chatUuid = null;
if (!desktopLayoutRequired(
context)) {
Navigator.of(context).pop();
}
}
setState(() {});
}
deleteChatDialog(
context, setState,
additionalCondition: false,
uuid:
jsonDecode(item)["uuid"],
popSidebar: true);
return;
}
if (!chatAllowed) return;
if (!desktopLayoutRequired(
context)) {
Navigator.of(context).pop();
@ -636,7 +531,22 @@ class _MainAppState extends State<MainApp> {
showModalBottomSheet(
context: context,
builder: (context) {
return Padding(
return Container(
decoration: (Theme.of(context)
.brightness ==
Brightness.dark)
? BoxDecoration(
border: Border.all(
color: Colors
.white),
borderRadius: const BorderRadius.only(
topLeft:
Radius.circular(
26),
topRight:
Radius.circular(
26)))
: null,
padding:
const EdgeInsets.only(
left: 16,
@ -655,68 +565,11 @@ class _MainAppState extends State<MainApp> {
() {
Navigator.of(context)
.pop();
if (prefs!.getBool("askBeforeDeletion") ??
false) {
showDialog(
context: context,
builder: (context) {
return StatefulBuilder(builder: (context, setLocalState) {
return AlertDialog(
title: Text(AppLocalizations.of(context)!.deleteDialogTitle),
content: Column(mainAxisSize: MainAxisSize.min, children: [
Text(AppLocalizations.of(context)!.deleteDialogDescription),
]),
actions: [
TextButton(
onPressed: () {
Navigator.of(context).pop();
},
child: Text(AppLocalizations.of(context)!.deleteDialogCancel)),
TextButton(
onPressed: () {
Navigator.of(context).pop();
for (var i = 0; i < (prefs!.getStringList("chats") ?? []).length; i++) {
if (jsonDecode((prefs!.getStringList("chats") ?? [])[i])["uuid"] == jsonDecode(item)["uuid"]) {
List<String> tmp = prefs!.getStringList("chats")!;
tmp.removeAt(i);
prefs!.setStringList("chats", tmp);
break;
}
}
if (chatUuid == jsonDecode(item)["uuid"]) {
messages = [];
chatUuid = null;
if (!desktopLayoutRequired(context)) {
Navigator.of(context).pop();
}
}
setState(() {});
},
child: Text(AppLocalizations.of(context)!.deleteDialogDelete))
]);
});
});
} else {
for (var i = 0;
i < (prefs!.getStringList("chats") ?? []).length;
i++) {
if (jsonDecode((prefs!.getStringList("chats") ?? [])[i])["uuid"] == jsonDecode(item)["uuid"]) {
List<String> tmp = prefs!.getStringList("chats")!;
tmp.removeAt(i);
prefs!.setStringList("chats", tmp);
break;
}
}
if (chatUuid ==
jsonDecode(item)["uuid"]) {
messages = [];
chatUuid = null;
if (!desktopLayoutRequired(context)) {
Navigator.of(context).pop();
}
}
setState(() {});
}
deleteChatDialog(
context,
setState,
uuid: jsonDecode(item)["uuid"],
popSidebar: true);
},
icon: const Icon(Icons
.delete_forever_rounded),
@ -793,48 +646,10 @@ class _MainAppState extends State<MainApp> {
? DismissDirection.startToEnd
: DismissDirection.none,
confirmDismiss: (direction) async {
bool returnValue = false;
if (!chatAllowed) return false;
if (prefs!.getBool("askBeforeDeletion") ?? false) {
await showDialog(
context: context,
builder: (context) {
return StatefulBuilder(
builder: (context, setLocalState) {
return AlertDialog(
title: Text(AppLocalizations.of(context)!
.deleteDialogTitle),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(AppLocalizations.of(context)!
.deleteDialogDescription),
]),
actions: [
TextButton(
onPressed: () {
selectionHaptic();
Navigator.of(context).pop();
returnValue = false;
},
child: Text(AppLocalizations.of(context)!
.deleteDialogCancel)),
TextButton(
onPressed: () {
selectionHaptic();
Navigator.of(context).pop();
returnValue = true;
},
child: Text(AppLocalizations.of(context)!
.deleteDialogDelete))
]);
});
});
} else {
returnValue = true;
}
return returnValue;
if (!chatAllowed && chatUuid == jsonDecode(item)["uuid"])
return false;
return await deleteChatDialog(context, setState,
takeAction: false);
},
onDismissed: (direction) {
selectionHaptic();
@ -937,15 +752,18 @@ class _MainAppState extends State<MainApp> {
resetSystemNavigation(context);
Widget selector = InkWell(
onTap: () {
onTap: !useModel
? () {
if (host == null) {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text(AppLocalizations.of(context)!.noHostSelected),
content:
Text(AppLocalizations.of(context)!.noHostSelected),
showCloseIcon: true));
return;
}
setModel(context, setState);
},
}
: null,
splashFactory: NoSplash.splashFactory,
highlightColor: Colors.transparent,
enableFeedback: false,
@ -1053,90 +871,8 @@ class _MainAppState extends State<MainApp> {
onPressed: () {
selectionHaptic();
if (!chatAllowed) return;
if (prefs!.getBool("askBeforeDeletion") ??
// ignore: dead_code
false && messages.isNotEmpty) {
showDialog(
context: context,
builder: (context) {
return StatefulBuilder(
builder: (context, setLocalState) {
return AlertDialog(
title: Text(
AppLocalizations.of(context)!
.deleteDialogTitle),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(AppLocalizations.of(context)!
.deleteDialogDescription),
]),
actions: [
TextButton(
onPressed: () {
selectionHaptic();
Navigator.of(context).pop();
},
child: Text(
AppLocalizations.of(context)!
.deleteDialogCancel)),
TextButton(
onPressed: () {
selectionHaptic();
Navigator.of(context).pop();
for (var i = 0;
i <
(prefs!.getStringList(
"chats") ??
[])
.length;
i++) {
if (jsonDecode((prefs!
.getStringList(
"chats") ??
[])[i])["uuid"] ==
chatUuid) {
List<String> tmp = prefs!
.getStringList(
"chats")!;
tmp.removeAt(i);
prefs!.setStringList(
"chats", tmp);
break;
}
}
messages = [];
chatUuid = null;
setState(() {});
},
child: Text(
AppLocalizations.of(context)!
.deleteDialogDelete))
]);
});
});
} else {
for (var i = 0;
i <
(prefs!.getStringList("chats") ?? [])
.length;
i++) {
if (jsonDecode((prefs!.getStringList("chats") ??
[])[i])["uuid"] ==
chatUuid) {
List<String> tmp =
prefs!.getStringList("chats")!;
tmp.removeAt(i);
prefs!.setStringList("chats", tmp);
break;
}
}
messages = [];
chatUuid = null;
}
setState(() {});
deleteChatDialog(context, setState,
additionalCondition: messages.isNotEmpty);
},
icon: const Icon(Icons.restart_alt_rounded))
: const SizedBox.shrink()
@ -1533,27 +1269,42 @@ class _MainAppState extends State<MainApp> {
context: context,
builder: (context) {
return Container(
decoration: (Theme.of(context)
.brightness ==
Brightness.dark)
? BoxDecoration(
border: Border.all(
color:
Colors.white),
borderRadius:
const BorderRadius.only(
topLeft: Radius
.circular(
26),
topRight:
Radius.circular(
26)))
: null,
width: double.infinity,
padding: const EdgeInsets.only(
left: 16,
right: 16,
top: 16),
child: Column(
mainAxisSize:
MainAxisSize.min,
children: [
child:
Column(mainAxisSize: MainAxisSize.min, children: [
(prefs?.getBool(
"voiceModeEnabled") ??
false)
? SizedBox(
width: double
.infinity,
width:
double.infinity,
child: OutlinedButton
.icon(
onPressed:
() async {
selectionHaptic();
Navigator.of(context)
Navigator.of(
context)
.pop();
setMainState =
setState;
@ -1561,30 +1312,29 @@ class _MainAppState extends State<MainApp> {
true;
logoVisible =
false;
Navigator.of(context).push(MaterialPageRoute(
Navigator.of(
context)
.push(MaterialPageRoute(
builder: (context) =>
const ScreenVoice()));
},
icon: const Icon(
Icons
.headphones_rounded),
label: Text(
AppLocalizations.of(context)!
label: Text(AppLocalizations.of(
context)!
.settingsTitleVoice)))
: const SizedBox
.shrink(),
: const SizedBox.shrink(),
(prefs?.getBool(
"voiceModeEnabled") ??
false)
? const SizedBox(
height: 8)
: const SizedBox
.shrink(),
: const SizedBox.shrink(),
SizedBox(
width:
double.infinity,
child: OutlinedButton
.icon(
width: double.infinity,
child:
OutlinedButton.icon(
onPressed:
() async {
selectionHaptic();
@ -1595,7 +1345,8 @@ class _MainAppState extends State<MainApp> {
final result =
await ImagePicker()
.pickImage(
source: ImageSource
source:
ImageSource
.camera,
);
if (result ==
@ -1613,10 +1364,9 @@ class _MainAppState extends State<MainApp> {
final message =
types
.ImageMessage(
author:
user,
createdAt:
DateTime.now()
author: user,
createdAt: DateTime
.now()
.millisecondsSinceEpoch,
height: image
.height
@ -1635,24 +1385,21 @@ class _MainAppState extends State<MainApp> {
);
messages.insert(
0,
message);
setState(
() {});
0, message);
setState(() {});
selectionHaptic();
},
icon: const Icon(
Icons
icon: const Icon(Icons
.photo_camera_rounded),
label: Text(AppLocalizations.of(
label: Text(
AppLocalizations.of(
context)!
.takeImage))),
const SizedBox(height: 8),
SizedBox(
width:
double.infinity,
child: OutlinedButton
.icon(
width: double.infinity,
child:
OutlinedButton.icon(
onPressed:
() async {
selectionHaptic();
@ -1663,7 +1410,8 @@ class _MainAppState extends State<MainApp> {
final result =
await ImagePicker()
.pickImage(
source: ImageSource
source:
ImageSource
.gallery,
);
if (result ==
@ -1681,10 +1429,9 @@ class _MainAppState extends State<MainApp> {
final message =
types
.ImageMessage(
author:
user,
createdAt:
DateTime.now()
author: user,
createdAt: DateTime
.now()
.millisecondsSinceEpoch,
height: image
.height
@ -1703,16 +1450,14 @@ class _MainAppState extends State<MainApp> {
);
messages.insert(
0,
message);
setState(
() {});
0, message);
setState(() {});
selectionHaptic();
},
icon: const Icon(
Icons
icon: const Icon(Icons
.image_rounded),
label: Text(AppLocalizations.of(
label: Text(
AppLocalizations.of(
context)!
.uploadImage)))
]));

View File

@ -125,14 +125,15 @@ Widget title(String text, {double top = 16, double bottom = 16}) {
Padding(
padding: const EdgeInsets.only(left: 24, right: 24),
child: Text(text)),
const Expanded(child: Divider())
const Expanded(child: Divider(height: 1))
]));
}
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 AnimatedContainer(
duration: const Duration(milliseconds: 200),
padding: EdgeInsets.only(left: 8, right: 8, top: top, bottom: bottom),
child: const Row(
mainAxisSize: MainAxisSize.max,
@ -143,13 +144,12 @@ Widget verticalTitleDivider(
{double? left, double? right, BuildContext? context}) {
left ??= (context != null && desktopLayoutNotRequired(context)) ? 32 : 16;
right ??= (context != null && desktopLayoutNotRequired(context)) ? 32 : 16;
return Padding(
return AnimatedContainer(
duration: const Duration(milliseconds: 200),
padding: EdgeInsets.only(left: left, right: right, top: 8, bottom: 8),
child: const Row(mainAxisSize: MainAxisSize.max, children: [
// Expanded(child:
VerticalDivider()
// ),
]));
child: const Row(
mainAxisSize: MainAxisSize.max,
children: [VerticalDivider(width: 1)]));
}
Widget button(String text, IconData? icon, void Function()? onPressed,
@ -359,6 +359,7 @@ class _ScreenSettingsState extends State<ScreenSettings> {
TextField(
controller: hostInputController,
keyboardType: TextInputType.url,
autofillHints: const [AutofillHints.url],
readOnly: useHost,
onSubmitted: (value) {
selectionHaptic();

View File

@ -42,7 +42,9 @@ class _ScreenSettingsAboutState extends State<ScreenSettingsAbout> {
Expanded(child: SizedBox(height: 200, child: MoveWindow()))
]),
actions: desktopControlsActions(context)),
body: Padding(
body: Center(
child: Container(
constraints: const BoxConstraints(maxWidth: 1000),
padding: const EdgeInsets.only(left: 16, right: 16),
child: Column(children: [
Expanded(
@ -73,10 +75,12 @@ class _ScreenSettingsAboutState extends State<ScreenSettingsAbout> {
Version.parse(
currentVersion ??
"2.0.0"))
? AppLocalizations.of(context)!
? AppLocalizations.of(
context)!
.settingsUpdateAvailable(
latestVersion!)
: AppLocalizations.of(context)!
: AppLocalizations.of(
context)!
.settingsUpdateLatest),
((updateStatus != "ok")
? Icons.warning_rounded
@ -88,7 +92,8 @@ class _ScreenSettingsAboutState extends State<ScreenSettingsAbout> {
if (updateLoading) return;
selectionHaptic();
if ((Version.parse(latestVersion ?? "1.0.0") >
Version.parse(currentVersion ?? "2.0.0")) &&
Version.parse(
currentVersion ?? "2.0.0")) &&
(updateStatus == "ok")) {
updateDialog(context, title);
} else {
@ -105,7 +110,8 @@ class _ScreenSettingsAboutState extends State<ScreenSettingsAbout> {
(prefs!.getBool("checkUpdateOnSettingsOpen") ??
false), (value) {
selectionHaptic();
prefs!.setBool("checkUpdateOnSettingsOpen", value);
prefs!
.setBool("checkUpdateOnSettingsOpen", value);
setState(() {});
}),
titleDivider(context: context),
@ -158,7 +164,8 @@ class _ScreenSettingsAboutState extends State<ScreenSettingsAbout> {
const SizedBox(height: 16)
]),
)
]))),
])),
)),
);
}
}

View File

@ -37,7 +37,9 @@ class _ScreenSettingsBehaviorState extends State<ScreenSettingsBehavior> {
Expanded(child: SizedBox(height: 200, child: MoveWindow()))
]),
actions: desktopControlsActions(context)),
body: Padding(
body: Center(
child: Container(
constraints: const BoxConstraints(maxWidth: 1000),
padding: const EdgeInsets.only(left: 16, right: 16),
child: Column(children: [
Expanded(
@ -50,6 +52,7 @@ class _ScreenSettingsBehaviorState extends State<ScreenSettingsBehavior> {
decoration: InputDecoration(
labelText: AppLocalizations.of(context)!
.settingsSystemMessage,
alignLabelWithHint: true,
hintText: "You are a helpful assistant",
suffixIcon: IconButton(
tooltip:
@ -101,7 +104,8 @@ class _ScreenSettingsBehaviorState extends State<ScreenSettingsBehavior> {
null,
color: Colors.grey
.harmonizeWith(Theme.of(context).colorScheme.primary))
]))),
])),
)),
);
}
}

View File

@ -36,7 +36,9 @@ class _ScreenSettingsExportState extends State<ScreenSettingsExport> {
Expanded(child: SizedBox(height: 200, child: MoveWindow()))
]),
actions: desktopControlsActions(context)),
body: Padding(
body: Center(
child: Container(
constraints: const BoxConstraints(maxWidth: 1000),
padding: const EdgeInsets.only(left: 16, right: 16),
child: Column(children: [
Expanded(
@ -71,7 +73,8 @@ class _ScreenSettingsExportState extends State<ScreenSettingsExport> {
path = (await file_selector
.getSaveLocation(acceptedTypeGroups: [
const file_selector.XTypeGroup(
label: "Ollama App File", extensions: ["json"])
label: "Ollama App File",
extensions: ["json"])
], suggestedName: name))
?.path;
} catch (_) {
@ -104,10 +107,16 @@ class _ScreenSettingsExportState extends State<ScreenSettingsExport> {
context: context,
builder: (context) {
return AlertDialog(
title: Text(AppLocalizations.of(context)!
.settingsImportChatsTitle),
content: Text(
surfaceTintColor:
(Theme.of(context).brightness ==
Brightness.dark)
? Colors.grey[800]
: null,
title: Text(
AppLocalizations.of(context)!
.settingsImportChatsTitle),
content: Text(AppLocalizations.of(
context)!
.settingsImportChatsDescription),
actions: [
TextButton(
@ -134,21 +143,23 @@ class _ScreenSettingsExportState extends State<ScreenSettingsExport> {
.XTypeGroup(
label:
"Ollama App File",
extensions: ["json"])
extensions: [
"json"
])
]);
if (result == null) {
// ignore: use_build_context_synchronously
Navigator.of(context).pop();
return;
}
content =
await result.readAsString();
content = await result
.readAsString();
} catch (_) {
FilePickerResult? result =
await FilePicker.platform
.pickFiles(
type:
FileType.custom,
type: FileType
.custom,
allowedExtensions: [
"json"
]);
@ -160,8 +171,8 @@ class _ScreenSettingsExportState extends State<ScreenSettingsExport> {
try {
File file = File(result
.files.single.path!);
content =
await file.readAsString();
content = await file
.readAsString();
} catch (_) {
// web fallback
content = utf8.decode(result
@ -203,8 +214,8 @@ class _ScreenSettingsExportState extends State<ScreenSettingsExport> {
.settingsImportChatsSuccess),
showCloseIcon: true));
},
child: Text(
AppLocalizations.of(context)!
child: Text(AppLocalizations.of(
context)!
.settingsImportChatsImport))
]);
});
@ -215,13 +226,14 @@ class _ScreenSettingsExportState extends State<ScreenSettingsExport> {
const SizedBox(height: 8),
button(AppLocalizations.of(context)!.settingsExportInfo,
Icons.info_rounded, null,
color: Colors.grey
.harmonizeWith(Theme.of(context).colorScheme.primary)),
color: Colors.grey.harmonizeWith(
Theme.of(context).colorScheme.primary)),
button(AppLocalizations.of(context)!.settingsExportWarning,
Icons.warning_rounded, null,
color: Colors.orange
.harmonizeWith(Theme.of(context).colorScheme.primary))
]))),
])),
)),
);
}
}

View File

@ -36,7 +36,9 @@ class _ScreenSettingsInterfaceState extends State<ScreenSettingsInterface> {
Expanded(child: SizedBox(height: 200, child: MoveWindow()))
]),
actions: desktopControlsActions(context)),
body: Padding(
body: Center(
child: Container(
constraints: const BoxConstraints(maxWidth: 1000),
padding: const EdgeInsets.only(left: 16, right: 16),
child: Column(children: [
Expanded(
@ -132,8 +134,8 @@ class _ScreenSettingsInterfaceState extends State<ScreenSettingsInterface> {
context,
AppLocalizations.of(context)!
.settingsKeepModelLoadedAlways,
int.parse(prefs!.getString("keepAlive") ?? "300") == -1,
(value) {
int.parse(prefs!.getString("keepAlive") ?? "300") ==
-1, (value) {
selectionHaptic();
setState(() {
if (value) {
@ -147,8 +149,8 @@ class _ScreenSettingsInterfaceState extends State<ScreenSettingsInterface> {
context,
AppLocalizations.of(context)!
.settingsKeepModelLoadedNever,
int.parse(prefs!.getString("keepAlive") ?? "300") == 0,
(value) {
int.parse(prefs!.getString("keepAlive") ?? "300") ==
0, (value) {
selectionHaptic();
setState(() {
if (value) {
@ -159,7 +161,8 @@ class _ScreenSettingsInterfaceState extends State<ScreenSettingsInterface> {
});
}),
button(
(int.parse(prefs!.getString("keepAlive") ?? "300") > 0)
(int.parse(prefs!.getString("keepAlive") ?? "300") >
0)
? AppLocalizations.of(context)!
.settingsKeepModelLoadedSet((int.parse(
prefs!.getString("keepAlive") ??
@ -175,12 +178,14 @@ class _ScreenSettingsInterfaceState extends State<ScreenSettingsInterface> {
context: context,
builder: (context) {
return Dialog(
surfaceTintColor: (Theme.of(context).brightness == Brightness.dark) ? Colors.grey[800] : null,
alignment: desktopLayout(context)
? null
: Alignment.bottomRight,
child: StatefulBuilder(
builder: (context, setLocalState) {
if (int.parse(prefs!.getString("keepAlive") ??
if (int.parse(
prefs!.getString("keepAlive") ??
"0") <=
0 &&
loaded == false) {
@ -193,7 +198,8 @@ class _ScreenSettingsInterfaceState extends State<ScreenSettingsInterface> {
while (int.parse(prefs!
.getString("keepAlive")!) <
300) {
await Future.delayed(const Duration(
await Future.delayed(
const Duration(
milliseconds: 5));
prefs!.setString(
"keepAlive",
@ -204,10 +210,12 @@ class _ScreenSettingsInterfaceState extends State<ScreenSettingsInterface> {
setLocalState(() {});
setState(() {});
}
prefs!.setString("keepAlive", "300");
prefs!
.setString("keepAlive", "300");
loaded = true;
} catch (_) {
prefs!.setString("keepAlive", "300");
prefs!
.setString("keepAlive", "300");
loaded = true;
}
}
@ -220,16 +228,20 @@ class _ScreenSettingsInterfaceState extends State<ScreenSettingsInterface> {
return Padding(
padding: const EdgeInsets.all(16),
child: Theme(
data: (prefs?.getBool("useDeviceTheme") ??
data:
(prefs?.getBool("useDeviceTheme") ??
false)
? Theme.of(context)
: ThemeData.from(
colorScheme: ColorScheme.fromSeed(
seedColor: Colors.black)),
colorScheme:
ColorScheme.fromSeed(
seedColor:
Colors.black)),
child: DurationPicker(
duration: Duration(
seconds: int.parse(prefs!
.getString("keepAlive") ??
.getString(
"keepAlive") ??
"300")),
baseUnit: BaseUnit.minute,
lowerBound:
@ -283,7 +295,8 @@ class _ScreenSettingsInterfaceState extends State<ScreenSettingsInterface> {
value: "system",
label: Text(AppLocalizations.of(context)!
.settingsBrightnessSystem),
icon: const Icon(Icons.brightness_auto_rounded)),
icon:
const Icon(Icons.brightness_auto_rounded)),
ButtonSegment(
value: "light",
label: Text(AppLocalizations.of(context)!
@ -295,7 +308,8 @@ class _ScreenSettingsInterfaceState extends State<ScreenSettingsInterface> {
},
onSelectionChanged: (p0) {
selectionHaptic();
var tmp = prefs!.getString("brightness") ?? "system";
var tmp =
prefs!.getString("brightness") ?? "system";
prefs!.setString("brightness", p0.elementAt(0));
setState(() {});
showDialog(
@ -309,6 +323,7 @@ class _ScreenSettingsInterfaceState extends State<ScreenSettingsInterface> {
setState(() {});
},
child: AlertDialog(
surfaceTintColor: (Theme.of(context).brightness == Brightness.dark) ? Colors.grey[800] : null,
title: Text(AppLocalizations.of(
context)!
.settingsBrightnessRestartTitle),
@ -325,8 +340,8 @@ class _ScreenSettingsInterfaceState extends State<ScreenSettingsInterface> {
selectionHaptic();
Navigator.of(context).pop();
},
child: Text(AppLocalizations.of(
context)!
child: Text(AppLocalizations
.of(context)!
.settingsBrightnessRestartCancel)),
TextButton(
onPressed: () async {
@ -340,8 +355,8 @@ class _ScreenSettingsInterfaceState extends State<ScreenSettingsInterface> {
Restart.restartApp();
}
},
child: Text(AppLocalizations.of(
context)!
child: Text(AppLocalizations
.of(context)!
.settingsBrightnessRestartRestart))
]));
});
@ -376,6 +391,7 @@ class _ScreenSettingsInterfaceState extends State<ScreenSettingsInterface> {
return StatefulBuilder(
builder: (context, setLocalState) {
return AlertDialog(
surfaceTintColor: (Theme.of(context).brightness == Brightness.dark) ? Colors.grey[800] : null,
title: Text(
AppLocalizations.of(context)!
.settingsThemeRestartTitle),
@ -392,8 +408,8 @@ class _ScreenSettingsInterfaceState extends State<ScreenSettingsInterface> {
selectionHaptic();
Navigator.of(context).pop();
},
child: Text(AppLocalizations.of(
context)!
child: Text(AppLocalizations
.of(context)!
.settingsThemeRestartCancel)),
TextButton(
onPressed: () async {
@ -408,8 +424,8 @@ class _ScreenSettingsInterfaceState extends State<ScreenSettingsInterface> {
Restart.restartApp();
}
},
child: Text(AppLocalizations.of(
context)!
child: Text(AppLocalizations
.of(context)!
.settingsThemeRestartRestart))
]);
});
@ -417,7 +433,8 @@ class _ScreenSettingsInterfaceState extends State<ScreenSettingsInterface> {
})
: const SizedBox.shrink(),
titleDivider(),
button(AppLocalizations.of(context)!.settingsTemporaryFixes,
button(
AppLocalizations.of(context)!.settingsTemporaryFixes,
Icons.fast_forward_rounded, () {
selectionHaptic();
showModalBottomSheet(
@ -427,6 +444,15 @@ class _ScreenSettingsInterfaceState extends State<ScreenSettingsInterface> {
builder: (context, setState) {
return Container(
width: double.infinity,
decoration: (Theme.of(context).brightness ==
Brightness.dark)
? BoxDecoration(
border:
Border.all(color: Colors.white),
borderRadius: const BorderRadius.only(
topLeft: Radius.circular(26),
topRight: Radius.circular(26)))
: null,
padding: EdgeInsets.only(
left: 16,
right: 16,
@ -489,7 +515,8 @@ class _ScreenSettingsInterfaceState extends State<ScreenSettingsInterface> {
const SizedBox(height: 16)
]),
)
]))),
])),
)),
);
}
}

View File

@ -216,6 +216,21 @@ class _ScreenSettingsVoiceState extends State<ScreenSettingsVoice> {
});
},
child: Container(
decoration: (Theme.of(context)
.brightness ==
Brightness.dark)
? BoxDecoration(
border: Border.all(
color: Colors.white),
borderRadius:
const BorderRadius.only(
topLeft:
Radius.circular(
26),
topRight:
Radius.circular(
26)))
: null,
width: double.infinity,
padding: const EdgeInsets.only(
left: 16,

View File

@ -80,7 +80,6 @@ List getHistoryString([String? uuid]) {
}
Future<String> getTitleAi(List history) async {
print(history);
final generated = await (llama.OllamaClient(
headers: (jsonDecode(prefs!.getString("hostHeaders") ?? "{}") as Map)
.cast<String, String>(),
@ -92,7 +91,7 @@ Future<String> getTitleAi(List history) async {
const llama.Message(
role: llama.MessageRole.system,
content:
"Generate a three to six word title for the conversation provided by the user. If an object or person is very important in the conversation, put it in the title as well; keep the focus on the main subject. You must not put the assistant in the focus and you must not put the word 'assistant' in the title! Do preferably use title case. Use a formal tone, don't use dramatic words, like 'mystery' Use spaces between words, do not use camel case! You must not use markdown or any other formatting language! You must not use emojis or any other symbols! You must not use general clauses like 'assistance', 'help' or 'session' in your title! \n\n~~User Introduces Themselves~~ -> User Introduction\n~~User Asks for Help with a Problem~~ -> Problem Help\n~~User has a _**big**_ Problem~~ -> Big Problem\n~~Conversation~~ -> Conversation about Fireflies"),
"Generate a three to six word title for the conversation provided by the user. If an object or person is very important in the conversation, put it in the title as well; keep the focus on the main subject. You must not put the assistant in the focus and you must not put the word 'assistant' in the title! Do preferably use title case. Use a formal tone, don't use dramatic words, like 'mystery' Use spaces between words, do not use camel case! You must not use markdown or any other formatting language! You must not use emojis or any other symbols! You must not use general clauses like 'assistance', 'help' or 'session' in your title! \n\n~~User Introduces Themselves~~ -> User Introduction\n~~User Asks for Help with a Problem~~ -> Problem Help\n~~User has a _**big**_ Problem~~ -> Big Problem"),
llama.Message(
role: llama.MessageRole.user,
content: "```\n${jsonEncode(history)}\n```")

View File

@ -278,6 +278,10 @@ void setModel(BuildContext context, Function setState) {
? const Offset(289, 0)
: const Offset(0, 0),
child: Dialog(
surfaceTintColor:
(Theme.of(context).brightness == Brightness.dark)
? Colors.grey[800]
: null,
alignment: desktopLayoutRequired(context)
? Alignment.topLeft
: Alignment.topCenter,
@ -285,7 +289,17 @@ void setModel(BuildContext context, Function setState) {
);
});
} else {
showModalBottomSheet(context: context, builder: (context) => content);
showModalBottomSheet(
context: context,
builder: (context) => Container(
decoration: (Theme.of(context).brightness == Brightness.dark)
? BoxDecoration(
border: Border.all(color: Colors.white),
borderRadius: const BorderRadius.only(
topLeft: Radius.circular(26),
topRight: Radius.circular(26)))
: null,
child: content));
}
}
@ -406,6 +420,79 @@ void loadChat(String uuid, Function setState) {
setState(() {});
}
Future<bool> deleteChatDialog(BuildContext context, Function setState,
{bool takeAction = true,
bool? additionalCondition,
String? uuid,
bool popSidebar = false}) async {
additionalCondition ??= true;
uuid ??= chatUuid;
bool returnValue = false;
void delete() {
returnValue = true;
if (takeAction) {
for (var i = 0; i < (prefs!.getStringList("chats") ?? []).length; i++) {
if (jsonDecode((prefs!.getStringList("chats") ?? [])[i])["uuid"] ==
uuid) {
List<String> tmp = prefs!.getStringList("chats")!;
tmp.removeAt(i);
prefs!.setStringList("chats", tmp);
break;
}
}
if (chatUuid == uuid) {
messages = [];
chatUuid = null;
if (!desktopLayoutRequired(context) &&
Navigator.of(context).canPop() &&
popSidebar) {
Navigator.of(context).pop();
}
}
}
}
if ((prefs!.getBool("askBeforeDeletion") ?? false) && additionalCondition) {
await showDialog(
context: context,
builder: (context) {
return StatefulBuilder(builder: (context, setLocalState) {
return AlertDialog(
surfaceTintColor:
(Theme.of(context).brightness == Brightness.dark)
? Colors.grey[800]
: null,
title: Text(AppLocalizations.of(context)!.deleteDialogTitle),
content: Column(mainAxisSize: MainAxisSize.min, children: [
Text(AppLocalizations.of(context)!.deleteDialogDescription),
]),
actions: [
TextButton(
onPressed: () {
selectionHaptic();
Navigator.of(context).pop();
},
child: Text(
AppLocalizations.of(context)!.deleteDialogCancel)),
TextButton(
onPressed: () {
selectionHaptic();
Navigator.of(context).pop();
delete();
},
child: Text(
AppLocalizations.of(context)!.deleteDialogDelete))
]);
});
});
} else {
delete();
}
setState(() {});
return returnValue;
}
Future<String> prompt(BuildContext context,
{String description = "",
String value = "",
@ -431,6 +518,13 @@ Future<String> prompt(BuildContext context,
return StatefulBuilder(builder: (context, setLocalState) {
return PopScope(
child: Container(
decoration: (Theme.of(context).brightness == Brightness.dark)
? BoxDecoration(
border: Border.all(color: Colors.white),
borderRadius: const BorderRadius.only(
topLeft: Radius.circular(26),
topRight: Radius.circular(26)))
: null,
padding: EdgeInsets.only(
left: 16,
right: 16,

View File

@ -125,6 +125,7 @@ void updateDialog(BuildContext context, Function title) {
context: context,
builder: (context) {
return AlertDialog(
surfaceTintColor: (Theme.of(context).brightness == Brightness.dark) ? Colors.grey[800] : null,
title:
Text(AppLocalizations.of(context)!.settingsUpdateDialogTitle),
content: Column(mainAxisSize: MainAxisSize.min, children: [
@ -133,9 +134,12 @@ void updateDialog(BuildContext context, Function title) {
title(AppLocalizations.of(context)!.settingsUpdateChangeLog),
Flexible(
child: SingleChildScrollView(
child: Container(
constraints: const BoxConstraints(maxWidth: 1000),
child: MarkdownBody(
data: updateChangeLog ?? "No changelog given.",
shrinkWrap: true)))
shrinkWrap: true),
)))
]),
actions: [
TextButton(