This commit is contained in:
JHubi1 2024-08-20 20:31:51 +02:00
commit 4d63da801c
No known key found for this signature in database
GPG Key ID: F538DC3FC5B07498
17 changed files with 364 additions and 218 deletions

View File

@ -12,6 +12,11 @@ on:
required: true required: true
default: false default: false
type: boolean type: boolean
buildLinuxX64:
description: Build for Linux x64
required: true
default: false
type: boolean
jobs: jobs:
analyze: 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 $'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 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 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 - name: Disabling flutter analytics
run: flutter config --no-analytics run: flutter config --no-analytics
- name: Running build - name: Running build
@ -52,15 +60,13 @@ jobs:
run: flutter build apk --obfuscate --split-debug-info=build/debugAndroid run: flutter build apk --obfuscate --split-debug-info=build/debugAndroid
- name: Preparing files - name: Preparing files
run: | 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 build/app/outputs/flutter-apk/ollama-android-v${{ steps.get_flutter_version.outputs.version_number }}.apk
cp build/app/outputs/flutter-apk/app-release.apk.sha1 build/app/outputs/flutter-apk/ollama.apk.sha1
- name: Uploading APK - name: Uploading APK
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4
with: with:
name: ollama-android name: ollama-android
path: | path: |
build/app/outputs/flutter-apk/ollama.apk build/app/outputs/flutter-apk/ollama-android-v${{ steps.get_flutter_version.outputs.version_number }}.apk
build/app/outputs/flutter-apk/ollama.apk.sha1
build-windows-x64: build-windows-x64:
name: Building for Windows x64 name: Building for Windows x64
if: ${{ github.event.inputs.buildWindowsX64 == 'true' }} if: ${{ github.event.inputs.buildWindowsX64 == 'true' }}
@ -88,12 +94,43 @@ jobs:
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4
with: with:
name: ollama-windows-x64 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: bundle:
name: Creating bundle name: Creating bundle
runs-on: ubuntu-latest runs-on: ubuntu-latest
if: ${{ always() }} if: ${{ always() }}
needs: [build-android, build-windows-x64] needs: [build-android, build-windows-x64, build-linux-x64]
steps: steps:
- name: Adding builds - name: Adding builds
uses: actions/download-artifact@v4 uses: actions/download-artifact@v4
@ -105,4 +142,4 @@ jobs:
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4
with: with:
name: ollama name: ollama
path: ./ path: ./

View File

@ -2,7 +2,8 @@
<application <application
android:label="Ollama" android:label="Ollama"
android:name="${applicationName}" android:name="${applicationName}"
android:icon="@mipmap/ic_launcher"> android:icon="@mipmap/ic_launcher"
android:enableOnBackInvokedCallback="true">
<activity <activity
android:name=".MainActivity" android:name=".MainActivity"
android:exported="true" android:exported="true"

View File

@ -1,4 +1,5 @@
arb-dir: lib/l10n arb-dir: lib/l10n
template-arb-file: app_en.arb template-arb-file: app_en.arb
preferred-supported-locales: en
output-localization-file: app_localizations.dart output-localization-file: app_localizations.dart
untranslated-messages-file: untranslated_messages.json untranslated-messages-file: untranslated_messages.json

View File

@ -544,6 +544,11 @@
"description": "Text displayed as description for export chats button", "description": "Text displayed as description for export chats button",
"context": "Visible in the settings view" "context": "Visible in the settings view"
}, },
"settingsExportChatsSuccess": "Chats exported successfully",
"@settingsExportChatsSuccess": {
"description": "Text displayed when chats are exported successfully",
"context": "Visible in the settings view"
},
"settingsImportChats": "Import chats", "settingsImportChats": "Import chats",
"@settingsImportChats": { "@settingsImportChats": {
"description": "Text displayed as description for import chats button", "description": "Text displayed as description for import chats button",
@ -660,9 +665,9 @@
"description": "Text displayed as description for report issue button", "description": "Text displayed as description for report issue button",
"context": "Visible in the settings view" "context": "Visible in the settings view"
}, },
"settingsMainDeveloper": "Main Developer", "settingsLicenses": "Licenses",
"@settingsMainDeveloper": { "@settingsLicenses": {
"description": "Text displayed as description for main developer button", "description": "Text displayed as description for licenses button",
"context": "Visible in the settings view" "context": "Visible in the settings view"
}, },
"settingsVersion": "Ollama App v{version}", "settingsVersion": "Ollama App v{version}",

