Restrict desktop settings width, centralized delete dialog, allow changing titles and deleting non current chats
This commit is contained in:
parent
8813571b65
commit
efcca113c8
701
lib/main.dart
701
lib/main.dart
|
@ -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: () {
|
||||
if (host == null) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
|
||||
content: Text(AppLocalizations.of(context)!.noHostSelected),
|
||||
showCloseIcon: true));
|
||||
return;
|
||||
}
|
||||
setModel(context, setState);
|
||||
},
|
||||
onTap: !useModel
|
||||
? () {
|
||||
if (host == null) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
|
||||
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,189 +1269,198 @@ 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: [
|
||||
(prefs?.getBool(
|
||||
"voiceModeEnabled") ??
|
||||
false)
|
||||
? SizedBox(
|
||||
width: double
|
||||
.infinity,
|
||||
child: OutlinedButton
|
||||
.icon(
|
||||
onPressed:
|
||||
() async {
|
||||
selectionHaptic();
|
||||
Navigator.of(context)
|
||||
.pop();
|
||||
setMainState =
|
||||
setState;
|
||||
settingsOpen =
|
||||
true;
|
||||
logoVisible =
|
||||
false;
|
||||
Navigator.of(context).push(MaterialPageRoute(
|
||||
child:
|
||||
Column(mainAxisSize: MainAxisSize.min, children: [
|
||||
(prefs?.getBool(
|
||||
"voiceModeEnabled") ??
|
||||
false)
|
||||
? SizedBox(
|
||||
width:
|
||||
double.infinity,
|
||||
child: OutlinedButton
|
||||
.icon(
|
||||
onPressed:
|
||||
() async {
|
||||
selectionHaptic();
|
||||
Navigator.of(
|
||||
context)
|
||||
.pop();
|
||||
setMainState =
|
||||
setState;
|
||||
settingsOpen =
|
||||
true;
|
||||
logoVisible =
|
||||
false;
|
||||
Navigator.of(
|
||||
context)
|
||||
.push(MaterialPageRoute(
|
||||
builder: (context) =>
|
||||
const ScreenVoice()));
|
||||
},
|
||||
icon: const Icon(
|
||||
Icons
|
||||
.headphones_rounded),
|
||||
label: Text(
|
||||
AppLocalizations.of(context)!
|
||||
.settingsTitleVoice)))
|
||||
: const SizedBox
|
||||
.shrink(),
|
||||
(prefs?.getBool(
|
||||
"voiceModeEnabled") ??
|
||||
false)
|
||||
? const SizedBox(
|
||||
height: 8)
|
||||
: const SizedBox
|
||||
.shrink(),
|
||||
SizedBox(
|
||||
width:
|
||||
double.infinity,
|
||||
child: OutlinedButton
|
||||
.icon(
|
||||
onPressed:
|
||||
() async {
|
||||
selectionHaptic();
|
||||
|
||||
Navigator.of(
|
||||
context)
|
||||
.pop();
|
||||
final result =
|
||||
await ImagePicker()
|
||||
.pickImage(
|
||||
source: ImageSource
|
||||
.camera,
|
||||
);
|
||||
if (result ==
|
||||
null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final bytes =
|
||||
await result
|
||||
.readAsBytes();
|
||||
final image =
|
||||
await decodeImageFromList(
|
||||
bytes);
|
||||
|
||||
final message =
|
||||
types
|
||||
.ImageMessage(
|
||||
author:
|
||||
user,
|
||||
createdAt:
|
||||
DateTime.now()
|
||||
.millisecondsSinceEpoch,
|
||||
height: image
|
||||
.height
|
||||
.toDouble(),
|
||||
id: const Uuid()
|
||||
.v4(),
|
||||
name: result
|
||||
.name,
|
||||
size: bytes
|
||||
.length,
|
||||
uri: result
|
||||
.path,
|
||||
width: image
|
||||
.width
|
||||
.toDouble(),
|
||||
);
|
||||
|
||||
messages.insert(
|
||||
0,
|
||||
message);
|
||||
setState(
|
||||
() {});
|
||||
selectionHaptic();
|
||||
},
|
||||
icon: const Icon(
|
||||
Icons
|
||||
.photo_camera_rounded),
|
||||
.headphones_rounded),
|
||||
label: Text(AppLocalizations.of(
|
||||
context)!
|
||||
.settingsTitleVoice)))
|
||||
: const SizedBox.shrink(),
|
||||
(prefs?.getBool(
|
||||
"voiceModeEnabled") ??
|
||||
false)
|
||||
? const SizedBox(
|
||||
height: 8)
|
||||
: const SizedBox.shrink(),
|
||||
SizedBox(
|
||||
width: double.infinity,
|
||||
child:
|
||||
OutlinedButton.icon(
|
||||
onPressed:
|
||||
() async {
|
||||
selectionHaptic();
|
||||
|
||||
Navigator.of(
|
||||
context)
|
||||
.pop();
|
||||
final result =
|
||||
await ImagePicker()
|
||||
.pickImage(
|
||||
source:
|
||||
ImageSource
|
||||
.camera,
|
||||
);
|
||||
if (result ==
|
||||
null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final bytes =
|
||||
await result
|
||||
.readAsBytes();
|
||||
final image =
|
||||
await decodeImageFromList(
|
||||
bytes);
|
||||
|
||||
final message =
|
||||
types
|
||||
.ImageMessage(
|
||||
author: user,
|
||||
createdAt: DateTime
|
||||
.now()
|
||||
.millisecondsSinceEpoch,
|
||||
height: image
|
||||
.height
|
||||
.toDouble(),
|
||||
id: const Uuid()
|
||||
.v4(),
|
||||
name: result
|
||||
.name,
|
||||
size: bytes
|
||||
.length,
|
||||
uri: result
|
||||
.path,
|
||||
width: image
|
||||
.width
|
||||
.toDouble(),
|
||||
);
|
||||
|
||||
messages.insert(
|
||||
0, message);
|
||||
setState(() {});
|
||||
selectionHaptic();
|
||||
},
|
||||
icon: const Icon(Icons
|
||||
.photo_camera_rounded),
|
||||
label: Text(
|
||||
AppLocalizations.of(
|
||||
context)!
|
||||
.takeImage))),
|
||||
const SizedBox(height: 8),
|
||||
SizedBox(
|
||||
width:
|
||||
double.infinity,
|
||||
child: OutlinedButton
|
||||
.icon(
|
||||
onPressed:
|
||||
() async {
|
||||
selectionHaptic();
|
||||
const SizedBox(height: 8),
|
||||
SizedBox(
|
||||
width: double.infinity,
|
||||
child:
|
||||
OutlinedButton.icon(
|
||||
onPressed:
|
||||
() async {
|
||||
selectionHaptic();
|
||||
|
||||
Navigator.of(
|
||||
context)
|
||||
.pop();
|
||||
final result =
|
||||
await ImagePicker()
|
||||
.pickImage(
|
||||
source: ImageSource
|
||||
Navigator.of(
|
||||
context)
|
||||
.pop();
|
||||
final result =
|
||||
await ImagePicker()
|
||||
.pickImage(
|
||||
source:
|
||||
ImageSource
|
||||
.gallery,
|
||||
);
|
||||
if (result ==
|
||||
null) {
|
||||
return;
|
||||
}
|
||||
);
|
||||
if (result ==
|
||||
null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final bytes =
|
||||
await result
|
||||
.readAsBytes();
|
||||
final image =
|
||||
await decodeImageFromList(
|
||||
bytes);
|
||||
final bytes =
|
||||
await result
|
||||
.readAsBytes();
|
||||
final image =
|
||||
await decodeImageFromList(
|
||||
bytes);
|
||||
|
||||
final message =
|
||||
types
|
||||
.ImageMessage(
|
||||
author:
|
||||
user,
|
||||
createdAt:
|
||||
DateTime.now()
|
||||
.millisecondsSinceEpoch,
|
||||
height: image
|
||||
.height
|
||||
.toDouble(),
|
||||
id: const Uuid()
|
||||
.v4(),
|
||||
name: result
|
||||
.name,
|
||||
size: bytes
|
||||
.length,
|
||||
uri: result
|
||||
.path,
|
||||
width: image
|
||||
.width
|
||||
.toDouble(),
|
||||
);
|
||||
final message =
|
||||
types
|
||||
.ImageMessage(
|
||||
author: user,
|
||||
createdAt: DateTime
|
||||
.now()
|
||||
.millisecondsSinceEpoch,
|
||||
height: image
|
||||
.height
|
||||
.toDouble(),
|
||||
id: const Uuid()
|
||||
.v4(),
|
||||
name: result
|
||||
.name,
|
||||
size: bytes
|
||||
.length,
|
||||
uri: result
|
||||
.path,
|
||||
width: image
|
||||
.width
|
||||
.toDouble(),
|
||||
);
|
||||
|
||||
messages.insert(
|
||||
0,
|
||||
message);
|
||||
setState(
|
||||
() {});
|
||||
selectionHaptic();
|
||||
},
|
||||
icon: const Icon(
|
||||
Icons
|
||||
.image_rounded),
|
||||
label: Text(AppLocalizations.of(
|
||||
messages.insert(
|
||||
0, message);
|
||||
setState(() {});
|
||||
selectionHaptic();
|
||||
},
|
||||
icon: const Icon(Icons
|
||||
.image_rounded),
|
||||
label: Text(
|
||||
AppLocalizations.of(
|
||||
context)!
|
||||
.uploadImage)))
|
||||
]));
|
||||
]));
|
||||
});
|
||||
},
|
||||
l10n: ChatL10nEn(
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -42,123 +42,130 @@ class _ScreenSettingsAboutState extends State<ScreenSettingsAbout> {
|
|||
Expanded(child: SizedBox(height: 200, child: MoveWindow()))
|
||||
]),
|
||||
actions: desktopControlsActions(context)),
|
||||
body: Padding(
|
||||
padding: const EdgeInsets.only(left: 16, right: 16),
|
||||
child: Column(children: [
|
||||
Expanded(
|
||||
child: ListView(children: [
|
||||
// const SizedBox(height: 8),
|
||||
button(
|
||||
AppLocalizations.of(context)!
|
||||
.settingsVersion(currentVersion ?? ""),
|
||||
Icons.verified_rounded,
|
||||
null),
|
||||
(updateStatus == "notAvailable")
|
||||
? const SizedBox.shrink()
|
||||
: button(
|
||||
(!updateChecked
|
||||
? AppLocalizations.of(context)!
|
||||
.settingsUpdateCheck
|
||||
: updateLoading
|
||||
? AppLocalizations.of(context)!
|
||||
.settingsUpdateChecking
|
||||
: (updateStatus == "rateLimit")
|
||||
? AppLocalizations.of(context)!
|
||||
.settingsUpdateRateLimit
|
||||
: (updateStatus != "ok")
|
||||
? AppLocalizations.of(context)!
|
||||
.settingsUpdateIssue
|
||||
: (Version.parse(latestVersion ??
|
||||
"1.0.0") >
|
||||
Version.parse(
|
||||
currentVersion ??
|
||||
"2.0.0"))
|
||||
? AppLocalizations.of(context)!
|
||||
.settingsUpdateAvailable(
|
||||
latestVersion!)
|
||||
: AppLocalizations.of(context)!
|
||||
.settingsUpdateLatest),
|
||||
((updateStatus != "ok")
|
||||
? Icons.warning_rounded
|
||||
: (Version.parse(latestVersion ?? "1.0.0") >
|
||||
Version.parse(
|
||||
currentVersion ?? "2.0.0"))
|
||||
? Icons.info_outline_rounded
|
||||
: Icons.update_rounded), () {
|
||||
if (updateLoading) return;
|
||||
selectionHaptic();
|
||||
if ((Version.parse(latestVersion ?? "1.0.0") >
|
||||
Version.parse(currentVersion ?? "2.0.0")) &&
|
||||
(updateStatus == "ok")) {
|
||||
updateDialog(context, title);
|
||||
} else {
|
||||
checkUpdate(setState);
|
||||
return;
|
||||
}
|
||||
}),
|
||||
(updateStatus == "notAvailable")
|
||||
? const SizedBox.shrink()
|
||||
: toggle(
|
||||
context,
|
||||
AppLocalizations.of(context)!
|
||||
.settingsCheckForUpdates,
|
||||
(prefs!.getBool("checkUpdateOnSettingsOpen") ??
|
||||
false), (value) {
|
||||
selectionHaptic();
|
||||
prefs!.setBool("checkUpdateOnSettingsOpen", value);
|
||||
setState(() {});
|
||||
}),
|
||||
titleDivider(context: context),
|
||||
button(AppLocalizations.of(context)!.settingsGithub,
|
||||
SimpleIcons.github, () {
|
||||
selectionHaptic();
|
||||
launchUrl(
|
||||
mode: LaunchMode.inAppBrowserView,
|
||||
Uri.parse(repoUrl));
|
||||
}),
|
||||
button(AppLocalizations.of(context)!.settingsReportIssue,
|
||||
Icons.report_rounded, () {
|
||||
selectionHaptic();
|
||||
launchUrl(
|
||||
mode: LaunchMode.inAppBrowserView,
|
||||
Uri.parse("$repoUrl/issues"));
|
||||
}),
|
||||
button(AppLocalizations.of(context)!.settingsLicenses,
|
||||
Icons.gavel_rounded, () {
|
||||
selectionHaptic();
|
||||
String legal = "Copyright 2024 JHubi1";
|
||||
Widget icon = const Padding(
|
||||
padding: EdgeInsets.all(16),
|
||||
child: ImageIcon(AssetImage("assets/logo512.png"),
|
||||
size: 48),
|
||||
);
|
||||
if (desktopFeature()) {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return Dialog(
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(28),
|
||||
child: LicensePage(
|
||||
applicationName: "Ollama App",
|
||||
applicationVersion: currentVersion,
|
||||
applicationIcon: icon,
|
||||
applicationLegalese: legal),
|
||||
));
|
||||
});
|
||||
} else {
|
||||
showLicensePage(
|
||||
context: context,
|
||||
applicationName: "Ollama App",
|
||||
applicationVersion: currentVersion,
|
||||
applicationIcon: icon,
|
||||
applicationLegalese: legal);
|
||||
}
|
||||
}),
|
||||
const SizedBox(height: 16)
|
||||
]),
|
||||
)
|
||||
]))),
|
||||
body: Center(
|
||||
child: Container(
|
||||
constraints: const BoxConstraints(maxWidth: 1000),
|
||||
padding: const EdgeInsets.only(left: 16, right: 16),
|
||||
child: Column(children: [
|
||||
Expanded(
|
||||
child: ListView(children: [
|
||||
// const SizedBox(height: 8),
|
||||
button(
|
||||
AppLocalizations.of(context)!
|
||||
.settingsVersion(currentVersion ?? ""),
|
||||
Icons.verified_rounded,
|
||||
null),
|
||||
(updateStatus == "notAvailable")
|
||||
? const SizedBox.shrink()
|
||||
: button(
|
||||
(!updateChecked
|
||||
? AppLocalizations.of(context)!
|
||||
.settingsUpdateCheck
|
||||
: updateLoading
|
||||
? AppLocalizations.of(context)!
|
||||
.settingsUpdateChecking
|
||||
: (updateStatus == "rateLimit")
|
||||
? AppLocalizations.of(context)!
|
||||
.settingsUpdateRateLimit
|
||||
: (updateStatus != "ok")
|
||||
? AppLocalizations.of(context)!
|
||||
.settingsUpdateIssue
|
||||
: (Version.parse(latestVersion ??
|
||||
"1.0.0") >
|
||||
Version.parse(
|
||||
currentVersion ??
|
||||
"2.0.0"))
|
||||
? AppLocalizations.of(
|
||||
context)!
|
||||
.settingsUpdateAvailable(
|
||||
latestVersion!)
|
||||
: AppLocalizations.of(
|
||||
context)!
|
||||
.settingsUpdateLatest),
|
||||
((updateStatus != "ok")
|
||||
? Icons.warning_rounded
|
||||
: (Version.parse(latestVersion ?? "1.0.0") >
|
||||
Version.parse(
|
||||
currentVersion ?? "2.0.0"))
|
||||
? Icons.info_outline_rounded
|
||||
: Icons.update_rounded), () {
|
||||
if (updateLoading) return;
|
||||
selectionHaptic();
|
||||
if ((Version.parse(latestVersion ?? "1.0.0") >
|
||||
Version.parse(
|
||||
currentVersion ?? "2.0.0")) &&
|
||||
(updateStatus == "ok")) {
|
||||
updateDialog(context, title);
|
||||
} else {
|
||||
checkUpdate(setState);
|
||||
return;
|
||||
}
|
||||
}),
|
||||
(updateStatus == "notAvailable")
|
||||
? const SizedBox.shrink()
|
||||
: toggle(
|
||||
context,
|
||||
AppLocalizations.of(context)!
|
||||
.settingsCheckForUpdates,
|
||||
(prefs!.getBool("checkUpdateOnSettingsOpen") ??
|
||||
false), (value) {
|
||||
selectionHaptic();
|
||||
prefs!
|
||||
.setBool("checkUpdateOnSettingsOpen", value);
|
||||
setState(() {});
|
||||
}),
|
||||
titleDivider(context: context),
|
||||
button(AppLocalizations.of(context)!.settingsGithub,
|
||||
SimpleIcons.github, () {
|
||||
selectionHaptic();
|
||||
launchUrl(
|
||||
mode: LaunchMode.inAppBrowserView,
|
||||
Uri.parse(repoUrl));
|
||||
}),
|
||||
button(AppLocalizations.of(context)!.settingsReportIssue,
|
||||
Icons.report_rounded, () {
|
||||
selectionHaptic();
|
||||
launchUrl(
|
||||
mode: LaunchMode.inAppBrowserView,
|
||||
Uri.parse("$repoUrl/issues"));
|
||||
}),
|
||||
button(AppLocalizations.of(context)!.settingsLicenses,
|
||||
Icons.gavel_rounded, () {
|
||||
selectionHaptic();
|
||||
String legal = "Copyright 2024 JHubi1";
|
||||
Widget icon = const Padding(
|
||||
padding: EdgeInsets.all(16),
|
||||
child: ImageIcon(AssetImage("assets/logo512.png"),
|
||||
size: 48),
|
||||
);
|
||||
if (desktopFeature()) {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return Dialog(
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(28),
|
||||
child: LicensePage(
|
||||
applicationName: "Ollama App",
|
||||
applicationVersion: currentVersion,
|
||||
applicationIcon: icon,
|
||||
applicationLegalese: legal),
|
||||
));
|
||||
});
|
||||
} else {
|
||||
showLicensePage(
|
||||
context: context,
|
||||
applicationName: "Ollama App",
|
||||
applicationVersion: currentVersion,
|
||||
applicationIcon: icon,
|
||||
applicationLegalese: legal);
|
||||
}
|
||||
}),
|
||||
const SizedBox(height: 16)
|
||||
]),
|
||||
)
|
||||
])),
|
||||
)),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,71 +37,75 @@ class _ScreenSettingsBehaviorState extends State<ScreenSettingsBehavior> {
|
|||
Expanded(child: SizedBox(height: 200, child: MoveWindow()))
|
||||
]),
|
||||
actions: desktopControlsActions(context)),
|
||||
body: Padding(
|
||||
padding: const EdgeInsets.only(left: 16, right: 16),
|
||||
child: Column(children: [
|
||||
Expanded(
|
||||
child: ListView(children: [
|
||||
const SizedBox(height: 8),
|
||||
TextField(
|
||||
controller: systemInputController,
|
||||
keyboardType: TextInputType.multiline,
|
||||
maxLines: desktopLayoutNotRequired(context) ? 5 : 2,
|
||||
decoration: InputDecoration(
|
||||
labelText: AppLocalizations.of(context)!
|
||||
.settingsSystemMessage,
|
||||
hintText: "You are a helpful assistant",
|
||||
suffixIcon: IconButton(
|
||||
tooltip:
|
||||
AppLocalizations.of(context)!.tooltipSave,
|
||||
onPressed: () {
|
||||
selectionHaptic();
|
||||
prefs?.setString(
|
||||
"system",
|
||||
(systemInputController.text.isNotEmpty)
|
||||
? systemInputController.text
|
||||
: "You are a helpful assistant");
|
||||
},
|
||||
icon: const Icon(Icons.save_rounded),
|
||||
),
|
||||
border: const OutlineInputBorder())),
|
||||
const SizedBox(height: 16),
|
||||
toggle(
|
||||
context,
|
||||
AppLocalizations.of(context)!.settingsUseSystem,
|
||||
(prefs!.getBool("useSystem") ?? true),
|
||||
(value) {
|
||||
selectionHaptic();
|
||||
prefs!.setBool("useSystem", value);
|
||||
setState(() {});
|
||||
},
|
||||
icon: const Icon(Icons.info_outline_rounded),
|
||||
onLongTap: () {
|
||||
selectionHaptic();
|
||||
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
|
||||
content: Text(AppLocalizations.of(context)!
|
||||
.settingsUseSystemDescription),
|
||||
showCloseIcon: true));
|
||||
}),
|
||||
toggle(
|
||||
context,
|
||||
AppLocalizations.of(context)!.settingsDisableMarkdown,
|
||||
(prefs!.getBool("noMarkdown") ?? false), (value) {
|
||||
selectionHaptic();
|
||||
prefs!.setBool("noMarkdown", value);
|
||||
setState(() {});
|
||||
})
|
||||
]),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
button(
|
||||
AppLocalizations.of(context)!
|
||||
.settingsBehaviorNotUpdatedForOlderChats,
|
||||
Icons.info_rounded,
|
||||
null,
|
||||
color: Colors.grey
|
||||
.harmonizeWith(Theme.of(context).colorScheme.primary))
|
||||
]))),
|
||||
body: Center(
|
||||
child: Container(
|
||||
constraints: const BoxConstraints(maxWidth: 1000),
|
||||
padding: const EdgeInsets.only(left: 16, right: 16),
|
||||
child: Column(children: [
|
||||
Expanded(
|
||||
child: ListView(children: [
|
||||
const SizedBox(height: 8),
|
||||
TextField(
|
||||
controller: systemInputController,
|
||||
keyboardType: TextInputType.multiline,
|
||||
maxLines: desktopLayoutNotRequired(context) ? 5 : 2,
|
||||
decoration: InputDecoration(
|
||||
labelText: AppLocalizations.of(context)!
|
||||
.settingsSystemMessage,
|
||||
alignLabelWithHint: true,
|
||||
hintText: "You are a helpful assistant",
|
||||
suffixIcon: IconButton(
|
||||
tooltip:
|
||||
AppLocalizations.of(context)!.tooltipSave,
|
||||
onPressed: () {
|
||||
selectionHaptic();
|
||||
prefs?.setString(
|
||||
"system",
|
||||
(systemInputController.text.isNotEmpty)
|
||||
? systemInputController.text
|
||||
: "You are a helpful assistant");
|
||||
},
|
||||
icon: const Icon(Icons.save_rounded),
|
||||
),
|
||||
border: const OutlineInputBorder())),
|
||||
const SizedBox(height: 16),
|
||||
toggle(
|
||||
context,
|
||||
AppLocalizations.of(context)!.settingsUseSystem,
|
||||
(prefs!.getBool("useSystem") ?? true),
|
||||
(value) {
|
||||
selectionHaptic();
|
||||
prefs!.setBool("useSystem", value);
|
||||
setState(() {});
|
||||
},
|
||||
icon: const Icon(Icons.info_outline_rounded),
|
||||
onLongTap: () {
|
||||
selectionHaptic();
|
||||
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
|
||||
content: Text(AppLocalizations.of(context)!
|
||||
.settingsUseSystemDescription),
|
||||
showCloseIcon: true));
|
||||
}),
|
||||
toggle(
|
||||
context,
|
||||
AppLocalizations.of(context)!.settingsDisableMarkdown,
|
||||
(prefs!.getBool("noMarkdown") ?? false), (value) {
|
||||
selectionHaptic();
|
||||
prefs!.setBool("noMarkdown", value);
|
||||
setState(() {});
|
||||
})
|
||||
]),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
button(
|
||||
AppLocalizations.of(context)!
|
||||
.settingsBehaviorNotUpdatedForOlderChats,
|
||||
Icons.info_rounded,
|
||||
null,
|
||||
color: Colors.grey
|
||||
.harmonizeWith(Theme.of(context).colorScheme.primary))
|
||||
])),
|
||||
)),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,192 +36,204 @@ class _ScreenSettingsExportState extends State<ScreenSettingsExport> {
|
|||
Expanded(child: SizedBox(height: 200, child: MoveWindow()))
|
||||
]),
|
||||
actions: desktopControlsActions(context)),
|
||||
body: Padding(
|
||||
padding: const EdgeInsets.only(left: 16, right: 16),
|
||||
child: Column(children: [
|
||||
Expanded(
|
||||
child: ListView(children: [
|
||||
// const SizedBox(height: 8),
|
||||
button(AppLocalizations.of(context)!.settingsExportChats,
|
||||
Icons.upload_rounded, () async {
|
||||
selectionHaptic();
|
||||
var name =
|
||||
"ollama-export-${DateFormat('yyyy-MM-dd-H-m-s').format(DateTime.now())}.json";
|
||||
var content =
|
||||
jsonEncode(prefs!.getStringList("chats") ?? []);
|
||||
if (kIsWeb) {
|
||||
// web fallback
|
||||
final bytes = utf8.encode(content);
|
||||
final blob = html.Blob([bytes]);
|
||||
final url = html.Url.createObjectUrlFromBlob(blob);
|
||||
final anchor = html.document.createElement("a")
|
||||
as html.AnchorElement
|
||||
..href = url
|
||||
..style.display = "none"
|
||||
..download = name;
|
||||
html.document.body!.children.add(anchor);
|
||||
|
||||
anchor.click();
|
||||
|
||||
html.document.body!.children.remove(anchor);
|
||||
html.Url.revokeObjectUrl(url);
|
||||
} else {
|
||||
String? path = "";
|
||||
try {
|
||||
path = (await file_selector
|
||||
.getSaveLocation(acceptedTypeGroups: [
|
||||
const file_selector.XTypeGroup(
|
||||
label: "Ollama App File", extensions: ["json"])
|
||||
], suggestedName: name))
|
||||
?.path;
|
||||
} catch (_) {
|
||||
path = await FilePicker.platform.saveFile(
|
||||
type: FileType.custom,
|
||||
allowedExtensions: ["json"],
|
||||
fileName: name,
|
||||
bytes: utf8.encode(jsonEncode(
|
||||
prefs!.getStringList("chats") ?? [])));
|
||||
}
|
||||
body: Center(
|
||||
child: Container(
|
||||
constraints: const BoxConstraints(maxWidth: 1000),
|
||||
padding: const EdgeInsets.only(left: 16, right: 16),
|
||||
child: Column(children: [
|
||||
Expanded(
|
||||
child: ListView(children: [
|
||||
// const SizedBox(height: 8),
|
||||
button(AppLocalizations.of(context)!.settingsExportChats,
|
||||
Icons.upload_rounded, () async {
|
||||
selectionHaptic();
|
||||
if (path == null) return;
|
||||
if (desktopFeature()) {
|
||||
File(path).writeAsString(content);
|
||||
var name =
|
||||
"ollama-export-${DateFormat('yyyy-MM-dd-H-m-s').format(DateTime.now())}.json";
|
||||
var content =
|
||||
jsonEncode(prefs!.getStringList("chats") ?? []);
|
||||
if (kIsWeb) {
|
||||
// web fallback
|
||||
final bytes = utf8.encode(content);
|
||||
final blob = html.Blob([bytes]);
|
||||
final url = html.Url.createObjectUrlFromBlob(blob);
|
||||
final anchor = html.document.createElement("a")
|
||||
as html.AnchorElement
|
||||
..href = url
|
||||
..style.display = "none"
|
||||
..download = name;
|
||||
html.document.body!.children.add(anchor);
|
||||
|
||||
anchor.click();
|
||||
|
||||
html.document.body!.children.remove(anchor);
|
||||
html.Url.revokeObjectUrl(url);
|
||||
} else {
|
||||
String? path = "";
|
||||
try {
|
||||
path = (await file_selector
|
||||
.getSaveLocation(acceptedTypeGroups: [
|
||||
const file_selector.XTypeGroup(
|
||||
label: "Ollama App File",
|
||||
extensions: ["json"])
|
||||
], suggestedName: name))
|
||||
?.path;
|
||||
} catch (_) {
|
||||
path = await FilePicker.platform.saveFile(
|
||||
type: FileType.custom,
|
||||
allowedExtensions: ["json"],
|
||||
fileName: name,
|
||||
bytes: utf8.encode(jsonEncode(
|
||||
prefs!.getStringList("chats") ?? [])));
|
||||
}
|
||||
selectionHaptic();
|
||||
if (path == null) return;
|
||||
if (desktopFeature()) {
|
||||
File(path).writeAsString(content);
|
||||
}
|
||||
}
|
||||
}
|
||||
// ignore: use_build_context_synchronously
|
||||
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
|
||||
// ignore: use_build_context_synchronously
|
||||
content: Text(AppLocalizations.of(context)!
|
||||
.settingsExportChatsSuccess),
|
||||
showCloseIcon: true));
|
||||
}),
|
||||
allowMultipleChats
|
||||
? button(
|
||||
AppLocalizations.of(context)!.settingsImportChats,
|
||||
Icons.download_rounded, () {
|
||||
selectionHaptic();
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return AlertDialog(
|
||||
title: Text(AppLocalizations.of(context)!
|
||||
.settingsImportChatsTitle),
|
||||
content: Text(
|
||||
AppLocalizations.of(context)!
|
||||
.settingsImportChatsDescription),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
selectionHaptic();
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
child: Text(AppLocalizations.of(
|
||||
context)!
|
||||
.settingsImportChatsCancel)),
|
||||
TextButton(
|
||||
onPressed: () async {
|
||||
selectionHaptic();
|
||||
String content;
|
||||
try {
|
||||
if (kIsWeb) {
|
||||
throw Exception(
|
||||
"web must use file picker");
|
||||
}
|
||||
file_selector.XFile? result =
|
||||
await file_selector.openFile(
|
||||
acceptedTypeGroups: [
|
||||
const file_selector
|
||||
.XTypeGroup(
|
||||
label:
|
||||
"Ollama App File",
|
||||
extensions: ["json"])
|
||||
]);
|
||||
if (result == null) {
|
||||
// ignore: use_build_context_synchronously
|
||||
Navigator.of(context).pop();
|
||||
return;
|
||||
}
|
||||
content =
|
||||
await result.readAsString();
|
||||
} catch (_) {
|
||||
FilePickerResult? result =
|
||||
await FilePicker.platform
|
||||
.pickFiles(
|
||||
type:
|
||||
FileType.custom,
|
||||
allowedExtensions: [
|
||||
"json"
|
||||
]);
|
||||
if (result == null) {
|
||||
// ignore: use_build_context_synchronously
|
||||
Navigator.of(context).pop();
|
||||
return;
|
||||
}
|
||||
// ignore: use_build_context_synchronously
|
||||
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
|
||||
// ignore: use_build_context_synchronously
|
||||
content: Text(AppLocalizations.of(context)!
|
||||
.settingsExportChatsSuccess),
|
||||
showCloseIcon: true));
|
||||
}),
|
||||
allowMultipleChats
|
||||
? button(
|
||||
AppLocalizations.of(context)!.settingsImportChats,
|
||||
Icons.download_rounded, () {
|
||||
selectionHaptic();
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return AlertDialog(
|
||||
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(
|
||||
onPressed: () {
|
||||
selectionHaptic();
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
child: Text(AppLocalizations.of(
|
||||
context)!
|
||||
.settingsImportChatsCancel)),
|
||||
TextButton(
|
||||
onPressed: () async {
|
||||
selectionHaptic();
|
||||
String content;
|
||||
try {
|
||||
File file = File(result
|
||||
.files.single.path!);
|
||||
content =
|
||||
await file.readAsString();
|
||||
if (kIsWeb) {
|
||||
throw Exception(
|
||||
"web must use file picker");
|
||||
}
|
||||
file_selector.XFile? result =
|
||||
await file_selector.openFile(
|
||||
acceptedTypeGroups: [
|
||||
const file_selector
|
||||
.XTypeGroup(
|
||||
label:
|
||||
"Ollama App File",
|
||||
extensions: [
|
||||
"json"
|
||||
])
|
||||
]);
|
||||
if (result == null) {
|
||||
// ignore: use_build_context_synchronously
|
||||
Navigator.of(context).pop();
|
||||
return;
|
||||
}
|
||||
content = await result
|
||||
.readAsString();
|
||||
} catch (_) {
|
||||
// web fallback
|
||||
content = utf8.decode(result
|
||||
.files
|
||||
.single
|
||||
.bytes as List<int>);
|
||||
FilePickerResult? result =
|
||||
await FilePicker.platform
|
||||
.pickFiles(
|
||||
type: FileType
|
||||
.custom,
|
||||
allowedExtensions: [
|
||||
"json"
|
||||
]);
|
||||
if (result == null) {
|
||||
// ignore: use_build_context_synchronously
|
||||
Navigator.of(context).pop();
|
||||
return;
|
||||
}
|
||||
try {
|
||||
File file = File(result
|
||||
.files.single.path!);
|
||||
content = await file
|
||||
.readAsString();
|
||||
} catch (_) {
|
||||
// web fallback
|
||||
content = utf8.decode(result
|
||||
.files
|
||||
.single
|
||||
.bytes as List<int>);
|
||||
}
|
||||
}
|
||||
}
|
||||
List<dynamic> tmpHistory =
|
||||
jsonDecode(content);
|
||||
List<String> history = [];
|
||||
List<dynamic> tmpHistory =
|
||||
jsonDecode(content);
|
||||
List<String> history = [];
|
||||
|
||||
for (var i = 0;
|
||||
i < tmpHistory.length;
|
||||
i++) {
|
||||
history.add(tmpHistory[i]);
|
||||
}
|
||||
for (var i = 0;
|
||||
i < tmpHistory.length;
|
||||
i++) {
|
||||
history.add(tmpHistory[i]);
|
||||
}
|
||||
|
||||
prefs!.setStringList(
|
||||
"chats", history);
|
||||
prefs!.setStringList(
|
||||
"chats", history);
|
||||
|
||||
messages = [];
|
||||
chatUuid = null;
|
||||
messages = [];
|
||||
chatUuid = null;
|
||||
|
||||
setState(() {});
|
||||
setState(() {});
|
||||
|
||||
// ignore: use_build_context_synchronously
|
||||
Navigator.of(context).pop();
|
||||
// ignore: use_build_context_synchronously
|
||||
Navigator.of(context).pop();
|
||||
// ignore: use_build_context_synchronously
|
||||
Navigator.of(context).pop();
|
||||
// ignore: use_build_context_synchronously
|
||||
ScaffoldMessenger.of(context)
|
||||
.showSnackBar(SnackBar(
|
||||
content: Text(AppLocalizations
|
||||
// ignore: use_build_context_synchronously
|
||||
.of(context)!
|
||||
.settingsImportChatsSuccess),
|
||||
showCloseIcon: true));
|
||||
},
|
||||
child: Text(
|
||||
AppLocalizations.of(context)!
|
||||
.settingsImportChatsImport))
|
||||
]);
|
||||
});
|
||||
})
|
||||
: const SizedBox.shrink()
|
||||
]),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
button(AppLocalizations.of(context)!.settingsExportInfo,
|
||||
Icons.info_rounded, null,
|
||||
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))
|
||||
]))),
|
||||
// ignore: use_build_context_synchronously
|
||||
Navigator.of(context).pop();
|
||||
// ignore: use_build_context_synchronously
|
||||
Navigator.of(context).pop();
|
||||
// ignore: use_build_context_synchronously
|
||||
Navigator.of(context).pop();
|
||||
// ignore: use_build_context_synchronously
|
||||
ScaffoldMessenger.of(context)
|
||||
.showSnackBar(SnackBar(
|
||||
content: Text(AppLocalizations
|
||||
// ignore: use_build_context_synchronously
|
||||
.of(context)!
|
||||
.settingsImportChatsSuccess),
|
||||
showCloseIcon: true));
|
||||
},
|
||||
child: Text(AppLocalizations.of(
|
||||
context)!
|
||||
.settingsImportChatsImport))
|
||||
]);
|
||||
});
|
||||
})
|
||||
: const SizedBox.shrink()
|
||||
]),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
button(AppLocalizations.of(context)!.settingsExportInfo,
|
||||
Icons.info_rounded, null,
|
||||
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))
|
||||
])),
|
||||
)),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,460 +36,487 @@ class _ScreenSettingsInterfaceState extends State<ScreenSettingsInterface> {
|
|||
Expanded(child: SizedBox(height: 200, child: MoveWindow()))
|
||||
]),
|
||||
actions: desktopControlsActions(context)),
|
||||
body: Padding(
|
||||
padding: const EdgeInsets.only(left: 16, right: 16),
|
||||
child: Column(children: [
|
||||
Expanded(
|
||||
child: ListView(children: [
|
||||
// const SizedBox(height: 8),
|
||||
toggle(
|
||||
context,
|
||||
AppLocalizations.of(context)!.settingsShowModelTags,
|
||||
(prefs!.getBool("modelTags") ?? false), (value) {
|
||||
selectionHaptic();
|
||||
prefs!.setBool("modelTags", value);
|
||||
setState(() {});
|
||||
}),
|
||||
toggle(
|
||||
context,
|
||||
AppLocalizations.of(context)!.settingsPreloadModels,
|
||||
(prefs!.getBool("preloadModel") ?? true), (value) {
|
||||
selectionHaptic();
|
||||
prefs!.setBool("preloadModel", value);
|
||||
setState(() {});
|
||||
}),
|
||||
toggle(
|
||||
context,
|
||||
AppLocalizations.of(context)!
|
||||
.settingsResetOnModelChange,
|
||||
(prefs!.getBool("resetOnModelSelect") ?? true),
|
||||
(value) {
|
||||
selectionHaptic();
|
||||
prefs!.setBool("resetOnModelSelect", value);
|
||||
setState(() {});
|
||||
}),
|
||||
titleDivider(
|
||||
bottom: desktopLayoutNotRequired(context) ? 38 : 20,
|
||||
context: context),
|
||||
SegmentedButton(
|
||||
segments: [
|
||||
ButtonSegment(
|
||||
value: "stream",
|
||||
label: Text(AppLocalizations.of(context)!
|
||||
.settingsRequestTypeStream),
|
||||
icon: const Icon(Icons.stream_rounded)),
|
||||
ButtonSegment(
|
||||
value: "request",
|
||||
label: Text(AppLocalizations.of(context)!
|
||||
.settingsRequestTypeRequest),
|
||||
icon: const Icon(Icons.send_rounded))
|
||||
],
|
||||
selected: {
|
||||
prefs!.getString("requestType") ?? "stream"
|
||||
},
|
||||
onSelectionChanged: (p0) {
|
||||
selectionHaptic();
|
||||
setState(() {
|
||||
prefs!.setString("requestType", p0.elementAt(0));
|
||||
});
|
||||
}),
|
||||
const SizedBox(height: 16),
|
||||
toggle(
|
||||
context,
|
||||
AppLocalizations.of(context)!.settingsGenerateTitles,
|
||||
(prefs!.getBool("generateTitles") ?? true), (value) {
|
||||
selectionHaptic();
|
||||
prefs!.setBool("generateTitles", value);
|
||||
setState(() {});
|
||||
}),
|
||||
toggle(
|
||||
context,
|
||||
AppLocalizations.of(context)!.settingsEnableEditing,
|
||||
(prefs!.getBool("enableEditing") ?? true), (value) {
|
||||
selectionHaptic();
|
||||
prefs!.setBool("enableEditing", value);
|
||||
setState(() {});
|
||||
}),
|
||||
toggle(
|
||||
context,
|
||||
AppLocalizations.of(context)!.settingsAskBeforeDelete,
|
||||
(prefs!.getBool("askBeforeDeletion") ?? false),
|
||||
(value) {
|
||||
selectionHaptic();
|
||||
prefs!.setBool("askBeforeDeletion", value);
|
||||
setState(() {});
|
||||
}),
|
||||
toggle(
|
||||
context,
|
||||
AppLocalizations.of(context)!.settingsShowTips,
|
||||
(prefs!.getBool("tips") ?? true), (value) {
|
||||
selectionHaptic();
|
||||
prefs!.setBool("tips", value);
|
||||
setState(() {});
|
||||
}),
|
||||
titleDivider(context: context),
|
||||
toggle(
|
||||
context,
|
||||
AppLocalizations.of(context)!
|
||||
.settingsKeepModelLoadedAlways,
|
||||
int.parse(prefs!.getString("keepAlive") ?? "300") == -1,
|
||||
(value) {
|
||||
selectionHaptic();
|
||||
setState(() {
|
||||
if (value) {
|
||||
prefs!.setString("keepAlive", "-1");
|
||||
} else {
|
||||
prefs!.setString("keepAlive", "300");
|
||||
}
|
||||
});
|
||||
}),
|
||||
toggle(
|
||||
context,
|
||||
AppLocalizations.of(context)!
|
||||
.settingsKeepModelLoadedNever,
|
||||
int.parse(prefs!.getString("keepAlive") ?? "300") == 0,
|
||||
(value) {
|
||||
selectionHaptic();
|
||||
setState(() {
|
||||
if (value) {
|
||||
prefs!.setString("keepAlive", "0");
|
||||
} else {
|
||||
prefs!.setString("keepAlive", "300");
|
||||
}
|
||||
});
|
||||
}),
|
||||
button(
|
||||
(int.parse(prefs!.getString("keepAlive") ?? "300") > 0)
|
||||
? AppLocalizations.of(context)!
|
||||
.settingsKeepModelLoadedSet((int.parse(
|
||||
prefs!.getString("keepAlive") ??
|
||||
"300") ~/
|
||||
60)
|
||||
.toString())
|
||||
: AppLocalizations.of(context)!
|
||||
.settingsKeepModelLoadedFor,
|
||||
Icons.snooze_rounded, () async {
|
||||
selectionHaptic();
|
||||
bool loaded = false;
|
||||
await showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return Dialog(
|
||||
alignment: desktopLayout(context)
|
||||
? null
|
||||
: Alignment.bottomRight,
|
||||
child: StatefulBuilder(
|
||||
builder: (context, setLocalState) {
|
||||
if (int.parse(prefs!.getString("keepAlive") ??
|
||||
"0") <=
|
||||
0 &&
|
||||
loaded == false) {
|
||||
prefs!.setString("keepAlive", "0");
|
||||
WidgetsBinding.instance
|
||||
.addPostFrameCallback((timeStamp) {
|
||||
setLocalState(() {});
|
||||
void load() async {
|
||||
try {
|
||||
while (int.parse(prefs!
|
||||
.getString("keepAlive")!) <
|
||||
300) {
|
||||
await Future.delayed(const Duration(
|
||||
milliseconds: 5));
|
||||
prefs!.setString(
|
||||
"keepAlive",
|
||||
(int.parse(prefs!.getString(
|
||||
"keepAlive")!) +
|
||||
30)
|
||||
.toString());
|
||||
setLocalState(() {});
|
||||
setState(() {});
|
||||
}
|
||||
prefs!.setString("keepAlive", "300");
|
||||
loaded = true;
|
||||
} catch (_) {
|
||||
prefs!.setString("keepAlive", "300");
|
||||
loaded = true;
|
||||
}
|
||||
}
|
||||
|
||||
load();
|
||||
});
|
||||
} else {
|
||||
loaded = true;
|
||||
}
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Theme(
|
||||
data: (prefs?.getBool("useDeviceTheme") ??
|
||||
false)
|
||||
? Theme.of(context)
|
||||
: ThemeData.from(
|
||||
colorScheme: ColorScheme.fromSeed(
|
||||
seedColor: Colors.black)),
|
||||
child: DurationPicker(
|
||||
duration: Duration(
|
||||
seconds: int.parse(prefs!
|
||||
.getString("keepAlive") ??
|
||||
"300")),
|
||||
baseUnit: BaseUnit.minute,
|
||||
lowerBound:
|
||||
const Duration(minutes: 1),
|
||||
upperBound:
|
||||
const Duration(minutes: 60),
|
||||
onChange: (value) {
|
||||
if (!loaded) return;
|
||||
if (value.inSeconds == 0) return;
|
||||
prefs!.setString("keepAlive",
|
||||
value.inSeconds.toString());
|
||||
setLocalState(() {});
|
||||
setState(() {});
|
||||
}),
|
||||
),
|
||||
);
|
||||
}));
|
||||
});
|
||||
}),
|
||||
titleDivider(context: context),
|
||||
toggle(
|
||||
context,
|
||||
AppLocalizations.of(context)!
|
||||
.settingsEnableHapticFeedback,
|
||||
(prefs!.getBool("enableHaptic") ?? true), (value) {
|
||||
prefs!.setBool("enableHaptic", value);
|
||||
selectionHaptic();
|
||||
setState(() {});
|
||||
}),
|
||||
desktopFeature()
|
||||
? toggle(
|
||||
context,
|
||||
AppLocalizations.of(context)!
|
||||
.settingsMaximizeOnStart,
|
||||
(prefs!.getBool("maximizeOnStart") ?? false),
|
||||
(value) {
|
||||
body: Center(
|
||||
child: Container(
|
||||
constraints: const BoxConstraints(maxWidth: 1000),
|
||||
padding: const EdgeInsets.only(left: 16, right: 16),
|
||||
child: Column(children: [
|
||||
Expanded(
|
||||
child: ListView(children: [
|
||||
// const SizedBox(height: 8),
|
||||
toggle(
|
||||
context,
|
||||
AppLocalizations.of(context)!.settingsShowModelTags,
|
||||
(prefs!.getBool("modelTags") ?? false), (value) {
|
||||
selectionHaptic();
|
||||
prefs!.setBool("modelTags", value);
|
||||
setState(() {});
|
||||
}),
|
||||
toggle(
|
||||
context,
|
||||
AppLocalizations.of(context)!.settingsPreloadModels,
|
||||
(prefs!.getBool("preloadModel") ?? true), (value) {
|
||||
selectionHaptic();
|
||||
prefs!.setBool("preloadModel", value);
|
||||
setState(() {});
|
||||
}),
|
||||
toggle(
|
||||
context,
|
||||
AppLocalizations.of(context)!
|
||||
.settingsResetOnModelChange,
|
||||
(prefs!.getBool("resetOnModelSelect") ?? true),
|
||||
(value) {
|
||||
selectionHaptic();
|
||||
prefs!.setBool("resetOnModelSelect", value);
|
||||
setState(() {});
|
||||
}),
|
||||
titleDivider(
|
||||
bottom: desktopLayoutNotRequired(context) ? 38 : 20,
|
||||
context: context),
|
||||
SegmentedButton(
|
||||
segments: [
|
||||
ButtonSegment(
|
||||
value: "stream",
|
||||
label: Text(AppLocalizations.of(context)!
|
||||
.settingsRequestTypeStream),
|
||||
icon: const Icon(Icons.stream_rounded)),
|
||||
ButtonSegment(
|
||||
value: "request",
|
||||
label: Text(AppLocalizations.of(context)!
|
||||
.settingsRequestTypeRequest),
|
||||
icon: const Icon(Icons.send_rounded))
|
||||
],
|
||||
selected: {
|
||||
prefs!.getString("requestType") ?? "stream"
|
||||
},
|
||||
onSelectionChanged: (p0) {
|
||||
selectionHaptic();
|
||||
prefs!.setBool("maximizeOnStart", value);
|
||||
setState(() {});
|
||||
})
|
||||
: const SizedBox.shrink(),
|
||||
const SizedBox(height: 8),
|
||||
SegmentedButton(
|
||||
segments: [
|
||||
ButtonSegment(
|
||||
value: "dark",
|
||||
label: Text(AppLocalizations.of(context)!
|
||||
.settingsBrightnessDark),
|
||||
icon: const Icon(Icons.brightness_4_rounded)),
|
||||
ButtonSegment(
|
||||
value: "system",
|
||||
label: Text(AppLocalizations.of(context)!
|
||||
.settingsBrightnessSystem),
|
||||
icon: const Icon(Icons.brightness_auto_rounded)),
|
||||
ButtonSegment(
|
||||
value: "light",
|
||||
label: Text(AppLocalizations.of(context)!
|
||||
.settingsBrightnessLight),
|
||||
icon: const Icon(Icons.brightness_high_rounded))
|
||||
],
|
||||
selected: {
|
||||
prefs!.getString("brightness") ?? "system"
|
||||
},
|
||||
onSelectionChanged: (p0) {
|
||||
selectionHaptic();
|
||||
var tmp = prefs!.getString("brightness") ?? "system";
|
||||
prefs!.setString("brightness", p0.elementAt(0));
|
||||
setState(() {});
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return StatefulBuilder(
|
||||
builder: (context, setLocalState) {
|
||||
return PopScope(
|
||||
onPopInvoked: (didPop) {
|
||||
prefs!.setString("brightness", tmp);
|
||||
setState(() {});
|
||||
},
|
||||
child: AlertDialog(
|
||||
title: Text(AppLocalizations.of(
|
||||
context)!
|
||||
.settingsBrightnessRestartTitle),
|
||||
content: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text(AppLocalizations.of(
|
||||
context)!
|
||||
.settingsBrightnessRestartDescription),
|
||||
]),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
selectionHaptic();
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
child: Text(AppLocalizations.of(
|
||||
context)!
|
||||
.settingsBrightnessRestartCancel)),
|
||||
TextButton(
|
||||
onPressed: () async {
|
||||
selectionHaptic();
|
||||
await prefs!.setString(
|
||||
"brightness",
|
||||
p0.elementAt(0));
|
||||
if (desktopFeature()) {
|
||||
exit(0);
|
||||
} else {
|
||||
Restart.restartApp();
|
||||
}
|
||||
},
|
||||
child: Text(AppLocalizations.of(
|
||||
context)!
|
||||
.settingsBrightnessRestartRestart))
|
||||
]));
|
||||
});
|
||||
});
|
||||
}),
|
||||
const SizedBox(height: 8),
|
||||
!kIsWeb
|
||||
? 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 (desktopFeature()) {
|
||||
exit(0);
|
||||
} else {
|
||||
Restart.restartApp();
|
||||
}
|
||||
},
|
||||
child: Text(AppLocalizations.of(
|
||||
context)!
|
||||
.settingsThemeRestartRestart))
|
||||
]);
|
||||
});
|
||||
});
|
||||
})
|
||||
: const SizedBox.shrink(),
|
||||
titleDivider(),
|
||||
button(AppLocalizations.of(context)!.settingsTemporaryFixes,
|
||||
Icons.fast_forward_rounded, () {
|
||||
selectionHaptic();
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return StatefulBuilder(
|
||||
builder: (context, setState) {
|
||||
return Container(
|
||||
width: double.infinity,
|
||||
padding: EdgeInsets.only(
|
||||
left: 16,
|
||||
right: 16,
|
||||
top: 16,
|
||||
bottom: desktopLayout(context) ? 16 : 0),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
button(
|
||||
AppLocalizations.of(context)!
|
||||
.settingsTemporaryFixesDescription,
|
||||
Icons.info_rounded,
|
||||
null,
|
||||
color: Colors.grey.harmonizeWith(
|
||||
Theme.of(context)
|
||||
.colorScheme
|
||||
.primary)),
|
||||
button(
|
||||
AppLocalizations.of(context)!
|
||||
.settingsTemporaryFixesInstructions,
|
||||
Icons.warning_rounded,
|
||||
null,
|
||||
color: Colors.orange.harmonizeWith(
|
||||
Theme.of(context)
|
||||
.colorScheme
|
||||
.primary)),
|
||||
titleDivider(),
|
||||
// Text(
|
||||
// AppLocalizations.of(context)!
|
||||
// .settingsTemporaryFixesNoFixes,
|
||||
// style: const TextStyle(
|
||||
// color: Colors.grey)),
|
||||
toggle(
|
||||
context,
|
||||
"Fixing code block not scrollable",
|
||||
(prefs!.getBool(
|
||||
"fixCodeblockScroll") ??
|
||||
false), (value) {
|
||||
selectionHaptic();
|
||||
prefs!.setBool(
|
||||
"fixCodeblockScroll", value);
|
||||
if ((prefs!.getBool(
|
||||
"fixCodeblockScroll") ??
|
||||
false) ==
|
||||
false) {
|
||||
prefs!.remove("fixCodeblockScroll");
|
||||
}
|
||||
setState(() {});
|
||||
}, onLongTap: () {
|
||||
selectionHaptic();
|
||||
launchUrl(Uri.parse(
|
||||
"https://github.com/JHubi1/ollama-app/issues/26"));
|
||||
}),
|
||||
const SizedBox(height: 16)
|
||||
]),
|
||||
);
|
||||
setState(() {
|
||||
prefs!.setString("requestType", p0.elementAt(0));
|
||||
});
|
||||
});
|
||||
}),
|
||||
const SizedBox(height: 16)
|
||||
]),
|
||||
)
|
||||
]))),
|
||||
}),
|
||||
const SizedBox(height: 16),
|
||||
toggle(
|
||||
context,
|
||||
AppLocalizations.of(context)!.settingsGenerateTitles,
|
||||
(prefs!.getBool("generateTitles") ?? true), (value) {
|
||||
selectionHaptic();
|
||||
prefs!.setBool("generateTitles", value);
|
||||
setState(() {});
|
||||
}),
|
||||
toggle(
|
||||
context,
|
||||
AppLocalizations.of(context)!.settingsEnableEditing,
|
||||
(prefs!.getBool("enableEditing") ?? true), (value) {
|
||||
selectionHaptic();
|
||||
prefs!.setBool("enableEditing", value);
|
||||
setState(() {});
|
||||
}),
|
||||
toggle(
|
||||
context,
|
||||
AppLocalizations.of(context)!.settingsAskBeforeDelete,
|
||||
(prefs!.getBool("askBeforeDeletion") ?? false),
|
||||
(value) {
|
||||
selectionHaptic();
|
||||
prefs!.setBool("askBeforeDeletion", value);
|
||||
setState(() {});
|
||||
}),
|
||||
toggle(
|
||||
context,
|
||||
AppLocalizations.of(context)!.settingsShowTips,
|
||||
(prefs!.getBool("tips") ?? true), (value) {
|
||||
selectionHaptic();
|
||||
prefs!.setBool("tips", value);
|
||||
setState(() {});
|
||||
}),
|
||||
titleDivider(context: context),
|
||||
toggle(
|
||||
context,
|
||||
AppLocalizations.of(context)!
|
||||
.settingsKeepModelLoadedAlways,
|
||||
int.parse(prefs!.getString("keepAlive") ?? "300") ==
|
||||
-1, (value) {
|
||||
selectionHaptic();
|
||||
setState(() {
|
||||
if (value) {
|
||||
prefs!.setString("keepAlive", "-1");
|
||||
} else {
|
||||
prefs!.setString("keepAlive", "300");
|
||||
}
|
||||
});
|
||||
}),
|
||||
toggle(
|
||||
context,
|
||||
AppLocalizations.of(context)!
|
||||
.settingsKeepModelLoadedNever,
|
||||
int.parse(prefs!.getString("keepAlive") ?? "300") ==
|
||||
0, (value) {
|
||||
selectionHaptic();
|
||||
setState(() {
|
||||
if (value) {
|
||||
prefs!.setString("keepAlive", "0");
|
||||
} else {
|
||||
prefs!.setString("keepAlive", "300");
|
||||
}
|
||||
});
|
||||
}),
|
||||
button(
|
||||
(int.parse(prefs!.getString("keepAlive") ?? "300") >
|
||||
0)
|
||||
? AppLocalizations.of(context)!
|
||||
.settingsKeepModelLoadedSet((int.parse(
|
||||
prefs!.getString("keepAlive") ??
|
||||
"300") ~/
|
||||
60)
|
||||
.toString())
|
||||
: AppLocalizations.of(context)!
|
||||
.settingsKeepModelLoadedFor,
|
||||
Icons.snooze_rounded, () async {
|
||||
selectionHaptic();
|
||||
bool loaded = false;
|
||||
await showDialog(
|
||||
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") ??
|
||||
"0") <=
|
||||
0 &&
|
||||
loaded == false) {
|
||||
prefs!.setString("keepAlive", "0");
|
||||
WidgetsBinding.instance
|
||||
.addPostFrameCallback((timeStamp) {
|
||||
setLocalState(() {});
|
||||
void load() async {
|
||||
try {
|
||||
while (int.parse(prefs!
|
||||
.getString("keepAlive")!) <
|
||||
300) {
|
||||
await Future.delayed(
|
||||
const Duration(
|
||||
milliseconds: 5));
|
||||
prefs!.setString(
|
||||
"keepAlive",
|
||||
(int.parse(prefs!.getString(
|
||||
"keepAlive")!) +
|
||||
30)
|
||||
.toString());
|
||||
setLocalState(() {});
|
||||
setState(() {});
|
||||
}
|
||||
prefs!
|
||||
.setString("keepAlive", "300");
|
||||
loaded = true;
|
||||
} catch (_) {
|
||||
prefs!
|
||||
.setString("keepAlive", "300");
|
||||
loaded = true;
|
||||
}
|
||||
}
|
||||
|
||||
load();
|
||||
});
|
||||
} else {
|
||||
loaded = true;
|
||||
}
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Theme(
|
||||
data:
|
||||
(prefs?.getBool("useDeviceTheme") ??
|
||||
false)
|
||||
? Theme.of(context)
|
||||
: ThemeData.from(
|
||||
colorScheme:
|
||||
ColorScheme.fromSeed(
|
||||
seedColor:
|
||||
Colors.black)),
|
||||
child: DurationPicker(
|
||||
duration: Duration(
|
||||
seconds: int.parse(prefs!
|
||||
.getString(
|
||||
"keepAlive") ??
|
||||
"300")),
|
||||
baseUnit: BaseUnit.minute,
|
||||
lowerBound:
|
||||
const Duration(minutes: 1),
|
||||
upperBound:
|
||||
const Duration(minutes: 60),
|
||||
onChange: (value) {
|
||||
if (!loaded) return;
|
||||
if (value.inSeconds == 0) return;
|
||||
prefs!.setString("keepAlive",
|
||||
value.inSeconds.toString());
|
||||
setLocalState(() {});
|
||||
setState(() {});
|
||||
}),
|
||||
),
|
||||
);
|
||||
}));
|
||||
});
|
||||
}),
|
||||
titleDivider(context: context),
|
||||
toggle(
|
||||
context,
|
||||
AppLocalizations.of(context)!
|
||||
.settingsEnableHapticFeedback,
|
||||
(prefs!.getBool("enableHaptic") ?? true), (value) {
|
||||
prefs!.setBool("enableHaptic", value);
|
||||
selectionHaptic();
|
||||
setState(() {});
|
||||
}),
|
||||
desktopFeature()
|
||||
? toggle(
|
||||
context,
|
||||
AppLocalizations.of(context)!
|
||||
.settingsMaximizeOnStart,
|
||||
(prefs!.getBool("maximizeOnStart") ?? false),
|
||||
(value) {
|
||||
selectionHaptic();
|
||||
prefs!.setBool("maximizeOnStart", value);
|
||||
setState(() {});
|
||||
})
|
||||
: const SizedBox.shrink(),
|
||||
const SizedBox(height: 8),
|
||||
SegmentedButton(
|
||||
segments: [
|
||||
ButtonSegment(
|
||||
value: "dark",
|
||||
label: Text(AppLocalizations.of(context)!
|
||||
.settingsBrightnessDark),
|
||||
icon: const Icon(Icons.brightness_4_rounded)),
|
||||
ButtonSegment(
|
||||
value: "system",
|
||||
label: Text(AppLocalizations.of(context)!
|
||||
.settingsBrightnessSystem),
|
||||
icon:
|
||||
const Icon(Icons.brightness_auto_rounded)),
|
||||
ButtonSegment(
|
||||
value: "light",
|
||||
label: Text(AppLocalizations.of(context)!
|
||||
.settingsBrightnessLight),
|
||||
icon: const Icon(Icons.brightness_high_rounded))
|
||||
],
|
||||
selected: {
|
||||
prefs!.getString("brightness") ?? "system"
|
||||
},
|
||||
onSelectionChanged: (p0) {
|
||||
selectionHaptic();
|
||||
var tmp =
|
||||
prefs!.getString("brightness") ?? "system";
|
||||
prefs!.setString("brightness", p0.elementAt(0));
|
||||
setState(() {});
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return StatefulBuilder(
|
||||
builder: (context, setLocalState) {
|
||||
return PopScope(
|
||||
onPopInvoked: (didPop) {
|
||||
prefs!.setString("brightness", tmp);
|
||||
setState(() {});
|
||||
},
|
||||
child: AlertDialog(
|
||||
surfaceTintColor: (Theme.of(context).brightness == Brightness.dark) ? Colors.grey[800] : null,
|
||||
title: Text(AppLocalizations.of(
|
||||
context)!
|
||||
.settingsBrightnessRestartTitle),
|
||||
content: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text(AppLocalizations.of(
|
||||
context)!
|
||||
.settingsBrightnessRestartDescription),
|
||||
]),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
selectionHaptic();
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
child: Text(AppLocalizations
|
||||
.of(context)!
|
||||
.settingsBrightnessRestartCancel)),
|
||||
TextButton(
|
||||
onPressed: () async {
|
||||
selectionHaptic();
|
||||
await prefs!.setString(
|
||||
"brightness",
|
||||
p0.elementAt(0));
|
||||
if (desktopFeature()) {
|
||||
exit(0);
|
||||
} else {
|
||||
Restart.restartApp();
|
||||
}
|
||||
},
|
||||
child: Text(AppLocalizations
|
||||
.of(context)!
|
||||
.settingsBrightnessRestartRestart))
|
||||
]));
|
||||
});
|
||||
});
|
||||
}),
|
||||
const SizedBox(height: 8),
|
||||
!kIsWeb
|
||||
? 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(
|
||||
surfaceTintColor: (Theme.of(context).brightness == Brightness.dark) ? Colors.grey[800] : null,
|
||||
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 (desktopFeature()) {
|
||||
exit(0);
|
||||
} else {
|
||||
Restart.restartApp();
|
||||
}
|
||||
},
|
||||
child: Text(AppLocalizations
|
||||
.of(context)!
|
||||
.settingsThemeRestartRestart))
|
||||
]);
|
||||
});
|
||||
});
|
||||
})
|
||||
: const SizedBox.shrink(),
|
||||
titleDivider(),
|
||||
button(
|
||||
AppLocalizations.of(context)!.settingsTemporaryFixes,
|
||||
Icons.fast_forward_rounded, () {
|
||||
selectionHaptic();
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return StatefulBuilder(
|
||||
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,
|
||||
top: 16,
|
||||
bottom: desktopLayout(context) ? 16 : 0),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
button(
|
||||
AppLocalizations.of(context)!
|
||||
.settingsTemporaryFixesDescription,
|
||||
Icons.info_rounded,
|
||||
null,
|
||||
color: Colors.grey.harmonizeWith(
|
||||
Theme.of(context)
|
||||
.colorScheme
|
||||
.primary)),
|
||||
button(
|
||||
AppLocalizations.of(context)!
|
||||
.settingsTemporaryFixesInstructions,
|
||||
Icons.warning_rounded,
|
||||
null,
|
||||
color: Colors.orange.harmonizeWith(
|
||||
Theme.of(context)
|
||||
.colorScheme
|
||||
.primary)),
|
||||
titleDivider(),
|
||||
// Text(
|
||||
// AppLocalizations.of(context)!
|
||||
// .settingsTemporaryFixesNoFixes,
|
||||
// style: const TextStyle(
|
||||
// color: Colors.grey)),
|
||||
toggle(
|
||||
context,
|
||||
"Fixing code block not scrollable",
|
||||
(prefs!.getBool(
|
||||
"fixCodeblockScroll") ??
|
||||
false), (value) {
|
||||
selectionHaptic();
|
||||
prefs!.setBool(
|
||||
"fixCodeblockScroll", value);
|
||||
if ((prefs!.getBool(
|
||||
"fixCodeblockScroll") ??
|
||||
false) ==
|
||||
false) {
|
||||
prefs!.remove("fixCodeblockScroll");
|
||||
}
|
||||
setState(() {});
|
||||
}, onLongTap: () {
|
||||
selectionHaptic();
|
||||
launchUrl(Uri.parse(
|
||||
"https://github.com/JHubi1/ollama-app/issues/26"));
|
||||
}),
|
||||
const SizedBox(height: 16)
|
||||
]),
|
||||
);
|
||||
});
|
||||
});
|
||||
}),
|
||||
const SizedBox(height: 16)
|
||||
]),
|
||||
)
|
||||
])),
|
||||
)),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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```")
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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: MarkdownBody(
|
||||
data: updateChangeLog ?? "No changelog given.",
|
||||
shrinkWrap: true)))
|
||||
child: Container(
|
||||
constraints: const BoxConstraints(maxWidth: 1000),
|
||||
child: MarkdownBody(
|
||||
data: updateChangeLog ?? "No changelog given.",
|
||||
shrinkWrap: true),
|
||||
)))
|
||||
]),
|
||||
actions: [
|
||||
TextButton(
|
||||
|
|
Loading…
Reference in New Issue