Added update checker, updated desktop view

This commit is contained in:
JHubi1 2024-06-05 18:25:29 +02:00
parent 08d566e855
commit 0a996e6ed2
No known key found for this signature in database
GPG Key ID: 7BF82570CBBBD050
6 changed files with 512 additions and 215 deletions

View File

@ -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",

View File

@ -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<App> {
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<MainApp> {
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<MainApp> {
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<MainApp> {
splashFactory: NoSplash.splashFactory,
highlightColor: Colors.transparent,
enableFeedback: false,
hoverColor: Colors.transparent,
onTap: () {
HapticFeedback.selectionClick();
setState(() {
@ -422,7 +437,12 @@ class _MainAppState extends State<MainApp> {
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<MainApp> {
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<MainApp> {
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<MainApp> {
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<MainApp> {
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<MainApp> {
: 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<MainApp> {
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<MainApp> {
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<MainApp> {
: 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) {

View File

@ -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<ScreenSettings> {
}
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<ScreenSettings> {
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
void initState() {
super.initState();
WidgetsFlutterBinding.ensureInitialized();
checkHost();
updatesSupported(true);
if (prefs!.getBool("checkUpdateOnSettingsOpen") ?? false) {
checkUpdate();
}
}
@override
@ -153,73 +247,54 @@ class _ScreenSettingsState extends State<ScreenSettings> {
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<ScreenSettings> {
.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(

View File

@ -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<Widget>.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<Widget>.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 {

View File

@ -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:

View File

@ -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: