diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 814bf01..f97016e 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -12,6 +12,11 @@ on: required: true default: false type: boolean + buildLinuxX64: + description: Build for Linux x64 + required: true + default: false + type: boolean jobs: analyze: @@ -45,6 +50,9 @@ jobs: echo $'storePassword=${{ secrets.ANDROID_KEYSTORE_PASSPHRASE }}\nkeyPassword=${{ secrets.ANDROID_KEYSTORE_PASSPHRASE }}\nkeyAlias=upload\nstoreFile=upload-keystore.jks\n' > ./android/key.properties echo "${{ secrets.ANDROID_KEYSTORE }}" > ./android/app/upload-keystore.jks.asc gpg -d --passphrase "${{ secrets.ANDROID_KEYSTORE_PASSPHRASE }}" --batch ./android/app/upload-keystore.jks.asc > ./android/app/upload-keystore.jks + - name: Get flutter version + id: get_flutter_version + uses: its404/get-flutter-version@v1.0.0 - name: Disabling flutter analytics run: flutter config --no-analytics - name: Running build @@ -52,15 +60,13 @@ jobs: run: flutter build apk --obfuscate --split-debug-info=build/debugAndroid - name: Preparing files run: | - cp build/app/outputs/flutter-apk/app-release.apk build/app/outputs/flutter-apk/ollama.apk - cp build/app/outputs/flutter-apk/app-release.apk.sha1 build/app/outputs/flutter-apk/ollama.apk.sha1 + cp build/app/outputs/flutter-apk/app-release.apk build/app/outputs/flutter-apk/ollama-android-v${{ steps.get_flutter_version.outputs.version_number }}.apk - name: Uploading APK uses: actions/upload-artifact@v4 with: name: ollama-android path: | - build/app/outputs/flutter-apk/ollama.apk - build/app/outputs/flutter-apk/ollama.apk.sha1 + build/app/outputs/flutter-apk/ollama-android-v${{ steps.get_flutter_version.outputs.version_number }}.apk build-windows-x64: name: Building for Windows x64 if: ${{ github.event.inputs.buildWindowsX64 == 'true' }} @@ -88,12 +94,43 @@ jobs: uses: actions/upload-artifact@v4 with: name: ollama-windows-x64 - path: build\windows\x64\runner\ollama-v${{ steps.get_flutter_version.outputs.version_number }}-x64.exe + path: build\windows\x64\runner\ollama-windows-x64-v${{ steps.get_flutter_version.outputs.version_number }}.exe + build-linux-x64: + name: Building for Linux + if: ${{ github.event.inputs.buildLinuxX64 == 'true' }} + runs-on: ubuntu-latest + needs: analyze + steps: + - uses: actions/checkout@v4 + - uses: subosito/flutter-action@v2 + with: + flutter-version: 3.22.1 + - name: Get flutter version + id: get_flutter_version + uses: its404/get-flutter-version@v1.0.0 + - name: Disabling flutter analytics + run: flutter config --no-analytics + - name: Installing linux dependencies + run: | + sudo apt-get install ninja-build + sudo apt-get install build-essential libgtk-3-dev + - name: Running build + id: compile + run: flutter build linux --obfuscate --split-debug-info=build/debugLinux + - name: Creating archive + run: | + cd build/linux/x64/release/bundle + tar -czf ollama-linux-x64-v${{ steps.get_flutter_version.outputs.version_number }}.tar.gz * + - name: Uploading archive + uses: actions/upload-artifact@v4 + with: + name: ollama-linux-x64 + path: build/linux/x64/release/bundle/ollama-linux-x64-v${{ steps.get_flutter_version.outputs.version_number }}.tar.gz bundle: name: Creating bundle runs-on: ubuntu-latest if: ${{ always() }} - needs: [build-android, build-windows-x64] + needs: [build-android, build-windows-x64, build-linux-x64] steps: - name: Adding builds uses: actions/download-artifact@v4 @@ -105,4 +142,4 @@ jobs: uses: actions/upload-artifact@v4 with: name: ollama - path: ./ + path: ./ \ No newline at end of file diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 1069bb9..a548855 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -2,7 +2,8 @@ + android:icon="@mipmap/ic_launcher" + android:enableOnBackInvokedCallback="true"> { ], ), imageBuilder: (uri, title, alt) { + Widget errorImage = InkWell( + onTap: () { + selectionHaptic(); + ScaffoldMessenger.of(context) + .showSnackBar(SnackBar( + content: Text( + AppLocalizations.of( + context)! + .notAValidImage), + showCloseIcon: true)); + }, + child: Container( + decoration: BoxDecoration( + borderRadius: + BorderRadius + .circular(8), + color: Theme.of(context) + .brightness == + Brightness.light + ? Colors.white + : Colors.black), + padding: + const EdgeInsets.only( + left: 100, + right: 100, + top: 32), + child: const Image( + image: AssetImage( + "assets/logo512error.png")))); if (uri.isAbsolute) { return Image.network( uri.toString(), errorBuilder: (context, error, stackTrace) { - return InkWell( - onTap: () { - selectionHaptic(); - ScaffoldMessenger.of( - context) - .showSnackBar(SnackBar( - content: Text( - AppLocalizations.of( - context)! - .notAValidImage), - showCloseIcon: - true)); - }, - child: Container( - decoration: BoxDecoration( - borderRadius: - BorderRadius - .circular( - 8), - color: Theme.of(context) - .brightness == - Brightness - .light - ? Colors.white - : Colors.black), - padding: - const EdgeInsets - .only( - left: 100, - right: 100, - top: 32), - child: const Image( - image: AssetImage( - "assets/logo512error.png")))); + return errorImage; }); } else { - return InkWell( - onTap: () { - selectionHaptic(); - ScaffoldMessenger.of( - context) - .showSnackBar(SnackBar( - content: Text( - AppLocalizations.of( - context)! - .notAValidImage), - showCloseIcon: - true)); - }, - child: Container( - decoration: BoxDecoration( - borderRadius: - BorderRadius - .circular(8), - color: Theme.of(context) - .brightness == - Brightness - .light - ? Colors.white - : Colors.black), - padding: - const EdgeInsets.only( - left: 100, - right: 100, - top: 32), - child: const Image( - image: AssetImage( - "assets/logo512error.png")))); + return errorImage; } }, styleSheet: (p0.author == user) @@ -1535,7 +1500,9 @@ class _MainAppState extends State { : null : () { selectionHaptic(); - if (!chatAllowed || model == null) return; + if (!chatAllowed || model == null) { + return; + } if (desktopFeature()) { FilePicker.platform .pickFiles(type: FileType.image) diff --git a/lib/settings/about.dart b/lib/settings/about.dart index b5b3a81..854bfc2 100644 --- a/lib/settings/about.dart +++ b/lib/settings/about.dart @@ -123,13 +123,37 @@ class _ScreenSettingsAboutState extends State { mode: LaunchMode.inAppBrowserView, Uri.parse("$repoUrl/issues")); }), - button(AppLocalizations.of(context)!.settingsMainDeveloper, - Icons.developer_board_rounded, () { + button(AppLocalizations.of(context)!.settingsLicenses, + Icons.gavel_rounded, () { selectionHaptic(); - launchUrl( - mode: LaunchMode.inAppBrowserView, - Uri.parse( - repoUrl.substring(0, repoUrl.lastIndexOf('/')))); + 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) ]), diff --git a/lib/settings/export.dart b/lib/settings/export.dart index fc31956..c5c344d 100644 --- a/lib/settings/export.dart +++ b/lib/settings/export.dart @@ -1,7 +1,6 @@ import 'dart:io'; import 'dart:convert'; -// ignore: avoid_web_libraries_in_flutter -import 'dart:html' as html; +import 'package:universal_html/html.dart' as html; import 'package:flutter/material.dart'; import 'package:flutter/foundation.dart'; @@ -14,6 +13,7 @@ import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:bitsdojo_window/bitsdojo_window.dart'; import 'package:file_picker/file_picker.dart'; +import 'package:file_selector/file_selector.dart' as file_selector; import 'package:intl/intl.dart'; import 'package:dynamic_color/dynamic_color.dart'; @@ -50,6 +50,7 @@ class _ScreenSettingsExportState extends State { 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); @@ -65,18 +66,34 @@ class _ScreenSettingsExportState extends State { html.document.body!.children.remove(anchor); html.Url.revokeObjectUrl(url); } else { - var path = await FilePicker.platform.saveFile( - type: FileType.custom, - allowedExtensions: ["json"], - fileName: name, - bytes: utf8.encode(jsonEncode( - prefs!.getStringList("chats") ?? []))); + 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( @@ -104,30 +121,54 @@ class _ScreenSettingsExportState extends State { TextButton( onPressed: () async { selectionHaptic(); - FilePickerResult? result = - await FilePicker.platform - .pickFiles( - type: FileType.custom, - allowedExtensions: [ - "json" - ]); - if (result == null) { - // ignore: use_build_context_synchronously - Navigator.of(context).pop(); - return; - } - String content; try { - File file = File( - result.files.single.path!); + 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 file.readAsString(); + await result.readAsString(); } catch (_) { - content = utf8.decode(result - .files - .single - .bytes as List); + 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); + } } List tmpHistory = jsonDecode(content); diff --git a/lib/settings/voice.dart b/lib/settings/voice.dart index 0af758a..0de3fe3 100644 --- a/lib/settings/voice.dart +++ b/lib/settings/voice.dart @@ -95,14 +95,10 @@ class _ScreenSettingsVoiceState extends State { : !(permissionBluetooth && permissionRecord) ? AppLocalizations.of(context)! .settingsVoicePermissionNot - : !(prefs!.getBool( - "voiceModeEnabled") ?? - false) - ? AppLocalizations.of(context)! - .settingsVoiceNotEnabled - : AppLocalizations.of(context)! - .settingsVoiceNotSupported, + : AppLocalizations.of(context)! + .settingsVoiceNotSupported, Icons.info_rounded, () { + selectionHaptic(); if (permissionLoading) return; if (!(permissionBluetooth && permissionRecord)) { void load() async { @@ -139,7 +135,6 @@ class _ScreenSettingsVoiceState extends State { } else if (!voiceLanguageOptions.contains( (prefs!.getString("voiceLanguage") ?? "en_US"))) { - selectionHaptic(); ScaffoldMessenger.of(context).showSnackBar(SnackBar( content: Text(AppLocalizations.of(context)! .settingsVoiceTtsNotSupportedDescription), diff --git a/lib/worker/sender.dart b/lib/worker/sender.dart index d6711df..4759c14 100644 --- a/lib/worker/sender.dart +++ b/lib/worker/sender.dart @@ -79,6 +79,9 @@ Future getTitleAi(List history) async { .replaceAll("_", "") .replaceAll("\n", " ") .trim(); + while (title.contains(" ")) { + title = title.replaceAll(" ", " "); + } return title; } @@ -169,58 +172,58 @@ Future send(String value, BuildContext context, Function setState, baseUrl: "$host/api"); try { - if ((prefs!.getString("requestType") ?? "stream") == "stream") { - final stream = client - .generateChatCompletionStream( - request: llama.GenerateChatCompletionRequest( - model: model!, - messages: history, - keepAlive: int.parse(prefs!.getString("keepAlive") ?? "300")), - ) - .timeout(const Duration(seconds: 30)); + if ((prefs!.getString("requestType") ?? "stream") == "stream") { + final stream = client + .generateChatCompletionStream( + request: llama.GenerateChatCompletionRequest( + model: model!, + messages: history, + keepAlive: int.parse(prefs!.getString("keepAlive") ?? "300")), + ) + .timeout(const Duration(seconds: 30)); - await for (final res in stream) { - text += (res.message?.content ?? ""); - for (var i = 0; i < messages.length; i++) { - if (messages[i].id == newId) { - messages.removeAt(i); - break; + await for (final res in stream) { + text += (res.message?.content ?? ""); + for (var i = 0; i < messages.length; i++) { + if (messages[i].id == newId) { + messages.removeAt(i); + break; + } } + if (chatAllowed) return ""; + // if (text.trim() == "") { + // throw Exception(); + // } + messages.insert( + 0, types.TextMessage(author: assistant, id: newId, text: text)); + if (onStream != null) { + onStream(text, false); + } + setState(() {}); + heavyHaptic(); } + } else { + llama.GenerateChatCompletionResponse request; + request = await client + .generateChatCompletion( + request: llama.GenerateChatCompletionRequest( + model: model!, + messages: history, + keepAlive: int.parse(prefs!.getString("keepAlive") ?? "300")), + ) + .timeout(const Duration(seconds: 30)); if (chatAllowed) return ""; - // if (text.trim() == "") { + // if (request.message!.content.trim() == "") { // throw Exception(); // } messages.insert( - 0, types.TextMessage(author: assistant, id: newId, text: text)); - if (onStream != null) { - onStream(text, false); - } + 0, + types.TextMessage( + author: assistant, id: newId, text: request.message!.content)); + text = request.message!.content; setState(() {}); heavyHaptic(); } - } else { - llama.GenerateChatCompletionResponse request; - request = await client - .generateChatCompletion( - request: llama.GenerateChatCompletionRequest( - model: model!, - messages: history, - keepAlive: int.parse(prefs!.getString("keepAlive") ?? "300")), - ) - .timeout(const Duration(seconds: 30)); - if (chatAllowed) return ""; - // if (request.message!.content.trim() == "") { - // throw Exception(); - // } - messages.insert( - 0, - types.TextMessage( - author: assistant, id: newId, text: request.message!.content)); - text = request.message!.content; - setState(() {}); - heavyHaptic(); - } } catch (e) { for (var i = 0; i < messages.length; i++) { if (messages[i].id == newId) { diff --git a/lib/worker/setter.dart b/lib/worker/setter.dart index 3427b00..ea16aad 100644 --- a/lib/worker/setter.dart +++ b/lib/worker/setter.dart @@ -216,12 +216,8 @@ void setModel(BuildContext context, Function setState) { ? ((MediaQuery.of(context) .platformBrightness == Brightness.light) - ? themeLight() - .colorScheme - .secondary - : themeDark() - .colorScheme - .secondary) + ? themeLight().colorScheme.secondary + : themeDark().colorScheme.secondary) : null, labelStyle: (usedIndex == index && !(prefs?.getBool( @@ -245,12 +241,8 @@ void setModel(BuildContext context, Function setState) { : (MediaQuery.of(context) .platformBrightness == Brightness.light) - ?themeLight() - .colorScheme - .primary - : themeDark() - .colorScheme - .primary, + ? themeLight().colorScheme.primary + : themeDark().colorScheme.primary, onSelected: (bool selected) { selectionHaptic(); if (addIndex == index) { @@ -539,7 +531,11 @@ Future prompt(BuildContext context, uuid) { try { var title = await getTitleAi( - await getHistory()); + jsonDecode(jsonDecode( + (prefs!.getStringList( + "chats") ?? + [])[ + i])["messages"])); controller.text = title; setLocalState(() { loading = false; diff --git a/lib/worker/theme.dart b/lib/worker/theme.dart index c82d0f7..b2827f8 100644 --- a/lib/worker/theme.dart +++ b/lib/worker/theme.dart @@ -54,10 +54,20 @@ void resetSystemNavigation(BuildContext context, }); } +ThemeData themeModifier(ThemeData theme) { + return theme.copyWith( + // https://docs.flutter.dev/platform-integration/android/predictive-back#set-up-your-app + pageTransitionsTheme: const PageTransitionsTheme( + builders: { + TargetPlatform.android: PredictiveBackPageTransitionsBuilder(), + }, + )); +} + ThemeData themeLight() { if (!(prefs?.getBool("useDeviceTheme") ?? false) || colorSchemeLight == null) { - return ThemeData.from( + return themeModifier(ThemeData.from( colorScheme: const ColorScheme( brightness: Brightness.light, primary: Colors.black, @@ -67,15 +77,15 @@ ThemeData themeLight() { error: Colors.red, onError: Colors.white, surface: Colors.white, - onSurface: Colors.black)); + onSurface: Colors.black))); } else { - return ThemeData.from(colorScheme: colorSchemeLight!); + return themeModifier(ThemeData.from(colorScheme: colorSchemeLight!)); } } ThemeData themeDark() { if (!(prefs?.getBool("useDeviceTheme") ?? false) || colorSchemeDark == null) { - return ThemeData.from( + return themeModifier(ThemeData.from( colorScheme: const ColorScheme( brightness: Brightness.dark, primary: Colors.white, @@ -85,9 +95,9 @@ ThemeData themeDark() { error: Colors.red, onError: Colors.black, surface: Colors.black, - onSurface: Colors.white)); + onSurface: Colors.white))); } else { - return ThemeData.from(colorScheme: colorSchemeDark!); + return themeModifier(ThemeData.from(colorScheme: colorSchemeDark!)); } } diff --git a/pubspec.lock b/pubspec.lock index 175338e..a886f4c 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -81,6 +81,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.3.0" + charcode: + dependency: transitive + description: + name: charcode + sha256: fb98c0f6d12c920a02ee2d998da788bca066ca5f148492b7085ee23372b12306 + url: "https://pub.dev" + source: hosted + version: "1.3.1" clock: dependency: transitive description: @@ -101,10 +109,10 @@ packages: dependency: transitive description: name: cross_file - sha256: "55d7b444feb71301ef6b8838dbc1ae02e63dd48c8773f3810ff53bb1e2945b32" + sha256: "7caf6a750a0c04effbb52a676dce9a4a592e10ad35c34d6d2d0e4811160d5670" url: "https://pub.dev" source: hosted - version: "0.3.4+1" + version: "0.3.4+2" crypto: dependency: transitive description: @@ -213,10 +221,34 @@ packages: dependency: "direct main" description: name: file_picker - sha256: "29c90806ac5f5fb896547720b73b17ee9aed9bba540dc5d91fe29f8c5745b10a" + sha256: "167bb619cdddaa10ef2907609feb8a79c16dfa479d3afaf960f8e223f754bf12" url: "https://pub.dev" source: hosted - version: "8.0.3" + version: "8.1.2" + file_selector: + dependency: "direct main" + description: + name: file_selector + sha256: "5019692b593455127794d5718304ff1ae15447dea286cdda9f0db2a796a1b828" + url: "https://pub.dev" + source: hosted + version: "1.0.3" + file_selector_android: + dependency: transitive + description: + name: file_selector_android + sha256: "77f23eb5916fd0875946720d1f286f809a28a867d4882db6ac2cf053e2d5f7c6" + url: "https://pub.dev" + source: hosted + version: "0.5.1+6" + file_selector_ios: + dependency: transitive + description: + name: file_selector_ios + sha256: "38ebf91ecbcfa89a9639a0854ccaed8ab370c75678938eebca7d34184296f0bb" + url: "https://pub.dev" + source: hosted + version: "0.5.3" file_selector_linux: dependency: transitive description: @@ -241,6 +273,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.6.2" + file_selector_web: + dependency: transitive + description: + name: file_selector_web + sha256: c4c0ea4224d97a60a7067eca0c8fd419e708ff830e0c83b11a48faf566cec3e7 + url: "https://pub.dev" + source: hosted + version: "0.9.4+2" file_selector_windows: dependency: transitive description: @@ -377,10 +417,10 @@ packages: dependency: "direct main" description: name: http - sha256: "761a297c042deedc1ffbb156d6e2af13886bb305c2a343a4d972504cd67dd938" + sha256: b9c29a161230ee03d3ccf545097fccd9b87a5264228c5d348202e0f0c28f9010 url: "https://pub.dev" source: hosted - version: "1.2.1" + version: "1.2.2" http_parser: dependency: transitive description: @@ -409,10 +449,10 @@ packages: dependency: transitive description: name: image_picker_for_web - sha256: "5d6eb13048cd47b60dbf1a5495424dea226c5faf3950e20bf8120a58efb5b5f3" + sha256: "65d94623e15372c5c51bebbcb820848d7bcb323836e12dfdba60b5d3a8b39e50" url: "https://pub.dev" source: hosted - version: "3.0.4" + version: "3.0.5" image_picker_ios: dependency: transitive description: @@ -577,18 +617,18 @@ packages: dependency: "direct main" description: name: package_info_plus - sha256: b93d8b4d624b4ea19b0a5a208b2d6eff06004bc3ce74c06040b120eeadd00ce0 + sha256: a75164ade98cb7d24cfd0a13c6408927c6b217fa60dee5a7ff5c116a58f28918 url: "https://pub.dev" source: hosted - version: "8.0.0" + version: "8.0.2" package_info_plus_platform_interface: dependency: transitive description: name: package_info_plus_platform_interface - sha256: f49918f3433a3146047372f9d4f1f847511f2acd5cd030e1f44fe5a50036b70e + sha256: ac1f4a4847f1ade8e6a87d1f39f5d7c67490738642e2542f559ec38c37489a66 url: "https://pub.dev" source: hosted - version: "3.0.0" + version: "3.0.1" path: dependency: transitive description: @@ -761,10 +801,10 @@ packages: dependency: transitive description: name: shared_preferences_web - sha256: "9aee1089b36bd2aafe06582b7d7817fd317ef05fc30e6ba14bff247d0933042a" + sha256: d762709c2bbe80626ecc819143013cc820fa49ca5e363620ee20a8b15a3e3daf url: "https://pub.dev" source: hosted - version: "2.3.0" + version: "2.2.1" shared_preferences_windows: dependency: transitive description: @@ -898,6 +938,22 @@ packages: url: "https://pub.dev" source: hosted version: "1.3.2" + universal_html: + dependency: "direct main" + description: + name: universal_html + sha256: "56536254004e24d9d8cfdb7dbbf09b74cf8df96729f38a2f5c238163e3d58971" + url: "https://pub.dev" + source: hosted + version: "2.2.4" + universal_io: + dependency: transitive + description: + name: universal_io + sha256: "1722b2dcc462b4b2f3ee7d188dad008b6eb4c40bbd03a3de451d82c78bba9aad" + url: "https://pub.dev" + source: hosted + version: "2.2.2" url_launcher: dependency: "direct main" description: @@ -950,10 +1006,10 @@ packages: dependency: transitive description: name: url_launcher_web - sha256: "8d9e750d8c9338601e709cd0885f95825086bd8b642547f26bda435aade95d8a" + sha256: "772638d3b34c779ede05ba3d38af34657a05ac55b06279ea6edd409e323dca8e" url: "https://pub.dev" source: hosted - version: "2.3.1" + version: "2.3.3" url_launcher_windows: dependency: transitive description: @@ -1014,10 +1070,10 @@ packages: dependency: transitive description: name: web - sha256: "97da13628db363c635202ad97068d47c5b8aa555808e7a9411963c533b449b27" + sha256: d43c1d6b787bf0afad444700ae7f4db8827f701bc61c255ac8d328c6f4d52062 url: "https://pub.dev" source: hosted - version: "0.5.1" + version: "1.0.0" win32: dependency: transitive description: @@ -1036,4 +1092,4 @@ packages: version: "1.0.4" sdks: dart: ">=3.4.0 <4.0.0" - flutter: ">=3.19.0" + flutter: ">=3.22.0" diff --git a/pubspec.yaml b/pubspec.yaml index ab19d47..f78b8c8 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -28,6 +28,7 @@ dependencies: restart_app: ^1.2.1 flutter_markdown: ^0.7.1 file_picker: ^8.0.3 + file_selector: ^1.0.3 bitsdojo_window: ^0.1.6 install_referrer: ^1.2.1 package_info_plus: ^8.0.0 @@ -40,6 +41,7 @@ dependencies: datetime_loop: ^1.2.0 dynamic_color: ^1.7.0 volume_controller: ^2.0.7 + universal_html: ^2.2.4 dev_dependencies: flutter_test: diff --git a/scripts/build.dart b/scripts/build.dart index 773d7f0..c4711e8 100644 --- a/scripts/build.dart +++ b/scripts/build.dart @@ -32,18 +32,18 @@ void main() async { // ---------- - await execute('Windows x64', flutterExecutable, [ - 'build', - 'windows', - '--obfuscate', - '--split-debug-info=build\\debugWindows' - ]); + // await execute('Windows x64', flutterExecutable, [ + // 'build', + // 'windows', + // '--obfuscate', + // '--split-debug-info=build\\debugWindows' + // ]); - await execute( - 'Windows x64 installer', - 'iscc.exe', - ['windows_installer/x64.iss', '/qp', '/dAppVersion=$version'], - " > Inno Setup is not installed. Please install it from https://www.jrsoftware.org/isdl.php#stable\n Then add the Inno Setup directory to your PATH environment variable."); + // await execute( + // 'Windows x64 installer', + // 'iscc.exe', + // ['windows_installer/x64.iss', '/qp', '/dAppVersion=$version'], + // " > Inno Setup is not installed. Please install it from https://www.jrsoftware.org/isdl.php#stable\n Then add the Inno Setup directory to your PATH environment variable."); // ---------- diff --git a/untranslated_messages.json b/untranslated_messages.json index c3704c3..c098fe4 100644 --- a/untranslated_messages.json +++ b/untranslated_messages.json @@ -16,7 +16,9 @@ "settingsTemporaryFixesNoFixes", "settingsVoiceTtsNotSupported", "settingsVoiceTtsNotSupportedDescription", - "settingsVoiceNotEnabled" + "settingsVoiceNotEnabled", + "settingsExportChatsSuccess", + "settingsLicenses" ], "it": [ @@ -36,7 +38,9 @@ "settingsTemporaryFixesNoFixes", "settingsVoiceTtsNotSupported", "settingsVoiceTtsNotSupportedDescription", - "settingsVoiceNotEnabled" + "settingsVoiceNotEnabled", + "settingsExportChatsSuccess", + "settingsLicenses" ], "tr": [ @@ -56,7 +60,9 @@ "settingsTemporaryFixesNoFixes", "settingsVoiceTtsNotSupported", "settingsVoiceTtsNotSupportedDescription", - "settingsVoiceNotEnabled" + "settingsVoiceNotEnabled", + "settingsExportChatsSuccess", + "settingsLicenses" ], "zh": [ @@ -76,6 +82,8 @@ "settingsTemporaryFixesNoFixes", "settingsVoiceTtsNotSupported", "settingsVoiceTtsNotSupportedDescription", - "settingsVoiceNotEnabled" + "settingsVoiceNotEnabled", + "settingsExportChatsSuccess", + "settingsLicenses" ] } diff --git a/windows_installer/arm64.iss b/windows_installer/arm64.iss index 8d8cc8f..c1c1122 100644 --- a/windows_installer/arm64.iss +++ b/windows_installer/arm64.iss @@ -1,7 +1,7 @@ ; Script generated by the Inno Setup Script Wizard. ; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES! -; #define AppVersion "1.0.1" +;#define AppVersion "1.0.1" #define AppName "Ollama App" #define AppPublisher "JHubi1" @@ -27,7 +27,7 @@ UninstallDisplayName={#AppName} DefaultDirName={autopf}\OllamaApp OutputDir=build\windows\{#AppArchitectures}\runner -OutputBaseFilename=ollama-v{#AppVersion}-{#AppArchitectures} +OutputBaseFilename=ollama-windows-{#AppArchitectures}-v{#AppVersion} AppSupportURL=https://github.com/JHubi1/ollama-app/issues AppUpdatesURL=https://github.com/JHubi1/ollama-app/releases diff --git a/windows_installer/x64.iss b/windows_installer/x64.iss index 97d3cf0..e8b25c2 100644 --- a/windows_installer/x64.iss +++ b/windows_installer/x64.iss @@ -28,7 +28,7 @@ UninstallDisplayName={#AppName} DefaultDirName={autopf}\OllamaApp OutputDir=build\windows\{#AppArchitectures}\runner -OutputBaseFilename=ollama-v{#AppVersion}-{#AppArchitectures} +OutputBaseFilename=ollama-windows-{#AppArchitectures}-v{#AppVersion} AppSupportURL=https://github.com/JHubi1/ollama-app/issues AppUpdatesURL=https://github.com/JHubi1/ollama-app/releases