View File

@ -1261,79 +1261,44 @@ class _MainAppState extends State<MainApp> {
], ],
), ),
imageBuilder: (uri, title, alt) { 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) { if (uri.isAbsolute) {
return Image.network( return Image.network(
uri.toString(), errorBuilder: uri.toString(), errorBuilder:
(context, error, (context, error,
stackTrace) { stackTrace) {
return InkWell( return errorImage;
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"))));
}); });
} else { } else {
return InkWell( return errorImage;
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"))));
} }
}, },
styleSheet: (p0.author == user) styleSheet: (p0.author == user)
@ -1535,7 +1500,9 @@ class _MainAppState extends State<MainApp> {
: null : null
: () { : () {
selectionHaptic(); selectionHaptic();
if (!chatAllowed || model == null) return; if (!chatAllowed || model == null) {
return;
}
if (desktopFeature()) { if (desktopFeature()) {
FilePicker.platform FilePicker.platform
.pickFiles(type: FileType.image) .pickFiles(type: FileType.image)

View File

@ -123,13 +123,37 @@ class _ScreenSettingsAboutState extends State<ScreenSettingsAbout> {
mode: LaunchMode.inAppBrowserView, mode: LaunchMode.inAppBrowserView,
Uri.parse("$repoUrl/issues")); Uri.parse("$repoUrl/issues"));
}), }),
button(AppLocalizations.of(context)!.settingsMainDeveloper, button(AppLocalizations.of(context)!.settingsLicenses,
Icons.developer_board_rounded, () { Icons.gavel_rounded, () {
selectionHaptic(); selectionHaptic();
launchUrl( String legal = "Copyright 2024 JHubi1";
mode: LaunchMode.inAppBrowserView, Widget icon = const Padding(
Uri.parse( padding: EdgeInsets.all(16),
repoUrl.substring(0, repoUrl.lastIndexOf('/')))); 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) const SizedBox(height: 16)
]), ]),

View File

