├── assets ├── images │ ├── logo.png │ └── logo_latte.png └── fonts │ ├── OpenSans-Bold.ttf │ ├── OpenSans-Regular.ttf │ └── OpenSans-SemiBold.ttf ├── android ├── gradle.properties ├── app │ ├── src │ │ ├── main │ │ │ ├── res │ │ │ │ ├── mipmap-hdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-mdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xhdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xxhdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xxxhdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── drawable │ │ │ │ │ └── launch_background.xml │ │ │ │ ├── drawable-v21 │ │ │ │ │ └── launch_background.xml │ │ │ │ ├── values │ │ │ │ │ └── styles.xml │ │ │ │ └── values-night │ │ │ │ │ └── styles.xml │ │ │ ├── kotlin │ │ │ │ └── com │ │ │ │ │ └── example │ │ │ │ │ └── ollama_app │ │ │ │ │ └── MainActivity.kt │ │ │ └── AndroidManifest.xml │ │ ├── debug │ │ │ └── AndroidManifest.xml │ │ └── profile │ │ │ └── AndroidManifest.xml │ └── build.gradle ├── gradle │ └── wrapper │ │ └── gradle-wrapper.properties ├── .gitignore ├── build.gradle └── settings.gradle ├── analysis_options.yaml ├── lib ├── types │ └── message.dart ├── widgets │ ├── icons │ │ ├── bars3.dart │ │ ├── check.dart │ │ ├── xmark.dart │ │ ├── arrowup.dart │ │ ├── arrowleft.dart │ │ ├── cog6tooth.dart │ │ ├── usercircle.dart │ │ └── ollama_logo.dart │ ├── ez │ │ ├── button.dart │ │ ├── text.dart │ │ ├── dropdown.dart │ │ ├── scaffold.dart │ │ ├── appbar.dart │ │ ├── message.dart │ │ └── textfield.dart │ └── rerender_widget.dart ├── main.dart ├── utils │ └── api.dart ├── globals.dart └── routes │ ├── home.dart │ └── settings.dart ├── pubspec.yaml ├── .gitignore ├── LICENSE ├── .metadata └── pubspec.lock /assets/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/duccdev/ollama_app/HEAD/assets/images/logo.png -------------------------------------------------------------------------------- /assets/images/logo_latte.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/duccdev/ollama_app/HEAD/assets/images/logo_latte.png -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx4G 2 | android.useAndroidX=true 3 | android.enableJetifier=true 4 | -------------------------------------------------------------------------------- /assets/fonts/OpenSans-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/duccdev/ollama_app/HEAD/assets/fonts/OpenSans-Bold.ttf -------------------------------------------------------------------------------- /assets/fonts/OpenSans-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/duccdev/ollama_app/HEAD/assets/fonts/OpenSans-Regular.ttf -------------------------------------------------------------------------------- /assets/fonts/OpenSans-SemiBold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/duccdev/ollama_app/HEAD/assets/fonts/OpenSans-SemiBold.ttf -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/duccdev/ollama_app/HEAD/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/duccdev/ollama_app/HEAD/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: package:flutter_lints/flutter.yaml 2 | 3 | linter: 4 | rules: 5 | avoid_print: true 6 | prefer_single_quotes: true 7 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/duccdev/ollama_app/HEAD/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/duccdev/ollama_app/HEAD/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/duccdev/ollama_app/HEAD/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/kotlin/com/example/ollama_app/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.ollama 2 | 3 | import io.flutter.embedding.android.FlutterActivity 4 | 5 | class MainActivity: FlutterActivity() 6 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | zipStoreBase=GRADLE_USER_HOME 4 | zipStorePath=wrapper/dists 5 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.3-all.zip 6 | -------------------------------------------------------------------------------- /lib/types/message.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class Message { 4 | Message({ 5 | required this.username, 6 | this.content, 7 | required this.pfp, 8 | this.error, 9 | }); 10 | 11 | String username; 12 | String? content; 13 | Widget pfp; 14 | bool? error; 15 | } 16 | -------------------------------------------------------------------------------- /android/.gitignore: -------------------------------------------------------------------------------- 1 | gradle-wrapper.jar 2 | /.gradle 3 | /captures/ 4 | /gradlew 5 | /gradlew.bat 6 | /local.properties 7 | GeneratedPluginRegistrant.java 8 | 9 | # Remember to never publicly share your keystore. 10 | # See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app 11 | key.properties 12 | **/*.keystore 13 | **/*.jks 14 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | allprojects { 2 | repositories { 3 | google() 4 | mavenCentral() 5 | } 6 | } 7 | 8 | rootProject.buildDir = '../build' 9 | subprojects { 10 | project.buildDir = "${rootProject.buildDir}/${project.name}" 11 | } 12 | subprojects { 13 | project.evaluationDependsOn(':app') 14 | } 15 | 16 | tasks.register("clean", Delete) { 17 | delete rootProject.buildDir 18 | } 19 | -------------------------------------------------------------------------------- /android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /lib/widgets/icons/bars3.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:heroicons/heroicons.dart'; 3 | 4 | class Bars3 extends StatelessWidget { 5 | const Bars3({super.key, this.color, this.size}); 6 | 7 | final Color? color; 8 | final double? size; 9 | 10 | @override 11 | Widget build(BuildContext context) { 12 | return HeroIcon( 13 | HeroIcons.bars3, 14 | color: color ?? Colors.white, 15 | style: HeroIconStyle.mini, 16 | size: size ?? 32, 17 | ); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /lib/widgets/icons/check.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:heroicons/heroicons.dart'; 3 | 4 | class Check extends StatelessWidget { 5 | const Check({super.key, this.color, this.size}); 6 | 7 | final Color? color; 8 | final double? size; 9 | 10 | @override 11 | Widget build(BuildContext context) { 12 | return HeroIcon( 13 | HeroIcons.check, 14 | color: color ?? Colors.white, 15 | style: HeroIconStyle.mini, 16 | size: size ?? 32, 17 | ); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /lib/widgets/icons/xmark.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:heroicons/heroicons.dart'; 3 | 4 | class XMark extends StatelessWidget { 5 | const XMark({super.key, this.color, this.size}); 6 | 7 | final Color? color; 8 | final double? size; 9 | 10 | @override 11 | Widget build(BuildContext context) { 12 | return HeroIcon( 13 | HeroIcons.xMark, 14 | color: color ?? Colors.white, 15 | style: HeroIconStyle.mini, 16 | size: size ?? 32, 17 | ); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /lib/widgets/icons/arrowup.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:heroicons/heroicons.dart'; 3 | 4 | class ArrowUp extends StatelessWidget { 5 | const ArrowUp({super.key, this.color, this.size}); 6 | 7 | final Color? color; 8 | final double? size; 9 | 10 | @override 11 | Widget build(BuildContext context) { 12 | return HeroIcon( 13 | HeroIcons.arrowUp, 14 | color: color ?? Colors.white, 15 | style: HeroIconStyle.mini, 16 | size: size ?? 32, 17 | ); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-v21/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /lib/widgets/icons/arrowleft.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:heroicons/heroicons.dart'; 3 | 4 | class ArrowLeft extends StatelessWidget { 5 | const ArrowLeft({super.key, this.color, this.size}); 6 | 7 | final Color? color; 8 | final double? size; 9 | 10 | @override 11 | Widget build(BuildContext context) { 12 | return HeroIcon( 13 | HeroIcons.arrowLeft, 14 | color: color ?? Colors.white, 15 | style: HeroIconStyle.mini, 16 | size: size ?? 32, 17 | ); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /lib/widgets/icons/cog6tooth.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:heroicons/heroicons.dart'; 3 | 4 | class Cog6Tooth extends StatelessWidget { 5 | const Cog6Tooth({super.key, this.color, this.size}); 6 | 7 | final Color? color; 8 | final double? size; 9 | 10 | @override 11 | Widget build(BuildContext context) { 12 | return HeroIcon( 13 | HeroIcons.cog6Tooth, 14 | color: color ?? Colors.white, 15 | style: HeroIconStyle.mini, 16 | size: size ?? 32, 17 | ); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /lib/widgets/icons/usercircle.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:heroicons/heroicons.dart'; 3 | 4 | class UserCircle extends StatelessWidget { 5 | const UserCircle({super.key, this.color, this.size}); 6 | 7 | final Color? color; 8 | final double? size; 9 | 10 | @override 11 | Widget build(BuildContext context) { 12 | return HeroIcon( 13 | HeroIcons.userCircle, 14 | color: color ?? Colors.white, 15 | style: HeroIconStyle.mini, 16 | size: size ?? 32, 17 | ); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /lib/widgets/ez/button.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:ollama_app/globals.dart'; 3 | 4 | typedef OnPressedCallback = void Function(); 5 | 6 | class EzButton extends StatelessWidget { 7 | const EzButton({super.key, required this.child, required this.onPressed}); 8 | 9 | final Widget child; 10 | final OnPressedCallback onPressed; 11 | 12 | @override 13 | Widget build(BuildContext context) { 14 | return ElevatedButton( 15 | onPressed: onPressed, 16 | style: ElevatedButton.styleFrom(backgroundColor: Globals.ctp.surface0), 17 | child: child, 18 | ); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /lib/widgets/icons/ollama_logo.dart: -------------------------------------------------------------------------------- 1 | import 'package:catppuccin_flutter/catppuccin_flutter.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:ollama_app/globals.dart'; 4 | 5 | class OllamaLogo extends StatelessWidget { 6 | const OllamaLogo({super.key, this.width, this.height}); 7 | 8 | final double? width; 9 | final double? height; 10 | 11 | @override 12 | Widget build(BuildContext context) { 13 | return Globals.ctp == catppuccin.latte 14 | ? Image.asset('assets/images/logo_latte.png', 15 | width: width ?? 48, height: height ?? 48) 16 | : Image.asset('assets/images/logo.png', 17 | width: width ?? 48, height: height ?? 48); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /lib/widgets/rerender_widget.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class RerenderWidget extends StatefulWidget { 4 | const RerenderWidget({super.key, required this.child}); 5 | 6 | final Widget child; 7 | 8 | static void rerenderApp(BuildContext context) { 9 | context.findAncestorStateOfType()?.rerenderApp(); 10 | } 11 | 12 | @override 13 | RerenderWidgetState createState() => RerenderWidgetState(); 14 | } 15 | 16 | class RerenderWidgetState extends State { 17 | Key key = UniqueKey(); 18 | 19 | void rerenderApp() { 20 | setState(() { 21 | key = UniqueKey(); 22 | }); 23 | } 24 | 25 | @override 26 | Widget build(BuildContext context) { 27 | return KeyedSubtree( 28 | key: key, 29 | child: widget.child, 30 | ); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: ollama_app 2 | description: "Android app for Ollama" 3 | publish_to: "none" 4 | version: 1.0.0+1 5 | 6 | environment: 7 | sdk: ">=3.3.4 <4.0.0" 8 | 9 | dependencies: 10 | flutter: 11 | sdk: flutter 12 | 13 | catppuccin_flutter: ^1.0.0 14 | fluttertoast: ^8.2.5 15 | heroicons: ^0.10.0 16 | http: ^1.2.1 17 | shared_preferences: ^2.2.3 18 | shimmer: ^3.0.0 19 | 20 | dev_dependencies: 21 | flutter_lints: ^4.0.0 22 | 23 | flutter: 24 | uses-material-design: true 25 | 26 | assets: 27 | - assets/images/ 28 | 29 | fonts: 30 | - family: OpenSans 31 | fonts: 32 | - asset: assets/fonts/OpenSans-Regular.ttf 33 | weight: 400 34 | - asset: assets/fonts/OpenSans-SemiBold.ttf 35 | weight: 600 36 | - asset: assets/fonts/OpenSans-Bold.ttf 37 | weight: 700 38 | -------------------------------------------------------------------------------- /lib/main.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:ollama_app/globals.dart'; 3 | import 'package:ollama_app/routes/home.dart'; 4 | import 'package:ollama_app/routes/settings.dart'; 5 | import 'package:ollama_app/widgets/ez/scaffold.dart'; 6 | import 'package:ollama_app/widgets/rerender_widget.dart'; 7 | 8 | void main() async { 9 | WidgetsFlutterBinding.ensureInitialized(); 10 | await Globals.init(); 11 | runApp(const RerenderWidget(child: Entry())); 12 | } 13 | 14 | class Entry extends StatelessWidget { 15 | const Entry({super.key}); 16 | 17 | @override 18 | Widget build(BuildContext context) { 19 | return MaterialApp( 20 | title: 'Ollama', 21 | theme: ThemeData(fontFamily: 'OpenSans'), 22 | routes: {'/settings': (context) => const Settings()}, 23 | home: const EzScaffold(body: Home()), 24 | ); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | migrate_working_dir/ 12 | 13 | # IntelliJ related 14 | *.iml 15 | *.ipr 16 | *.iws 17 | .idea/ 18 | 19 | # The .vscode folder contains launch configuration and tasks you configure in 20 | # VS Code which you may wish to be included in version control, so this line 21 | # is commented out by default. 22 | #.vscode/ 23 | 24 | # Flutter/Dart/Pub related 25 | **/doc/api/ 26 | **/ios/Flutter/.last_build_id 27 | .dart_tool/ 28 | .flutter-plugins 29 | .flutter-plugins-dependencies 30 | .pub-cache/ 31 | .pub/ 32 | /build/ 33 | 34 | # Symbolication related 35 | app.*.symbols 36 | 37 | # Obfuscation related 38 | app.*.map.json 39 | 40 | # Android Studio will place build artifacts here 41 | /android/app/debug 42 | /android/app/profile 43 | /android/app/release 44 | -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | def flutterSdkPath = { 3 | def properties = new Properties() 4 | file("local.properties").withInputStream { properties.load(it) } 5 | def flutterSdkPath = properties.getProperty("flutter.sdk") 6 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties" 7 | return flutterSdkPath 8 | } 9 | settings.ext.flutterSdkPath = flutterSdkPath() 10 | 11 | includeBuild("${settings.ext.flutterSdkPath}/packages/flutter_tools/gradle") 12 | 13 | repositories { 14 | google() 15 | mavenCentral() 16 | gradlePluginPortal() 17 | } 18 | } 19 | 20 | plugins { 21 | id "dev.flutter.flutter-plugin-loader" version "1.0.0" 22 | id "com.android.application" version "7.3.0" apply false 23 | id "org.jetbrains.kotlin.android" version "1.7.10" apply false 24 | } 25 | 26 | include ":app" 27 | -------------------------------------------------------------------------------- /lib/widgets/ez/text.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:ollama_app/globals.dart'; 3 | 4 | class EzText extends StatelessWidget { 5 | const EzText(this.content, 6 | {super.key, 7 | this.fontSize, 8 | this.color, 9 | this.textAlign, 10 | this.bold, 11 | this.semibold}); 12 | 13 | final String content; 14 | final Color? color; 15 | final TextAlign? textAlign; 16 | final double? fontSize; 17 | final bool? bold; 18 | final bool? semibold; 19 | 20 | @override 21 | Widget build(BuildContext context) { 22 | return Text( 23 | content, 24 | softWrap: true, 25 | textAlign: textAlign, 26 | style: TextStyle( 27 | fontSize: fontSize ?? 24, 28 | color: color ?? Globals.ctp.text, 29 | fontWeight: (bold ?? false) 30 | ? FontWeight.w700 31 | : ((semibold ?? false) ? FontWeight.w600 : FontWeight.normal), 32 | ), 33 | ); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /lib/utils/api.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | import 'package:http/http.dart' as http; 4 | import 'package:ollama_app/globals.dart'; 5 | 6 | Future isConnected() async { 7 | if (Globals.baseUrl == null) return false; 8 | 9 | try { 10 | var response = await http.get(Uri.parse(Globals.baseUrl!)); 11 | if (response.statusCode != 200) return false; 12 | return true; 13 | } catch (e) { 14 | return false; 15 | } 16 | } 17 | 18 | Future infer(String prompt, String model) async { 19 | if (Globals.baseUrl == null) return null; 20 | 21 | try { 22 | var response = await http.post( 23 | Uri.parse('${Globals.baseUrl!}/api/generate'), 24 | body: jsonEncode({'model': model, 'prompt': prompt, 'stream': false}), 25 | headers: {'Content-Type': 'application/json'}, 26 | ); 27 | if (response.statusCode != 200) return null; 28 | 29 | return (jsonDecode(response.body) as Map)['response']; 30 | } catch (e) { 31 | return null; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /android/app/src/main/res/values-night/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /lib/globals.dart: -------------------------------------------------------------------------------- 1 | import 'package:catppuccin_flutter/catppuccin_flutter.dart'; 2 | import 'package:shared_preferences/shared_preferences.dart'; 3 | 4 | class Globals { 5 | static Flavor ctp = catppuccin.mocha; 6 | static String? model; 7 | static String? baseUrl; 8 | static String? apiKey; 9 | static late SharedPreferences prefs; 10 | 11 | static Future init() async { 12 | prefs = await SharedPreferences.getInstance(); 13 | reloadGlobals(); 14 | } 15 | 16 | static void reloadGlobals() { 17 | if (prefs.containsKey('theme')) { 18 | switch (prefs.getString('theme')) { 19 | case 'Latte': 20 | ctp = catppuccin.latte; 21 | break; 22 | case 'Frappé': 23 | ctp = catppuccin.frappe; 24 | break; 25 | case 'Macchiato': 26 | ctp = catppuccin.macchiato; 27 | break; 28 | case 'Mocha': 29 | ctp = catppuccin.mocha; 30 | break; 31 | } 32 | } 33 | 34 | model = prefs.getString('model'); 35 | baseUrl = prefs.getString('baseUrl'); 36 | apiKey = prefs.getString('apiKey'); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023-present duccdev 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /lib/widgets/ez/dropdown.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:ollama_app/globals.dart'; 3 | import 'package:ollama_app/widgets/ez/text.dart'; 4 | 5 | typedef OnChangedCallback = void Function(String value); 6 | 7 | class Dropdown extends StatefulWidget { 8 | const Dropdown( 9 | {super.key, 10 | required this.items, 11 | required this.defaultItem, 12 | this.onChanged}); 13 | 14 | final List items; 15 | final String defaultItem; 16 | final OnChangedCallback? onChanged; 17 | 18 | @override 19 | State createState() => _DropdownState(); 20 | } 21 | 22 | class _DropdownState extends State { 23 | String? _value; 24 | 25 | @override 26 | Widget build(BuildContext context) { 27 | return DropdownButton( 28 | value: _value ?? widget.defaultItem, 29 | items: widget.items 30 | .map((value) => DropdownMenuItem( 31 | value: value, 32 | child: EzText(value, fontSize: 18), 33 | )) 34 | .toList(), 35 | dropdownColor: Globals.ctp.base, 36 | onChanged: (value) { 37 | setState(() => _value = value!); 38 | if (widget.onChanged != null) widget.onChanged!(value!); 39 | }, 40 | ); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /lib/widgets/ez/scaffold.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:ollama_app/globals.dart'; 3 | import 'package:ollama_app/widgets/ez/appbar.dart'; 4 | 5 | class EzScaffold extends StatelessWidget { 6 | const EzScaffold( 7 | {super.key, this.body, this.noAppBar, this.appBar, this.centerAppBar}); 8 | 9 | final Widget? body; 10 | final bool? noAppBar; 11 | final Widget? appBar; 12 | final bool? centerAppBar; 13 | 14 | @override 15 | Widget build(BuildContext context) { 16 | if (noAppBar ?? false) { 17 | return Scaffold( 18 | backgroundColor: Globals.ctp.base, 19 | body: Padding(padding: const EdgeInsets.all(12), child: body), 20 | appBar: AppBar( 21 | backgroundColor: Colors.transparent, 22 | iconTheme: IconThemeData(color: Globals.ctp.text), 23 | ), 24 | ); 25 | } 26 | 27 | if (appBar != null) { 28 | return Scaffold( 29 | backgroundColor: Globals.ctp.base, 30 | body: Padding(padding: const EdgeInsets.all(12), child: body), 31 | appBar: AppBar( 32 | backgroundColor: Colors.transparent, 33 | iconTheme: IconThemeData(color: Globals.ctp.text), 34 | title: appBar, 35 | centerTitle: centerAppBar, 36 | ), 37 | ); 38 | } 39 | 40 | return Scaffold( 41 | backgroundColor: Globals.ctp.base, 42 | body: Padding(padding: const EdgeInsets.all(12), child: body), 43 | appBar: const EzAppBar(), 44 | ); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /lib/widgets/ez/appbar.dart: -------------------------------------------------------------------------------- 1 | import 'package:catppuccin_flutter/catppuccin_flutter.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:ollama_app/globals.dart'; 4 | import 'package:ollama_app/widgets/ez/text.dart'; 5 | import 'package:ollama_app/widgets/icons/bars3.dart'; 6 | import 'package:ollama_app/widgets/icons/cog6tooth.dart'; 7 | import 'package:ollama_app/widgets/icons/ollama_logo.dart'; 8 | 9 | class EzAppBar extends StatefulWidget implements PreferredSizeWidget { 10 | const EzAppBar({super.key}); 11 | 12 | @override 13 | EzAppBarState createState() => EzAppBarState(); 14 | 15 | @override 16 | Size get preferredSize => const Size.fromHeight(kToolbarHeight); 17 | } 18 | 19 | class EzAppBarState extends State { 20 | @override 21 | Widget build(BuildContext context) { 22 | return AppBar( 23 | backgroundColor: Colors.transparent, 24 | iconTheme: IconThemeData(color: Globals.ctp.text), 25 | title: Row( 26 | mainAxisAlignment: MainAxisAlignment.spaceBetween, 27 | children: [ 28 | IconButton( 29 | onPressed: () {}, 30 | icon: Bars3(color: Globals.ctp.text), 31 | ), 32 | Row(children: [ 33 | const Padding( 34 | padding: EdgeInsets.only(right: 8), 35 | child: OllamaLogo(), 36 | ), 37 | EzText('Ollama', 38 | color: Globals.ctp == catppuccin.latte 39 | ? Colors.black 40 | : Colors.white, 41 | bold: true, 42 | fontSize: 28), 43 | ]), 44 | IconButton( 45 | onPressed: () => Navigator.of(context).pushNamed('/settings'), 46 | icon: Cog6Tooth(color: Globals.ctp.text), 47 | ), 48 | ], 49 | ), 50 | ); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: "54e66469a933b60ddf175f858f82eaeb97e48c8d" 8 | channel: "stable" 9 | 10 | project_type: app 11 | 12 | # Tracks metadata for the flutter migrate command 13 | migration: 14 | platforms: 15 | - platform: root 16 | create_revision: 54e66469a933b60ddf175f858f82eaeb97e48c8d 17 | base_revision: 54e66469a933b60ddf175f858f82eaeb97e48c8d 18 | - platform: android 19 | create_revision: 54e66469a933b60ddf175f858f82eaeb97e48c8d 20 | base_revision: 54e66469a933b60ddf175f858f82eaeb97e48c8d 21 | - platform: ios 22 | create_revision: 54e66469a933b60ddf175f858f82eaeb97e48c8d 23 | base_revision: 54e66469a933b60ddf175f858f82eaeb97e48c8d 24 | - platform: linux 25 | create_revision: 54e66469a933b60ddf175f858f82eaeb97e48c8d 26 | base_revision: 54e66469a933b60ddf175f858f82eaeb97e48c8d 27 | - platform: macos 28 | create_revision: 54e66469a933b60ddf175f858f82eaeb97e48c8d 29 | base_revision: 54e66469a933b60ddf175f858f82eaeb97e48c8d 30 | - platform: web 31 | create_revision: 54e66469a933b60ddf175f858f82eaeb97e48c8d 32 | base_revision: 54e66469a933b60ddf175f858f82eaeb97e48c8d 33 | - platform: windows 34 | create_revision: 54e66469a933b60ddf175f858f82eaeb97e48c8d 35 | base_revision: 54e66469a933b60ddf175f858f82eaeb97e48c8d 36 | 37 | # User provided section 38 | 39 | # List of Local paths (relative to this file) that should be 40 | # ignored by the migrate tool. 41 | # 42 | # Files that are not part of the templates will be ignored by default. 43 | unmanaged_files: 44 | - 'lib/main.dart' 45 | - 'ios/Runner.xcodeproj/project.pbxproj' 46 | -------------------------------------------------------------------------------- /android/app/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id "com.android.application" 3 | id "kotlin-android" 4 | id "dev.flutter.flutter-gradle-plugin" 5 | } 6 | 7 | def localProperties = new Properties() 8 | def localPropertiesFile = rootProject.file('local.properties') 9 | if (localPropertiesFile.exists()) { 10 | localPropertiesFile.withReader('UTF-8') { reader -> 11 | localProperties.load(reader) 12 | } 13 | } 14 | 15 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode') 16 | if (flutterVersionCode == null) { 17 | flutterVersionCode = '1' 18 | } 19 | 20 | def flutterVersionName = localProperties.getProperty('flutter.versionName') 21 | if (flutterVersionName == null) { 22 | flutterVersionName = '1.0' 23 | } 24 | 25 | android { 26 | namespace "com.ollama" 27 | compileSdk flutter.compileSdkVersion 28 | ndkVersion flutter.ndkVersion 29 | 30 | compileOptions { 31 | sourceCompatibility JavaVersion.VERSION_1_8 32 | targetCompatibility JavaVersion.VERSION_1_8 33 | } 34 | 35 | kotlinOptions { 36 | jvmTarget = '1.8' 37 | } 38 | 39 | sourceSets { 40 | main.java.srcDirs += 'src/main/kotlin' 41 | } 42 | 43 | defaultConfig { 44 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). 45 | applicationId "com.ollama" 46 | // You can update the following values to match your application needs. 47 | // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration. 48 | minSdkVersion flutter.minSdkVersion 49 | targetSdkVersion flutter.targetSdkVersion 50 | versionCode flutterVersionCode.toInteger() 51 | versionName flutterVersionName 52 | } 53 | 54 | buildTypes { 55 | release { 56 | // TODO: Add your own signing config for the release build. 57 | // Signing with the debug keys for now, so `flutter run --release` works. 58 | signingConfig signingConfigs.debug 59 | } 60 | } 61 | } 62 | 63 | flutter { 64 | source '../..' 65 | } 66 | 67 | dependencies {} 68 | -------------------------------------------------------------------------------- /lib/routes/home.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:ollama_app/types/message.dart'; 3 | import 'package:ollama_app/widgets/ez/message.dart'; 4 | import 'package:ollama_app/widgets/ez/textfield.dart'; 5 | import 'package:ollama_app/utils/api.dart' as api; 6 | import 'package:ollama_app/widgets/icons/ollama_logo.dart'; 7 | import 'package:ollama_app/widgets/icons/usercircle.dart'; 8 | 9 | class Home extends StatefulWidget { 10 | const Home({super.key}); 11 | 12 | @override 13 | State createState() => _HomeState(); 14 | } 15 | 16 | class _HomeState extends State { 17 | late List _messages; 18 | 19 | @override 20 | void initState() { 21 | super.initState(); 22 | _messages = []; 23 | } 24 | 25 | @override 26 | Widget build(BuildContext context) { 27 | return Column( 28 | children: [ 29 | Column( 30 | children: _messages 31 | .map((message) => EzMessage(message: message)) 32 | .toList()), 33 | Align( 34 | alignment: FractionalOffset.bottomCenter, 35 | child: EzTextField( 36 | hintText: 'Message Ollama', 37 | onSubmitted: (text) async { 38 | setState(() { 39 | _messages.add(Message( 40 | username: 'You', 41 | content: text, 42 | pfp: const UserCircle(size: 55), 43 | )); 44 | 45 | _messages.add(Message( 46 | username: 'LLaMA 3', 47 | content: null, 48 | pfp: const OllamaLogo(width: 55, height: 55), 49 | )); 50 | }); 51 | 52 | String? res = await api.infer(text, 'llama3'); 53 | if (res == null) { 54 | setState(() { 55 | _messages.last.error = true; 56 | _messages.last.content = 'Failed to infer Ollama!'; 57 | }); 58 | 59 | return; 60 | } 61 | 62 | setState(() => _messages.last.content = res); 63 | }, 64 | ), 65 | ), 66 | ], 67 | ); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /lib/widgets/ez/message.dart: -------------------------------------------------------------------------------- 1 | import 'package:shimmer/shimmer.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:ollama_app/globals.dart'; 4 | import 'package:ollama_app/types/message.dart'; 5 | import 'package:ollama_app/widgets/ez/text.dart'; 6 | 7 | class EzMessage extends StatelessWidget { 8 | const EzMessage({super.key, required this.message}); 9 | 10 | final Message message; 11 | 12 | @override 13 | Widget build(BuildContext context) { 14 | return Padding( 15 | padding: const EdgeInsets.symmetric(vertical: 4), 16 | child: Row( 17 | children: [ 18 | message.pfp, 19 | Padding( 20 | padding: const EdgeInsets.only(left: 8), 21 | child: Column( 22 | crossAxisAlignment: CrossAxisAlignment.start, 23 | mainAxisAlignment: MainAxisAlignment.start, 24 | children: [ 25 | EzText(message.username, fontSize: 20, bold: true), 26 | message.content == null 27 | ? SizedBox( 28 | width: MediaQuery.of(context).size.width - 100, 29 | height: 30, 30 | child: Shimmer.fromColors( 31 | baseColor: Globals.ctp.surface0, 32 | highlightColor: Globals.ctp.text, 33 | period: const Duration(milliseconds: 1500), 34 | child: Container( 35 | decoration: const BoxDecoration( 36 | borderRadius: BorderRadius.all( 37 | Radius.circular(3.3), 38 | ), 39 | color: Colors.white, 40 | ), 41 | ), 42 | ), 43 | ) 44 | : EzText( 45 | message.content!, 46 | fontSize: 20, 47 | color: (message.error ?? false) 48 | ? Globals.ctp.red 49 | : Globals.ctp.text, 50 | ), 51 | ], 52 | ), 53 | ), 54 | ], 55 | ), 56 | ); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 14 | 18 | 22 | 23 | 24 | 25 | 26 | 27 | 29 | 32 | 33 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /lib/widgets/ez/textfield.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:ollama_app/globals.dart'; 3 | import 'package:ollama_app/widgets/icons/arrowup.dart'; 4 | 5 | typedef OnSubmittedCallback = void Function(String text); 6 | typedef OnChangedCallback = void Function(String text); 7 | 8 | class EzTextField extends StatefulWidget { 9 | const EzTextField({ 10 | super.key, 11 | this.onSubmitted, 12 | this.onChanged, 13 | this.disableSubmitButton, 14 | this.hintText, 15 | this.obscureText, 16 | this.defaultValue, 17 | }); 18 | 19 | final OnSubmittedCallback? onSubmitted; 20 | final OnChangedCallback? onChanged; 21 | final bool? disableSubmitButton; 22 | final String? hintText; 23 | final bool? obscureText; 24 | final String? defaultValue; 25 | 26 | @override 27 | State createState() => _EzTextFieldState(); 28 | } 29 | 30 | class _EzTextFieldState extends State { 31 | bool _sendButtonDisabled = true; 32 | late TextEditingController _controller; 33 | 34 | @override 35 | void initState() { 36 | super.initState(); 37 | _controller = TextEditingController(); 38 | _controller.addListener(_onTextChanged); 39 | _controller.text = widget.defaultValue ?? ''; 40 | } 41 | 42 | @override 43 | void dispose() { 44 | _controller.removeListener(_onTextChanged); 45 | _controller.dispose(); 46 | super.dispose(); 47 | } 48 | 49 | void _onTextChanged() { 50 | setState(() { 51 | if (widget.onChanged != null) { 52 | widget.onChanged!(_controller.text); 53 | } 54 | 55 | if (_controller.text.trim().isNotEmpty) { 56 | _sendButtonDisabled = false; 57 | return; 58 | } 59 | 60 | _sendButtonDisabled = true; 61 | }); 62 | } 63 | 64 | @override 65 | Widget build(BuildContext context) { 66 | const border = OutlineInputBorder( 67 | borderSide: BorderSide.none, 68 | borderRadius: BorderRadius.horizontal( 69 | left: Radius.circular(9999), 70 | right: Radius.circular(9999), 71 | ), 72 | ); 73 | 74 | return SizedBox( 75 | height: 48, 76 | child: TextField( 77 | controller: _controller, 78 | style: TextStyle(color: Globals.ctp.text, fontWeight: FontWeight.w600), 79 | decoration: InputDecoration( 80 | filled: true, 81 | fillColor: Globals.ctp.surface2, 82 | border: border, 83 | focusedBorder: border, 84 | contentPadding: const EdgeInsets.symmetric(horizontal: 18), 85 | hintText: widget.hintText, 86 | hintStyle: TextStyle( 87 | color: Globals.ctp.overlay2, 88 | fontWeight: FontWeight.w600, 89 | ), 90 | suffixIcon: (widget.disableSubmitButton ?? false) 91 | ? null 92 | : Padding( 93 | padding: const EdgeInsets.all(4), 94 | child: IconButton.filled( 95 | icon: ArrowUp( 96 | color: _sendButtonDisabled 97 | ? Globals.ctp.text 98 | : Globals.ctp.base), 99 | style: ButtonStyle( 100 | backgroundColor: WidgetStateProperty.all( 101 | _sendButtonDisabled 102 | ? Globals.ctp.surface0 103 | : Globals.ctp.green, 104 | ), 105 | ), 106 | onPressed: _sendButtonDisabled 107 | ? null 108 | : () => (widget.onSubmitted ?? 109 | (String text) {})(_controller.text), 110 | ), 111 | ), 112 | ), 113 | obscureText: widget.obscureText ?? false, 114 | cursorColor: Globals.ctp.lavender, 115 | ), 116 | ); 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /lib/routes/settings.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:ollama_app/globals.dart'; 3 | import 'package:ollama_app/widgets/ez/button.dart'; 4 | import 'package:ollama_app/widgets/ez/dropdown.dart'; 5 | import 'package:ollama_app/widgets/ez/scaffold.dart'; 6 | import 'package:ollama_app/widgets/ez/text.dart'; 7 | import 'package:ollama_app/widgets/ez/textfield.dart'; 8 | import 'package:ollama_app/widgets/icons/check.dart'; 9 | import 'package:ollama_app/widgets/icons/cog6tooth.dart'; 10 | import 'package:ollama_app/widgets/icons/xmark.dart'; 11 | import 'package:ollama_app/widgets/rerender_widget.dart'; 12 | import 'package:ollama_app/utils/api.dart' as api; 13 | 14 | class Settings extends StatefulWidget { 15 | const Settings({super.key}); 16 | 17 | @override 18 | State createState() => _SettingsState(); 19 | } 20 | 21 | class _SettingsState extends State { 22 | late Map _connectionTestStates; 23 | late String _currentConnectionTestState; 24 | 25 | @override 26 | void initState() { 27 | super.initState(); 28 | _connectionTestStates = { 29 | 'notTesting': EzButton( 30 | onPressed: () async { 31 | setState(() => _currentConnectionTestState = 'testing'); 32 | 33 | if (await api.isConnected()) { 34 | setState(() => _currentConnectionTestState = 'success'); 35 | } else { 36 | setState(() => _currentConnectionTestState = 'failed'); 37 | } 38 | 39 | Future.delayed( 40 | const Duration(seconds: 3), 41 | () => setState(() => _currentConnectionTestState = 'notTesting'), 42 | ); 43 | }, 44 | child: const EzText( 45 | 'Test connection', 46 | fontSize: 20, 47 | ), 48 | ), 49 | 'testing': Center( 50 | child: CircularProgressIndicator( 51 | backgroundColor: Colors.transparent, 52 | color: Globals.ctp.blue, 53 | ), 54 | ), 55 | 'failed': const Row( 56 | mainAxisAlignment: MainAxisAlignment.center, 57 | crossAxisAlignment: CrossAxisAlignment.center, 58 | children: [ 59 | Padding( 60 | padding: EdgeInsets.only(right: 8), 61 | child: XMark(), 62 | ), 63 | EzText('Failed!'), 64 | ], 65 | ), 66 | 'success': const Row( 67 | mainAxisAlignment: MainAxisAlignment.center, 68 | crossAxisAlignment: CrossAxisAlignment.center, 69 | children: [ 70 | Padding( 71 | padding: EdgeInsets.only(right: 8), 72 | child: Check(), 73 | ), 74 | EzText('Connected!'), 75 | ], 76 | ), 77 | }; 78 | _currentConnectionTestState = 'notTesting'; 79 | } 80 | 81 | @override 82 | Widget build(BuildContext context) { 83 | return EzScaffold( 84 | appBar: Row( 85 | mainAxisAlignment: MainAxisAlignment.center, 86 | mainAxisSize: MainAxisSize.min, 87 | children: [ 88 | Padding( 89 | padding: const EdgeInsets.only(right: 8), 90 | child: Cog6Tooth(color: Globals.ctp.text), 91 | ), 92 | const EzText('Settings'), 93 | ], 94 | ), 95 | centerAppBar: true, 96 | body: Column( 97 | children: [ 98 | const Align( 99 | alignment: Alignment.topLeft, 100 | child: Padding( 101 | padding: EdgeInsets.only(right: 6, left: 6, bottom: 12), 102 | child: EzText('Ollama API', fontSize: 32, bold: true), 103 | ), 104 | ), 105 | Padding( 106 | padding: const EdgeInsets.only(bottom: 8), 107 | child: EzTextField( 108 | disableSubmitButton: true, 109 | hintText: 'Ollama Base URL (Required)', 110 | onChanged: (text) { 111 | Globals.prefs.setString('baseUrl', text); 112 | Globals.baseUrl = text; 113 | }, 114 | defaultValue: Globals.baseUrl, 115 | ), 116 | ), 117 | Padding( 118 | padding: const EdgeInsets.only(bottom: 6), 119 | child: EzTextField( 120 | disableSubmitButton: true, 121 | hintText: 'Ollama API Key (Optional)', 122 | onChanged: (text) { 123 | Globals.prefs.setString('apiKey', text); 124 | Globals.apiKey = text; 125 | }, 126 | obscureText: true, 127 | defaultValue: Globals.apiKey, 128 | ), 129 | ), 130 | Padding( 131 | padding: const EdgeInsets.only(top: 8), 132 | child: SizedBox( 133 | width: 200, 134 | height: 50, 135 | child: _connectionTestStates[_currentConnectionTestState]!, 136 | ), 137 | ), 138 | const Align( 139 | alignment: Alignment.topLeft, 140 | child: Padding( 141 | padding: EdgeInsets.only(right: 6, left: 6, top: 32), 142 | child: EzText('Personalization', fontSize: 32, bold: true), 143 | ), 144 | ), 145 | Padding( 146 | padding: const EdgeInsets.symmetric(horizontal: 6), 147 | child: Row(children: [ 148 | const EzText('Catppuccin Theme: ', fontSize: 20), 149 | Padding( 150 | padding: const EdgeInsets.symmetric(horizontal: 8), 151 | child: SizedBox( 152 | child: Dropdown( 153 | items: const ['Latte', 'Frappé', 'Macchiato', 'Mocha'], 154 | defaultItem: Globals.prefs.getString('theme') ?? 'Mocha', 155 | onChanged: (item) { 156 | Globals.prefs.setString('theme', item); 157 | Globals.reloadGlobals(); 158 | RerenderWidget.rerenderApp(context); 159 | }, 160 | ), 161 | ), 162 | ), 163 | ]), 164 | ), 165 | ], 166 | ), 167 | ); 168 | } 169 | } 170 | -------------------------------------------------------------------------------- /pubspec.lock: -------------------------------------------------------------------------------- 1 | # Generated by pub 2 | # See https://dart.dev/tools/pub/glossary#lockfile 3 | packages: 4 | args: 5 | dependency: transitive 6 | description: 7 | name: args 8 | sha256: "7cf60b9f0cc88203c5a190b4cd62a99feea42759a7fa695010eb5de1c0b2252a" 9 | url: "https://pub.dev" 10 | source: hosted 11 | version: "2.5.0" 12 | async: 13 | dependency: transitive 14 | description: 15 | name: async 16 | sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" 17 | url: "https://pub.dev" 18 | source: hosted 19 | version: "2.11.0" 20 | catppuccin_flutter: 21 | dependency: "direct main" 22 | description: 23 | name: catppuccin_flutter 24 | sha256: af76e96f39ebf228d943b46f64e50c683d2580b4ef4088f28214e35ff26a2543 25 | url: "https://pub.dev" 26 | source: hosted 27 | version: "1.0.0" 28 | characters: 29 | dependency: transitive 30 | description: 31 | name: characters 32 | sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" 33 | url: "https://pub.dev" 34 | source: hosted 35 | version: "1.3.0" 36 | collection: 37 | dependency: transitive 38 | description: 39 | name: collection 40 | sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a 41 | url: "https://pub.dev" 42 | source: hosted 43 | version: "1.18.0" 44 | ffi: 45 | dependency: transitive 46 | description: 47 | name: ffi 48 | sha256: "493f37e7df1804778ff3a53bd691d8692ddf69702cf4c1c1096a2e41b4779e21" 49 | url: "https://pub.dev" 50 | source: hosted 51 | version: "2.1.2" 52 | file: 53 | dependency: transitive 54 | description: 55 | name: file 56 | sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c" 57 | url: "https://pub.dev" 58 | source: hosted 59 | version: "7.0.0" 60 | flutter: 61 | dependency: "direct main" 62 | description: flutter 63 | source: sdk 64 | version: "0.0.0" 65 | flutter_lints: 66 | dependency: "direct dev" 67 | description: 68 | name: flutter_lints 69 | sha256: "3f41d009ba7172d5ff9be5f6e6e6abb4300e263aab8866d2a0842ed2a70f8f0c" 70 | url: "https://pub.dev" 71 | source: hosted 72 | version: "4.0.0" 73 | flutter_svg: 74 | dependency: transitive 75 | description: 76 | name: flutter_svg 77 | sha256: "7b4ca6cf3304575fe9c8ec64813c8d02ee41d2afe60bcfe0678bcb5375d596a2" 78 | url: "https://pub.dev" 79 | source: hosted 80 | version: "2.0.10+1" 81 | flutter_web_plugins: 82 | dependency: transitive 83 | description: flutter 84 | source: sdk 85 | version: "0.0.0" 86 | fluttertoast: 87 | dependency: "direct main" 88 | description: 89 | name: fluttertoast 90 | sha256: "81b68579e23fcbcada2db3d50302813d2371664afe6165bc78148050ab94bf66" 91 | url: "https://pub.dev" 92 | source: hosted 93 | version: "8.2.5" 94 | heroicons: 95 | dependency: "direct main" 96 | description: 97 | name: heroicons 98 | sha256: "762f907af146105a3956e61e16e0a2cafadd39317e88cc4e4d0ed32846a0452e" 99 | url: "https://pub.dev" 100 | source: hosted 101 | version: "0.10.0" 102 | http: 103 | dependency: "direct main" 104 | description: 105 | name: http 106 | sha256: "761a297c042deedc1ffbb156d6e2af13886bb305c2a343a4d972504cd67dd938" 107 | url: "https://pub.dev" 108 | source: hosted 109 | version: "1.2.1" 110 | http_parser: 111 | dependency: transitive 112 | description: 113 | name: http_parser 114 | sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" 115 | url: "https://pub.dev" 116 | source: hosted 117 | version: "4.0.2" 118 | lints: 119 | dependency: transitive 120 | description: 121 | name: lints 122 | sha256: "976c774dd944a42e83e2467f4cc670daef7eed6295b10b36ae8c85bcbf828235" 123 | url: "https://pub.dev" 124 | source: hosted 125 | version: "4.0.0" 126 | material_color_utilities: 127 | dependency: transitive 128 | description: 129 | name: material_color_utilities 130 | sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a" 131 | url: "https://pub.dev" 132 | source: hosted 133 | version: "0.8.0" 134 | meta: 135 | dependency: transitive 136 | description: 137 | name: meta 138 | sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136" 139 | url: "https://pub.dev" 140 | source: hosted 141 | version: "1.12.0" 142 | path: 143 | dependency: transitive 144 | description: 145 | name: path 146 | sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" 147 | url: "https://pub.dev" 148 | source: hosted 149 | version: "1.9.0" 150 | path_parsing: 151 | dependency: transitive 152 | description: 153 | name: path_parsing 154 | sha256: e3e67b1629e6f7e8100b367d3db6ba6af4b1f0bb80f64db18ef1fbabd2fa9ccf 155 | url: "https://pub.dev" 156 | source: hosted 157 | version: "1.0.1" 158 | path_provider_linux: 159 | dependency: transitive 160 | description: 161 | name: path_provider_linux 162 | sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279 163 | url: "https://pub.dev" 164 | source: hosted 165 | version: "2.2.1" 166 | path_provider_platform_interface: 167 | dependency: transitive 168 | description: 169 | name: path_provider_platform_interface 170 | sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334" 171 | url: "https://pub.dev" 172 | source: hosted 173 | version: "2.1.2" 174 | path_provider_windows: 175 | dependency: transitive 176 | description: 177 | name: path_provider_windows 178 | sha256: "8bc9f22eee8690981c22aa7fc602f5c85b497a6fb2ceb35ee5a5e5ed85ad8170" 179 | url: "https://pub.dev" 180 | source: hosted 181 | version: "2.2.1" 182 | petitparser: 183 | dependency: transitive 184 | description: 185 | name: petitparser 186 | sha256: c15605cd28af66339f8eb6fbe0e541bfe2d1b72d5825efc6598f3e0a31b9ad27 187 | url: "https://pub.dev" 188 | source: hosted 189 | version: "6.0.2" 190 | platform: 191 | dependency: transitive 192 | description: 193 | name: platform 194 | sha256: "12220bb4b65720483f8fa9450b4332347737cf8213dd2840d8b2c823e47243ec" 195 | url: "https://pub.dev" 196 | source: hosted 197 | version: "3.1.4" 198 | plugin_platform_interface: 199 | dependency: transitive 200 | description: 201 | name: plugin_platform_interface 202 | sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" 203 | url: "https://pub.dev" 204 | source: hosted 205 | version: "2.1.8" 206 | shared_preferences: 207 | dependency: "direct main" 208 | description: 209 | name: shared_preferences 210 | sha256: d3bbe5553a986e83980916ded2f0b435ef2e1893dfaa29d5a7a790d0eca12180 211 | url: "https://pub.dev" 212 | source: hosted 213 | version: "2.2.3" 214 | shared_preferences_android: 215 | dependency: transitive 216 | description: 217 | name: shared_preferences_android 218 | sha256: "1ee8bf911094a1b592de7ab29add6f826a7331fb854273d55918693d5364a1f2" 219 | url: "https://pub.dev" 220 | source: hosted 221 | version: "2.2.2" 222 | shared_preferences_foundation: 223 | dependency: transitive 224 | description: 225 | name: shared_preferences_foundation 226 | sha256: "0a8a893bf4fd1152f93fec03a415d11c27c74454d96e2318a7ac38dd18683ab7" 227 | url: "https://pub.dev" 228 | source: hosted 229 | version: "2.4.0" 230 | shared_preferences_linux: 231 | dependency: transitive 232 | description: 233 | name: shared_preferences_linux 234 | sha256: "9f2cbcf46d4270ea8be39fa156d86379077c8a5228d9dfdb1164ae0bb93f1faa" 235 | url: "https://pub.dev" 236 | source: hosted 237 | version: "2.3.2" 238 | shared_preferences_platform_interface: 239 | dependency: transitive 240 | description: 241 | name: shared_preferences_platform_interface 242 | sha256: "22e2ecac9419b4246d7c22bfbbda589e3acf5c0351137d87dd2939d984d37c3b" 243 | url: "https://pub.dev" 244 | source: hosted 245 | version: "2.3.2" 246 | shared_preferences_web: 247 | dependency: transitive 248 | description: 249 | name: shared_preferences_web 250 | sha256: "9aee1089b36bd2aafe06582b7d7817fd317ef05fc30e6ba14bff247d0933042a" 251 | url: "https://pub.dev" 252 | source: hosted 253 | version: "2.3.0" 254 | shared_preferences_windows: 255 | dependency: transitive 256 | description: 257 | name: shared_preferences_windows 258 | sha256: "841ad54f3c8381c480d0c9b508b89a34036f512482c407e6df7a9c4aa2ef8f59" 259 | url: "https://pub.dev" 260 | source: hosted 261 | version: "2.3.2" 262 | shimmer: 263 | dependency: "direct main" 264 | description: 265 | name: shimmer 266 | sha256: "5f88c883a22e9f9f299e5ba0e4f7e6054857224976a5d9f839d4ebdc94a14ac9" 267 | url: "https://pub.dev" 268 | source: hosted 269 | version: "3.0.0" 270 | sky_engine: 271 | dependency: transitive 272 | description: flutter 273 | source: sdk 274 | version: "0.0.99" 275 | source_span: 276 | dependency: transitive 277 | description: 278 | name: source_span 279 | sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" 280 | url: "https://pub.dev" 281 | source: hosted 282 | version: "1.10.0" 283 | string_scanner: 284 | dependency: transitive 285 | description: 286 | name: string_scanner 287 | sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" 288 | url: "https://pub.dev" 289 | source: hosted 290 | version: "1.2.0" 291 | term_glyph: 292 | dependency: transitive 293 | description: 294 | name: term_glyph 295 | sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 296 | url: "https://pub.dev" 297 | source: hosted 298 | version: "1.2.1" 299 | typed_data: 300 | dependency: transitive 301 | description: 302 | name: typed_data 303 | sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c 304 | url: "https://pub.dev" 305 | source: hosted 306 | version: "1.3.2" 307 | vector_graphics: 308 | dependency: transitive 309 | description: 310 | name: vector_graphics 311 | sha256: "32c3c684e02f9bc0afb0ae0aa653337a2fe022e8ab064bcd7ffda27a74e288e3" 312 | url: "https://pub.dev" 313 | source: hosted 314 | version: "1.1.11+1" 315 | vector_graphics_codec: 316 | dependency: transitive 317 | description: 318 | name: vector_graphics_codec 319 | sha256: c86987475f162fadff579e7320c7ddda04cd2fdeffbe1129227a85d9ac9e03da 320 | url: "https://pub.dev" 321 | source: hosted 322 | version: "1.1.11+1" 323 | vector_graphics_compiler: 324 | dependency: transitive 325 | description: 326 | name: vector_graphics_compiler 327 | sha256: "12faff3f73b1741a36ca7e31b292ddeb629af819ca9efe9953b70bd63fc8cd81" 328 | url: "https://pub.dev" 329 | source: hosted 330 | version: "1.1.11+1" 331 | vector_math: 332 | dependency: transitive 333 | description: 334 | name: vector_math 335 | sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" 336 | url: "https://pub.dev" 337 | source: hosted 338 | version: "2.1.4" 339 | web: 340 | dependency: transitive 341 | description: 342 | name: web 343 | sha256: "97da13628db363c635202ad97068d47c5b8aa555808e7a9411963c533b449b27" 344 | url: "https://pub.dev" 345 | source: hosted 346 | version: "0.5.1" 347 | win32: 348 | dependency: transitive 349 | description: 350 | name: win32 351 | sha256: "0eaf06e3446824099858367950a813472af675116bf63f008a4c2a75ae13e9cb" 352 | url: "https://pub.dev" 353 | source: hosted 354 | version: "5.5.0" 355 | xdg_directories: 356 | dependency: transitive 357 | description: 358 | name: xdg_directories 359 | sha256: faea9dee56b520b55a566385b84f2e8de55e7496104adada9962e0bd11bcff1d 360 | url: "https://pub.dev" 361 | source: hosted 362 | version: "1.0.4" 363 | xml: 364 | dependency: transitive 365 | description: 366 | name: xml 367 | sha256: b015a8ad1c488f66851d762d3090a21c600e479dc75e68328c52774040cf9226 368 | url: "https://pub.dev" 369 | source: hosted 370 | version: "6.5.0" 371 | sdks: 372 | dart: ">=3.3.4 <4.0.0" 373 | flutter: ">=3.19.0" 374 | --------------------------------------------------------------------------------