Added update checker, updated desktop view
This commit is contained in:
parent
08d566e855
commit
0a996e6ed2
|
@ -317,6 +317,47 @@
|
||||||
"description": "Text displayed when chats are imported successfully",
|
"description": "Text displayed when chats are imported successfully",
|
||||||
"context": "Visible in the settings view"
|
"context": "Visible in the settings view"
|
||||||
},
|
},
|
||||||
|
"settingsUpdateCheck": "Check for updates",
|
||||||
|
"@settingsUpdateCheck": {
|
||||||
|
"description": "Text displayed as description for check for updates button",
|
||||||
|
"context": "Visible in the settings view"
|
||||||
|
},
|
||||||
|
"settingsUpdateChecking": "Checking for updates ...",
|
||||||
|
"@settingsUpdateChecking": {
|
||||||
|
"description": "Text displayed while looking for updates",
|
||||||
|
"context": "Visible in the settings view"
|
||||||
|
},
|
||||||
|
"settingsUpdateLatest": "You are on the latest version",
|
||||||
|
"@settingsUpdateLatest": {
|
||||||
|
"description": "Text displayed when the app is up to date",
|
||||||
|
"context": "Visible in the settings view"
|
||||||
|
},
|
||||||
|
"settingsUpdateAvailable": "Update available (v{version})",
|
||||||
|
"@settingsUpdateAvailable": {
|
||||||
|
"description": "Text displayed when an update is available",
|
||||||
|
"context": "Visible in the settings view",
|
||||||
|
"placeholders": {
|
||||||
|
"version": {
|
||||||
|
"type": "String",
|
||||||
|
"description": "Version number of the available update"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"settingsUpdateRateLimit": "API rate limit exceeded. Not able to check for updates",
|
||||||
|
"@settingsUpdateRateLimit": {
|
||||||
|
"description": "Text displayed when the API rate limit is exceeded",
|
||||||
|
"context": "Visible in the settings view"
|
||||||
|
},
|
||||||
|
"settingsUpdateIssue": "An issue occurred while checking for updates. Click to retry",
|
||||||
|
"@settingsUpdateIssue": {
|
||||||
|
"description": "Text displayed when an issue occurs while checking for updates",
|
||||||
|
"context": "Visible in the settings view"
|
||||||
|
},
|
||||||
|
"settingsCheckForUpdates": "Check for update on settings open",
|
||||||
|
"@settingsCheckForUpdates": {
|
||||||
|
"description": "Text displayed as description for check for updates toggle",
|
||||||
|
"context": "Visible in the settings view"
|
||||||
|
},
|
||||||
"settingsGithub": "GitHub",
|
"settingsGithub": "GitHub",
|
||||||
"@settingsGithub": {
|
"@settingsGithub": {
|
||||||
"description": "Text displayed as description for GitHub button",
|
"description": "Text displayed as description for GitHub button",
|
||||||
|
|
|
@ -64,6 +64,8 @@ bool chatAllowed = true;
|
||||||
final user = types.User(id: const Uuid().v4());
|
final user = types.User(id: const Uuid().v4());
|
||||||
final assistant = types.User(id: const Uuid().v4());
|
final assistant = types.User(id: const Uuid().v4());
|
||||||
|
|
||||||
|
bool settingsOpen = false;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
runApp(const App());
|
runApp(const App());
|
||||||
|
|
||||||
|
@ -92,7 +94,9 @@ class _AppState extends State<App> {
|
||||||
super.initState();
|
super.initState();
|
||||||
|
|
||||||
void load() async {
|
void load() async {
|
||||||
|
try {
|
||||||
await FlutterDisplayMode.setHighRefreshRate();
|
await FlutterDisplayMode.setHighRefreshRate();
|
||||||
|
} catch (_) {}
|
||||||
SharedPreferences.setPrefix("ollama.");
|
SharedPreferences.setPrefix("ollama.");
|
||||||
SharedPreferences tmp = await SharedPreferences.getInstance();
|
SharedPreferences tmp = await SharedPreferences.getInstance();
|
||||||
setState(() {
|
setState(() {
|
||||||
|
@ -215,7 +219,12 @@ class _MainAppState extends State<MainApp> {
|
||||||
borderRadius: BorderRadius.all(Radius.circular(50))),
|
borderRadius: BorderRadius.all(Radius.circular(50))),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
HapticFeedback.selectionClick();
|
HapticFeedback.selectionClick();
|
||||||
|
if (!(Platform.isWindows ||
|
||||||
|
Platform.isLinux ||
|
||||||
|
Platform.isMacOS) &&
|
||||||
|
MediaQuery.of(context).size.width <= 1000) {
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
|
}
|
||||||
if (!chatAllowed) return;
|
if (!chatAllowed) return;
|
||||||
chatUuid = null;
|
chatUuid = null;
|
||||||
messages = [];
|
messages = [];
|
||||||
|
@ -246,9 +255,14 @@ class _MainAppState extends State<MainApp> {
|
||||||
borderRadius: BorderRadius.all(Radius.circular(50))),
|
borderRadius: BorderRadius.all(Radius.circular(50))),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
HapticFeedback.selectionClick();
|
HapticFeedback.selectionClick();
|
||||||
|
if (!(Platform.isWindows ||
|
||||||
|
Platform.isLinux ||
|
||||||
|
Platform.isMacOS) &&
|
||||||
|
MediaQuery.of(context).size.width <= 1000) {
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
|
}
|
||||||
setState(() {
|
setState(() {
|
||||||
logoVisible = false;
|
settingsOpen = true;
|
||||||
});
|
});
|
||||||
Navigator.push(
|
Navigator.push(
|
||||||
context,
|
context,
|
||||||
|
@ -328,6 +342,7 @@ class _MainAppState extends State<MainApp> {
|
||||||
splashFactory: NoSplash.splashFactory,
|
splashFactory: NoSplash.splashFactory,
|
||||||
highlightColor: Colors.transparent,
|
highlightColor: Colors.transparent,
|
||||||
enableFeedback: false,
|
enableFeedback: false,
|
||||||
|
hoverColor: Colors.transparent,
|
||||||
onTap: () {
|
onTap: () {
|
||||||
HapticFeedback.selectionClick();
|
HapticFeedback.selectionClick();
|
||||||
setState(() {
|
setState(() {
|
||||||
|
@ -422,8 +437,13 @@ class _MainAppState extends State<MainApp> {
|
||||||
if (chatUuid == jsonDecode(item)["uuid"]) {
|
if (chatUuid == jsonDecode(item)["uuid"]) {
|
||||||
messages = [];
|
messages = [];
|
||||||
chatUuid = null;
|
chatUuid = null;
|
||||||
|
if (!(Platform.isWindows ||
|
||||||
|
Platform.isLinux ||
|
||||||
|
Platform.isMacOS) &&
|
||||||
|
MediaQuery.of(context).size.width <= 1000) {
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
setState(() {});
|
setState(() {});
|
||||||
},
|
},
|
||||||
child: Padding(
|
child: Padding(
|
||||||
|
@ -433,7 +453,12 @@ class _MainAppState extends State<MainApp> {
|
||||||
borderRadius: BorderRadius.all(Radius.circular(50))),
|
borderRadius: BorderRadius.all(Radius.circular(50))),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
HapticFeedback.selectionClick();
|
HapticFeedback.selectionClick();
|
||||||
|
if (!(Platform.isWindows ||
|
||||||
|
Platform.isLinux ||
|
||||||
|
Platform.isMacOS) &&
|
||||||
|
MediaQuery.of(context).size.width <= 1000) {
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
|
}
|
||||||
if (!chatAllowed) return;
|
if (!chatAllowed) return;
|
||||||
loadChat(jsonDecode(item)["uuid"], setState);
|
loadChat(jsonDecode(item)["uuid"], setState);
|
||||||
chatUuid = jsonDecode(item)["uuid"];
|
chatUuid = jsonDecode(item)["uuid"];
|
||||||
|
@ -609,6 +634,7 @@ class _MainAppState extends State<MainApp> {
|
||||||
splashFactory: NoSplash.splashFactory,
|
splashFactory: NoSplash.splashFactory,
|
||||||
highlightColor: Colors.transparent,
|
highlightColor: Colors.transparent,
|
||||||
enableFeedback: false,
|
enableFeedback: false,
|
||||||
|
hoverColor: Colors.transparent,
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
height: 200,
|
height: 200,
|
||||||
child: Row(
|
child: Row(
|
||||||
|
@ -787,6 +813,19 @@ class _MainAppState extends State<MainApp> {
|
||||||
preferredSize: const Size.fromHeight(1),
|
preferredSize: const Size.fromHeight(1),
|
||||||
child: (!chatAllowed && model != null)
|
child: (!chatAllowed && model != null)
|
||||||
? const LinearProgressIndicator()
|
? const LinearProgressIndicator()
|
||||||
|
: ((Platform.isWindows ||
|
||||||
|
Platform.isLinux ||
|
||||||
|
Platform.isMacOS) &&
|
||||||
|
MediaQuery.of(context).size.width >= 1000)
|
||||||
|
? AnimatedOpacity(
|
||||||
|
opacity: menuVisible ? 1.0 : 0.0,
|
||||||
|
duration: const Duration(milliseconds: 500),
|
||||||
|
child: Divider(
|
||||||
|
height: 2,
|
||||||
|
color: (Theme.of(context).brightness ==
|
||||||
|
Brightness.light)
|
||||||
|
? Colors.grey[400]
|
||||||
|
: Colors.grey[900]))
|
||||||
: const SizedBox.shrink()),
|
: const SizedBox.shrink()),
|
||||||
leading: ((Platform.isWindows ||
|
leading: ((Platform.isWindows ||
|
||||||
Platform.isLinux ||
|
Platform.isLinux ||
|
||||||
|
@ -806,6 +845,7 @@ class _MainAppState extends State<MainApp> {
|
||||||
child: VisibilityDetector(
|
child: VisibilityDetector(
|
||||||
key: const Key("menuVisible"),
|
key: const Key("menuVisible"),
|
||||||
onVisibilityChanged: (VisibilityInfo info) {
|
onVisibilityChanged: (VisibilityInfo info) {
|
||||||
|
if (settingsOpen) return;
|
||||||
menuVisible = info.visibleFraction > 0;
|
menuVisible = info.visibleFraction > 0;
|
||||||
try {
|
try {
|
||||||
setState(() {});
|
setState(() {});
|
||||||
|
@ -819,11 +859,15 @@ class _MainAppState extends State<MainApp> {
|
||||||
: const SizedBox.shrink(),
|
: const SizedBox.shrink(),
|
||||||
((Platform.isWindows || Platform.isLinux || Platform.isMacOS) &&
|
((Platform.isWindows || Platform.isLinux || Platform.isMacOS) &&
|
||||||
MediaQuery.of(context).size.width >= 1000)
|
MediaQuery.of(context).size.width >= 1000)
|
||||||
? VerticalDivider(
|
? AnimatedOpacity(
|
||||||
|
opacity: menuVisible ? 1.0 : 0.0,
|
||||||
|
duration: const Duration(milliseconds: 500),
|
||||||
|
child: VerticalDivider(
|
||||||
width: 2,
|
width: 2,
|
||||||
color: (Theme.of(context).brightness == Brightness.light)
|
color:
|
||||||
|
(Theme.of(context).brightness == Brightness.light)
|
||||||
? Colors.grey[400]
|
? Colors.grey[400]
|
||||||
: Colors.grey[900])
|
: Colors.grey[900]))
|
||||||
: const SizedBox.shrink(),
|
: const SizedBox.shrink(),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Chat(
|
child: Chat(
|
||||||
|
@ -1021,6 +1065,7 @@ class _MainAppState extends State<MainApp> {
|
||||||
child: VisibilityDetector(
|
child: VisibilityDetector(
|
||||||
key: const Key("logoVisible"),
|
key: const Key("logoVisible"),
|
||||||
onVisibilityChanged: (VisibilityInfo info) {
|
onVisibilityChanged: (VisibilityInfo info) {
|
||||||
|
if (settingsOpen) return;
|
||||||
logoVisible = info.visibleFraction > 0;
|
logoVisible = info.visibleFraction > 0;
|
||||||
try {
|
try {
|
||||||
setState(() {});
|
setState(() {});
|
||||||
|
@ -1515,7 +1560,11 @@ class _MainAppState extends State<MainApp> {
|
||||||
sendable = p0.trim().isNotEmpty;
|
sendable = p0.trim().isNotEmpty;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
sendButtonVisibilityMode: (sendable)
|
sendButtonVisibilityMode: (Platform.isWindows ||
|
||||||
|
Platform.isLinux ||
|
||||||
|
Platform.isMacOS)
|
||||||
|
? SendButtonVisibilityMode.always
|
||||||
|
: (sendable)
|
||||||
? SendButtonVisibilityMode.always
|
? SendButtonVisibilityMode.always
|
||||||
: SendButtonVisibilityMode.hidden),
|
: SendButtonVisibilityMode.hidden),
|
||||||
user: user,
|
user: user,
|
||||||
|
@ -1585,6 +1634,10 @@ class _MainAppState extends State<MainApp> {
|
||||||
: 440))),
|
: 440))),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
drawerEdgeDragWidth:
|
||||||
|
(Platform.isWindows || Platform.isLinux || Platform.isMacOS)
|
||||||
|
? null
|
||||||
|
: MediaQuery.of(context).size.width,
|
||||||
drawer: Builder(builder: (context) {
|
drawer: Builder(builder: (context) {
|
||||||
if ((Platform.isWindows || Platform.isLinux || Platform.isMacOS) &&
|
if ((Platform.isWindows || Platform.isLinux || Platform.isMacOS) &&
|
||||||
MediaQuery.of(context).size.width >= 1000) {
|
MediaQuery.of(context).size.width >= 1000) {
|
||||||
|
|
|
@ -16,6 +16,9 @@ import 'package:url_launcher/url_launcher.dart';
|
||||||
import 'package:restart_app/restart_app.dart';
|
import 'package:restart_app/restart_app.dart';
|
||||||
import 'package:file_picker/file_picker.dart';
|
import 'package:file_picker/file_picker.dart';
|
||||||
import 'package:intl/intl.dart';
|
import 'package:intl/intl.dart';
|
||||||
|
import 'package:install_referrer/install_referrer.dart';
|
||||||
|
import 'package:package_info_plus/package_info_plus.dart';
|
||||||
|
import 'package:version/version.dart';
|
||||||
|
|
||||||
class ScreenSettings extends StatefulWidget {
|
class ScreenSettings extends StatefulWidget {
|
||||||
const ScreenSettings({super.key});
|
const ScreenSettings({super.key});
|
||||||
|
@ -68,7 +71,6 @@ class _ScreenSettingsState extends State<ScreenSettings> {
|
||||||
}
|
}
|
||||||
if ((request.statusCode == 200 && request.body == "Ollama is running") ||
|
if ((request.statusCode == 200 && request.body == "Ollama is running") ||
|
||||||
(Uri.parse(tmpHost).toString() == fixedHost)) {
|
(Uri.parse(tmpHost).toString() == fixedHost)) {
|
||||||
// messages = [];
|
|
||||||
setState(() {
|
setState(() {
|
||||||
hostLoading = false;
|
hostLoading = false;
|
||||||
host = tmpHost;
|
host = tmpHost;
|
||||||
|
@ -91,10 +93,102 @@ class _ScreenSettingsState extends State<ScreenSettings> {
|
||||||
|
|
||||||
final repoUrl = "https://github.com/JHubi1/ollama-app";
|
final repoUrl = "https://github.com/JHubi1/ollama-app";
|
||||||
|
|
||||||
|
bool updateChecked = false;
|
||||||
|
bool updateLoading = false;
|
||||||
|
String updateStatus = "ok";
|
||||||
|
String? updateUrl;
|
||||||
|
String? latestVersion;
|
||||||
|
String? currentVersion;
|
||||||
|
Future<bool> updatesSupported([bool takeAction = false]) async {
|
||||||
|
bool returnValue = true;
|
||||||
|
var installerApps = [
|
||||||
|
"org.fdroid.fdroid",
|
||||||
|
"org.gdroid.gdroid",
|
||||||
|
"eu.bubu1.fdroidclassic",
|
||||||
|
"in.sunilpaulmathew.izzyondroid",
|
||||||
|
"com.looker.droidify",
|
||||||
|
"com.machiav3lli.fdroid",
|
||||||
|
"nya.kitsunyan.foxydroid"
|
||||||
|
];
|
||||||
|
if ((await InstallReferrer.referrer ==
|
||||||
|
InstallationAppReferrer.androidManually) &&
|
||||||
|
!(installerApps
|
||||||
|
.contains((await InstallReferrer.app).packageName ?? ""))) {
|
||||||
|
returnValue = false;
|
||||||
|
}
|
||||||
|
if (!repoUrl.startsWith("https://github.com")) {
|
||||||
|
returnValue = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!returnValue && takeAction) {
|
||||||
|
setState(() {
|
||||||
|
updateStatus = "notAvailable";
|
||||||
|
updateLoading = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return returnValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
void checkUpdate() async {
|
||||||
|
setState(() {
|
||||||
|
updateChecked = true;
|
||||||
|
updateLoading = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!await updatesSupported()) {
|
||||||
|
setState(() {
|
||||||
|
updateStatus = "notAvailable";
|
||||||
|
updateLoading = false;
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var repo = repoUrl.split("/");
|
||||||
|
|
||||||
|
currentVersion = (await PackageInfo.fromPlatform()).version;
|
||||||
|
// currentVersion = "1.0.0";
|
||||||
|
|
||||||
|
String? version;
|
||||||
|
try {
|
||||||
|
var request = await http
|
||||||
|
.get(Uri.parse(
|
||||||
|
"https://api.github.com/repos/${repo[3]}/${repo[4]}/tags"))
|
||||||
|
.timeout(const Duration(seconds: 5));
|
||||||
|
if (request.statusCode == 403) {
|
||||||
|
setState(() {
|
||||||
|
updateStatus = "rateLimit";
|
||||||
|
updateLoading = false;
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
version = jsonDecode(request.body)[0]["name"];
|
||||||
|
} catch (_) {
|
||||||
|
setState(() {
|
||||||
|
updateStatus = "error";
|
||||||
|
updateLoading = false;
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
latestVersion = version;
|
||||||
|
updateUrl = "$repoUrl/releases/tag/$latestVersion";
|
||||||
|
updateStatus = "ok";
|
||||||
|
|
||||||
|
setState(() {
|
||||||
|
updateLoading = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
|
|
||||||
checkHost();
|
checkHost();
|
||||||
|
updatesSupported(true);
|
||||||
|
if (prefs!.getBool("checkUpdateOnSettingsOpen") ?? false) {
|
||||||
|
checkUpdate();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -153,6 +247,7 @@ class _ScreenSettingsState extends State<ScreenSettings> {
|
||||||
return PopScope(
|
return PopScope(
|
||||||
canPop: !hostLoading,
|
canPop: !hostLoading,
|
||||||
onPopInvoked: (didPop) {
|
onPopInvoked: (didPop) {
|
||||||
|
settingsOpen = false;
|
||||||
FocusManager.instance.primaryFocus?.unfocus();
|
FocusManager.instance.primaryFocus?.unfocus();
|
||||||
},
|
},
|
||||||
child: WindowBorder(
|
child: WindowBorder(
|
||||||
|
@ -171,7 +266,6 @@ class _ScreenSettingsState extends State<ScreenSettings> {
|
||||||
child: WindowTitleBarBox(
|
child: WindowTitleBarBox(
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
// Expanded(child: MoveWindow()),
|
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: 200,
|
height: 200,
|
||||||
child: MinimizeWindowButton(
|
child: MinimizeWindowButton(
|
||||||
|
@ -200,26 +294,7 @@ class _ScreenSettingsState extends State<ScreenSettings> {
|
||||||
)))
|
)))
|
||||||
]
|
]
|
||||||
: null,
|
: null,
|
||||||
leading: (Navigator.of(context).canPop())
|
),
|
||||||
? null
|
|
||||||
: IconButton(
|
|
||||||
icon: const Icon(Icons.arrow_back),
|
|
||||||
onPressed: () {
|
|
||||||
if (hostLoading) return;
|
|
||||||
Navigator.of(context).pushReplacement(
|
|
||||||
// PageRouteBuilder(
|
|
||||||
// pageBuilder: (context, animation,
|
|
||||||
// secondaryAnimation) =>
|
|
||||||
// const MainApp(),
|
|
||||||
// // transitionDuration: const Duration(seconds: 1),
|
|
||||||
// transitionsBuilder: (context, animation,
|
|
||||||
// secondaryAnimation, child) {
|
|
||||||
// return FadeTransition(
|
|
||||||
// opacity: animation, child: child);
|
|
||||||
// })
|
|
||||||
MaterialPageRoute(
|
|
||||||
builder: (context) => const MainApp()));
|
|
||||||
})),
|
|
||||||
body: Padding(
|
body: Padding(
|
||||||
padding: const EdgeInsets.only(left: 16, right: 16),
|
padding: const EdgeInsets.only(left: 16, right: 16),
|
||||||
child: ListView(children: [
|
child: ListView(children: [
|
||||||
|
@ -619,6 +694,77 @@ class _ScreenSettingsState extends State<ScreenSettings> {
|
||||||
.settingsImportChats))
|
.settingsImportChats))
|
||||||
])),
|
])),
|
||||||
title(AppLocalizations.of(context)!.settingsTitleContact),
|
title(AppLocalizations.of(context)!.settingsTitleContact),
|
||||||
|
(updateStatus == "notAvailable")
|
||||||
|
? const SizedBox.shrink()
|
||||||
|
: InkWell(
|
||||||
|
onTap: () {
|
||||||
|
if (updateLoading) return;
|
||||||
|
if ((Version.parse(latestVersion ?? "1.0.0") >
|
||||||
|
Version.parse(currentVersion ?? "2.0.0")) &&
|
||||||
|
(updateStatus == "ok")) {
|
||||||
|
launchUrl(
|
||||||
|
mode: LaunchMode.inAppBrowserView,
|
||||||
|
Uri.parse(updateUrl!));
|
||||||
|
} else {
|
||||||
|
checkUpdate();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
child: Row(children: [
|
||||||
|
updateLoading
|
||||||
|
? SizedBox(
|
||||||
|
width: 24,
|
||||||
|
height: 24,
|
||||||
|
child: Transform.scale(
|
||||||
|
scale: 0.5,
|
||||||
|
child:
|
||||||
|
const CircularProgressIndicator()),
|
||||||
|
)
|
||||||
|
: Icon((updateStatus != "ok")
|
||||||
|
? Icons.warning_rounded
|
||||||
|
: (Version.parse(latestVersion ?? "1.0.0") >
|
||||||
|
Version.parse(
|
||||||
|
currentVersion ?? "2.0.0"))
|
||||||
|
? Icons.info_outline_rounded
|
||||||
|
: Icons.update_rounded),
|
||||||
|
const SizedBox(width: 16, height: 42),
|
||||||
|
Expanded(
|
||||||
|
child: Text(!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 == "notAvailable")
|
||||||
|
? const SizedBox.shrink()
|
||||||
|
: toggle(
|
||||||
|
AppLocalizations.of(context)!.settingsCheckForUpdates,
|
||||||
|
(prefs!.getBool("checkUpdateOnSettingsOpen") ??
|
||||||
|
false), (value) {
|
||||||
|
HapticFeedback.selectionClick();
|
||||||
|
prefs!.setBool("checkUpdateOnSettingsOpen", value);
|
||||||
|
setState(() {});
|
||||||
|
}),
|
||||||
InkWell(
|
InkWell(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
launchUrl(
|
launchUrl(
|
||||||
|
|
|
@ -64,10 +64,8 @@ void setModel(BuildContext context, Function setState) {
|
||||||
|
|
||||||
if (useModel) return;
|
if (useModel) return;
|
||||||
HapticFeedback.selectionClick();
|
HapticFeedback.selectionClick();
|
||||||
showModalBottomSheet(
|
|
||||||
context: context,
|
var content = StatefulBuilder(builder: (context, setLocalState) {
|
||||||
builder: (context) {
|
|
||||||
return StatefulBuilder(builder: (context, setLocalState) {
|
|
||||||
setModalState = setLocalState;
|
setModalState = setLocalState;
|
||||||
return PopScope(
|
return PopScope(
|
||||||
canPop: loaded,
|
canPop: loaded,
|
||||||
|
@ -90,50 +88,65 @@ void setModel(BuildContext context, Function setState) {
|
||||||
setState(() {});
|
setState(() {});
|
||||||
},
|
},
|
||||||
child: Container(
|
child: Container(
|
||||||
width: double.infinity,
|
width:
|
||||||
|
((Platform.isWindows || Platform.isLinux || Platform.isMacOS) &&
|
||||||
|
MediaQuery.of(context).size.width >= 1000)
|
||||||
|
? null
|
||||||
|
: double.infinity,
|
||||||
padding: EdgeInsets.only(
|
padding: EdgeInsets.only(
|
||||||
left: 16,
|
left: 16,
|
||||||
right: 16,
|
right: 16,
|
||||||
top: 16,
|
top: 16,
|
||||||
bottom: (Platform.isWindows ||
|
bottom:
|
||||||
Platform.isLinux ||
|
(Platform.isWindows || Platform.isLinux || Platform.isMacOS)
|
||||||
Platform.isMacOS)
|
|
||||||
? 16
|
? 16
|
||||||
: 0),
|
: 0),
|
||||||
child: (!loaded)
|
child: (!loaded)
|
||||||
? const LinearProgressIndicator()
|
? const LinearProgressIndicator()
|
||||||
: Column(mainAxisSize: MainAxisSize.min, children: [
|
: Column(mainAxisSize: MainAxisSize.min, children: [
|
||||||
Container(
|
Container(
|
||||||
width: double.infinity,
|
width: ((Platform.isWindows ||
|
||||||
|
Platform.isLinux ||
|
||||||
|
Platform.isMacOS) &&
|
||||||
|
MediaQuery.of(context).size.width >= 1000)
|
||||||
|
? 300
|
||||||
|
: double.infinity,
|
||||||
constraints: BoxConstraints(
|
constraints: BoxConstraints(
|
||||||
maxHeight:
|
maxHeight:
|
||||||
MediaQuery.of(context).size.height * 0.4),
|
MediaQuery.of(context).size.height * 0.4),
|
||||||
child: SingleChildScrollView(
|
child: SingleChildScrollView(
|
||||||
scrollDirection: Axis.vertical,
|
scrollDirection: Axis.vertical,
|
||||||
child: Wrap(
|
child: Wrap(
|
||||||
spacing: 5.0,
|
spacing: ((Platform.isWindows ||
|
||||||
runSpacing: 5.0,
|
Platform.isLinux ||
|
||||||
|
Platform.isMacOS) &&
|
||||||
|
MediaQuery.of(context).size.width >= 1000)
|
||||||
|
? 10.0
|
||||||
|
: 5.0,
|
||||||
|
runSpacing: (Platform.isWindows ||
|
||||||
|
Platform.isLinux ||
|
||||||
|
Platform.isMacOS)
|
||||||
|
? (MediaQuery.of(context).size.width >= 1000)
|
||||||
|
? 10.0
|
||||||
|
: 5.0
|
||||||
|
: 0.0,
|
||||||
alignment: WrapAlignment.center,
|
alignment: WrapAlignment.center,
|
||||||
children: List<Widget>.generate(
|
children: List<Widget>.generate(
|
||||||
models.length,
|
models.length,
|
||||||
(int index) {
|
(int index) {
|
||||||
return ChoiceChip(
|
return ChoiceChip(
|
||||||
label: Text(
|
label: Text(
|
||||||
(prefs!.getBool("modelTags") ??
|
(prefs!.getBool("modelTags") ?? false)
|
||||||
false)
|
|
||||||
? modelsReal[index]
|
? modelsReal[index]
|
||||||
: models[index]),
|
: models[index]),
|
||||||
selected: usedIndex == index,
|
selected: usedIndex == index,
|
||||||
avatar: (usedIndex == index)
|
avatar: (usedIndex == index)
|
||||||
? null
|
? null
|
||||||
: (addIndex == index)
|
: (addIndex == index)
|
||||||
? const Icon(
|
? const Icon(Icons.add_rounded)
|
||||||
Icons.add_rounded)
|
|
||||||
: ((recommendedModels
|
: ((recommendedModels
|
||||||
.contains(
|
.contains(models[index]))
|
||||||
models[index]))
|
? const Icon(Icons.star_rounded)
|
||||||
? const Icon(
|
|
||||||
Icons.star_rounded)
|
|
||||||
: ((modal[index])
|
: ((modal[index])
|
||||||
? const Icon(Icons
|
? const Icon(Icons
|
||||||
.collections_rounded)
|
.collections_rounded)
|
||||||
|
@ -145,8 +158,7 @@ void setModel(BuildContext context, Function setState) {
|
||||||
? (theme ?? ThemeData())
|
? (theme ?? ThemeData())
|
||||||
.colorScheme
|
.colorScheme
|
||||||
.secondary
|
.secondary
|
||||||
: (themeDark ??
|
: (themeDark ?? ThemeData.dark())
|
||||||
ThemeData.dark())
|
|
||||||
.colorScheme
|
.colorScheme
|
||||||
.secondary)
|
.secondary)
|
||||||
: null,
|
: null,
|
||||||
|
@ -196,7 +208,17 @@ void setModel(BuildContext context, Function setState) {
|
||||||
)))
|
)))
|
||||||
])));
|
])));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if ((Platform.isWindows || Platform.isLinux || Platform.isMacOS) &&
|
||||||
|
MediaQuery.of(context).size.width >= 1000) {
|
||||||
|
showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (context) {
|
||||||
|
return Dialog(alignment: Alignment.topCenter, child: content);
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
showModalBottomSheet(context: context, builder: (context) => content);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void saveChat(String uuid, Function setState) async {
|
void saveChat(String uuid, Function setState) async {
|
||||||
|
|
32
pubspec.lock
32
pubspec.lock
|
@ -421,6 +421,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.2.1+1"
|
version: "0.2.1+1"
|
||||||
|
install_referrer:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: install_referrer
|
||||||
|
sha256: "901c56d24ee3c3010dfd0bbebf305ed6b4b0f3fe969192081c167590a64cd78b"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.2.1"
|
||||||
intl:
|
intl:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
@ -526,6 +534,22 @@ packages:
|
||||||
url: "https://github.com/davidmigloz/langchain_dart.git"
|
url: "https://github.com/davidmigloz/langchain_dart.git"
|
||||||
source: git
|
source: git
|
||||||
version: "0.1.0+1"
|
version: "0.1.0+1"
|
||||||
|
package_info_plus:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: package_info_plus
|
||||||
|
sha256: b93d8b4d624b4ea19b0a5a208b2d6eff06004bc3ce74c06040b120eeadd00ce0
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "8.0.0"
|
||||||
|
package_info_plus_platform_interface:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: package_info_plus_platform_interface
|
||||||
|
sha256: f49918f3433a3146047372f9d4f1f847511f2acd5cd030e1f44fe5a50036b70e
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.0.0"
|
||||||
path:
|
path:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -835,6 +859,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.4"
|
version: "2.1.4"
|
||||||
|
version:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: version
|
||||||
|
sha256: "3d4140128e6ea10d83da32fef2fa4003fccbf6852217bb854845802f04191f94"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.0.2"
|
||||||
visibility_detector:
|
visibility_detector:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
|
19
pubspec.yaml
19
pubspec.yaml
|
@ -9,22 +9,22 @@ environment:
|
||||||
dependencies:
|
dependencies:
|
||||||
flutter:
|
flutter:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
|
flutter_localizations:
|
||||||
|
sdk: flutter
|
||||||
|
ollama_dart:
|
||||||
|
git:
|
||||||
|
url: https://github.com/davidmigloz/langchain_dart.git
|
||||||
|
path: packages/ollama_dart
|
||||||
|
ref: ce2ef30c9a9a0dfe8f3059988b7007c94c45b9bd
|
||||||
|
intl: any
|
||||||
shared_preferences: ^2.2.3
|
shared_preferences: ^2.2.3
|
||||||
flutter_chat_ui: ^1.6.13
|
flutter_chat_ui: ^1.6.13
|
||||||
uuid: ^4.4.0
|
uuid: ^4.4.0
|
||||||
animated_text_kit: ^4.2.2
|
animated_text_kit: ^4.2.2
|
||||||
image_picker: ^1.1.1
|
image_picker: ^1.1.1
|
||||||
visibility_detector: ^0.4.0+2
|
visibility_detector: ^0.4.0+2
|
||||||
flutter_localizations:
|
|
||||||
sdk: flutter
|
|
||||||
intl: any
|
|
||||||
http: ^1.2.1
|
http: ^1.2.1
|
||||||
dartx: ^1.2.0
|
dartx: ^1.2.0
|
||||||
ollama_dart:
|
|
||||||
git:
|
|
||||||
url: https://github.com/davidmigloz/langchain_dart.git
|
|
||||||
path: packages/ollama_dart
|
|
||||||
ref: ce2ef30c9a9a0dfe8f3059988b7007c94c45b9bd
|
|
||||||
smooth_page_indicator: ^1.1.0
|
smooth_page_indicator: ^1.1.0
|
||||||
transparent_image: ^2.0.1
|
transparent_image: ^2.0.1
|
||||||
simple_icons: ^10.1.3
|
simple_icons: ^10.1.3
|
||||||
|
@ -33,6 +33,9 @@ dependencies:
|
||||||
flutter_markdown: ^0.7.1
|
flutter_markdown: ^0.7.1
|
||||||
file_picker: ^8.0.3
|
file_picker: ^8.0.3
|
||||||
bitsdojo_window: ^0.1.6
|
bitsdojo_window: ^0.1.6
|
||||||
|
install_referrer: ^1.2.1
|
||||||
|
package_info_plus: ^8.0.0
|
||||||
|
version: ^3.0.2
|
||||||
flutter_displaymode: ^0.6.0
|
flutter_displaymode: ^0.6.0
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
|
|
Loading…
Reference in New Issue