diff --git a/android/app/build.gradle b/android/app/build.gradle old mode 100644 new mode 100755 index 8e29607..8215c9b --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -6,10 +6,10 @@ plugins { } android { - namespace = "com.example.muzzlevelocity" + namespace = "vision.flux.muzzlevelocity" compileSdk = flutter.compileSdkVersion ndkVersion = flutter.ndkVersion - compileSdkVersion 34 + compileSdkVersion 36 compileOptions { sourceCompatibility = JavaVersion.VERSION_1_8 @@ -22,14 +22,14 @@ android { defaultConfig { // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). - applicationId = "com.example.muzzlevelocity" + applicationId = "vision.flux.muzzlevelocity" // You can update the following values to match your application needs. // For more information, see: https://flutter.dev/to/review-gradle-config. minSdk = flutter.minSdkVersion targetSdk = flutter.targetSdkVersion versionCode = flutter.versionCode versionName = flutter.versionName - targetSdkVersion 34 + targetSdkVersion 36 } buildTypes { diff --git a/android/build.gradle b/android/build.gradle old mode 100644 new mode 100755 index d2ffbff..37c9540 --- a/android/build.gradle +++ b/android/build.gradle @@ -7,10 +7,36 @@ allprojects { rootProject.buildDir = "../build" subprojects { + afterEvaluate { project -> + if (project.hasProperty("android")) { + project.android { + compileSdkVersion 36 + } + } + } project.buildDir = "${rootProject.buildDir}/${project.name}" -} -subprojects { - project.evaluationDependsOn(":app") + project.evaluationDependsOn(':app') + + plugins.withId('com.android.library') { + extensions.configure(com.android.build.gradle.LibraryExtension) { android -> + def manifestFile = android.sourceSets.main.manifest.srcFile + def packageName = null + if (manifestFile.exists()) { + def manifestContent = new XmlParser().parse(file(manifestFile)) + packageName = manifestContent.@package + } + if (!android.hasProperty("namespace") || android.namespace == null || android.namespace.isEmpty()) { + if (packageName) { + println ">> Derived Namespace for: '${project.name}' to '${packageName}'" + android.namespace = packageName + } else { + def defaultNamespace = "com.example.${project.name}" + println "?? Made up Namespace for: '${project.name}' to '${defaultNamespace}'" + android.namespace = defaultNamespace + } + } + } + } } tasks.register("clean", Delete) { diff --git a/android/gradle.properties b/android/gradle.properties old mode 100644 new mode 100755 index 2597170..c702cbd --- a/android/gradle.properties +++ b/android/gradle.properties @@ -1,3 +1,5 @@ org.gradle.jvmargs=-Xmx4G -XX:MaxMetaspaceSize=2G -XX:+HeapDumpOnOutOfMemoryError android.useAndroidX=true android.enableJetifier=true +kotlin.incremental=false +kotlin.compiler.execution.strategy=in-process diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties old mode 100644 new mode 100755 index 7bb2df6..efdcc4a --- a/android/gradle/wrapper/gradle-wrapper.properties +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-all.zip diff --git a/android/nix-android-sdk/android-studio-devbox-config.sh b/android/nix-android-sdk/android-studio-devbox-config.sh new file mode 100755 index 0000000..55f37ae --- /dev/null +++ b/android/nix-android-sdk/android-studio-devbox-config.sh @@ -0,0 +1,59 @@ +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(cd -- "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_DIR="$(cd -- "$SCRIPT_DIR/../.." && pwd)" +IDEA_DIR="$PROJECT_DIR/.idea" +LIBRARIES_DIR="$IDEA_DIR/libraries" +FLUTTER_SDK="$PROJECT_DIR/.devbox/nix/profile/default" +DART_SDK="$FLUTTER_SDK/bin/cache/dart-sdk" + +mkdir -p "$IDEA_DIR" +if [ ! -x "$FLUTTER_SDK/bin/flutter" ]; then + echo "Flutter not found at $FLUTTER_SDK/bin/flutter. Run devbox install to download it." >&2 + exit 1 +fi + +if [ ! -d "$DART_SDK" ]; then + echo "Dart SDK not found at $DART_SDK. Run flutter doctor to populate the cache." >&2 + exit 1 +fi + +mkdir -p "$LIBRARIES_DIR" + +cat > "$IDEA_DIR/flutter.xml" <<'EOF' + + + + + +EOF + +cat > "$IDEA_DIR/dart.xml" <<'EOF' + + + + + +EOF + +dart_libs=$(find "$DART_SDK/lib" -maxdepth 1 -mindepth 1 -type d -printf '%f\n' | sort) +tmp_file=$(mktemp) +{ + echo '' + echo ' ' + echo ' ' + for lib in $dart_libs; do + printf ' \n' "$lib" + done + echo ' ' + echo ' ' + echo ' ' + echo ' ' + echo '' +} > "$tmp_file" +mv "$tmp_file" "$LIBRARIES_DIR/Dart_SDK.xml" + +echo "Android Studio configured. Flutter SDK: $FLUTTER_SDK" diff --git a/android/nix-android-sdk/flake.lock b/android/nix-android-sdk/flake.lock new file mode 100644 index 0000000..23c99f2 --- /dev/null +++ b/android/nix-android-sdk/flake.lock @@ -0,0 +1,136 @@ +{ + "nodes": { + "android-nixpkgs": { + "inputs": { + "devshell": "devshell", + "flake-utils": "flake-utils", + "nixpkgs": "nixpkgs" + }, + "locked": { + "lastModified": 1768249546, + "narHash": "sha256-cpNxcSNveCBSDmocYlPrayaP8CX8ik0SKR4aNbrxOqA=", + "owner": "tadfisher", + "repo": "android-nixpkgs", + "rev": "001ffcb40e86888d38acf7b851f9a1bfac7d3a81", + "type": "github" + }, + "original": { + "owner": "tadfisher", + "ref": "stable", + "repo": "android-nixpkgs", + "type": "github" + } + }, + "devshell": { + "inputs": { + "nixpkgs": [ + "android-nixpkgs", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1764011051, + "narHash": "sha256-M7SZyPZiqZUR/EiiBJnmyUbOi5oE/03tCeFrTiUZchI=", + "owner": "numtide", + "repo": "devshell", + "rev": "17ed8d9744ebe70424659b0ef74ad6d41fc87071", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "devshell", + "type": "github" + } + }, + "flake-utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "flake-utils_2": { + "inputs": { + "systems": "systems_2" + }, + "locked": { + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1768127708, + "narHash": "sha256-1Sm77VfZh3mU0F5OqKABNLWxOuDeHIlcFjsXeeiPazs=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "ffbc9f8cbaacfb331b6017d5a5abb21a492c9a38", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "android-nixpkgs": "android-nixpkgs", + "flake-utils": "flake-utils_2" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "systems_2": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/android/nix-android-sdk/flake.nix b/android/nix-android-sdk/flake.nix new file mode 100644 index 0000000..f7bcb08 --- /dev/null +++ b/android/nix-android-sdk/flake.nix @@ -0,0 +1,27 @@ +{ + description = "A Flake for the Android SDK"; + + inputs = { + flake-utils.url = "github:numtide/flake-utils"; + android-nixpkgs.url = "github:tadfisher/android-nixpkgs/stable"; + }; + + outputs = { self, flake-utils, android-nixpkgs }: + flake-utils.lib.eachSystem ["x86_64-linux" "x86_64-darwin" "aarch64-darwin"] (system: { + packages.android-sdk = android-nixpkgs.sdk."${system}" (sdkPkgs: with sdkPkgs; [ + cmdline-tools-latest + build-tools-33-0-0 + build-tools-34-0-0 + build-tools-35-0-0 + build-tools-36-1-0 + cmake-3-22-1 + platform-tools + platforms-android-33 + platforms-android-34 + platforms-android-35 + platforms-android-36 + emulator + ndk-27-0-12077973 + ]); + }); +} diff --git a/android/settings.gradle b/android/settings.gradle old mode 100644 new mode 100755 index e07c1cb..e12d764 --- a/android/settings.gradle +++ b/android/settings.gradle @@ -18,8 +18,8 @@ pluginManagement { plugins { id "dev.flutter.flutter-plugin-loader" version "1.0.0" - id "com.android.application" version "8.2.2" apply false - id "org.jetbrains.kotlin.android" version "1.8.22" apply false + id "com.android.application" version "8.9.1" apply false + id "org.jetbrains.kotlin.android" version "2.2.20" apply false } include ":app" diff --git a/devbox.json b/devbox.json new file mode 100644 index 0000000..366845e --- /dev/null +++ b/devbox.json @@ -0,0 +1,32 @@ +{ + "$schema": "https://raw.githubusercontent.com/jetify-com/devbox/main/packages/devbox.schema.json", + "packages": [ + "nixpkgs#git", + "path:./android/nix-android-sdk#android-sdk", + "nixpkgs#android-tools", + "nixpkgs#openjdk17", + "just@latest", + "openssl@latest", + "flutter@3.35.7-sdk-links" + ], + "env": { + "ANDROID_SDK_ROOT": "$DEVBOX_PACKAGES_DIR/share/android-sdk", + "ANDROID_HOME": "$DEVBOX_PACKAGES_DIR/share/android-sdk" + }, + "nix_config": { + "allow-unfree": "true" + }, + "shell": { + "init_hook": [ + "flutter --version", + "if command -v android >/dev/null 2>&1; then export ANDROID_HOME=$(command -v android | sed -E 's|(.*libexec/android-sdk).*|\\1|'); fi", + "if [ -n \"$ANDROID_HOME\" ]; then export PATH=$ANDROID_HOME/cmdline-tools/latest/bin:$PATH; fi" + ], + "scripts": { + "doctor": "flutter doctor -v", + "link-android-tools": "if [ -n \"$ANDROID_HOME\" ] && [ ! -d \"$ANDROID_HOME/cmdline-tools/latest\" ] && [ -d \"$ANDROID_HOME/cmdline-tools/8.0\" ]; then ln -s \"$ANDROID_HOME/cmdline-tools/8.0\" \"$ANDROID_HOME/cmdline-tools/latest\"; fi", + "studio-config": "./android/nix-android-sdk/android-studio-devbox-config.sh", + "studio": "PROJECT_DIR=${DEVBOX_PROJECT_ROOT:-$(pwd)}; if command -v android-studio >/dev/null 2>&1; then android-studio \"$PROJECT_DIR\" >/dev/null 2>&1 &\nelif [ -x \"$HOME/.local/share/JetBrains/Toolbox/apps/android-studio/bin/studio.sh\" ]; then \"$HOME/.local/share/JetBrains/Toolbox/apps/android-studio/bin/studio.sh\" \"$PROJECT_DIR\" >/dev/null 2>&1 &\nelse echo \"Android Studio not found. Install it via JetBrains Toolbox.\" >&2; exit 1; fi" + } + } +} diff --git a/devbox.lock b/devbox.lock new file mode 100644 index 0000000..00baf68 --- /dev/null +++ b/devbox.lock @@ -0,0 +1,277 @@ +{ + "lockfile_version": "1", + "packages": { + "flutter@3.35.7-sdk-links": { + "last_modified": "2025-11-05T16:44:39Z", + "resolved": "github:NixOS/nixpkgs/ffcdcf99d65c61956d882df249a9be53e5902ea5#flutter", + "source": "devbox-search", + "version": "3.35.7-sdk-links", + "systems": { + "aarch64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/jkk73gnffwqw9mhcsk1ajiwnws9jlczm-flutter-wrapped-3.35.7-sdk-links", + "default": true + } + ], + "store_path": "/nix/store/jkk73gnffwqw9mhcsk1ajiwnws9jlczm-flutter-wrapped-3.35.7-sdk-links" + }, + "aarch64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/h5cfzbsnsjcb8kj2m3426bc7hp084fqa-flutter-wrapped-3.35.7-sdk-links", + "default": true + } + ], + "store_path": "/nix/store/h5cfzbsnsjcb8kj2m3426bc7hp084fqa-flutter-wrapped-3.35.7-sdk-links" + }, + "x86_64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/a6ckgh19iwmswmdhxrcilf7p6zzmqr8g-flutter-wrapped-3.35.7-sdk-links", + "default": true + } + ], + "store_path": "/nix/store/a6ckgh19iwmswmdhxrcilf7p6zzmqr8g-flutter-wrapped-3.35.7-sdk-links" + }, + "x86_64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/5hdc6vzas1kp7hkc1r8j14sdplfy954z-flutter-wrapped-3.35.7-sdk-links", + "default": true + } + ], + "store_path": "/nix/store/5hdc6vzas1kp7hkc1r8j14sdplfy954z-flutter-wrapped-3.35.7-sdk-links" + } + } + }, + "github:NixOS/nixpkgs/nixpkgs-unstable": { + "last_modified": "2026-06-16T10:57:20Z", + "resolved": "github:NixOS/nixpkgs/3e41b24abd260e8f71dbe2f5737d24122f972158?lastModified=1781607440&narHash=sha256-rxO%2Buc%2FKFbSJp%2BpgyXRuAX6QlG9hJdnt0BXpEQRXY%2BU%3D" + }, + "just@latest": { + "last_modified": "2026-05-21T08:15:18Z", + "resolved": "github:NixOS/nixpkgs/4a29d733e8a7d5b824c3d8c958a946a9867b3eb2#just", + "source": "devbox-search", + "version": "1.51.0", + "systems": { + "aarch64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/18ml04rix1526kmcv5fcir6n7cb8lxyf-just-1.51.0", + "default": true + }, + { + "name": "man", + "path": "/nix/store/48iac05gjz4kjpx605hcgn95an8ary9q-just-1.51.0-man", + "default": true + }, + { + "name": "doc", + "path": "/nix/store/d0n7b7xd2miyja6m2nlzc2szj0gqzgxb-just-1.51.0-doc" + } + ], + "store_path": "/nix/store/18ml04rix1526kmcv5fcir6n7cb8lxyf-just-1.51.0" + }, + "aarch64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/6q8i59br2gzxnqax4dz3g1fmkwp2mfs2-just-1.51.0", + "default": true + }, + { + "name": "man", + "path": "/nix/store/8ygmlmpxmggc2wqbkz1yhf7fz5nwg084-just-1.51.0-man", + "default": true + }, + { + "name": "doc", + "path": "/nix/store/ppj3c78k6x3bql77f3mgrjjrxb2jjc0q-just-1.51.0-doc" + } + ], + "store_path": "/nix/store/6q8i59br2gzxnqax4dz3g1fmkwp2mfs2-just-1.51.0" + }, + "x86_64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/7ppiil9ycr565vqgbc18x4rpgbfgcnzy-just-1.51.0", + "default": true + }, + { + "name": "man", + "path": "/nix/store/144wqvh3s441y05xvzn8m16rhcqbki7d-just-1.51.0-man", + "default": true + }, + { + "name": "doc", + "path": "/nix/store/x5g644hwbjdlij9w37gwgg1z1h4b6qqk-just-1.51.0-doc" + } + ], + "store_path": "/nix/store/7ppiil9ycr565vqgbc18x4rpgbfgcnzy-just-1.51.0" + }, + "x86_64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/3j32zmchv9wd60qng1mm04yj07wf04i8-just-1.51.0", + "default": true + }, + { + "name": "man", + "path": "/nix/store/p04vig0h2hj7hg5vgd74n5nphlcy23l8-just-1.51.0-man", + "default": true + }, + { + "name": "doc", + "path": "/nix/store/r800x8xppg70s00hw3h6x9cxpd6nh06y-just-1.51.0-doc" + } + ], + "store_path": "/nix/store/3j32zmchv9wd60qng1mm04yj07wf04i8-just-1.51.0" + } + } + }, + "nixpkgs#android-tools": { + "last_modified": "1970-01-01T00:00:00Z", + "resolved": "path:/nix/store/fm3z9r7r90yh8l7ai6cn6gsrp6h27ira-source?narHash=sha256-ypxFOeDz%2BCqADEQNL72haqGjvZQdBR5Vc7pyx2JDttI%3D#android-tools" + }, + "nixpkgs#git": { + "last_modified": "1970-01-01T00:00:00Z", + "resolved": "path:/nix/store/fm3z9r7r90yh8l7ai6cn6gsrp6h27ira-source?narHash=sha256-ypxFOeDz%2BCqADEQNL72haqGjvZQdBR5Vc7pyx2JDttI%3D#git" + }, + "nixpkgs#openjdk17": { + "last_modified": "1970-01-01T00:00:00Z", + "resolved": "path:/nix/store/fm3z9r7r90yh8l7ai6cn6gsrp6h27ira-source?narHash=sha256-ypxFOeDz%2BCqADEQNL72haqGjvZQdBR5Vc7pyx2JDttI%3D#openjdk17" + }, + "openssl@latest": { + "last_modified": "2025-12-05T06:24:47Z", + "resolved": "github:NixOS/nixpkgs/42e29df35be6ef54091d3a3b4e97056ce0a98ce8#openssl", + "source": "devbox-search", + "version": "3.6.0", + "systems": { + "aarch64-darwin": { + "outputs": [ + { + "name": "bin", + "path": "/nix/store/z9prisxci5h5lsk3rdknd4jzq7k9q13d-openssl-3.6.0-bin", + "default": true + }, + { + "name": "man", + "path": "/nix/store/ii9mnzr3i92mgk9dkgg65739mavd0j6f-openssl-3.6.0-man", + "default": true + }, + { + "name": "dev", + "path": "/nix/store/h0qgqik0mk0wn7rmm2kk3grfi1wzly74-openssl-3.6.0-dev" + }, + { + "name": "doc", + "path": "/nix/store/yx3ip21fdaaxpjn5fbir02mqnaw9cm4f-openssl-3.6.0-doc" + }, + { + "name": "out", + "path": "/nix/store/3z54dgks2mz3dhwddj158sdibll8xmq5-openssl-3.6.0" + } + ], + "store_path": "/nix/store/z9prisxci5h5lsk3rdknd4jzq7k9q13d-openssl-3.6.0-bin" + }, + "aarch64-linux": { + "outputs": [ + { + "name": "bin", + "path": "/nix/store/wb6q44n9kcb5acmaa4rgqsajadx1fhhl-openssl-3.6.0-bin", + "default": true + }, + { + "name": "man", + "path": "/nix/store/c9n1alb7ypzjvzd47m16fiwfczz23qs3-openssl-3.6.0-man", + "default": true + }, + { + "name": "debug", + "path": "/nix/store/ci6d4k1sj4bnr892lsrqqmjiihqsk0bl-openssl-3.6.0-debug" + }, + { + "name": "dev", + "path": "/nix/store/pq8b7fb3282g68pmk14mbyi20qn6chid-openssl-3.6.0-dev" + }, + { + "name": "doc", + "path": "/nix/store/vaplp6w56dyz38986bgkf0pbg3r486b2-openssl-3.6.0-doc" + }, + { + "name": "out", + "path": "/nix/store/nj50gkyx813dxvfmsg1q8m330hmf3h86-openssl-3.6.0" + } + ], + "store_path": "/nix/store/wb6q44n9kcb5acmaa4rgqsajadx1fhhl-openssl-3.6.0-bin" + }, + "x86_64-darwin": { + "outputs": [ + { + "name": "bin", + "path": "/nix/store/m3xwn9n0jypwjgi256idfzs979g30j29-openssl-3.6.0-bin", + "default": true + }, + { + "name": "man", + "path": "/nix/store/hw43f3y1vl7ydrd4samnwnrwqqwkpisv-openssl-3.6.0-man", + "default": true + }, + { + "name": "dev", + "path": "/nix/store/dirjrfjk8jgsbdpslgb51cav6qaxn2vm-openssl-3.6.0-dev" + }, + { + "name": "doc", + "path": "/nix/store/va1zhkz0nfmycvd0h239hi4w40qgaxcx-openssl-3.6.0-doc" + }, + { + "name": "out", + "path": "/nix/store/q9a4wssx24xsy28w8kifdqizc01fh7sc-openssl-3.6.0" + } + ], + "store_path": "/nix/store/m3xwn9n0jypwjgi256idfzs979g30j29-openssl-3.6.0-bin" + }, + "x86_64-linux": { + "outputs": [ + { + "name": "bin", + "path": "/nix/store/k0gl1zc7f5hk87lylxwbipb0b870bcmk-openssl-3.6.0-bin", + "default": true + }, + { + "name": "man", + "path": "/nix/store/a9jdl6xq9fc98ykpvqmc9kf0b0j9y8wh-openssl-3.6.0-man", + "default": true + }, + { + "name": "debug", + "path": "/nix/store/sqv8kbdgfxlr2d6nysr8c2715qpsi6f5-openssl-3.6.0-debug" + }, + { + "name": "dev", + "path": "/nix/store/ydrckgnllgg8nmhdwni81h7xhcpnrlhd-openssl-3.6.0-dev" + }, + { + "name": "doc", + "path": "/nix/store/cgp9ig35iwicfb9spcrgyg2m5dmlcgrv-openssl-3.6.0-doc" + }, + { + "name": "out", + "path": "/nix/store/61i74yjkj9p1qphfl7018ja4sdwkipx0-openssl-3.6.0" + } + ], + "store_path": "/nix/store/k0gl1zc7f5hk87lylxwbipb0b870bcmk-openssl-3.6.0-bin" + } + } + } + } +} diff --git a/justfile b/justfile new file mode 100644 index 0000000..4778c37 --- /dev/null +++ b/justfile @@ -0,0 +1,17 @@ +build: + flutter build apk --release + +get: + flutter pub get + +upgrade: + flutter clean && flutter pub upgrade + +icons: + flutter pub run flutter_launcher_icons + +analyze: + flutter analyze + +rebuild: + flutter clean && flutter pub upgrade && flutter pub run flutter_launcher_icons diff --git a/lib/codefield.dart b/lib/codefield.dart old mode 100644 new mode 100755 index b42b26b..cbc52b5 --- a/lib/codefield.dart +++ b/lib/codefield.dart @@ -24,7 +24,7 @@ class WrappedCodeField extends StatefulWidget { }); @override - _WrappedCodeFieldState createState() => _WrappedCodeFieldState(); + State createState() => _WrappedCodeFieldState(); } class _WrappedCodeFieldState extends State { diff --git a/lib/main.dart b/lib/main.dart old mode 100644 new mode 100755 index cb28a10..0850248 --- a/lib/main.dart +++ b/lib/main.dart @@ -14,12 +14,14 @@ void main() async { final license = await rootBundle.loadString('google_fonts/OFL.txt'); yield LicenseEntryWithLineBreaks(['google_fonts'], license); }); - runApp(MuzzleVelocityApp()); + runApp(const MuzzleVelocityApp()); } class MuzzleVelocityApp extends StatefulWidget { + const MuzzleVelocityApp({super.key}); + @override - _MuzzleVelocityAppState createState() => _MuzzleVelocityAppState(); + State createState() => _MuzzleVelocityAppState(); } class _MuzzleVelocityAppState extends State { @@ -31,7 +33,7 @@ class _MuzzleVelocityAppState extends State { super.initState(); // Ensure the correct theme mode is set on startup _themeMode = - WidgetsBinding.instance.window.platformBrightness == Brightness.dark + WidgetsBinding.instance.platformDispatcher.platformBrightness == Brightness.dark ? ThemeMode.dark : ThemeMode.light; } diff --git a/lib/note_editor.dart b/lib/note_editor.dart old mode 100644 new mode 100755 index e9e4a46..47edbb8 --- a/lib/note_editor.dart +++ b/lib/note_editor.dart @@ -6,6 +6,7 @@ import 'package:flutter_markdown_latex/flutter_markdown_latex.dart'; import 'package:flutter_svg/svg.dart'; import 'package:markdown/markdown.dart' as md; import 'package:shared_preferences/shared_preferences.dart'; +import 'package:share_plus/share_plus.dart'; import 'themes/day.dart'; import 'themes/night.dart'; import 'themes/markdown.dart'; @@ -16,13 +17,15 @@ class NoteEditorScreen extends StatefulWidget { final String? notesDirectoryPath; // ✅ Add this final bool isDarkMode; - NoteEditorScreen( - {required this.note, - required this.isDarkMode, - required this.notesDirectoryPath}); + const NoteEditorScreen({ + super.key, + required this.note, + required this.isDarkMode, + required this.notesDirectoryPath, + }); @override - _NoteEditorScreenState createState() => _NoteEditorScreenState(); + State createState() => _NoteEditorScreenState(); } class _NoteEditorScreenState extends State { @@ -59,7 +62,7 @@ class _NoteEditorScreenState extends State { try { _initialContent = await widget.note.readAsString(); } catch (e) { - print("❌ Failed to read file: ${widget.note.path}"); + debugPrint("❌ Failed to read file: ${widget.note.path}"); _initialContent = ""; } @@ -86,9 +89,18 @@ class _NoteEditorScreenState extends State { await widget.note.writeAsString(_controller.text); _initialContent = _controller.text; // Update initial state - print("✅ Note saved successfully"); + debugPrint("✅ Note saved successfully"); } catch (e) { - print("❌ Error saving note: ${widget.note.path}"); + debugPrint("❌ Error saving note: ${widget.note.path}"); + } + } + + void _shareNote() { + if (_controller.text.isNotEmpty) { + SharePlus.instance.share(ShareParams( + text: _controller.text, + subject: widget.note.uri.pathSegments.last, + )); } } @@ -108,7 +120,7 @@ class _NoteEditorScreenState extends State { TextButton( onPressed: () async { await _saveNote(); - Navigator.of(context).pop(true); // Save and exit + if (context.mounted) Navigator.of(context).pop(true); }, child: Text("Save"), ), @@ -137,8 +149,13 @@ class _NoteEditorScreenState extends State { @override Widget build(BuildContext context) { - return WillPopScope( - onWillPop: _onWillPop, + return PopScope( + canPop: false, + onPopInvokedWithResult: (bool didPop, Object? result) async { + if (didPop) return; + final bool shouldPop = await _onWillPop(); + if (shouldPop && context.mounted) Navigator.of(context).pop(); + }, child: Scaffold( appBar: AppBar( title: Text(widget.note.uri.pathSegments.last.replaceAll('.md', '')), @@ -146,7 +163,7 @@ class _NoteEditorScreenState extends State { icon: Icon(Icons.arrow_back), onPressed: () async { if (await _onWillPop()) { - Navigator.pop(context); + if (context.mounted) Navigator.pop(context); } }, ), @@ -157,10 +174,13 @@ class _NoteEditorScreenState extends State { icon: SvgPicture.asset( "assets/blaster.svg", width: 30, - color: Colors.orange, + colorFilter: const ColorFilter.mode(Colors.orange, BlendMode.srcIn), ), onSelected: (String value) { switch (value) { + case 'Share': // ✅ New case for sharing + _shareNote(); + break; case 'Save': _saveNote(); break; @@ -175,6 +195,14 @@ class _NoteEditorScreenState extends State { } }, itemBuilder: (BuildContext context) => [ + PopupMenuItem( // ✅ Share button + value: 'Share', + child: ListTile( + leading: Icon(Icons.share_outlined), + title: Text("Share"), + ), + ), + PopupMenuDivider(), PopupMenuItem( value: 'Save', child: ListTile( @@ -193,6 +221,7 @@ class _NoteEditorScreenState extends State { : "Enable Autosave"), ), ), + PopupMenuDivider(), PopupMenuItem( enabled: false, child: Column( @@ -219,6 +248,7 @@ class _NoteEditorScreenState extends State { ], ), ), + PopupMenuDivider(), PopupMenuItem( value: 'Toggle Preview', child: ListTile( diff --git a/lib/note_list.dart b/lib/note_list.dart old mode 100644 new mode 100755 index 1ead6b8..87d884d --- a/lib/note_list.dart +++ b/lib/note_list.dart @@ -19,7 +19,8 @@ class NoteListScreen extends StatefulWidget { final bool isDarkMode; final bool showTags; - NoteListScreen({ + const NoteListScreen({ + super.key, required this.toggleTheme, required this.toggleTags, required this.isDarkMode, @@ -27,11 +28,12 @@ class NoteListScreen extends StatefulWidget { }); @override - _NoteListScreenState createState() => _NoteListScreenState(); + State createState() => _NoteListScreenState(); } class _NoteListScreenState extends State { TextEditingController searchController = TextEditingController(); + final FocusNode searchFocusNode = FocusNode(); List notes = []; List filteredNotes = []; List _visibleNotes = []; @@ -52,6 +54,9 @@ class _NoteListScreenState extends State { searchController.addListener(() { _debouncedFilterNotes(); }); + WidgetsBinding.instance.addPostFrameCallback((_) { + FocusScope.of(context).requestFocus(searchFocusNode); + }); } void _debouncedFilterNotes() { @@ -95,16 +100,16 @@ class _NoteListScreenState extends State { Future _requestStoragePermission() async { if (Platform.isAndroid) { if (await Permission.storage.request().isGranted) { - print("✅ Basic storage permission granted."); + debugPrint("✅ Basic storage permission granted."); return; } if (await Permission.manageExternalStorage.request().isGranted) { - print("✅ Full file access granted."); + debugPrint("✅ Full file access granted."); return; } - print("❌ Storage permission denied. Opening settings..."); + debugPrint("❌ Storage permission denied. Opening settings..."); await openAppSettings(); // Open settings if denied } } @@ -116,12 +121,46 @@ class _NoteListScreenState extends State { setState(() { defaultDir = dir.path; _useExternalEditor = prefs.getBool('use_external_editor') ?? false; - _includeSubdirectories = prefs.getBool('include_subdirectories') ?? true; // ✅ Load setting + _includeSubdirectories = prefs.getBool('include_subdirectories') ?? true; }); + notesDirectoryPath = prefs.getString('notes_directory') ?? defaultDir; + + // 🚀 Check if it's the first start OR if the directory is empty + final directory = Directory(notesDirectoryPath!); + if (prefs.getBool('initialized') == null || + !directory.listSync().any((entity) => entity is File && entity.path.endsWith('.md'))) { + await _createDefaultNotes(); + await prefs.setBool('initialized', true); + } + await _loadNotes(); } + Future _createDefaultNotes() async { + final quickStartNote = File(path.join(notesDirectoryPath!, "QuickStart.md")); + + if (!quickStartNote.existsSync()) { + quickStartNote.writeAsStringSync(""" +# Quick Start Guide + +Welcome to *Muzzle Velocity*. +This is your fast and minimal note-taking app. + +1. ✍️ Create Notes quickly: just type a title in the search bar and press enter. +2. 🔍 Type keywords to filter notes instantly. +3. 💻 Type commands like :help to get more information. +4. 🏷️ Use hashtags like #quickstart, context tags like @help, or project tags like +muzzle in your notes for categorization. +5. 🔫 Tap the blaster at the top right for more settings or to clear the search field. + +*Muzzle Velocity* is built for speed and simplicity! 🚀 + +Happy note taking! ✨ + """); + } + } + + void _toggleIncludeSubdirectories(bool value) { setState(() { _includeSubdirectories = value; @@ -157,7 +196,7 @@ class _NoteListScreenState extends State { setState(() { notesDirectoryPath = defaultDir; // Reset to default directory }); - Navigator.pop(context); // Close dialog + if (context.mounted) Navigator.pop(context); _loadNotes(); // Reload notes from the default directory }, child: Text("Use Default"), @@ -165,7 +204,7 @@ class _NoteListScreenState extends State { TextButton( onPressed: () async { await _requestStoragePermission(); - Navigator.pop(context); // Close the current dialog + if (context.mounted) Navigator.pop(context); await _selectNotesDirectory(); // Allow user to pick a folder }, child: Text("Choose Folder"), @@ -177,7 +216,7 @@ class _NoteListScreenState extends State { } Future _selectNotesDirectory() async { - String? selectedDirectory = await FilePicker.platform.getDirectoryPath(); + String? selectedDirectory = await FilePicker.getDirectoryPath(); if (selectedDirectory != null) { final prefs = await SharedPreferences.getInstance(); await prefs.setString( @@ -206,7 +245,7 @@ class _NoteListScreenState extends State { final entries = dir.listSync(recursive: _includeSubdirectories); for (var entry in entries) { - if (entry is File && entry.path.endsWith('.md')) { + if (entry is File && _isValidNoteFile(entry)) { if (path.basename(path.dirname(entry.path)) == "trash") { continue; @@ -268,6 +307,11 @@ class _NoteListScreenState extends State { return sortedTags.toSet(); // Convert back to a set after sorting } + bool _isValidNoteFile(File file) { + final validExtensions = ['.md', '.txt', '.markdown']; + return validExtensions.any((ext) => file.path.toLowerCase().endsWith(ext)); + } + void _filterNotes() { final query = searchController.text.trim().toLowerCase(); @@ -351,6 +395,15 @@ class _NoteListScreenState extends State { String notePath = title.trim(); String? subfolder; String safeTitle; + String extension = '.md'; // Default extension + + // ✅ Check if user specified an extension manually + if (title.contains('.')) { + final ext = path.extension(title); + if (['.txt', '.markdown', '.md'].contains(ext)) { + extension = ext; + } + } if (notePath.startsWith('/')) { final parts = notePath.split('/'); @@ -358,21 +411,21 @@ class _NoteListScreenState extends State { if (parts.length > 1) { subfolder = parts.sublist(0, parts.length - 1).join('/'); } - safeTitle = _sanitizeFilename(parts.last); + safeTitle = _sanitizeFilename(parts.last.replaceAll(extension, '')); // Remove extension from input } else { - safeTitle = _sanitizeFilename(title); + safeTitle = _sanitizeFilename(title.replaceAll(extension, '')); } // Construct the final file path String fullPath = subfolder != null - ? path.join(notesDirectoryPath!, subfolder, '$safeTitle.md') - : path.join(notesDirectoryPath!, '$safeTitle.md'); + ? path.join(notesDirectoryPath!, subfolder, '$safeTitle$extension') + : path.join(notesDirectoryPath!, '$safeTitle$extension'); final newNote = File(fullPath); // Prevent duplicate note creation if (notes.any((note) => note.path == newNote.path)) { - print("❌ Note already exists at: $fullPath"); + debugPrint("❌ Note already exists at: $fullPath"); return; } @@ -416,7 +469,7 @@ class _NoteListScreenState extends State { if (notePath.startsWith('/')) { final parts = notePath.split('/'); - parts.removeWhere((element) => element.isEmpty); // Remove empty elements + parts.removeWhere((element) => element.isEmpty); if (parts.length > 1) { subfolder = parts.sublist(0, parts.length - 1).join('/'); } @@ -425,12 +478,18 @@ class _NoteListScreenState extends State { safeTitle = _sanitizeFilename(title); } - // Construct the expected file path - String fullPath = subfolder != null - ? path.join(notesDirectoryPath!, subfolder, '$safeTitle.md') - : path.join(notesDirectoryPath!, '$safeTitle.md'); + // ✅ Allow multiple file extensions + for (var ext in ['.md', '.txt', '.markdown']) { + String fullPath = subfolder != null + ? path.join(notesDirectoryPath!, subfolder, '$safeTitle$ext') + : path.join(notesDirectoryPath!, '$safeTitle$ext'); - return !notes.any((note) => note.path == fullPath); + if (notes.any((note) => note.path == fullPath)) { + return false; // A note with this name already exists + } + } + + return true; } String _sanitizeFilename(String title) { @@ -508,7 +567,7 @@ class _NoteListScreenState extends State { _deleteEmptyParentFolders(folder.parent); // Recursively check parent } } catch (e) { - print("❌ Error deleting empty folder: $e"); + debugPrint("❌ Error deleting empty folder: $e"); } } @@ -577,13 +636,14 @@ class _NoteListScreenState extends State { break; case ':help': _showInfoPage(context, "Help", helpContent); + break; default: return; // Do nothing for unrecognized commands } searchController.clear(); } - _showInfoPage(BuildContext context, String title, String content) { + void _showInfoPage(BuildContext context, String title, String content) { Navigator.push( context, MaterialPageRoute( @@ -603,6 +663,7 @@ class _NoteListScreenState extends State { title: Padding( padding: EdgeInsets.symmetric(horizontal: 10), child: TextField( + focusNode: searchFocusNode, enableInteractiveSelection: true, autocorrect: false, textInputAction: TextInputAction.done, @@ -615,10 +676,11 @@ class _NoteListScreenState extends State { style: GoogleFonts.ibmPlexMono(color: Colors.grey[300]), onSubmitted: (text) { final trimmedText = text.trim(); - if (trimmedText.isNotEmpty && _isNewNote(trimmedText)) { + if (trimmedText.startsWith(':')) { + _handleCommand(trimmedText); + } else if (trimmedText.isNotEmpty && _isNewNote(trimmedText)) { _createNewNote(trimmedText); - searchController - .clear(); // Clears the search field after creation + searchController.clear(); } }, ), @@ -626,137 +688,145 @@ class _NoteListScreenState extends State { actions: [ Padding( padding: EdgeInsets.symmetric(horizontal: 15), - child: PopupMenuButton( - icon: SvgPicture.asset( - "assets/blaster.svg", - width: 30, - color: Colors.orange, - ), - onSelected: (String value) { - switch (value) { - case 'Toggle Tags': - widget.toggleTags(); - break; - case 'Toggle Theme': - setState(() { - widget.toggleTheme(!widget.isDarkMode); - }); - break; - case 'External Editor': - _toggleExternalEditor(!_useExternalEditor); - break; - case 'Select Folder': - _showDirectoryChoiceDialog( - notesDirectoryPath ?? ''); // Re-trigger popup - break; - case 'Empty Trash': - _confirmEmptyTrash(); - break; - case 'Help': - _showInfoPage(context, "Help", helpContent); - break; - case 'About': - _showInfoPage(context, "About", aboutContent); - break; - } + child: GestureDetector( + onTap: () { + if (searchController.text.isNotEmpty) { + searchController.clear(); + } }, - itemBuilder: (BuildContext context) => [ - PopupMenuItem( - value: 'Toggle Tags', - child: ListTile( - leading: - Icon(widget.showTags ? Icons.short_text : Icons.tag), - title: Text(widget.showTags ? 'Hide Tags' : 'Show Tags'), - ), + child: PopupMenuButton( + enabled: searchController.text.isEmpty, + icon: SvgPicture.asset( + "assets/blaster.svg", + width: 30, + colorFilter: const ColorFilter.mode(Colors.orange, BlendMode.srcIn), ), - PopupMenuItem( - value: 'Toggle Theme', - child: ListTile( - leading: Icon( - Theme.of(context).brightness == Brightness.dark - ? Icons.light_mode - : Icons.dark_mode, - ), - title: Text( - Theme.of(context).brightness == Brightness.dark - ? 'Switch to Light Mode' - : 'Switch to Dark Mode', + onSelected: (String value) { + switch (value) { + case 'Toggle Tags': + widget.toggleTags(); + break; + case 'Toggle Theme': + setState(() { + widget.toggleTheme(!widget.isDarkMode); + }); + break; + case 'External Editor': + _toggleExternalEditor(!_useExternalEditor); + break; + case 'Select Folder': + _showDirectoryChoiceDialog( + notesDirectoryPath ?? ''); // Re-trigger popup + break; + case 'Empty Trash': + _confirmEmptyTrash(); + break; + case 'Help': + _showInfoPage(context, "Help", helpContent); + break; + case 'About': + _showInfoPage(context, "About", aboutContent); + break; + } + }, + itemBuilder: (BuildContext context) => [ + PopupMenuItem( + value: 'Toggle Tags', + child: ListTile( + leading: + Icon(widget.showTags ? Icons.short_text : Icons.tag), + title: Text(widget.showTags ? 'Hide Tags' : 'Show Tags'), ), ), - ), - PopupMenuItem( - value: 'Include Subdirectories', - child: ListTile( - leading: Icon(_includeSubdirectories ? Icons.file_copy_outlined : Icons.folder_copy_outlined), - title: Text(_includeSubdirectories ? 'Exclude Subdirectories' : 'Include Subdirectories'), - onTap: () { - _toggleIncludeSubdirectories(!_includeSubdirectories); - Navigator.pop(context); // Close menu after toggle - }, - ), - ), - PopupMenuItem( - value: 'Include File Content', - child: ListTile( - leading: Icon( - _includeFileContent ? Icons.highlight_off : Icons.file_open_outlined, - ), - title: Text( - _includeFileContent ? 'Exclude File Content' : 'Include File Content', - ), - onTap: () { - _toggleIncludeFileContent(!_includeFileContent); - Navigator.pop(context); - }, - ), - ), - PopupMenuItem( - value: 'External Editor', - child: ListTile( - leading: Icon( - _useExternalEditor - ? Icons.open_in_new_off - : Icons.open_in_new, - ), - title: Text( - !_useExternalEditor - ? 'Use External Editor' - : 'Use Internal Editor', + PopupMenuItem( + value: 'Toggle Theme', + child: ListTile( + leading: Icon( + Theme.of(context).brightness == Brightness.dark + ? Icons.light_mode + : Icons.dark_mode, + ), + title: Text( + Theme.of(context).brightness == Brightness.dark + ? 'Switch to Light Mode' + : 'Switch to Dark Mode', + ), ), ), - ), - PopupMenuItem( - value: 'Select Folder', - child: ListTile( - leading: Icon(Icons.folder_shared_outlined), - title: Text('Set Notes Directory'), + PopupMenuItem( + value: 'Include Subdirectories', + child: ListTile( + leading: Icon(_includeSubdirectories ? Icons.file_copy_outlined : Icons.folder_copy_outlined), + title: Text(_includeSubdirectories ? 'Exclude Subdirectories' : 'Search Subdirectories'), + onTap: () { + _toggleIncludeSubdirectories(!_includeSubdirectories); + Navigator.pop(context); // Close menu after toggle + }, + ), ), - ), - PopupMenuDivider(), - PopupMenuItem( - value: 'Empty Trash', - child: ListTile( - leading: Icon(Icons.delete, color: Colors.redAccent), - title: Text('Empty Trash', - style: TextStyle(color: Colors.redAccent)), + PopupMenuItem( + value: 'Include File Content', + child: ListTile( + leading: Icon( + _includeFileContent ? Icons.highlight_off : Icons.file_open_outlined, + ), + title: Text( + _includeFileContent ? 'Exclude File Content' : 'Search File Content', + ), + onTap: () { + _toggleIncludeFileContent(!_includeFileContent); + Navigator.pop(context); + }, + ), ), - ), - PopupMenuDivider(), - PopupMenuItem( - value: 'Help', - child: ListTile( - leading: Icon(Icons.help_outline), - title: Text('Help'), + PopupMenuItem( + value: 'External Editor', + child: ListTile( + leading: Icon( + _useExternalEditor + ? Icons.open_in_new_off + : Icons.open_in_new, + ), + title: Text( + !_useExternalEditor + ? 'Use External Editor' + : 'Use Internal Editor', + ), + ), ), - ), - PopupMenuItem( - value: 'About', - child: ListTile( - leading: Icon(Icons.info_outline), - title: Text('About'), + PopupMenuItem( + value: 'Select Folder', + child: ListTile( + leading: Icon(Icons.folder_shared_outlined), + title: Text('Set Notes Directory'), + ), ), - ), - ], + PopupMenuDivider(), + PopupMenuItem( + value: 'Empty Trash', + child: ListTile( + leading: Icon(Icons.delete, color: Colors.redAccent), + title: Text('Empty Trash', + style: TextStyle(color: Colors.redAccent)), + ), + ), + PopupMenuDivider(), + PopupMenuItem( + value: 'Help', + child: ListTile( + leading: Icon(Icons.help_outline), + title: Text('Help'), + ), + ), + PopupMenuItem( + value: 'About', + child: ListTile( + leading: Icon(Icons.info_outline), + title: Text('About'), + ), + ), + ], + ), ), ), ], @@ -783,11 +853,6 @@ class _NoteListScreenState extends State { } final noteFile = filteredNotes[index]; - final noteContent = _includeFileContent ? noteFile.readAsStringSync() : ""; // ✅ Read content only if needed - final tagSpans = _formatTags(noteContent).isNotEmpty - ? _formatTags(noteContent) - : [TextSpan(text: '')]; - return Dismissible( key: Key(noteFile.path), direction: DismissDirection.endToStart, @@ -836,7 +901,7 @@ class _NoteListScreenState extends State { if (result.stdout.toString().trim().isNotEmpty) { await Process.run('xdg-open', [noteFile.path]); } else { - print("❌ `xdg-open` is not available."); + debugPrint("❌ `xdg-open` is not available."); } } else if (Platform.isAndroid) { await _requestStoragePermission(); @@ -844,10 +909,10 @@ class _NoteListScreenState extends State { noteFile.path, type: "text/markdown", ); - print("✅ OpenFilex result: ${result.type}, message: ${result.message}"); + debugPrint("✅ OpenFilex result: ${result.type}, message: ${result.message}"); } } catch (e) { - print("❌ Failed to open external editor: $e"); + debugPrint("❌ Failed to open external editor: $e"); } } else { await Navigator.push( diff --git a/lib/read_only.dart b/lib/read_only.dart old mode 100644 new mode 100755 index 621f9cd..892c01c --- a/lib/read_only.dart +++ b/lib/read_only.dart @@ -10,7 +10,8 @@ class ReadOnlyPage extends StatelessWidget { final String content; final bool isDarkMode; - ReadOnlyPage({ + const ReadOnlyPage({ + super.key, required this.title, required this.content, required this.isDarkMode, diff --git a/lib/themes/markdown.dart b/lib/themes/markdown.dart old mode 100644 new mode 100755 index e6efe51..34bed4a --- a/lib/themes/markdown.dart +++ b/lib/themes/markdown.dart @@ -1,61 +1,218 @@ import 'package:highlight/highlight.dart'; -final markdown = Mode(refs: {}, aliases: [ - "md", - "mkdown", - "mkd" -], contains: [ - Mode(className: "section", variants: [ - Mode(begin: "^#\\s{1,6}", end: "\$"), - Mode(begin: "^.+?\\n[=-]{2,}\$") - ]), - Mode(begin: "<", end: ">", subLanguage: ["xml"], relevance: 0), - Mode(className: "bullet", begin: "^\\s*([*+-]|(\\d+\\.))\\s+"), - Mode(className: "strong", begin: "[*_]{2}.+?[*_]{2}"), +final markdown = Mode( + refs: {}, + aliases: [ + "md", + "mkdown", + "mkd" + ], + contains: [ + // Headers (with distinct classes for each level) + Mode( + className: "header", + variants: [ + // Level 1 header (#) + Mode( + className: "header-h1", + begin: "^#\\s+", + end: "\$" + ), + // Level 2 header (##) + Mode( + className: "header-h2", + begin: "^##\\s+", + end: "\$" + ), + // Level 3 header (###) + Mode( + className: "header-h3", + begin: "^###\\s+", + end: "\$" + ), + // Level 4 header (####) + Mode( + className: "header-h4", + begin: "^####\\s+", + end: "\$" + ), + // Level 5 header (#####) + Mode( + className: "header-h5", + begin: "^#####\\s+", + end: "\$" + ), + // Level 6 header (######) + Mode( + className: "header-h6", + begin: "^######\\s+", + end: "\$" + ), + // Underlined headers (=== and ---) + Mode( + className: "header-underline", + begin: "^.+?\\n[=-]{2,}\$" + ) + ] + ), + + // HTML tags + Mode( + begin: "<", + end: ">", + subLanguage: ["xml"], + relevance: 0 + ), + + // Lists + Mode( + className: "list", + begin: "^\\s*([*+-]|(\\d+\\.))\\s+" + ), + + // Bold text + Mode( + className: "bold", + begin: "[*_]{2}.+?[*_]{2}" + ), + + // Italic text + Mode( + className: "italic", + variants: [ + Mode(begin: "\\*.+?\\*"), + Mode(begin: "_.+?_", relevance: 0) + ] + ), + + // Blockquotes + Mode( + className: "blockquote", + begin: "^>\\s+", + end: "\$" + ), + + // Code blocks and inline code + Mode( + className: "code", + variants: [ + Mode(begin: "^```\\w*\\s*\$", end: "^```[ ]*\$"), // Fenced code blocks + Mode(begin: "`.+?`"), // Inline code + Mode(begin: "^( {4}|\\t)", end: "\$", relevance: 0) // Indented code blocks + ] + ), + + // Horizontal rules + Mode( + className: "horizontal-rule", + begin: "^[-\\*]{3,}", + end: "\$" + ), + + // Links and images + Mode( + begin: "\\[.+?\\][\\(\\[].*?[\\)\\]]", + returnBegin: true, + contains: [ + Mode( + className: "link-text", + begin: "\\[", + end: "\\]", + excludeBegin: true, + returnEnd: true, + relevance: 0 + ), + Mode( + className: "link-url", + begin: "\\]\\(", + end: "\\)", + excludeBegin: true, + excludeEnd: true + ), + Mode( + className: "link-reference", + begin: "\\]\\[", + end: "\\]", + excludeBegin: true, + excludeEnd: true + ) + ], + relevance: 10 + ), + + // Reference-style links + Mode( + begin: "^\\[[^\\n]+\\]:", + returnBegin: true, + contains: [ + Mode( + className: "link-reference", + begin: "\\[", + end: "\\]", + excludeBegin: true, + excludeEnd: true + ), + Mode( + className: "link-url", + begin: ":\\s*", + end: "\$", + excludeBegin: true + ) + ] + ), + + // Strikethrough text + Mode( + className: "strikethrough", + begin: "~~.+?~~" + ), + + // Tables + Mode( + className: "table", + begin: "^\\|.+?\\|", + end: "\$", + contains: [ + Mode( + className: "table-header", + begin: "^\\|", + end: "\\|", + contains: [ + Mode( + className: "table-cell", + begin: "[^|]+", + end: "\$" + ) + ] + ), + Mode( + className: "table-row", + begin: "^\\|", + end: "\\|", + contains: [ + Mode( + className: "table-cell", + begin: "[^|]+", + end: "\$" + ) + ] + ) + ] + ), + + // Task lists + Mode( + className: "task-list", + begin: "^\\s*-\\s*\\[\\s*[xX ]?\\s*\\]\\s+" + ), + Mode( - className: "emphasis", - variants: [Mode(begin: "\\*.+?\\*"), Mode(begin: "_.+?_", relevance: 0)]), - Mode(className: "quote", begin: "^>\\s+", end: "\$"), - Mode(className: "code", variants: [ - Mode(begin: "^```\\w*\\s*\$", end: "^```[ ]*\$"), - Mode(begin: "`.+?`"), - Mode(begin: "^( {4}|\\t)", end: "\$", relevance: 0) - ]), - Mode(begin: "^[-\\*]{3,}", end: "\$"), - Mode( - begin: "\\[.+?\\][\\(\\[].*?[\\)\\]]", - returnBegin: true, - contains: [ - Mode( - className: "string", - begin: "\\[", - end: "\\]", - excludeBegin: true, - returnEnd: true, - relevance: 0), - Mode( - className: "link", - begin: "\\]\\(", - end: "\\)", - excludeBegin: true, - excludeEnd: true), - Mode( - className: "symbol", - begin: "\\]\\[", - end: "\\]", - excludeBegin: true, - excludeEnd: true) - ], - relevance: 10), - Mode(begin: "^\\[[^\\n]+\\]:", returnBegin: true, contains: [ - Mode( - className: "symbol", - begin: "\\[", - end: "\\]", - excludeBegin: true, - excludeEnd: true), - Mode(className: "link", begin: ":\\s*", end: "\$", excludeBegin: true) - ]), + className: "link-reference", + begin: "\\[", + end: "\\]", + excludeBegin: true, + excludeEnd: true + ), // Custom Tag Highlighting Mode( @@ -71,11 +228,11 @@ final markdown = Mode(refs: {}, aliases: [ begin: "(?<=\\s|^)@[a-zA-Z0-9_]+", relevance: 10), // Yellow Mode( - className: "keyword", + className: "command", begin: "(?<=\\s|^):[a-zA-Z0-9_]+", relevance: 10), Mode( - className: "variable", - begin: "(?<=\\s|^)\/[a-zA-Z0-9_\/]+", + className: "link-url", + begin: "(?<=\\s|^)/[a-zA-Z0-9_/]+", relevance: 10), // Yellow ]); diff --git a/pubspec.lock b/pubspec.lock old mode 100644 new mode 100755 index fd9abfb..6de71e9 --- a/pubspec.lock +++ b/pubspec.lock @@ -5,26 +5,26 @@ packages: dependency: transitive description: name: archive - sha256: "528579c7e4579719f04b21eeeeddfd73a18b31dabc22766893b7d1be7f49b967" + sha256: a96e8b390886ee8abb49b7bd3ac8df6f451c621619f52a26e815fdcf568959ff url: "https://pub.dev" source: hosted - version: "4.0.3" + version: "4.0.9" args: dependency: transitive description: name: args - sha256: bf9f5caeea8d8fe6721a9c358dd8a5c1947b27f1cfaa18b39c301273594919e6 + sha256: d0481093c50b1da8910eb0bb301626d4d8eb7284aa739614d2b394ee09e3ea04 url: "https://pub.dev" source: hosted - version: "2.6.0" + version: "2.7.0" async: dependency: transitive description: name: async - sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" + sha256: e2eb0491ba5ddb6177742d2da23904574082139b07c1e33b8503b9f46f3e1a37 url: "https://pub.dev" source: hosted - version: "2.11.0" + version: "2.13.1" autotrie: dependency: transitive description: @@ -37,18 +37,18 @@ packages: dependency: transitive description: name: boolean_selector - sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" + sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea" url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.1.2" characters: dependency: transitive description: name: characters - sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" + sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803 url: "https://pub.dev" source: hosted - version: "1.3.0" + version: "1.4.0" charcode: dependency: transitive description: @@ -61,10 +61,10 @@ packages: dependency: transitive description: name: checked_yaml - sha256: feb6bed21949061731a7a75fc5d2aa727cf160b91af9a3e464c5e3a32e28b5ff + sha256: "959525d3162f249993882720d52b7e0c833978df229be20702b33d48d91de70f" url: "https://pub.dev" source: hosted - version: "2.0.3" + version: "2.0.4" cli_util: dependency: transitive description: @@ -77,66 +77,74 @@ packages: dependency: transitive description: name: clock - sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf + sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b url: "https://pub.dev" source: hosted - version: "1.1.1" + version: "1.1.2" collection: dependency: transitive description: name: collection - sha256: a1ace0a119f20aabc852d165077c036cd864315bd99b7eaa10a60100341941bf + sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" url: "https://pub.dev" source: hosted - version: "1.19.0" + version: "1.19.1" cross_file: dependency: transitive description: name: cross_file - sha256: "7caf6a750a0c04effbb52a676dce9a4a592e10ad35c34d6d2d0e4811160d5670" + sha256: "28bb3ae56f117b5aec029d702a90f57d285cd975c3c5c281eaca38dbc47c5937" url: "https://pub.dev" source: hosted - version: "0.3.4+2" + version: "0.3.5+2" crypto: dependency: transitive description: name: crypto - sha256: "1e445881f28f22d6140f181e07737b22f1e099a5e1ff94b0af2f9e4a463f4855" + sha256: c8ea0233063ba03258fbcf2ca4d6dadfefe14f02fab57702265467a19f27fadf url: "https://pub.dev" source: hosted - version: "3.0.6" + version: "3.0.7" cupertino_icons: dependency: "direct main" description: name: cupertino_icons - sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6 + sha256: "41e005c33bd814be4d3096aff55b1908d419fde52ca656c8c47719ec745873cd" url: "https://pub.dev" source: hosted - version: "1.0.8" + version: "1.0.9" + dbus: + dependency: transitive + description: + name: dbus + sha256: "0ce9b0a839e6dee59a37a623d2fc26a35bbbe6404213e419b0d6411023d62645" + url: "https://pub.dev" + source: hosted + version: "0.7.14" equatable: dependency: transitive description: name: equatable - sha256: "567c64b3cb4cf82397aac55f4f0cbd3ca20d77c6c03bedbc4ceaddc08904aef7" + sha256: "3e0141505477fd8ad55d6eb4e7776d3fe8430be8e497ccb1521370c3f21a3e2b" url: "https://pub.dev" source: hosted - version: "2.0.7" + version: "2.0.8" fake_async: dependency: transitive description: name: fake_async - sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" + sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44" url: "https://pub.dev" source: hosted - version: "1.3.1" + version: "1.3.3" ffi: dependency: transitive description: name: ffi - sha256: "16ed7b077ef01ad6170a3d0c57caa4a112a38d7a2ed5602e0aca9ca6f3d98da6" + sha256: "6d7fd89431262d8f3125e81b50d3847a091d846eafcd4fdb88dd06f36d705a45" url: "https://pub.dev" source: hosted - version: "2.1.3" + version: "2.2.0" file: dependency: transitive description: @@ -149,10 +157,18 @@ packages: dependency: "direct main" description: name: file_picker - sha256: "6f6bfa8797f296965bdc3e1f702574ab49a540c19b9237b401e7c2b25dfe594c" + sha256: f13a03000d942e476bc1ff0a736d2e9de711d2f89a95cd4c1d88f861c3348387 url: "https://pub.dev" source: hosted - version: "9.0.0" + version: "11.0.2" + fixnum: + dependency: transitive + description: + name: fixnum + sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be + url: "https://pub.dev" + source: hosted + version: "1.1.1" flutter: dependency: "direct main" description: flutter @@ -162,10 +178,10 @@ packages: dependency: "direct main" description: name: flutter_code_editor - sha256: "505ad56dcc8a7be4b782c8113574571bc4b9723499b0c1f385b3e2c3fae11f5d" + sha256: "9af48ba8e3558b6ea4bb98b84c5eb1649702acf53e61a84d88383eeb79b239b0" url: "https://pub.dev" source: hosted - version: "0.3.2" + version: "0.3.5" flutter_highlight: dependency: "direct main" description: @@ -178,26 +194,26 @@ packages: dependency: "direct main" description: name: flutter_launcher_icons - sha256: bfa04787c85d80ecb3f8777bde5fc10c3de809240c48fa061a2c2bf15ea5211c + sha256: "10f13781741a2e3972126fae08393d3c4e01fa4cd7473326b94b72cf594195e7" url: "https://pub.dev" source: hosted - version: "0.14.3" + version: "0.14.4" flutter_lints: dependency: "direct dev" description: name: flutter_lints - sha256: "5398f14efa795ffb7a33e9b6a08798b26a180edac4ad7db3f231e40f82ce11e1" + sha256: "3105dc8492f6183fb076ccf1f351ac3d60564bff92e20bfc4af9cc1651f4e7e1" url: "https://pub.dev" source: hosted - version: "5.0.0" + version: "6.0.0" flutter_markdown: dependency: "direct main" description: name: flutter_markdown - sha256: e7bbc718adc9476aa14cfddc1ef048d2e21e4e8f18311aaac723266db9f9e7b5 + sha256: "08fb8315236099ff8e90cb87bb2b935e0a724a3af1623000a9cec930468e0f27" url: "https://pub.dev" source: hosted - version: "0.7.6+2" + version: "0.7.7+1" flutter_markdown_latex: dependency: "direct main" description: @@ -210,26 +226,26 @@ packages: dependency: transitive description: name: flutter_math_fork - sha256: "284bab89b2fbf1bc3a0baf13d011c1dd324d004e35d177626b77f2fc056366ac" + sha256: "6d5f2f1aa57ae539ffb0a04bb39d2da67af74601d685a161aff7ce5bda5fa407" url: "https://pub.dev" source: hosted - version: "0.7.3" + version: "0.7.4" flutter_plugin_android_lifecycle: dependency: transitive description: name: flutter_plugin_android_lifecycle - sha256: "615a505aef59b151b46bbeef55b36ce2b6ed299d160c51d84281946f0aa0ce0e" + sha256: "38d1c268de9097ff59cf0e844ac38759fc78f76836d37edad06fa21e182055a0" url: "https://pub.dev" source: hosted - version: "2.0.24" + version: "2.0.34" flutter_svg: dependency: "direct main" description: name: flutter_svg - sha256: c200fd79c918a40c5cd50ea0877fa13f81bdaf6f0a5d3dbcc2a13e3285d6aa1b + sha256: "35882981abcbfb8c15b286f0cd690ff25bac12d95eff3e25ee207f37d4c42e7f" url: "https://pub.dev" source: hosted - version: "2.0.17" + version: "2.3.0" flutter_test: dependency: "direct dev" description: flutter @@ -244,10 +260,10 @@ packages: dependency: "direct main" description: name: google_fonts - sha256: b1ac0fe2832c9cc95e5e88b57d627c5e68c223b9657f4b96e1487aa9098c7b82 + sha256: "4e9391085e524954a51e3625b7c9c7e9851dc3f376603208bb45c24b9a66255d" url: "https://pub.dev" source: hosted - version: "6.2.1" + version: "8.1.0" highlight: dependency: "direct main" description: @@ -268,10 +284,10 @@ packages: dependency: transitive description: name: http - sha256: fe7ab022b76f3034adc518fb6ea04a82387620e19977665ea18d30a1cf43442f + sha256: "87721a4a50b19c7f1d49001e51409bddc46303966ce89a65af4f4e6004896412" url: "https://pub.dev" source: hosted - version: "1.3.0" + version: "1.6.0" http_parser: dependency: transitive description: @@ -284,42 +300,58 @@ packages: dependency: transitive description: name: image - sha256: "13d3349ace88f12f4a0d175eb5c12dcdd39d35c4c109a8a13dfeb6d0bd9e31c3" + sha256: f9881ff4998044947ec38d098bc7c8316ae1186fa786eddffdb867b9bc94dfce url: "https://pub.dev" source: hosted - version: "4.5.3" + version: "4.8.0" + jni: + dependency: transitive + description: + name: jni + sha256: c2230682d5bc2362c1c9e8d3c7f406d9cbba23ab3f2e203a025dd47e0fb2e68f + url: "https://pub.dev" + source: hosted + version: "1.0.0" + jni_flutter: + dependency: transitive + description: + name: jni_flutter + sha256: "8b59e590786050b1cd866677dddaf76b1ade5e7bc751abe04b86e84d379d3ba6" + url: "https://pub.dev" + source: hosted + version: "1.0.1" json_annotation: dependency: transitive description: name: json_annotation - sha256: "1ce844379ca14835a50d2f019a3099f419082cfdd231cd86a142af94dd5c6bb1" + sha256: "2a743920d81b7910627f68ee2c9ac1fc0bfee32b9fc3403587d7c6791ca12f80" url: "https://pub.dev" source: hosted - version: "4.9.0" + version: "4.12.0" leak_tracker: dependency: transitive description: name: leak_tracker - sha256: "7bb2830ebd849694d1ec25bf1f44582d6ac531a57a365a803a6034ff751d2d06" + sha256: "33e2e26bdd85a0112ec15400c8cbffea70d0f9c3407491f672a2fad47915e2de" url: "https://pub.dev" source: hosted - version: "10.0.7" + version: "11.0.2" leak_tracker_flutter_testing: dependency: transitive description: name: leak_tracker_flutter_testing - sha256: "9491a714cca3667b60b5c420da8217e6de0d1ba7a5ec322fab01758f6998f379" + sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1" url: "https://pub.dev" source: hosted - version: "3.0.8" + version: "3.0.10" leak_tracker_testing: dependency: transitive description: name: leak_tracker_testing - sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" + sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1" url: "https://pub.dev" source: hosted - version: "3.0.1" + version: "3.0.2" linked_scroll_controller: dependency: transitive description: @@ -332,26 +364,26 @@ packages: dependency: transitive description: name: lints - sha256: c35bb79562d980e9a453fc715854e1ed39e24e7d0297a880ef54e17f9874a9d7 + sha256: "12f842a479589fea194fe5c5a3095abc7be0c1f2ddfa9a0e76aed1dbd26a87df" url: "https://pub.dev" source: hosted - version: "5.1.1" + version: "6.1.0" markdown: dependency: "direct main" description: name: markdown - sha256: "935e23e1ff3bc02d390bad4d4be001208ee92cc217cb5b5a6c19bc14aaa318c1" + sha256: ee85086ad7698b42522c6ad42fe195f1b9898e4d974a1af4576c1a3a176cada9 url: "https://pub.dev" source: hosted - version: "7.3.0" + version: "7.3.1" matcher: dependency: transitive description: name: matcher - sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb + sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2 url: "https://pub.dev" source: hosted - version: "0.12.16+1" + version: "0.12.17" material_color_utilities: dependency: transitive description: @@ -364,18 +396,26 @@ packages: dependency: transitive description: name: meta - sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7 + sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c url: "https://pub.dev" source: hosted - version: "1.15.0" + version: "1.16.0" + mime: + dependency: transitive + description: + name: mime + sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6" + url: "https://pub.dev" + source: hosted + version: "2.0.0" mocktail: dependency: transitive description: name: mocktail - sha256: "890df3f9688106f25755f26b1c60589a92b3ab91a22b8b224947ad041bf172d8" + sha256: "5e1bf53cc7baa8062a33b84424deb61513858ea05c601b8509e683815b5914aa" url: "https://pub.dev" source: hosted - version: "1.0.4" + version: "1.0.5" nested: dependency: transitive description: @@ -388,18 +428,26 @@ packages: dependency: "direct main" description: name: open_filex - sha256: dcb7bd3d32db8db5260253a62f1564c02c2c8df64bc0187cd213f65f827519bd + sha256: "9976da61b6a72302cf3b1efbce259200cd40232643a467aac7370addf94d6900" url: "https://pub.dev" source: hosted - version: "4.6.0" + version: "4.7.0" + package_config: + dependency: transitive + description: + name: package_config + sha256: f096c55ebb7deb7e384101542bfba8c52696c1b56fca2eb62827989ef2353bbc + url: "https://pub.dev" + source: hosted + version: "2.2.0" path: dependency: "direct main" description: name: path - sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" + sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" url: "https://pub.dev" source: hosted - version: "1.9.0" + version: "1.9.1" path_parsing: dependency: transitive description: @@ -420,18 +468,18 @@ packages: dependency: transitive description: name: path_provider_android - sha256: "4adf4fd5423ec60a29506c76581bc05854c55e3a0b72d35bb28d661c9686edf2" + sha256: "69cbd515a62b94d32a7944f086b2f82b4ac40a1d45bebfc00813a430ab2dabcd" url: "https://pub.dev" source: hosted - version: "2.2.15" + version: "2.3.1" path_provider_foundation: dependency: transitive description: name: path_provider_foundation - sha256: "4843174df4d288f5e29185bd6e72a6fbdf5a4a4602717eed565497429f179942" + sha256: "6d13aece7b3f5c5a9731eaf553ff9dcbc2eff41087fd2df587fd0fed9a3eb0c4" url: "https://pub.dev" source: hosted - version: "2.4.1" + version: "2.5.1" path_provider_linux: dependency: transitive description: @@ -460,26 +508,26 @@ packages: dependency: "direct main" description: name: permission_handler - sha256: "59adad729136f01ea9e35a48f5d1395e25cba6cea552249ddbe9cf950f5d7849" + sha256: fe54465bcc62a4564c6e4db337bbaded6c0c0fa6e10487414436d163114784f6 url: "https://pub.dev" source: hosted - version: "11.4.0" + version: "12.0.3" permission_handler_android: dependency: transitive description: name: permission_handler_android - sha256: d3971dcdd76182a0c198c096b5db2f0884b0d4196723d21a866fc4cdea057ebc + sha256: "1e3bc410ca1bf84662104b100eb126e066cb55791b7451307f9708d4007350e6" url: "https://pub.dev" source: hosted - version: "12.1.0" + version: "13.0.1" permission_handler_apple: dependency: transitive description: name: permission_handler_apple - sha256: f84a188e79a35c687c132a0a0556c254747a08561e99ab933f12f6ca71ef3c98 + sha256: "79dfa1df734798aa3cfdad166d3a3698c206d8813de13516ea1071b5d7e2f420" url: "https://pub.dev" source: hosted - version: "9.4.6" + version: "9.4.10" permission_handler_html: dependency: transitive description: @@ -508,10 +556,10 @@ packages: dependency: transitive description: name: petitparser - sha256: c15605cd28af66339f8eb6fbe0e541bfe2d1b72d5825efc6598f3e0a31b9ad27 + sha256: "91bd59303e9f769f108f8df05e371341b15d59e995e6806aefab827b58336675" url: "https://pub.dev" source: hosted - version: "6.0.2" + version: "7.0.2" platform: dependency: transitive description: @@ -532,18 +580,18 @@ packages: dependency: transitive description: name: posix - sha256: a0117dc2167805aa9125b82eee515cc891819bac2f538c83646d355b16f58b9a + sha256: "185ef7606574f789b40f289c233efa52e96dead518aed988e040a10737febb07" url: "https://pub.dev" source: hosted - version: "6.0.1" + version: "6.5.0" provider: dependency: transitive description: name: provider - sha256: c8a055ee5ce3fd98d6fc872478b03823ffdb448699c6ebdbbc71d59b596fd48c + sha256: "4e82183fa20e5ca25703ead7e05de9e4cceed1fbd1eadc1ac3cb6f565a09f272" url: "https://pub.dev" source: hosted - version: "6.1.2" + version: "6.1.5+1" scrollable_positioned_list: dependency: transitive description: @@ -552,30 +600,46 @@ packages: url: "https://pub.dev" source: hosted version: "0.3.8" + share_plus: + dependency: "direct main" + description: + name: share_plus + sha256: "223873d106614442ea6f20db5a038685cc5b32a2fba81cdecaefbbae0523f7fa" + url: "https://pub.dev" + source: hosted + version: "12.0.2" + share_plus_platform_interface: + dependency: transitive + description: + name: share_plus_platform_interface + sha256: "88023e53a13429bd65d8e85e11a9b484f49d4c190abbd96c7932b74d6927cc9a" + url: "https://pub.dev" + source: hosted + version: "6.1.0" shared_preferences: dependency: "direct main" description: name: shared_preferences - sha256: "846849e3e9b68f3ef4b60c60cf4b3e02e9321bc7f4d8c4692cf87ffa82fc8a3a" + sha256: c3025c5534b01739267eb7d76959bbc25a6d10f6988e1c2a3036940133dd10bf url: "https://pub.dev" source: hosted - version: "2.5.2" + version: "2.5.5" shared_preferences_android: dependency: transitive description: name: shared_preferences_android - sha256: a768fc8ede5f0c8e6150476e14f38e2417c0864ca36bb4582be8e21925a03c22 + sha256: e8d4762b1e2e8578fc4d0fd548cebf24afd24f49719c08974df92834565e2c53 url: "https://pub.dev" source: hosted - version: "2.4.6" + version: "2.4.23" shared_preferences_foundation: dependency: transitive description: name: shared_preferences_foundation - sha256: "6a52cfcdaeac77cad8c97b539ff688ccfc458c007b4db12be584fbe5c0e49e03" + sha256: "4e7eaffc2b17ba398759f1151415869a34771ba11ebbccd1b0145472a619a64f" url: "https://pub.dev" source: hosted - version: "2.5.4" + version: "2.5.6" shared_preferences_linux: dependency: transitive description: @@ -588,10 +652,10 @@ packages: dependency: transitive description: name: shared_preferences_platform_interface - sha256: "57cbf196c486bc2cf1f02b85784932c6094376284b3ad5779d1b1c6c6a816b80" + sha256: "649dc798a33931919ea356c4305c2d1f81619ea6e92244070b520187b5140ef9" url: "https://pub.dev" source: hosted - version: "2.4.1" + version: "2.4.2" shared_preferences_web: dependency: transitive description: @@ -617,50 +681,50 @@ packages: dependency: transitive description: name: source_span - sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" + sha256: "56a02f1f4cd1a2d96303c0144c93bd6d909eea6bee6bf5a0e0b685edbd4c47ab" url: "https://pub.dev" source: hosted - version: "1.10.0" + version: "1.10.2" stack_trace: dependency: transitive description: name: stack_trace - sha256: "9f47fd3630d76be3ab26f0ee06d213679aa425996925ff3feffdec504931c377" + sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1" url: "https://pub.dev" source: hosted - version: "1.12.0" + version: "1.12.1" stream_channel: dependency: transitive description: name: stream_channel - sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 + sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d" url: "https://pub.dev" source: hosted - version: "2.1.2" + version: "2.1.4" string_scanner: dependency: transitive description: name: string_scanner - sha256: "688af5ed3402a4bde5b3a6c15fd768dbf2621a614950b17f04626c431ab3c4c3" + sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43" url: "https://pub.dev" source: hosted - version: "1.3.0" + version: "1.4.1" term_glyph: dependency: transitive description: name: term_glyph - sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 + sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e" url: "https://pub.dev" source: hosted - version: "1.2.1" + version: "1.2.2" test_api: dependency: transitive description: name: test_api - sha256: "664d3a9a64782fcdeb83ce9c6b39e78fd2971d4e37827b9b06c3aa1edc5e760c" + sha256: "522f00f556e73044315fa4585ec3270f1808a4b186c936e612cab0b565ff1e00" url: "https://pub.dev" source: hosted - version: "0.7.3" + version: "0.7.6" tuple: dependency: transitive description: @@ -681,42 +745,42 @@ packages: dependency: transitive description: name: url_launcher - sha256: "9d06212b1362abc2f0f0d78e6f09f726608c74e3b9462e8368bb03314aa8d603" + sha256: f6a7e5c4835bb4e3026a04793a4199ca2d14c739ec378fdfe23fc8075d0439f8 url: "https://pub.dev" source: hosted - version: "6.3.1" + version: "6.3.2" url_launcher_android: dependency: transitive description: name: url_launcher_android - sha256: "6fc2f56536ee873eeb867ad176ae15f304ccccc357848b351f6f0d8d4a40d193" + sha256: "3bb000251e55d4a209aa0e2e563309dc9bb2befea2295fd0cec1f51760aac572" url: "https://pub.dev" source: hosted - version: "6.3.14" + version: "6.3.29" url_launcher_ios: dependency: transitive description: name: url_launcher_ios - sha256: "16a513b6c12bb419304e72ea0ae2ab4fed569920d1c7cb850263fe3acc824626" + sha256: cfde38aa257dae62ffe79c87fab20165dfdf6988c1d31b58ebf59b9106062aad url: "https://pub.dev" source: hosted - version: "6.3.2" + version: "6.3.6" url_launcher_linux: dependency: transitive description: name: url_launcher_linux - sha256: "4e9ba368772369e3e08f231d2301b4ef72b9ff87c31192ef471b380ef29a4935" + sha256: d5e14138b3bc193a0f63c10a53c94b91d399df0512b1f29b94a043db7482384a url: "https://pub.dev" source: hosted - version: "3.2.1" + version: "3.2.2" url_launcher_macos: dependency: transitive description: name: url_launcher_macos - sha256: "17ba2000b847f334f16626a574c702b196723af2a289e7a93ffcb79acff855c2" + sha256: "368adf46f71ad3c21b8f06614adb38346f193f3a59ba8fe9a2fd74133070ba18" url: "https://pub.dev" source: hosted - version: "3.2.2" + version: "3.2.5" url_launcher_platform_interface: dependency: transitive description: @@ -729,26 +793,34 @@ packages: dependency: transitive description: name: url_launcher_web - sha256: "3ba963161bd0fe395917ba881d320b9c4f6dd3c4a233da62ab18a5025c85f1e9" + sha256: "4bd2b7b4dc4d4d0b94e5babfffbca8eac1a126c7f3d6ecbc1a11013faa3abba2" url: "https://pub.dev" source: hosted - version: "2.4.0" + version: "2.4.1" url_launcher_windows: dependency: transitive description: name: url_launcher_windows - sha256: "3284b6d2ac454cf34f114e1d3319866fdd1e19cdc329999057e44ffe936cfa77" + sha256: "712c70ab1b99744ff066053cbe3e80c73332b38d46e5e945c98689b2e66fc15f" url: "https://pub.dev" source: hosted - version: "3.1.4" + version: "3.1.5" + uuid: + dependency: transitive + description: + name: uuid + sha256: "1fef9e8e11e2991bb773070d4656b7bd5d850967a2456cfc83cf47925ba79489" + url: "https://pub.dev" + source: hosted + version: "4.5.3" vector_graphics: dependency: transitive description: name: vector_graphics - sha256: "44cc7104ff32563122a929e4620cf3efd584194eec6d1d913eb5ba593dbcf6de" + sha256: "2306c03da2ba81724afeb589c351ebbc0aa7d86005925be8f8735856dbe5e42d" url: "https://pub.dev" source: hosted - version: "1.1.18" + version: "1.2.2" vector_graphics_codec: dependency: transitive description: @@ -761,42 +833,42 @@ packages: dependency: transitive description: name: vector_graphics_compiler - sha256: "1b4b9e706a10294258727674a340ae0d6e64a7231980f9f9a3d12e4b42407aad" + sha256: b9b3f391857781aa96acacef96066f2f49b4cd03cf9fce3ca4d8da2ef5ea129e url: "https://pub.dev" source: hosted - version: "1.1.16" + version: "1.2.3" vector_math: dependency: transitive description: name: vector_math - sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b url: "https://pub.dev" source: hosted - version: "2.1.4" + version: "2.2.0" vm_service: dependency: transitive description: name: vm_service - sha256: f6be3ed8bd01289b34d679c2b62226f63c0e69f9fd2e50a6b3c1c729a961041b + sha256: "0016aef94fc66495ac78af5859181e3f3bf2026bd8eecc72b9565601e19ab360" url: "https://pub.dev" source: hosted - version: "14.3.0" + version: "15.2.0" web: dependency: transitive description: name: web - sha256: cd3543bd5798f6ad290ea73d210f423502e71900302dde696f8bff84bf89a1cb + sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a" url: "https://pub.dev" source: hosted - version: "1.1.0" + version: "1.1.1" win32: dependency: transitive description: name: win32 - sha256: daf97c9d80197ed7b619040e86c8ab9a9dad285e7671ee7390f9180cc828a51e + sha256: d7cb55e04cd34096cd3a79b3330245f54cb96a370a1c27adb3c84b917de8b08e url: "https://pub.dev" source: hosted - version: "5.10.1" + version: "5.15.0" xdg_directories: dependency: transitive description: @@ -809,10 +881,10 @@ packages: dependency: transitive description: name: xml - sha256: b015a8ad1c488f66851d762d3090a21c600e479dc75e68328c52774040cf9226 + sha256: "971043b3a0d3da28727e40ed3e0b5d18b742fa5a68665cca88e74b7876d5e025" url: "https://pub.dev" source: hosted - version: "6.5.0" + version: "6.6.1" yaml: dependency: transitive description: @@ -822,5 +894,5 @@ packages: source: hosted version: "3.1.3" sdks: - dart: ">=3.6.0 <4.0.0" - flutter: ">=3.27.0" + dart: ">=3.9.0 <4.0.0" + flutter: ">=3.35.6" diff --git a/pubspec.yaml b/pubspec.yaml old mode 100644 new mode 100755 index 05575a3..6847ac9 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -10,26 +10,27 @@ dependencies: flutter: sdk: flutter cupertino_icons: ^1.0.8 - file_picker: ^9.0.0 + file_picker: ^11.0.2 flutter_highlight: ^0.7.0 flutter_code_editor: ^0.3.2 flutter_markdown: ^0.7.6+2 flutter_markdown_latex: ^0.3.4 - google_fonts: ^6.2.1 + google_fonts: ^8.1.0 markdown: ^7.3.0 path: ^1.9.0 path_provider: ^2.1.5 - permission_handler: ^11.4.0 + permission_handler: ^12.0.3 shared_preferences: ^2.5.2 highlight: ^0.7.0 open_filex: ^4.6.0 flutter_svg: ^2.0.17 flutter_launcher_icons: ^0.14.3 + share_plus: ^12.0.2 dev_dependencies: flutter_test: sdk: flutter - flutter_lints: ^5.0.0 + flutter_lints: ^6.0.0 flutter: uses-material-design: true