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