@ -1,7 +1,6 @@
import 'dart:io'; import 'dart:io';
import 'dart:convert'; import 'dart:convert';
// ignore: avoid_web_libraries_in_flutter import 'package:universal_html/html.dart' as html;
import 'dart:html' as html;
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/foundation.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:bitsdojo_window/bitsdojo_window.dart';
import 'package:file_picker/file_picker.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:intl/intl.dart';
import 'package:dynamic_color/dynamic_color.dart'; import 'package:dynamic_color/dynamic_color.dart';
@ -50,6 +50,7 @@ class _ScreenSettingsExportState extends State<ScreenSettingsExport> {
var content = var content =
jsonEncode(prefs!.getStringList("chats") ?? []); jsonEncode(prefs!.getStringList("chats") ?? []);
if (kIsWeb) { if (kIsWeb) {
// web fallback
final bytes = utf8.encode(content); final bytes = utf8.encode(content);
final blob = html.Blob([bytes]); final blob = html.Blob([bytes]);
final url = html.Url.createObjectUrlFromBlob(blob); final url = html.Url.createObjectUrlFromBlob(blob);
@ -65,18 +66,34 @@ class _ScreenSettingsExportState extends State<ScreenSettingsExport> {
html.document.body!.children.remove(anchor); html.document.body!.children.remove(anchor);
html.Url.revokeObjectUrl(url); html.Url.revokeObjectUrl(url);
} else { } else {
var path = await FilePicker.platform.saveFile( String? path = "";
type: FileType.custom, try {
allowedExtensions: ["json"], path = (await file_selector
fileName: name, .getSaveLocation(acceptedTypeGroups: [
bytes: utf8.encode(jsonEncode( const file_selector.XTypeGroup(
prefs!.getStringList("chats") ?? []))); 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(); selectionHaptic();
if (path == null) return; if (path == null) return;
if (desktopFeature()) { if (desktopFeature()) {
File(path).writeAsString(content); 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 allowMultipleChats
? button( ? button(
@ -104,30 +121,54 @@ class _ScreenSettingsExportState extends State<ScreenSettingsExport> {
TextButton( TextButton(
onPressed: () async { onPressed: () async {
selectionHaptic(); 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; String content;
try { try {
File file = File( if (kIsWeb) {
result.files.single.path!); 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 = content =
await file.readAsString(); await result.readAsString();
} catch (_) { } catch (_) {
content = utf8.decode(result FilePickerResult? result =
.files await FilePicker.platform
.single .pickFiles(
.bytes as List<int>); 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 = List<dynamic> tmpHistory =
jsonDecode(content); jsonDecode(content);

View File

@ -95,14 +95,10 @@ class _ScreenSettingsVoiceState extends State<ScreenSettingsVoice> {
: !(permissionBluetooth && permissionRecord) : !(permissionBluetooth && permissionRecord)
? AppLocalizations.of(context)! ? AppLocalizations.of(context)!
.settingsVoicePermissionNot .settingsVoicePermissionNot
: !(prefs!.getBool( : AppLocalizations.of(context)!
"voiceModeEnabled") ?? .settingsVoiceNotSupported,
false)
? AppLocalizations.of(context)!
.settingsVoiceNotEnabled
: AppLocalizations.of(context)!
.settingsVoiceNotSupported,
Icons.info_rounded, () { Icons.info_rounded, () {
selectionHaptic();
if (permissionLoading) return; if (permissionLoading) return;
if (!(permissionBluetooth && permissionRecord)) { if (!(permissionBluetooth && permissionRecord)) {
void load() async { void load() async {
@ -139,7 +135,6 @@ class _ScreenSettingsVoiceState extends State<ScreenSettingsVoice> {
} else if (!voiceLanguageOptions.contains( } else if (!voiceLanguageOptions.contains(
(prefs!.getString("voiceLanguage") ?? (prefs!.getString("voiceLanguage") ??
"en_US"))) { "en_US"))) {
selectionHaptic();
ScaffoldMessenger.of(context).showSnackBar(SnackBar( ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text(AppLocalizations.of(context)! content: Text(AppLocalizations.of(context)!
.settingsVoiceTtsNotSupportedDescription), .settingsVoiceTtsNotSupportedDescription),

View File

@ -79,6 +79,9 @@ Future<String> getTitleAi(List history) async {
.replaceAll("_", "") .replaceAll("_", "")
.replaceAll("\n", " ") .replaceAll("\n", " ")
.trim(); .trim();
while (title.contains(" ")) {
title = title.replaceAll(" ", " ");
}
return title; return title;
} }
@ -169,58 +172,58 @@ Future<String> send(String value, BuildContext context, Function setState,
baseUrl: "$host/api"); baseUrl: "$host/api");
try { try {
if ((prefs!.getString("requestType") ?? "stream") == "stream") { if ((prefs!.getString("requestType") ?? "stream") == "stream") {
final stream = client final stream = client
.generateChatCompletionStream( .generateChatCompletionStream(
request: llama.GenerateChatCompletionRequest( request: llama.GenerateChatCompletionRequest(
model: model!, model: model!,
messages: history, messages: history,
keepAlive: int.parse(prefs!.getString("keepAlive") ?? "300")), keepAlive: int.parse(prefs!.getString("keepAlive") ?? "300")),
) )
.timeout(const Duration(seconds: 30)); .timeout(const Duration(seconds: 30));
await for (final res in stream) { await for (final res in stream) {
text += (res.message?.content ?? ""); text += (res.message?.content ?? "");
for (var i = 0; i < messages.length; i++) { for (var i = 0; i < messages.length; i++) {
if (messages[i].id == newId) { if (messages[i].id == newId) {
messages.removeAt(i); messages.removeAt(i);
break; 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 (chatAllowed) return "";
// if (text.trim() == "") { // if (request.message!.content.trim() == "") {
// throw Exception(); // throw Exception();
// } // }
messages.insert( messages.insert(
0, types.TextMessage(author: assistant, id: newId, text: text)); 0,
if (onStream != null) { types.TextMessage(
onStream(text, false); author: assistant, id: newId, text: request.message!.content));
} text = request.message!.content;
setState(() {}); setState(() {});
heavyHaptic(); 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) { } catch (e) {
for (var i = 0; i < messages.length; i++) { for (var i = 0; i < messages.length; i++) {
if (messages[i].id == newId) { if (messages[i].id == newId) {

View File

@ -216,12 +216,8 @@ void setModel(BuildContext context, Function setState) {
? ((MediaQuery.of(context) ? ((MediaQuery.of(context)
.platformBrightness == .platformBrightness ==
Brightness.light) Brightness.light)
? themeLight() ? themeLight().colorScheme.secondary
.colorScheme : themeDark().colorScheme.secondary)
.secondary
: themeDark()
.colorScheme
.secondary)
: null, : null,
labelStyle: (usedIndex == index && labelStyle: (usedIndex == index &&
!(prefs?.getBool( !(prefs?.getBool(
@ -245,12 +241,8 @@ void setModel(BuildContext context, Function setState) {
: (MediaQuery.of(context) : (MediaQuery.of(context)
.platformBrightness == .platformBrightness ==
Brightness.light) Brightness.light)
?themeLight() ? themeLight().colorScheme.primary
.colorScheme : themeDark().colorScheme.primary,
.primary
: themeDark()
.colorScheme
.primary,
onSelected: (bool selected) { onSelected: (bool selected) {
selectionHaptic(); selectionHaptic();
if (addIndex == index) { if (addIndex == index) {
@ -539,7 +531,11 @@ Future<String> prompt(BuildContext context,
uuid) { uuid) {
try { try {
var title = await getTitleAi( var title = await getTitleAi(
await getHistory()); jsonDecode(jsonDecode(
(prefs!.getStringList(
"chats") ??
[])[
i])["messages"]));
controller.text = title; controller.text = title;
setLocalState(() { setLocalState(() {
loading = false; loading = false;

View File

@ -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, PageTransitionsBuilder>{
TargetPlatform.android: PredictiveBackPageTransitionsBuilder(),
},
));
}
ThemeData themeLight() { ThemeData themeLight() {
if (!(prefs?.getBool("useDeviceTheme") ?? false) || if (!(prefs?.getBool("useDeviceTheme") ?? false) ||
colorSchemeLight == null) { colorSchemeLight == null) {
return ThemeData.from( return themeModifier(ThemeData.from(
colorScheme: const ColorScheme( colorScheme: const ColorScheme(
brightness: Brightness.light, brightness: Brightness.light,
primary: Colors.black, primary: Colors.black,
@ -67,15 +77,15 @@ ThemeData themeLight() {
error: Colors.red, error: Colors.red,
onError: Colors.white, onError: Colors.white,
surface: Colors.white, surface: Colors.white,
onSurface: Colors.black)); onSurface: Colors.black)));
} else { } else {
return ThemeData.from(colorScheme: colorSchemeLight!); return themeModifier(ThemeData.from(colorScheme: colorSchemeLight!));
} }
} }
ThemeData themeDark() { ThemeData themeDark() {
if (!(prefs?.getBool("useDeviceTheme") ?? false) || colorSchemeDark == null) { if (!(prefs?.getBool("useDeviceTheme") ?? false) || colorSchemeDark == null) {
return ThemeData.from( return themeModifier(ThemeData.from(
colorScheme: const ColorScheme( colorScheme: const ColorScheme(
brightness: Brightness.dark, brightness: Brightness.dark,
primary: Colors.white, primary: Colors.white,
@ -85,9 +95,9 @@ ThemeData themeDark() {
error: Colors.red, error: Colors.red,
onError: Colors.black, onError: Colors.black,
surface: Colors.black, surface: Colors.black,
onSurface: Colors.white)); onSurface: Colors.white)));
} else { } else {
return ThemeData.from(colorScheme: colorSchemeDark!); return themeModifier(ThemeData.from(colorScheme: colorSchemeDark!));
} }
} }

View File

@ -81,6 +81,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.3.0" version: "1.3.0"
charcode:
dependency: transitive
description:
name: charcode
sha256: fb98c0f6d12c920a02ee2d998da788bca066ca5f148492b7085ee23372b12306
url: "https://pub.dev"
source: hosted
version: "1.3.1"
clock: clock:
dependency: transitive dependency: transitive
description: description:
@ -101,10 +109,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: cross_file name: cross_file
sha256: "55d7b444feb71301ef6b8838dbc1ae02e63dd48c8773f3810ff53bb1e2945b32" sha256: "7caf6a750a0c04effbb52a676dce9a4a592e10ad35c34d6d2d0e4811160d5670"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.3.4+1" version: "0.3.4+2"
crypto: crypto:
dependency: transitive dependency: transitive
description: description:
@ -213,10 +221,34 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: file_picker name: file_picker
sha256: "29c90806ac5f5fb896547720b73b17ee9aed9bba540dc5d91fe29f8c5745b10a" sha256: "167bb619cdddaa10ef2907609feb8a79c16dfa479d3afaf960f8e223f754bf12"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted 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: file_selector_linux:
dependency: transitive dependency: transitive
description: description:
@ -241,6 +273,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.6.2" 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: file_selector_windows:
dependency: transitive dependency: transitive
description: description:
@ -377,10 +417,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: http name: http
sha256: "761a297c042deedc1ffbb156d6e2af13886bb305c2a343a4d972504cd67dd938" sha256: b9c29a161230ee03d3ccf545097fccd9b87a5264228c5d348202e0f0c28f9010
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.2.1" version: "1.2.2"
http_parser: http_parser:
dependency: transitive dependency: transitive
description: description:
@ -409,10 +449,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: image_picker_for_web name: image_picker_for_web
sha256: "5d6eb13048cd47b60dbf1a5495424dea226c5faf3950e20bf8120a58efb5b5f3" sha256: "65d94623e15372c5c51bebbcb820848d7bcb323836e12dfdba60b5d3a8b39e50"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.0.4" version: "3.0.5"
image_picker_ios: image_picker_ios:
dependency: transitive dependency: transitive
description: description:
@ -577,18 +617,18 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: package_info_plus name: package_info_plus
sha256: b93d8b4d624b4ea19b0a5a208b2d6eff06004bc3ce74c06040b120eeadd00ce0 sha256: a75164ade98cb7d24cfd0a13c6408927c6b217fa60dee5a7ff5c116a58f28918
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "8.0.0" version: "8.0.2"
package_info_plus_platform_interface: package_info_plus_platform_interface:
dependency: transitive dependency: transitive
description: description:
name: package_info_plus_platform_interface name: package_info_plus_platform_interface
sha256: f49918f3433a3146047372f9d4f1f847511f2acd5cd030e1f44fe5a50036b70e sha256: ac1f4a4847f1ade8e6a87d1f39f5d7c67490738642e2542f559ec38c37489a66
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.0.0" version: "3.0.1"
path: path:
dependency: transitive dependency: transitive
description: description:
@ -761,10 +801,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: shared_preferences_web name: shared_preferences_web
sha256: "9aee1089b36bd2aafe06582b7d7817fd317ef05fc30e6ba14bff247d0933042a" sha256: d762709c2bbe80626ecc819143013cc820fa49ca5e363620ee20a8b15a3e3daf
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.3.0" version: "2.2.1"
shared_preferences_windows: shared_preferences_windows:
dependency: transitive dependency: transitive
description: description:
@ -898,6 +938,22 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.3.2" 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: url_launcher:
dependency: "direct main" dependency: "direct main"
description: description:
@ -950,10 +1006,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: url_launcher_web name: url_launcher_web
sha256: "8d9e750d8c9338601e709cd0885f95825086bd8b642547f26bda435aade95d8a" sha256: "772638d3b34c779ede05ba3d38af34657a05ac55b06279ea6edd409e323dca8e"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.3.1" version: "2.3.3"
url_launcher_windows: url_launcher_windows:
dependency: transitive dependency: transitive
description: description:
@ -1014,10 +1070,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: web name: web
sha256: "97da13628db363c635202ad97068d47c5b8aa555808e7a9411963c533b449b27" sha256: d43c1d6b787bf0afad444700ae7f4db8827f701bc61c255ac8d328c6f4d52062
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.5.1" version: "1.0.0"
win32: win32:
dependency: transitive dependency: transitive
description: description:
@ -1036,4 +1092,4 @@ packages:
version: "1.0.4" version: "1.0.4"
sdks: sdks:
dart: ">=3.4.0 <4.0.0" dart: ">=3.4.0 <4.0.0"
flutter: ">=3.19.0" flutter: ">=3.22.0"

View File

@ -28,6 +28,7 @@ dependencies:
restart_app: ^1.2.1 restart_app: ^1.2.1
flutter_markdown: ^0.7.1 flutter_markdown: ^0.7.1
file_picker: ^8.0.3 file_picker: ^8.0.3
file_selector: ^1.0.3
bitsdojo_window: ^0.1.6 bitsdojo_window: ^0.1.6
install_referrer: ^1.2.1 install_referrer: ^1.2.1
package_info_plus: ^8.0.0 package_info_plus: ^8.0.0
@ -40,6 +41,7 @@ dependencies:
datetime_loop: ^1.2.0 datetime_loop: ^1.2.0
dynamic_color: ^1.7.0 dynamic_color: ^1.7.0
volume_controller: ^2.0.7 volume_controller: ^2.0.7
universal_html: ^2.2.4
dev_dependencies: dev_dependencies:
flutter_test: flutter_test:

View File

@ -32,18 +32,18 @@ void main() async {
// ---------- // ----------
await execute('Windows x64', flutterExecutable, [ // await execute('Windows x64', flutterExecutable, [
'build', // 'build',
'windows', // 'windows',
'--obfuscate', // '--obfuscate',
'--split-debug-info=build\\debugWindows' // '--split-debug-info=build\\debugWindows'
]); // ]);
await execute( // await execute(
'Windows x64 installer', // 'Windows x64 installer',
'iscc.exe', // 'iscc.exe',
['windows_installer/x64.iss', '/qp', '/dAppVersion=$version'], // ['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."); // " > 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.");
// ---------- // ----------

View File

@ -16,7 +16,9 @@
"settingsTemporaryFixesNoFixes", "settingsTemporaryFixesNoFixes",
"settingsVoiceTtsNotSupported", "settingsVoiceTtsNotSupported",
"settingsVoiceTtsNotSupportedDescription", "settingsVoiceTtsNotSupportedDescription",
"settingsVoiceNotEnabled" "settingsVoiceNotEnabled",
"settingsExportChatsSuccess",
"settingsLicenses"
], ],
"it": [ "it": [
@ -36,7 +38,9 @@
"settingsTemporaryFixesNoFixes", "settingsTemporaryFixesNoFixes",
"settingsVoiceTtsNotSupported", "settingsVoiceTtsNotSupported",
"settingsVoiceTtsNotSupportedDescription", "settingsVoiceTtsNotSupportedDescription",
"settingsVoiceNotEnabled" "settingsVoiceNotEnabled",
"settingsExportChatsSuccess",
"settingsLicenses"
], ],
"tr": [ "tr": [
@ -56,7 +60,9 @@
"settingsTemporaryFixesNoFixes", "settingsTemporaryFixesNoFixes",
"settingsVoiceTtsNotSupported", "settingsVoiceTtsNotSupported",
"settingsVoiceTtsNotSupportedDescription", "settingsVoiceTtsNotSupportedDescription",
"settingsVoiceNotEnabled" "settingsVoiceNotEnabled",
"settingsExportChatsSuccess",
"settingsLicenses"
], ],
"zh": [ "zh": [
@ -76,6 +82,8 @@
"settingsTemporaryFixesNoFixes", "settingsTemporaryFixesNoFixes",
"settingsVoiceTtsNotSupported", "settingsVoiceTtsNotSupported",
"settingsVoiceTtsNotSupportedDescription", "settingsVoiceTtsNotSupportedDescription",
"settingsVoiceNotEnabled" "settingsVoiceNotEnabled",
"settingsExportChatsSuccess",
"settingsLicenses"
] ]
} }

View File

@ -1,7 +1,7 @@
; Script generated by the Inno Setup Script Wizard. ; Script generated by the Inno Setup Script Wizard.
; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES! ; 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 AppName "Ollama App"
#define AppPublisher "JHubi1" #define AppPublisher "JHubi1"
@ -27,7 +27,7 @@ UninstallDisplayName={#AppName}
DefaultDirName={autopf}\OllamaApp DefaultDirName={autopf}\OllamaApp
OutputDir=build\windows\{#AppArchitectures}\runner OutputDir=build\windows\{#AppArchitectures}\runner
OutputBaseFilename=ollama-v{#AppVersion}-{#AppArchitectures} OutputBaseFilename=ollama-windows-{#AppArchitectures}-v{#AppVersion}
AppSupportURL=https://github.com/JHubi1/ollama-app/issues AppSupportURL=https://github.com/JHubi1/ollama-app/issues
AppUpdatesURL=https://github.com/JHubi1/ollama-app/releases AppUpdatesURL=https://github.com/JHubi1/ollama-app/releases

View File

@ -28,7 +28,7 @@ UninstallDisplayName={#AppName}
DefaultDirName={autopf}\OllamaApp DefaultDirName={autopf}\OllamaApp
OutputDir=build\windows\{#AppArchitectures}\runner OutputDir=build\windows\{#AppArchitectures}\runner
OutputBaseFilename=ollama-v{#AppVersion}-{#AppArchitectures} OutputBaseFilename=ollama-windows-{#AppArchitectures}-v{#AppVersion}
AppSupportURL=https://github.com/JHubi1/ollama-app/issues AppSupportURL=https://github.com/JHubi1/ollama-app/issues
AppUpdatesURL=https://github.com/JHubi1/ollama-app/releases AppUpdatesURL=https://github.com/JHubi1/ollama-app/releases