diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index e6b8863..047a262 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -317,6 +317,47 @@ "description": "Text displayed when chats are imported successfully", "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": { "description": "Text displayed as description for GitHub button", diff --git a/lib/main.dart b/lib/main.dart index e3412c9..b2c68dc 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -64,6 +64,8 @@ bool chatAllowed = true; final user = types.User(id: const Uuid().v4()); final assistant = types.User(id: const Uuid().v4()); +bool settingsOpen = false; + void main() { runApp(const App()); @@ -92,7 +94,9 @@ class _AppState extends State { super.initState(); void load() async { + try { await FlutterDisplayMode.setHighRefreshRate(); + } catch (_) {} SharedPreferences.setPrefix("ollama."); SharedPreferences tmp = await SharedPreferences.getInstance(); setState(() { @@ -215,7 +219,12 @@ class _MainAppState extends State { borderRadius: BorderRadius.all(Radius.circular(50))), onTap: () { HapticFeedback.selectionClick(); - Navigator.of(context).pop(); + if (!(Platform.isWindows || + Platform.isLinux || + Platform.isMacOS) && + MediaQuery.of(context).size.width <= 1000) { + Navigator.of(context).pop(); + } if (!chatAllowed) return; chatUuid = null; messages = []; @@ -246,9 +255,14 @@ class _MainAppState extends State { borderRadius: BorderRadius.all(Radius.circular(50))), onTap: () { HapticFeedback.selectionClick(); - Navigator.of(context).pop(); + if (!(Platform.isWindows || + Platform.isLinux || + Platform.isMacOS) && + MediaQuery.of(context).size.width <= 1000) { + Navigator.of(context).pop(); + } setState(() { - logoVisible = false; + settingsOpen = true; }); Navigator.push( context, @@ -328,6 +342,7 @@ class _MainAppState extends State { splashFactory: NoSplash.splashFactory, highlightColor: Colors.transparent, enableFeedback: false, + hoverColor: Colors.transparent, onTap: () { HapticFeedback.selectionClick(); setState(() { @@ -422,7 +437,12 @@ class _MainAppState extends State { if (chatUuid == jsonDecode(item)["uuid"]) { messages = []; chatUuid = null; - Navigator.of(context).pop(); + if (!(Platform.isWindows || + Platform.isLinux || + Platform.isMacOS) && + MediaQuery.of(context).size.width <= 1000) { + Navigator.of(context).pop(); + } } setState(() {}); }, @@ -433,7 +453,12 @@ class _MainAppState extends State { borderRadius: BorderRadius.all(Radius.circular(50))), onTap: () { HapticFeedback.selectionClick(); - Navigator.of(context).pop(); + if (!(Platform.isWindows || + Platform.isLinux || + Platform.isMacOS) && + MediaQuery.of(context).size.width <= 1000) { + Navigator.of(context).pop(); + } if (!chatAllowed) return; loadChat(jsonDecode(item)["uuid"], setState); chatUuid = jsonDecode(item)["uuid"]; @@ -609,6 +634,7 @@ class _MainAppState extends State { splashFactory: NoSplash.splashFactory, highlightColor: Colors.transparent, enableFeedback: false, + hoverColor: Colors.transparent, child: SizedBox( height: 200, child: Row( @@ -787,7 +813,20 @@ class _MainAppState extends State { preferredSize: const Size.fromHeight(1), child: (!chatAllowed && model != null) ? const LinearProgressIndicator() - : const SizedBox.shrink()), + : ((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()), leading: ((Platform.isWindows || Platform.isLinux || Platform.isMacOS) && @@ -806,6 +845,7 @@ class _MainAppState extends State { child: VisibilityDetector( key: const Key("menuVisible"), onVisibilityChanged: (VisibilityInfo info) { + if (settingsOpen) return; menuVisible = info.visibleFraction > 0; try { setState(() {}); @@ -819,11 +859,15 @@ class _MainAppState extends State { : const SizedBox.shrink(), ((Platform.isWindows || Platform.isLinux || Platform.isMacOS) && MediaQuery.of(context).size.width >= 1000) - ? VerticalDivider( - width: 2, - color: (Theme.of(context).brightness == Brightness.light) - ? Colors.grey[400] - : Colors.grey[900]) + ? AnimatedOpacity( + opacity: menuVisible ? 1.0 : 0.0, + duration: const Duration(milliseconds: 500), + child: VerticalDivider( + width: 2, + color: + (Theme.of(context).brightness == Brightness.light) + ? Colors.grey[400] + : Colors.grey[900])) : const SizedBox.shrink(), Expanded( child: Chat( @@ -1021,6 +1065,7 @@ class _MainAppState extends State { child: VisibilityDetector( key: const Key("logoVisible"), onVisibilityChanged: (VisibilityInfo info) { + if (settingsOpen) return; logoVisible = info.visibleFraction > 0; try { setState(() {}); @@ -1515,9 +1560,13 @@ class _MainAppState extends State { sendable = p0.trim().isNotEmpty; }); }, - sendButtonVisibilityMode: (sendable) + sendButtonVisibilityMode: (Platform.isWindows || + Platform.isLinux || + Platform.isMacOS) ? SendButtonVisibilityMode.always - : SendButtonVisibilityMode.hidden), + : (sendable) + ? SendButtonVisibilityMode.always + : SendButtonVisibilityMode.hidden), user: user, hideBackgroundOnEmojiMessages: false, theme: (Theme.of(context).brightness == Brightness.light) @@ -1585,6 +1634,10 @@ class _MainAppState extends State { : 440))), ], ), + drawerEdgeDragWidth: + (Platform.isWindows || Platform.isLinux || Platform.isMacOS) + ? null + : MediaQuery.of(context).size.width, drawer: Builder(builder: (context) { if ((Platform.isWindows || Platform.isLinux || Platform.isMacOS) && MediaQuery.of(context).size.width >= 1000) { diff --git a/lib/screen_settings.dart b/lib/screen_settings.dart index 5f245d3..4999ec9 100644 --- a/lib/screen_settings.dart +++ b/lib/screen_settings.dart @@ -16,6 +16,9 @@ import 'package:url_launcher/url_launcher.dart'; import 'package:restart_app/restart_app.dart'; import 'package:file_picker/file_picker.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 { const ScreenSettings({super.key}); @@ -68,7 +71,6 @@ class _ScreenSettingsState extends State { } if ((request.statusCode == 200 && request.body == "Ollama is running") || (Uri.parse(tmpHost).toString() == fixedHost)) { - // messages = []; setState(() { hostLoading = false; host = tmpHost; @@ -91,10 +93,102 @@ class _ScreenSettingsState extends State { final repoUrl = "https://github.com/JHubi1/ollama-app"; + bool updateChecked = false; + bool updateLoading = false; + String updateStatus = "ok"; + String? updateUrl; + String? latestVersion; + String? currentVersion; + Future 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 void initState() { super.initState(); + WidgetsFlutterBinding.ensureInitialized(); + checkHost(); + updatesSupported(true); + if (prefs!.getBool("checkUpdateOnSettingsOpen") ?? false) { + checkUpdate(); + } } @override @@ -153,73 +247,54 @@ class _ScreenSettingsState extends State { return PopScope( canPop: !hostLoading, onPopInvoked: (didPop) { + settingsOpen = false; FocusManager.instance.primaryFocus?.unfocus(); }, child: WindowBorder( color: Theme.of(context).colorScheme.surface, child: Scaffold( appBar: AppBar( - title: Row(children: [ - Text(AppLocalizations.of(context)!.optionSettings), - Expanded(child: SizedBox(height: 200, child: MoveWindow())) - ]), - actions: - (Platform.isWindows || Platform.isLinux || Platform.isMacOS) - ? [ - SizedBox( - height: 200, - child: WindowTitleBarBox( - child: Row( - children: [ - // Expanded(child: MoveWindow()), - SizedBox( - height: 200, - child: MinimizeWindowButton( - animate: true, - colors: WindowButtonColors( - iconNormal: Theme.of(context) - .colorScheme - .primary))), - SizedBox( - height: 72, - child: MaximizeWindowButton( - animate: true, - colors: WindowButtonColors( - iconNormal: Theme.of(context) - .colorScheme - .primary))), - SizedBox( - height: 72, - child: CloseWindowButton( - animate: true, - colors: WindowButtonColors( - iconNormal: Theme.of(context) - .colorScheme - .primary))), - ], - ))) - ] - : 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())); - })), + title: Row(children: [ + Text(AppLocalizations.of(context)!.optionSettings), + Expanded(child: SizedBox(height: 200, child: MoveWindow())) + ]), + actions: + (Platform.isWindows || Platform.isLinux || Platform.isMacOS) + ? [ + SizedBox( + height: 200, + child: WindowTitleBarBox( + child: Row( + children: [ + SizedBox( + height: 200, + child: MinimizeWindowButton( + animate: true, + colors: WindowButtonColors( + iconNormal: Theme.of(context) + .colorScheme + .primary))), + SizedBox( + height: 72, + child: MaximizeWindowButton( + animate: true, + colors: WindowButtonColors( + iconNormal: Theme.of(context) + .colorScheme + .primary))), + SizedBox( + height: 72, + child: CloseWindowButton( + animate: true, + colors: WindowButtonColors( + iconNormal: Theme.of(context) + .colorScheme + .primary))), + ], + ))) + ] + : null, + ), body: Padding( padding: const EdgeInsets.only(left: 16, right: 16), child: ListView(children: [ @@ -619,6 +694,77 @@ class _ScreenSettingsState extends State { .settingsImportChats)) ])), 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( onTap: () { launchUrl( diff --git a/lib/worker_setter.dart b/lib/worker_setter.dart index b418ae8..4f0e3d1 100644 --- a/lib/worker_setter.dart +++ b/lib/worker_setter.dart @@ -64,139 +64,161 @@ void setModel(BuildContext context, Function setState) { if (useModel) return; HapticFeedback.selectionClick(); - showModalBottomSheet( - context: context, - builder: (context) { - return StatefulBuilder(builder: (context, setLocalState) { - setModalState = setLocalState; - return PopScope( - canPop: loaded, - onPopInvoked: (didPop) { - if (!loaded) return; - if (usedIndex >= 0 && - modelsReal[usedIndex] != model && - (prefs!.getBool("resetOnModelSelect") ?? true)) { - messages = []; - } - model = (usedIndex >= 0) ? modelsReal[usedIndex] : null; - chatAllowed = !(model == null); - multimodal = (usedIndex >= 0) ? modal[usedIndex] : false; - if (model != null) { - prefs?.setString("model", model!); - } else { - prefs?.remove("model"); - } - prefs?.setBool("multimodal", multimodal); - setState(() {}); - }, - child: Container( - width: double.infinity, - padding: EdgeInsets.only( - left: 16, - right: 16, - top: 16, - bottom: (Platform.isWindows || - Platform.isLinux || - Platform.isMacOS) - ? 16 - : 0), - child: (!loaded) - ? const LinearProgressIndicator() - : Column(mainAxisSize: MainAxisSize.min, children: [ - Container( - width: double.infinity, - constraints: BoxConstraints( - maxHeight: - MediaQuery.of(context).size.height * 0.4), - child: SingleChildScrollView( - scrollDirection: Axis.vertical, - child: Wrap( - spacing: 5.0, - runSpacing: 5.0, - alignment: WrapAlignment.center, - children: List.generate( - models.length, - (int index) { - return ChoiceChip( - label: Text( - (prefs!.getBool("modelTags") ?? - false) - ? modelsReal[index] - : models[index]), - selected: usedIndex == index, - avatar: (usedIndex == index) - ? null - : (addIndex == index) - ? const Icon( - Icons.add_rounded) - : ((recommendedModels - .contains( - models[index])) - ? const Icon( - Icons.star_rounded) - : ((modal[index]) - ? const Icon(Icons - .collections_rounded) - : null)), - checkmarkColor: (usedIndex == index) - ? ((MediaQuery.of(context) - .platformBrightness == - Brightness.light) - ? (theme ?? ThemeData()) - .colorScheme - .secondary - : (themeDark ?? - ThemeData.dark()) - .colorScheme - .secondary) - : null, - labelStyle: (usedIndex == index) - ? TextStyle( - color: (MediaQuery.of(context) - .platformBrightness == - Brightness.light) - ? (theme ?? ThemeData()) - .colorScheme - .secondary - : (themeDark ?? - ThemeData.dark()) - .colorScheme - .secondary) - : null, - selectedColor: (MediaQuery.of(context) - .platformBrightness == - Brightness.light) - ? (theme ?? ThemeData()) - .colorScheme - .primary - : (themeDark ?? ThemeData.dark()) - .colorScheme - .primary, - onSelected: (bool selected) { - if (addIndex == index) { - Navigator.of(context).pop(); - ScaffoldMessenger.of(context) - .showSnackBar(SnackBar( - content: Text( - AppLocalizations.of( - context)! - .modelDialogAddSteps), - showCloseIcon: true)); - } - if (!chatAllowed && model != null) { - return; - } - setLocalState(() { - usedIndex = selected ? index : -1; - }); - }, - ); - }, - ).toList(), - ))) - ]))); + + var content = StatefulBuilder(builder: (context, setLocalState) { + setModalState = setLocalState; + return PopScope( + canPop: loaded, + onPopInvoked: (didPop) { + if (!loaded) return; + if (usedIndex >= 0 && + modelsReal[usedIndex] != model && + (prefs!.getBool("resetOnModelSelect") ?? true)) { + messages = []; + } + model = (usedIndex >= 0) ? modelsReal[usedIndex] : null; + chatAllowed = !(model == null); + multimodal = (usedIndex >= 0) ? modal[usedIndex] : false; + if (model != null) { + prefs?.setString("model", model!); + } else { + prefs?.remove("model"); + } + prefs?.setBool("multimodal", multimodal); + setState(() {}); + }, + child: Container( + width: + ((Platform.isWindows || Platform.isLinux || Platform.isMacOS) && + MediaQuery.of(context).size.width >= 1000) + ? null + : double.infinity, + padding: EdgeInsets.only( + left: 16, + right: 16, + top: 16, + bottom: + (Platform.isWindows || Platform.isLinux || Platform.isMacOS) + ? 16 + : 0), + child: (!loaded) + ? const LinearProgressIndicator() + : Column(mainAxisSize: MainAxisSize.min, children: [ + Container( + width: ((Platform.isWindows || + Platform.isLinux || + Platform.isMacOS) && + MediaQuery.of(context).size.width >= 1000) + ? 300 + : double.infinity, + constraints: BoxConstraints( + maxHeight: + MediaQuery.of(context).size.height * 0.4), + child: SingleChildScrollView( + scrollDirection: Axis.vertical, + child: Wrap( + spacing: ((Platform.isWindows || + 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, + children: List.generate( + models.length, + (int index) { + return ChoiceChip( + label: Text( + (prefs!.getBool("modelTags") ?? false) + ? modelsReal[index] + : models[index]), + selected: usedIndex == index, + avatar: (usedIndex == index) + ? null + : (addIndex == index) + ? const Icon(Icons.add_rounded) + : ((recommendedModels + .contains(models[index])) + ? const Icon(Icons.star_rounded) + : ((modal[index]) + ? const Icon(Icons + .collections_rounded) + : null)), + checkmarkColor: (usedIndex == index) + ? ((MediaQuery.of(context) + .platformBrightness == + Brightness.light) + ? (theme ?? ThemeData()) + .colorScheme + .secondary + : (themeDark ?? ThemeData.dark()) + .colorScheme + .secondary) + : null, + labelStyle: (usedIndex == index) + ? TextStyle( + color: (MediaQuery.of(context) + .platformBrightness == + Brightness.light) + ? (theme ?? ThemeData()) + .colorScheme + .secondary + : (themeDark ?? + ThemeData.dark()) + .colorScheme + .secondary) + : null, + selectedColor: (MediaQuery.of(context) + .platformBrightness == + Brightness.light) + ? (theme ?? ThemeData()) + .colorScheme + .primary + : (themeDark ?? ThemeData.dark()) + .colorScheme + .primary, + onSelected: (bool selected) { + if (addIndex == index) { + Navigator.of(context).pop(); + ScaffoldMessenger.of(context) + .showSnackBar(SnackBar( + content: Text( + AppLocalizations.of( + context)! + .modelDialogAddSteps), + showCloseIcon: true)); + } + if (!chatAllowed && model != null) { + return; + } + setLocalState(() { + usedIndex = selected ? index : -1; + }); + }, + ); + }, + ).toList(), + ))) + ]))); + }); + + 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 { diff --git a/pubspec.lock b/pubspec.lock index e30849c..8e3dd9c 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -421,6 +421,14 @@ packages: url: "https://pub.dev" source: hosted 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: dependency: "direct main" description: @@ -526,6 +534,22 @@ packages: url: "https://github.com/davidmigloz/langchain_dart.git" source: git 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: dependency: transitive description: @@ -835,6 +859,14 @@ packages: url: "https://pub.dev" source: hosted 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: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index 3fc9619..fda0ad8 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -9,22 +9,22 @@ environment: dependencies: 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 flutter_chat_ui: ^1.6.13 uuid: ^4.4.0 animated_text_kit: ^4.2.2 image_picker: ^1.1.1 visibility_detector: ^0.4.0+2 - flutter_localizations: - sdk: flutter - intl: any http: ^1.2.1 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 transparent_image: ^2.0.1 simple_icons: ^10.1.3 @@ -33,6 +33,9 @@ dependencies: flutter_markdown: ^0.7.1 file_picker: ^8.0.3 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 dev_dependencies: