├── .github
└── FUNDING.yml
├── android
├── settings_aar.gradle
├── gradle.properties
├── .gitignore
├── app
│ ├── src
│ │ ├── main
│ │ │ ├── res
│ │ │ │ ├── mipmap-hdpi
│ │ │ │ │ └── ic_launcher.png
│ │ │ │ ├── mipmap-mdpi
│ │ │ │ │ └── ic_launcher.png
│ │ │ │ ├── mipmap-xhdpi
│ │ │ │ │ └── ic_launcher.png
│ │ │ │ ├── mipmap-xxhdpi
│ │ │ │ │ └── ic_launcher.png
│ │ │ │ ├── mipmap-xxxhdpi
│ │ │ │ │ └── ic_launcher.png
│ │ │ │ ├── drawable-hdpi
│ │ │ │ │ ├── ic_shortcut_add.png
│ │ │ │ │ └── ic_launcher_foreground.png
│ │ │ │ ├── drawable-mdpi
│ │ │ │ │ ├── ic_shortcut_add.png
│ │ │ │ │ └── ic_launcher_foreground.png
│ │ │ │ ├── drawable-xhdpi
│ │ │ │ │ ├── ic_shortcut_add.png
│ │ │ │ │ └── ic_launcher_foreground.png
│ │ │ │ ├── drawable-xxhdpi
│ │ │ │ │ ├── ic_shortcut_add.png
│ │ │ │ │ └── ic_launcher_foreground.png
│ │ │ │ ├── drawable-xxxhdpi
│ │ │ │ │ ├── ic_shortcut_add.png
│ │ │ │ │ └── ic_launcher_foreground.png
│ │ │ │ ├── values
│ │ │ │ │ ├── colors.xml
│ │ │ │ │ └── styles.xml
│ │ │ │ ├── mipmap-anydpi-v26
│ │ │ │ │ └── ic_launcher.xml
│ │ │ │ ├── drawable
│ │ │ │ │ └── launch_background.xml
│ │ │ │ ├── drawable-v21
│ │ │ │ │ └── launch_background.xml
│ │ │ │ └── values-night
│ │ │ │ │ └── styles.xml
│ │ │ ├── kotlin
│ │ │ │ └── net
│ │ │ │ │ └── redsolver
│ │ │ │ │ └── noteless
│ │ │ │ │ └── MainActivity.kt
│ │ │ └── AndroidManifest.xml
│ │ ├── debug
│ │ │ └── AndroidManifest.xml
│ │ └── profile
│ │ │ └── AndroidManifest.xml
│ └── build.gradle
├── gradle
│ └── wrapper
│ │ └── gradle-wrapper.properties
├── settings.gradle
└── build.gradle
├── fastlane
└── metadata
│ └── android
│ └── en-US
│ ├── title.txt
│ ├── short_description.txt
│ ├── images
│ └── phoneScreenshots
│ │ ├── 1.png
│ │ ├── 10.png
│ │ ├── 11.png
│ │ ├── 12.png
│ │ ├── 2.png
│ │ ├── 3.png
│ │ ├── 4.png
│ │ ├── 5.png
│ │ ├── 6.png
│ │ ├── 7.png
│ │ ├── 8.png
│ │ └── 9.png
│ └── full_description.txt
├── assets
├── i18n
│ └── en.json
├── icon
│ ├── icon.png
│ ├── icon_ios.png
│ └── adaptive_icon.png
├── fonts
│ ├── FiraMono-Regular.ttf
│ └── LICENSE
├── tutorial
│ ├── attachments
│ │ ├── icon.png
│ │ └── icon_small.png
│ └── notes
│ │ ├── 09 - Synchronization.md
│ │ ├── 10 - Version Control.md
│ │ ├── 04 - The Editor.md
│ │ ├── 02 - The Sidebar.md
│ │ ├── Wrapping up 🎉.md
│ │ ├── Welcome to Noteless 🙋.md
│ │ ├── 06 - Tags.md
│ │ ├── 01 - The Data Directory.md
│ │ ├── 03 - The Main Page.md
│ │ ├── 07 - Multi-Note Editing.md
│ │ ├── 08 - Linking Attachments, Notes, Tags and Searches.md
│ │ └── 05 - Notes.md
└── preview
│ ├── fonts
│ ├── KaTeX_AMS-Regular.ttf
│ ├── KaTeX_Main-Bold.ttf
│ ├── KaTeX_Main-Bold.woff
│ ├── KaTeX_Main-Bold.woff2
│ ├── KaTeX_Main-Italic.ttf
│ ├── KaTeX_Math-Italic.ttf
│ ├── KaTeX_AMS-Regular.woff
│ ├── KaTeX_AMS-Regular.woff2
│ ├── KaTeX_Fraktur-Bold.ttf
│ ├── KaTeX_Fraktur-Bold.woff
│ ├── KaTeX_Main-Italic.woff
│ ├── KaTeX_Main-Italic.woff2
│ ├── KaTeX_Main-Regular.ttf
│ ├── KaTeX_Main-Regular.woff
│ ├── KaTeX_Math-Italic.woff
│ ├── KaTeX_Math-Italic.woff2
│ ├── KaTeX_Size1-Regular.ttf
│ ├── KaTeX_Size2-Regular.ttf
│ ├── KaTeX_Size3-Regular.ttf
│ ├── KaTeX_Size4-Regular.ttf
│ ├── KaTeX_Caligraphic-Bold.ttf
│ ├── KaTeX_Fraktur-Bold.woff2
│ ├── KaTeX_Fraktur-Regular.ttf
│ ├── KaTeX_Fraktur-Regular.woff
│ ├── KaTeX_Main-BoldItalic.ttf
│ ├── KaTeX_Main-BoldItalic.woff
│ ├── KaTeX_Main-Regular.woff2
│ ├── KaTeX_Math-BoldItalic.ttf
│ ├── KaTeX_Math-BoldItalic.woff
│ ├── KaTeX_SansSerif-Bold.ttf
│ ├── KaTeX_SansSerif-Bold.woff
│ ├── KaTeX_SansSerif-Bold.woff2
│ ├── KaTeX_SansSerif-Italic.ttf
│ ├── KaTeX_Script-Regular.ttf
│ ├── KaTeX_Script-Regular.woff
│ ├── KaTeX_Script-Regular.woff2
│ ├── KaTeX_Size1-Regular.woff
│ ├── KaTeX_Size1-Regular.woff2
│ ├── KaTeX_Size2-Regular.woff
│ ├── KaTeX_Size2-Regular.woff2
│ ├── KaTeX_Size3-Regular.woff
│ ├── KaTeX_Size3-Regular.woff2
│ ├── KaTeX_Size4-Regular.woff
│ ├── KaTeX_Size4-Regular.woff2
│ ├── KaTeX_Caligraphic-Bold.woff
│ ├── KaTeX_Caligraphic-Bold.woff2
│ ├── KaTeX_Fraktur-Regular.woff2
│ ├── KaTeX_Main-BoldItalic.woff2
│ ├── KaTeX_Math-BoldItalic.woff2
│ ├── KaTeX_SansSerif-Italic.woff
│ ├── KaTeX_SansSerif-Italic.woff2
│ ├── KaTeX_SansSerif-Regular.ttf
│ ├── KaTeX_SansSerif-Regular.woff
│ ├── KaTeX_Typewriter-Regular.ttf
│ ├── KaTeX_Caligraphic-Regular.ttf
│ ├── KaTeX_Caligraphic-Regular.woff
│ ├── KaTeX_Caligraphic-Regular.woff2
│ ├── KaTeX_SansSerif-Regular.woff2
│ ├── KaTeX_Typewriter-Regular.woff
│ └── KaTeX_Typewriter-Regular.woff2
│ ├── prism.LICENSE
│ ├── katex.LICENSE
│ ├── mermaid.LICENSE
│ ├── katex.auto-render.min.js
│ └── prism.css
├── ios
├── Flutter
│ ├── Debug.xcconfig
│ ├── Release.xcconfig
│ └── AppFrameworkInfo.plist
├── Runner
│ ├── Runner-Bridging-Header.h
│ ├── Assets.xcassets
│ │ ├── LaunchImage.imageset
│ │ │ ├── LaunchImage.png
│ │ │ ├── LaunchImage@2x.png
│ │ │ ├── LaunchImage@3x.png
│ │ │ ├── README.md
│ │ │ └── Contents.json
│ │ └── AppIcon.appiconset
│ │ │ ├── Icon-App-20x20@1x.png
│ │ │ ├── Icon-App-20x20@2x.png
│ │ │ ├── Icon-App-20x20@3x.png
│ │ │ ├── Icon-App-29x29@1x.png
│ │ │ ├── Icon-App-29x29@2x.png
│ │ │ ├── Icon-App-29x29@3x.png
│ │ │ ├── Icon-App-40x40@1x.png
│ │ │ ├── Icon-App-40x40@2x.png
│ │ │ ├── Icon-App-40x40@3x.png
│ │ │ ├── Icon-App-50x50@1x.png
│ │ │ ├── Icon-App-50x50@2x.png
│ │ │ ├── Icon-App-57x57@1x.png
│ │ │ ├── Icon-App-57x57@2x.png
│ │ │ ├── Icon-App-60x60@2x.png
│ │ │ ├── Icon-App-60x60@3x.png
│ │ │ ├── Icon-App-72x72@1x.png
│ │ │ ├── Icon-App-72x72@2x.png
│ │ │ ├── Icon-App-76x76@1x.png
│ │ │ ├── Icon-App-76x76@2x.png
│ │ │ ├── Icon-App-1024x1024@1x.png
│ │ │ ├── Icon-App-83.5x83.5@2x.png
│ │ │ └── Contents.json
│ ├── AppDelegate.swift
│ ├── Base.lproj
│ │ ├── Main.storyboard
│ │ └── LaunchScreen.storyboard
│ └── Info.plist
├── Runner.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ ├── WorkspaceSettings.xcsettings
│ │ └── IDEWorkspaceChecks.plist
├── Runner.xcodeproj
│ ├── project.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ │ ├── WorkspaceSettings.xcsettings
│ │ │ └── IDEWorkspaceChecks.plist
│ └── xcshareddata
│ │ └── xcschemes
│ │ └── Runner.xcscheme
└── .gitignore
├── screenshots
├── screen1.png
├── screen10.png
├── screen11.png
├── screen12.png
├── screen2.png
├── screen3.png
├── screen4.png
├── screen5.png
├── screen6.png
├── screen7.png
├── screen8.png
└── screen9.png
├── .metadata
├── skydroid-dev.yaml
├── lib
├── data
│ └── samples.dart
├── model
│ └── note.dart
├── main.dart
├── page
│ ├── about.dart
│ ├── preview.dart
│ └── settings.dart
├── provider
│ └── theme.dart
├── editor
│ ├── pairer.dart
│ └── syntax_highlighter.dart
├── utils
│ └── yaml.dart
├── sync
│ └── webdav.dart
└── store
│ ├── persistent.dart
│ └── notes.dart
├── test
└── widget_test.dart
├── LICENSE
├── .gitignore
├── skydroid-app.yaml
├── pubspec.yaml
├── CHANGELOG.md
├── README.md
└── pubspec.lock
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | github: redsolver
--------------------------------------------------------------------------------
/android/settings_aar.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/title.txt:
--------------------------------------------------------------------------------
1 | Noteless
--------------------------------------------------------------------------------
/assets/i18n/en.json:
--------------------------------------------------------------------------------
1 | {
2 | "// TODO":"Add flutter_i18n"
3 | }
--------------------------------------------------------------------------------
/ios/Flutter/Debug.xcconfig:
--------------------------------------------------------------------------------
1 | #include "Generated.xcconfig"
2 |
--------------------------------------------------------------------------------
/ios/Flutter/Release.xcconfig:
--------------------------------------------------------------------------------
1 | #include "Generated.xcconfig"
2 |
--------------------------------------------------------------------------------
/ios/Runner/Runner-Bridging-Header.h:
--------------------------------------------------------------------------------
1 | #import "GeneratedPluginRegistrant.h"
--------------------------------------------------------------------------------
/assets/icon/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/assets/icon/icon.png
--------------------------------------------------------------------------------
/assets/icon/icon_ios.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/assets/icon/icon_ios.png
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/short_description.txt:
--------------------------------------------------------------------------------
1 | A markdown note-taking app for mobile devices.
--------------------------------------------------------------------------------
/screenshots/screen1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/screenshots/screen1.png
--------------------------------------------------------------------------------
/screenshots/screen10.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/screenshots/screen10.png
--------------------------------------------------------------------------------
/screenshots/screen11.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/screenshots/screen11.png
--------------------------------------------------------------------------------
/screenshots/screen12.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/screenshots/screen12.png
--------------------------------------------------------------------------------
/screenshots/screen2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/screenshots/screen2.png
--------------------------------------------------------------------------------
/screenshots/screen3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/screenshots/screen3.png
--------------------------------------------------------------------------------
/screenshots/screen4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/screenshots/screen4.png
--------------------------------------------------------------------------------
/screenshots/screen5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/screenshots/screen5.png
--------------------------------------------------------------------------------
/screenshots/screen6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/screenshots/screen6.png
--------------------------------------------------------------------------------
/screenshots/screen7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/screenshots/screen7.png
--------------------------------------------------------------------------------
/screenshots/screen8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/screenshots/screen8.png
--------------------------------------------------------------------------------
/screenshots/screen9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/screenshots/screen9.png
--------------------------------------------------------------------------------
/assets/icon/adaptive_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/assets/icon/adaptive_icon.png
--------------------------------------------------------------------------------
/assets/fonts/FiraMono-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/assets/fonts/FiraMono-Regular.ttf
--------------------------------------------------------------------------------
/assets/tutorial/attachments/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/assets/tutorial/attachments/icon.png
--------------------------------------------------------------------------------
/assets/preview/fonts/KaTeX_AMS-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/assets/preview/fonts/KaTeX_AMS-Regular.ttf
--------------------------------------------------------------------------------
/assets/preview/fonts/KaTeX_Main-Bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/assets/preview/fonts/KaTeX_Main-Bold.ttf
--------------------------------------------------------------------------------
/assets/preview/fonts/KaTeX_Main-Bold.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/assets/preview/fonts/KaTeX_Main-Bold.woff
--------------------------------------------------------------------------------
/assets/preview/fonts/KaTeX_Main-Bold.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/assets/preview/fonts/KaTeX_Main-Bold.woff2
--------------------------------------------------------------------------------
/assets/preview/fonts/KaTeX_Main-Italic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/assets/preview/fonts/KaTeX_Main-Italic.ttf
--------------------------------------------------------------------------------
/assets/preview/fonts/KaTeX_Math-Italic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/assets/preview/fonts/KaTeX_Math-Italic.ttf
--------------------------------------------------------------------------------
/assets/tutorial/attachments/icon_small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/assets/tutorial/attachments/icon_small.png
--------------------------------------------------------------------------------
/android/gradle.properties:
--------------------------------------------------------------------------------
1 | org.gradle.jvmargs=-Xmx1536M
2 | android.useAndroidX=true
3 | android.enableR8=true
4 | android.enableJetifier=true
--------------------------------------------------------------------------------
/assets/preview/fonts/KaTeX_AMS-Regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/assets/preview/fonts/KaTeX_AMS-Regular.woff
--------------------------------------------------------------------------------
/assets/preview/fonts/KaTeX_AMS-Regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/assets/preview/fonts/KaTeX_AMS-Regular.woff2
--------------------------------------------------------------------------------
/assets/preview/fonts/KaTeX_Fraktur-Bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/assets/preview/fonts/KaTeX_Fraktur-Bold.ttf
--------------------------------------------------------------------------------
/assets/preview/fonts/KaTeX_Fraktur-Bold.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/assets/preview/fonts/KaTeX_Fraktur-Bold.woff
--------------------------------------------------------------------------------
/assets/preview/fonts/KaTeX_Main-Italic.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/assets/preview/fonts/KaTeX_Main-Italic.woff
--------------------------------------------------------------------------------
/assets/preview/fonts/KaTeX_Main-Italic.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/assets/preview/fonts/KaTeX_Main-Italic.woff2
--------------------------------------------------------------------------------
/assets/preview/fonts/KaTeX_Main-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/assets/preview/fonts/KaTeX_Main-Regular.ttf
--------------------------------------------------------------------------------
/assets/preview/fonts/KaTeX_Main-Regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/assets/preview/fonts/KaTeX_Main-Regular.woff
--------------------------------------------------------------------------------
/assets/preview/fonts/KaTeX_Math-Italic.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/assets/preview/fonts/KaTeX_Math-Italic.woff
--------------------------------------------------------------------------------
/assets/preview/fonts/KaTeX_Math-Italic.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/assets/preview/fonts/KaTeX_Math-Italic.woff2
--------------------------------------------------------------------------------
/assets/preview/fonts/KaTeX_Size1-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/assets/preview/fonts/KaTeX_Size1-Regular.ttf
--------------------------------------------------------------------------------
/assets/preview/fonts/KaTeX_Size2-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/assets/preview/fonts/KaTeX_Size2-Regular.ttf
--------------------------------------------------------------------------------
/assets/preview/fonts/KaTeX_Size3-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/assets/preview/fonts/KaTeX_Size3-Regular.ttf
--------------------------------------------------------------------------------
/assets/preview/fonts/KaTeX_Size4-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/assets/preview/fonts/KaTeX_Size4-Regular.ttf
--------------------------------------------------------------------------------
/assets/preview/fonts/KaTeX_Caligraphic-Bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/assets/preview/fonts/KaTeX_Caligraphic-Bold.ttf
--------------------------------------------------------------------------------
/assets/preview/fonts/KaTeX_Fraktur-Bold.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/assets/preview/fonts/KaTeX_Fraktur-Bold.woff2
--------------------------------------------------------------------------------
/assets/preview/fonts/KaTeX_Fraktur-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/assets/preview/fonts/KaTeX_Fraktur-Regular.ttf
--------------------------------------------------------------------------------
/assets/preview/fonts/KaTeX_Fraktur-Regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/assets/preview/fonts/KaTeX_Fraktur-Regular.woff
--------------------------------------------------------------------------------
/assets/preview/fonts/KaTeX_Main-BoldItalic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/assets/preview/fonts/KaTeX_Main-BoldItalic.ttf
--------------------------------------------------------------------------------
/assets/preview/fonts/KaTeX_Main-BoldItalic.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/assets/preview/fonts/KaTeX_Main-BoldItalic.woff
--------------------------------------------------------------------------------
/assets/preview/fonts/KaTeX_Main-Regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/assets/preview/fonts/KaTeX_Main-Regular.woff2
--------------------------------------------------------------------------------
/assets/preview/fonts/KaTeX_Math-BoldItalic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/assets/preview/fonts/KaTeX_Math-BoldItalic.ttf
--------------------------------------------------------------------------------
/assets/preview/fonts/KaTeX_Math-BoldItalic.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/assets/preview/fonts/KaTeX_Math-BoldItalic.woff
--------------------------------------------------------------------------------
/assets/preview/fonts/KaTeX_SansSerif-Bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/assets/preview/fonts/KaTeX_SansSerif-Bold.ttf
--------------------------------------------------------------------------------
/assets/preview/fonts/KaTeX_SansSerif-Bold.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/assets/preview/fonts/KaTeX_SansSerif-Bold.woff
--------------------------------------------------------------------------------
/assets/preview/fonts/KaTeX_SansSerif-Bold.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/assets/preview/fonts/KaTeX_SansSerif-Bold.woff2
--------------------------------------------------------------------------------
/assets/preview/fonts/KaTeX_SansSerif-Italic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/assets/preview/fonts/KaTeX_SansSerif-Italic.ttf
--------------------------------------------------------------------------------
/assets/preview/fonts/KaTeX_Script-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/assets/preview/fonts/KaTeX_Script-Regular.ttf
--------------------------------------------------------------------------------
/assets/preview/fonts/KaTeX_Script-Regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/assets/preview/fonts/KaTeX_Script-Regular.woff
--------------------------------------------------------------------------------
/assets/preview/fonts/KaTeX_Script-Regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/assets/preview/fonts/KaTeX_Script-Regular.woff2
--------------------------------------------------------------------------------
/assets/preview/fonts/KaTeX_Size1-Regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/assets/preview/fonts/KaTeX_Size1-Regular.woff
--------------------------------------------------------------------------------
/assets/preview/fonts/KaTeX_Size1-Regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/assets/preview/fonts/KaTeX_Size1-Regular.woff2
--------------------------------------------------------------------------------
/assets/preview/fonts/KaTeX_Size2-Regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/assets/preview/fonts/KaTeX_Size2-Regular.woff
--------------------------------------------------------------------------------
/assets/preview/fonts/KaTeX_Size2-Regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/assets/preview/fonts/KaTeX_Size2-Regular.woff2
--------------------------------------------------------------------------------
/assets/preview/fonts/KaTeX_Size3-Regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/assets/preview/fonts/KaTeX_Size3-Regular.woff
--------------------------------------------------------------------------------
/assets/preview/fonts/KaTeX_Size3-Regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/assets/preview/fonts/KaTeX_Size3-Regular.woff2
--------------------------------------------------------------------------------
/assets/preview/fonts/KaTeX_Size4-Regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/assets/preview/fonts/KaTeX_Size4-Regular.woff
--------------------------------------------------------------------------------
/assets/preview/fonts/KaTeX_Size4-Regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/assets/preview/fonts/KaTeX_Size4-Regular.woff2
--------------------------------------------------------------------------------
/assets/preview/fonts/KaTeX_Caligraphic-Bold.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/assets/preview/fonts/KaTeX_Caligraphic-Bold.woff
--------------------------------------------------------------------------------
/assets/preview/fonts/KaTeX_Caligraphic-Bold.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/assets/preview/fonts/KaTeX_Caligraphic-Bold.woff2
--------------------------------------------------------------------------------
/assets/preview/fonts/KaTeX_Fraktur-Regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/assets/preview/fonts/KaTeX_Fraktur-Regular.woff2
--------------------------------------------------------------------------------
/assets/preview/fonts/KaTeX_Main-BoldItalic.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/assets/preview/fonts/KaTeX_Main-BoldItalic.woff2
--------------------------------------------------------------------------------
/assets/preview/fonts/KaTeX_Math-BoldItalic.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/assets/preview/fonts/KaTeX_Math-BoldItalic.woff2
--------------------------------------------------------------------------------
/assets/preview/fonts/KaTeX_SansSerif-Italic.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/assets/preview/fonts/KaTeX_SansSerif-Italic.woff
--------------------------------------------------------------------------------
/assets/preview/fonts/KaTeX_SansSerif-Italic.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/assets/preview/fonts/KaTeX_SansSerif-Italic.woff2
--------------------------------------------------------------------------------
/assets/preview/fonts/KaTeX_SansSerif-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/assets/preview/fonts/KaTeX_SansSerif-Regular.ttf
--------------------------------------------------------------------------------
/assets/preview/fonts/KaTeX_SansSerif-Regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/assets/preview/fonts/KaTeX_SansSerif-Regular.woff
--------------------------------------------------------------------------------
/assets/preview/fonts/KaTeX_Typewriter-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/assets/preview/fonts/KaTeX_Typewriter-Regular.ttf
--------------------------------------------------------------------------------
/android/.gitignore:
--------------------------------------------------------------------------------
1 | gradle-wrapper.jar
2 | /.gradle
3 | /captures/
4 | /gradlew
5 | /gradlew.bat
6 | /local.properties
7 | GeneratedPluginRegistrant.java
8 |
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/assets/preview/fonts/KaTeX_Caligraphic-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/assets/preview/fonts/KaTeX_Caligraphic-Regular.ttf
--------------------------------------------------------------------------------
/assets/preview/fonts/KaTeX_Caligraphic-Regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/assets/preview/fonts/KaTeX_Caligraphic-Regular.woff
--------------------------------------------------------------------------------
/assets/preview/fonts/KaTeX_Caligraphic-Regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/assets/preview/fonts/KaTeX_Caligraphic-Regular.woff2
--------------------------------------------------------------------------------
/assets/preview/fonts/KaTeX_SansSerif-Regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/assets/preview/fonts/KaTeX_SansSerif-Regular.woff2
--------------------------------------------------------------------------------
/assets/preview/fonts/KaTeX_Typewriter-Regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/assets/preview/fonts/KaTeX_Typewriter-Regular.woff
--------------------------------------------------------------------------------
/assets/preview/fonts/KaTeX_Typewriter-Regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/assets/preview/fonts/KaTeX_Typewriter-Regular.woff2
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-hdpi/ic_shortcut_add.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/android/app/src/main/res/drawable-hdpi/ic_shortcut_add.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-mdpi/ic_shortcut_add.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/android/app/src/main/res/drawable-mdpi/ic_shortcut_add.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-xhdpi/ic_shortcut_add.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/android/app/src/main/res/drawable-xhdpi/ic_shortcut_add.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-xxhdpi/ic_shortcut_add.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/android/app/src/main/res/drawable-xxhdpi/ic_shortcut_add.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-xxxhdpi/ic_shortcut_add.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/android/app/src/main/res/drawable-xxxhdpi/ic_shortcut_add.png
--------------------------------------------------------------------------------
/android/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #ffffff
4 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/images/phoneScreenshots/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/fastlane/metadata/android/en-US/images/phoneScreenshots/1.png
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/images/phoneScreenshots/10.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/fastlane/metadata/android/en-US/images/phoneScreenshots/10.png
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/images/phoneScreenshots/11.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/fastlane/metadata/android/en-US/images/phoneScreenshots/11.png
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/images/phoneScreenshots/12.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/fastlane/metadata/android/en-US/images/phoneScreenshots/12.png
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/images/phoneScreenshots/2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/fastlane/metadata/android/en-US/images/phoneScreenshots/2.png
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/images/phoneScreenshots/3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/fastlane/metadata/android/en-US/images/phoneScreenshots/3.png
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/images/phoneScreenshots/4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/fastlane/metadata/android/en-US/images/phoneScreenshots/4.png
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/images/phoneScreenshots/5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/fastlane/metadata/android/en-US/images/phoneScreenshots/5.png
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/images/phoneScreenshots/6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/fastlane/metadata/android/en-US/images/phoneScreenshots/6.png
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/images/phoneScreenshots/7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/fastlane/metadata/android/en-US/images/phoneScreenshots/7.png
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/images/phoneScreenshots/8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/fastlane/metadata/android/en-US/images/phoneScreenshots/8.png
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/images/phoneScreenshots/9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/fastlane/metadata/android/en-US/images/phoneScreenshots/9.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-hdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/android/app/src/main/res/drawable-hdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-mdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/android/app/src/main/res/drawable-mdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-xhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/android/app/src/main/res/drawable-xhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-xxhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/android/app/src/main/res/drawable-xxhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-xxxhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/android/app/src/main/res/drawable-xxxhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redsolver/noteless/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png
--------------------------------------------------------------------------------
/android/app/src/main/kotlin/net/redsolver/noteless/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package net.redsolver.noteless
2 |
3 | import io.flutter.embedding.android.FlutterActivity
4 |
5 | class MainActivity: FlutterActivity() {
6 |
7 | }
--------------------------------------------------------------------------------
/ios/Runner.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Fri Jun 23 08:50:38 CEST 2017
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip
7 |
--------------------------------------------------------------------------------
/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PreviewsEnabled
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PreviewsEnabled
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.metadata:
--------------------------------------------------------------------------------
1 | # This file tracks properties of this Flutter project.
2 | # Used by Flutter tool to assess capabilities and perform upgrades etc.
3 | #
4 | # This file should be version controlled and should not be manually edited.
5 |
6 | version:
7 | revision: 20e59316b8b8474554b38493b8ca888794b0234a
8 | channel: beta
9 |
10 | project_type: app
11 |
--------------------------------------------------------------------------------
/android/app/src/debug/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/android/app/src/profile/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md:
--------------------------------------------------------------------------------
1 | # Launch Screen Assets
2 |
3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory.
4 |
5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images.
--------------------------------------------------------------------------------
/skydroid-dev.yaml:
--------------------------------------------------------------------------------
1 | name: noteless.redsolver
2 | metadataFile: skydroid-app.yaml
3 | skynetPortal: https://skyportal.xyz
4 |
5 | checkVersion:
6 | file: pubspec.yaml
7 | versionCode: 'version:\s.+\+(\d+)'
8 | versionName: 'version:\s(.+)\+'
9 |
10 | uploadBuild:
11 | file: build/app/outputs/flutter-apk/app-release.apk
12 |
13 | updateMetadataFile:
14 | updateWhatsNew: false
15 |
16 | # uploadMetadata:
17 |
--------------------------------------------------------------------------------
/android/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
--------------------------------------------------------------------------------
/assets/tutorial/notes/09 - Synchronization.md:
--------------------------------------------------------------------------------
1 | ---
2 | tags: [Advanced, Notebooks/Tutorial]
3 | title: 09 - Synchronization
4 | created: '2018-12-16T23:15:11.439Z'
5 | modified: '2020-07-05T12:00:00.000Z'
6 | ---
7 |
8 | # 09 - Synchronization
9 |
10 | To synchronize your notes, you can use an external data directory via `Settings -> Data Directory` and then use any other Sync-App to sync your notes.
11 |
12 | Personally I recommend [Syncthing](https://syncthing.net/).
13 |
--------------------------------------------------------------------------------
/ios/Runner/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 | import Flutter
3 |
4 | @UIApplicationMain
5 | @objc class AppDelegate: FlutterAppDelegate {
6 | override func application(
7 | _ application: UIApplication,
8 | didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?
9 | ) -> Bool {
10 | GeneratedPluginRegistrant.register(with: self)
11 | return super.application(application, didFinishLaunchingWithOptions: launchOptions)
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable/launch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-v21/launch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/full_description.txt:
--------------------------------------------------------------------------------
1 | Features
2 |
3 | * Markdown-optimized editor with syntax highlighting
4 | * Supports Github Flavored Markdown, KaTeX and mermaidjs for diagrams
5 | * Tags for organizing your notes
6 | * Pin, Star and sort your notes by title or different dates
7 | * Very themable - dark/light mode and accent color
8 | * Full-text search
9 | * File Attachments that can be embedded into a note
10 | * Multi-Note Editing
11 | * Slide actions for easier editing
12 | * Tutorial notes which explain how to use the app
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "LaunchImage.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "LaunchImage@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "LaunchImage@3x.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/android/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
3 | def flutterProjectRoot = rootProject.projectDir.parentFile.toPath()
4 |
5 | def plugins = new Properties()
6 | def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins')
7 | if (pluginsFile.exists()) {
8 | pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) }
9 | }
10 |
11 | plugins.each { name, path ->
12 | def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile()
13 | include ":$name"
14 | project(":$name").projectDir = pluginDirectory
15 | }
16 |
--------------------------------------------------------------------------------
/lib/data/samples.dart:
--------------------------------------------------------------------------------
1 | class Samples {
2 | static List tutorialNotes = [
3 | 'Welcome to Noteless 🙋.md',
4 | '01 - The Data Directory.md',
5 | '02 - The Sidebar.md',
6 | '03 - The Main Page.md',
7 | '04 - The Editor.md',
8 | '05 - Notes.md',
9 | '06 - Tags.md',
10 | '07 - Multi-Note Editing.md',
11 | '08 - Linking Attachments, Notes, Tags and Searches.md',
12 | '09 - Synchronization.md',
13 | '10 - Version Control.md',
14 | 'Wrapping up 🎉.md',
15 | ];
16 | static List tutorialAttachments = ['icon.png', 'icon_small.png'];
17 | }
18 |
--------------------------------------------------------------------------------
/test/widget_test.dart:
--------------------------------------------------------------------------------
1 | // This is a basic Flutter widget test.
2 | //
3 | // To perform an interaction with a widget in your test, use the WidgetTester
4 | // utility that Flutter provides. For example, you can send tap and scroll
5 | // gestures. You can also use WidgetTester to find child widgets in the widget
6 | // tree, read text, and verify that the values of widget properties are correct.
7 |
8 | import 'package:flutter/material.dart';
9 | //import 'package:flutter_test/flutter_test.dart';
10 |
11 | import 'package:app/main.dart';
12 |
13 | void main() {
14 | // TODO Maybe add some tests
15 | }
16 |
--------------------------------------------------------------------------------
/assets/tutorial/notes/10 - Version Control.md:
--------------------------------------------------------------------------------
1 | ---
2 | tags: [Advanced, Notebooks/Tutorial]
3 | title: 10 - Version Control
4 | created: '2019-03-12T15:20:40.396Z'
5 | modified: '2020-07-05T12:00:00.000Z'
6 | ---
7 |
8 | # 10 - Version Control
9 |
10 | Noteless doesn't have version control built-in, but since the data directory is just a regular directory you could make it a git repository and every once in a while take a snapshot of your notes, or perhaps a small script could make commits automatically for you everytime something changes.
11 |
12 | You have to use an external data directory for this via `Settings -> Data Directory`.
--------------------------------------------------------------------------------
/ios/.gitignore:
--------------------------------------------------------------------------------
1 | *.mode1v3
2 | *.mode2v3
3 | *.moved-aside
4 | *.pbxuser
5 | *.perspectivev3
6 | **/*sync/
7 | .sconsign.dblite
8 | .tags*
9 | **/.vagrant/
10 | **/DerivedData/
11 | Icon?
12 | **/Pods/
13 | **/.symlinks/
14 | profile
15 | xcuserdata
16 | **/.generated/
17 | Flutter/App.framework
18 | Flutter/Flutter.framework
19 | Flutter/Flutter.podspec
20 | Flutter/Generated.xcconfig
21 | Flutter/app.flx
22 | Flutter/app.zip
23 | Flutter/flutter_assets/
24 | Flutter/flutter_export_environment.sh
25 | ServiceDefinitions.json
26 | Runner/GeneratedPluginRegistrant.*
27 |
28 | # Exceptions to above rules.
29 | !default.mode1v3
30 | !default.mode2v3
31 | !default.pbxuser
32 | !default.perspectivev3
33 |
--------------------------------------------------------------------------------
/assets/tutorial/notes/04 - The Editor.md:
--------------------------------------------------------------------------------
1 | ---
2 | tags: [Basics, Notebooks/Tutorial]
3 | title: 04 - The Editor
4 | created: '2019-03-12T15:20:40.393Z'
5 | modified: '2020-07-05T12:00:00.000Z'
6 | ---
7 |
8 | # 04 - The Editor
9 |
10 | The editor is where you can edit and preview the currently active note.
11 |
12 | It can be accessed by tapping on a note.
13 |
14 | ## Toolbar
15 |
16 | The toolbar has a slider to toggle between edit and preview mode.
17 |
18 | The popup menu in the top right allows you to favorite/unfavorite, pin/unpin a note and add edit tags or attachments.
19 |
20 | ## Editor
21 |
22 | When editing you'll use a simple text field. It features copy/paste functionality and an undo button
23 |
24 | ## Saving
25 |
26 | When you're done editing a note, you can save it via the "Save" button in the toolbar.
--------------------------------------------------------------------------------
/assets/tutorial/notes/02 - The Sidebar.md:
--------------------------------------------------------------------------------
1 | ---
2 | tags: [Basics, Notebooks/Tutorial]
3 | title: 02 - The Sidebar
4 | created: '2019-03-12T15:20:40.392Z'
5 | modified: '2020-07-05T12:00:00.000Z'
6 | ---
7 |
8 | # 02 - The Sidebar
9 |
10 | The sidebar lists all your tags and you can access the Settings from there.
11 |
12 | It can be opened by clicking the hamburger icon in the top left corner or by swiping from the left edge.
13 |
14 |
15 | ## Categories
16 |
17 | - **All Notes**: This section contains all notes.
18 | - **Favorites**: This section contains all notes you've favorited.
19 | - **Untagged**: This section contains all notes that have no tags.
20 | - **Trash**: This section contains all notes that have been deleted. These notes won't be displayed in any other category.
21 | - **All your other tags**
22 |
23 | You can create sub-categories by using nested tags. (`tag/subtag`)
24 |
--------------------------------------------------------------------------------
/assets/tutorial/notes/Wrapping up 🎉.md:
--------------------------------------------------------------------------------
1 | ---
2 | tags: [Notebooks/Tutorial]
3 | title: "Wrapping up \U0001F389"
4 | created: '2019-03-12T15:20:40.398Z'
5 | modified: '2020-07-05T12:00:00.000Z'
6 | ---
7 |
8 | # Wrapping up :tada:
9 |
10 | Awesome, you've reached the end of the tutorial!
11 |
12 | The next step is deleting all these tutorial notes, you can do this one-by-one, using multi-note editing, or you could just trash the whole `notes` sub-directory from your data directory.
13 |
14 | ## Feedback
15 |
16 | If you've reached this far chances are you're considering using Noteless as your main mobile note-taking app, that's great!
17 |
18 | Feel free to [contact us](https://github.com/redsolver/noteless/issues) about any issues you may encounter, any features suggestions and generally sharing your opinion about Noteless and how we can improve it.
19 |
20 | Have a wonderful day! :wave:
21 |
--------------------------------------------------------------------------------
/ios/Flutter/AppFrameworkInfo.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | App
9 | CFBundleIdentifier
10 | io.flutter.flutter.app
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | App
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1.0
23 | MinimumOSVersion
24 | 8.0
25 |
26 |
27 |
--------------------------------------------------------------------------------
/android/app/src/main/res/values-night/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
15 |
18 |
19 |
--------------------------------------------------------------------------------
/assets/tutorial/notes/Welcome to Noteless 🙋.md:
--------------------------------------------------------------------------------
1 | ---
2 | attachments: [icon.png]
3 | pinned: true
4 | tags: [Notebooks/Tutorial]
5 | title: "Welcome to Noteless \U0001F64B"
6 | created: '2019-05-16T14:56:08.914Z'
7 | modified: '2020-07-05T12:00:00.000Z'
8 | ---
9 |
10 | # Welcome to Noteless :raising_hand_woman:
11 |
12 |
13 |
14 |
15 |
16 | ## About
17 |
18 | Noteless is a markdown note-taking app which aims to be compatible with notes saved in [Notable](https://notable.app/).
19 |
20 | ## Tutorial
21 |
22 | Some tutorial notes have been added to your data directory.
23 |
24 | They will guide you towards the main features Noteless provides.
25 |
26 | You can read them in a nicer way by pressing the switch in the toolbar.
27 |
28 | Once you're done exploring feel free to permanently delete them, if at any point you'd like to read them again you can re-add them to your data directory via the `Settings -> More -> Recreate tutorial notes` option.
29 |
30 | ## Credits
31 |
32 | This tutorial notes are based on the ones in [Notable](https://notable.app/).
--------------------------------------------------------------------------------
/lib/model/note.dart:
--------------------------------------------------------------------------------
1 | import 'dart:io';
2 |
3 | class Note {
4 | String title;
5 | DateTime created;
6 | DateTime modified;
7 | List tags = [];
8 | List attachments = [];
9 | bool pinned = false;
10 | bool favorited = false;
11 | bool deleted = false;
12 | File file;
13 |
14 | bool usesMillis = false;
15 | bool usesUpdatedInsteadOfModified = false;
16 | Map additionalFrontMatterKeys;
17 |
18 | bool hasTag(String cTag) {
19 | if (cTag != '') {
20 | if (cTag == 'Trash') {
21 | return deleted;
22 | } else if (cTag == 'Favorites') {
23 | return favorited;
24 | } else if (cTag == 'Untagged') {
25 | return tags.isEmpty;
26 | } else {
27 | bool hasTag = false;
28 | for (String tag in tags) {
29 | if (tag.startsWith(cTag)) {
30 | hasTag = true;
31 | break;
32 | }
33 | }
34 | if (!hasTag) return false;
35 | }
36 | } else {}
37 | if (deleted) return false;
38 | //if (note.deleted) return false;
39 | return true;
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2019 redsolver
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a
6 | copy of this software and associated documentation files (the "Software"),
7 | to deal in the Software without restriction, including without limitation
8 | the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 | and/or sell copies of the Software, and to permit persons to whom the
10 | Software is furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 | DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/assets/preview/prism.LICENSE:
--------------------------------------------------------------------------------
1 | MIT LICENSE
2 |
3 | Copyright (c) 2012 Lea Verou
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
--------------------------------------------------------------------------------
/assets/preview/katex.LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2013-2018 Khan Academy
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/assets/preview/mermaid.LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2014 - 2018 Knut Sveidqvist
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/assets/tutorial/notes/06 - Tags.md:
--------------------------------------------------------------------------------
1 | ---
2 | tags: [Basics, Notebooks/Tutorial]
3 | title: 06 - Tags
4 | created: '2019-01-28T19:46:36.681Z'
5 | modified: '2020-07-05T12:00:00.000Z'
6 | ---
7 |
8 | # 06 - Tags
9 |
10 | Notes can have multiple tags, which are useful for better categorization.
11 |
12 | ## Syntax
13 |
14 | - **Root**: Root tags don't contain any forward slash (`/`), they will be rendered in the sidebar.
15 |
16 | - **Nested**: Tags can also be nested, _indefinitely_, just write them like a path, separating the levels with a forward slash: `foo/bar/baz`.
17 |
18 | ## Collapse/Expand
19 |
20 | Tags with children can be collapsed/expanded, just click the arrow next to them.
21 |
22 | ## Editing
23 |
24 | There are multiple ways to add/remove tags:
25 |
26 | - **Single-note editing**: You can edit a note's tags via the popup menu in the toolbar.
27 | - **Multi-note editing**: Tags can be added/removed from multiple notes at once via the [multi-note editing](@note/07 - Multi-Note Editing.md) features provided.
28 | - **Advanced search & replace**: Alternatively you could just open your data directory with your editor and perform a search & replace there, this way you can also use advanced features like regexes.
29 |
--------------------------------------------------------------------------------
/android/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | ext.kotlin_version = '1.3.50'
3 | repositories {
4 | google()
5 | jcenter()
6 | }
7 |
8 | dependencies {
9 | classpath 'com.android.tools.build:gradle:3.5.4'
10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
11 | }
12 |
13 | /* subprojects {
14 | project.configurations.all {
15 | resolutionStrategy.eachDependency { details ->
16 | if (details.requested.group == 'androidx.lifecycle' && details.requested.name == 'lifecycle-runtime') {
17 | details.useVersion "2.1.0"
18 | }else
19 | if (details.requested.group == 'androidx.core' && details.requested.name == 'core') {
20 | details.useVersion "1.1.0"
21 | }
22 | }
23 | }
24 | } */
25 | }
26 |
27 | allprojects {
28 | repositories {
29 | google()
30 | jcenter()
31 | }
32 | }
33 |
34 | rootProject.buildDir = '../build'
35 | subprojects {
36 | project.buildDir = "${rootProject.buildDir}/${project.name}"
37 | }
38 | subprojects {
39 | project.evaluationDependsOn(':app')
40 | }
41 |
42 | task clean(type: Delete) {
43 | delete rootProject.buildDir
44 | }
45 |
--------------------------------------------------------------------------------
/assets/tutorial/notes/01 - The Data Directory.md:
--------------------------------------------------------------------------------
1 | ---
2 | tags: [Basics, Notebooks/Tutorial]
3 | title: 01 - The Data Directory
4 | created: '2018-12-16T21:43:52.886Z'
5 | modified: '2020-07-05T12:00:00.000Z'
6 | ---
7 |
8 | # 01 - The Data Directory
9 |
10 | The data directory is where all your notes and attachments will be stored, it has the following structure:
11 |
12 | ```
13 | /path/to/your/data_directory
14 | ├─┬ attachments
15 | │ ├── foo.ext
16 | │ ├── bar.ext
17 | │ └── …
18 | └─┬ notes
19 | ├── foo.md
20 | ├── bar.md
21 | └── …
22 | ```
23 |
24 | ## Features
25 |
26 | - The data directory gives you freedom since your notes are never locked into some sort of proprietary database, all your files use sane formats and are easily accessible and portable.
27 | - You can also change the data directory at any time via `Settings -> Data Directory`, the current content won't be copied over to the new one.
28 | - You can edit your notes/attachments without even using Noteless, all changes you make to them will be reflected here (after a quick refresh). In fact you could also import a Markdown note simply by copying it into the `notes` directory.
29 |
30 | ## Advanced Features
31 |
32 | The data directory allows you to leverage third-party tools to have powerful features like synchronization, versioning and encryption, we'll talk about those in the [advanced](@tag/Advanced) sections.
33 |
--------------------------------------------------------------------------------
/assets/tutorial/notes/03 - The Main Page.md:
--------------------------------------------------------------------------------
1 | ---
2 | tags: [Basics, Notebooks/Tutorial]
3 | title: 03 - The Main Page
4 | created: '2019-03-12T15:20:46.181Z'
5 | modified: '2020-07-05T12:00:00.000Z'
6 | ---
7 |
8 | # 03 - The Main Page
9 |
10 | The main page shows you all notes contained in the currently active category, properly ordered and filtered by the search query.
11 |
12 | ## Search
13 |
14 | To search just click on the top right icon and type something in the search bar.
15 |
16 | The content of notes is searched in too, a full-match is always required.
17 |
18 | ## New Note Button
19 |
20 | On the bottom right there's a button for creating a new note.
21 |
22 | ## Sorting Order
23 |
24 | Right below the title bar you can change the order in which notes are being displayed.
25 |
26 | By default this is by `Title - Ascending`, so that the tutorial notes get displayed in order, but you might want to change this later to `Date Modified - Descending`, so that the most recently edited notes are at the top.
27 |
28 | ## Notes
29 |
30 | Lastly there's the notes list.
31 |
32 | Notes will have some badges if they are pinned, favorited or have attachments.
33 |
34 | Pinned notes are displayed before the others.
35 |
36 | If you long-press them you can access some commands, all of them are also available by sliding a note to the side, most of them are also available from the editor's toolbar.
37 |
--------------------------------------------------------------------------------
/assets/tutorial/notes/07 - Multi-Note Editing.md:
--------------------------------------------------------------------------------
1 | ---
2 | tags: [Intermediate, Notebooks/Tutorial]
3 | title: 07 - Multi-Note Editing
4 | created: '2018-12-16T23:45:42.026Z'
5 | modified: '2020-07-05T12:00:00.000Z'
6 | ---
7 |
8 | # 07 - Multi-Note Editing
9 |
10 | ## Built-in
11 |
12 | Some multi-note editing features are built-in.
13 |
14 | To select multiple notes, you need to **long-press** one and then simply **press** others to remove and add them. You can also use the `ALL` and `NONE` selectors which appear in the multi-note editing toolbar on the bottom.
15 |
16 | The selection is persisted if you change categories via the sidebar or search for notes, so you can perform advanced selections.
17 |
18 | These are the actions you can take on selected notes:
19 |
20 | - Favorite/unfavorite them.
21 | - Pin/unpin them.
22 | - Move to trash/restore/permanently delete them.
23 | - Add one or multiple tags to them.
24 | - Remove one or multiple tags from them.
25 |
26 | ## Advanced
27 |
28 | If you need more advanced multi-note editing, like global search & replace, remember that your notes are just plain Markdown files.
29 |
30 | You could open your data directory into your favorite editor of choice and perform the search & replace there, this way you can also use advanced features like regexes.
31 |
32 | All the edits performed with a third-party application will be reflected into Noteless after a quick refresh.
33 |
--------------------------------------------------------------------------------
/ios/Runner/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/ios/Runner/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | Noteless
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | $(FLUTTER_BUILD_NAME)
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | $(FLUTTER_BUILD_NUMBER)
23 | LSRequiresIPhoneOS
24 |
25 | UILaunchStoryboardName
26 | LaunchScreen
27 | UIMainStoryboardFile
28 | Main
29 | UISupportedInterfaceOrientations
30 |
31 | UIInterfaceOrientationPortrait
32 | UIInterfaceOrientationLandscapeLeft
33 | UIInterfaceOrientationLandscapeRight
34 |
35 | UISupportedInterfaceOrientations~ipad
36 |
37 | UIInterfaceOrientationPortrait
38 | UIInterfaceOrientationPortraitUpsideDown
39 | UIInterfaceOrientationLandscapeLeft
40 | UIInterfaceOrientationLandscapeRight
41 |
42 | UIViewControllerBasedStatusBarAppearance
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/lib/main.dart:
--------------------------------------------------------------------------------
1 | // @dart=2.9
2 |
3 | import 'package:device_info/device_info.dart';
4 | import 'package:flutter/material.dart';
5 | import 'package:preferences/preference_service.dart';
6 |
7 | import 'package:app/page/note_list.dart';
8 |
9 | import 'package:intl/intl.dart';
10 | import 'package:provider/provider.dart';
11 |
12 | import 'provider/theme.dart';
13 |
14 | main() async {
15 | WidgetsFlutterBinding.ensureInitialized();
16 |
17 | await PrefService.init(prefix: 'pref_');
18 | /*
19 | await initializeDateFormatting("en_US", null); */
20 | Intl.defaultLocale = 'en_US';
21 |
22 | final deviceInfo = DeviceInfoPlugin();
23 | androidDeviceInfo = await deviceInfo.androidInfo;
24 |
25 | // Disable note preview/render feature on Android KitKat see #32
26 | if (androidDeviceInfo.version.sdkInt < 20) {
27 | previewFeatureEnabled = false;
28 | }
29 |
30 | runApp(
31 | ChangeNotifierProvider(
32 | create: (_) => ThemeNotifier(),
33 | child: App(),
34 | ),
35 | );
36 | }
37 |
38 | AndroidDeviceInfo androidDeviceInfo;
39 |
40 | bool previewFeatureEnabled = true;
41 |
42 | class App extends StatelessWidget {
43 | @override
44 | Widget build(BuildContext context) {
45 | return MaterialApp(
46 | title: 'Noteless',
47 | theme: Provider.of(context).currentThemeData,
48 | home: NoteListPage(
49 | isFirstPage: true,
50 | ),
51 | /* localizationsDelegates: [
52 | FlutterI18nDelegate(path: 'assets/i18n', fallbackFile: 'en'),
53 | GlobalMaterialLocalizations.delegate,
54 | GlobalWidgetsLocalizations.delegate
55 | ], */
56 | /* debugShowCheckedModeBanner: false, */
57 | );
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/assets/tutorial/notes/08 - Linking Attachments, Notes, Tags and Searches.md:
--------------------------------------------------------------------------------
1 | ---
2 | attachments: [icon_small.png]
3 | tags: [Intermediate, Notebooks/Tutorial]
4 | title: '08 - Linking Attachments, Notes, Tags and Searches'
5 | created: '2018-12-27T18:53:01.510Z'
6 | modified: '2020-07-05T12:00:00.000Z'
7 | ---
8 |
9 | # 08 - Linking Attachments, Notes, Tags and Searches
10 |
11 | Sometimes, like when writing a tutorial for a note-taking app :wink:, you may need to link to other notes or embed a few attachments. Noteless makes this easy for you.
12 |
13 | ## Attachments
14 |
15 | Attachments can be rendered inline, linked to, and linked to via a button. The `@attachment` token is used for this.
16 |
17 | ##### Syntax
18 |
19 | ```markdown
20 | 
21 | [Icon](@attachment/icon_small.png)
22 | ```
23 |
24 | ##### Result
25 |
26 | 
27 |
28 | [Icon](@attachment/icon_small.png)
29 |
30 | ## Notes
31 |
32 | Notes can be linked to, and linked to via a button. The `@note` token is used for this. Wiki-style links are supported too.
33 |
34 | ##### Syntax
35 |
36 | ```markdown
37 | [Tags](@note/06 - Tags.md)
38 | [[06 - Tags]]
39 | ```
40 |
41 | ##### Result
42 |
43 | [Tags](@note/06 - Tags.md)
44 |
45 | [[06 - Tags]]
46 |
47 | ## Tags
48 |
49 | Tags can be linked to, and linked to via a button. The `@tag` token is used for this.
50 |
51 | ##### Syntax
52 |
53 | ```markdown
54 | [Basics](@tag/Basics)
55 | ```
56 |
57 | ##### Result
58 |
59 | [Basics](@tag/Basics)
60 |
61 | ## Searches
62 |
63 | Searches can be linked to, and linked to via a button. The `@search` token is used for this.
64 |
65 | ##### Syntax
66 |
67 | ```markdown
68 | [linking](@search/linking)
69 | ```
70 |
71 | ##### Result
72 |
73 | [linking](@search/linking)
74 |
--------------------------------------------------------------------------------
/lib/page/about.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:app/store/notes.dart';
3 | import 'package:url_launcher/url_launcher.dart';
4 | import 'package:package_info/package_info.dart';
5 |
6 | class AboutPage extends StatefulWidget {
7 | final NotesStore store;
8 | AboutPage(this.store);
9 | @override
10 | _AboutPageState createState() => _AboutPageState();
11 | }
12 |
13 | class _AboutPageState extends State {
14 | @override
15 | Widget build(BuildContext context) {
16 | return Scaffold(
17 | appBar: AppBar(
18 | title: Text('About'),
19 | ),
20 | body: Center(
21 | child: Column(
22 | mainAxisSize: MainAxisSize.min,
23 | children: [
24 | FutureBuilder(
25 | future: PackageInfo.fromPlatform(),
26 | builder: (context, snap) {
27 | if (!snap.hasData) return Container();
28 | PackageInfo info = snap.data;
29 | return Column(
30 | children: [
31 | Text('${info.appName}'),
32 | Text('${info.packageName}'),
33 | SizedBox(
34 | height: 8,
35 | ),
36 | Text('Version ${info.version}'),
37 | Text('Build ${info.buildNumber}'),
38 | ],
39 | );
40 | },
41 | ),
42 | SizedBox(
43 | height: 16,
44 | ),
45 | RaisedButton(
46 | child: Text('GitHub Repo'),
47 | onPressed: () {
48 | launch('https://github.com/redsolver/noteless');
49 | },
50 | ),
51 | ],
52 | )));
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Miscellaneous
2 | *.class
3 | *.log
4 | *.pyc
5 | *.swp
6 | .DS_Store
7 | .atom/
8 | .buildlog/
9 | .history
10 | .svn/
11 |
12 | # IntelliJ related
13 | *.iml
14 | *.ipr
15 | *.iws
16 | .idea/
17 |
18 | # The .vscode folder contains launch configuration and tasks you configure in
19 | # VS Code which you may wish to be included in version control, so this line
20 | # is commented out by default.
21 | #.vscode/
22 |
23 | # Flutter/Dart/Pub related
24 | **/doc/api/
25 | .dart_tool/
26 | .flutter-plugins
27 | .packages
28 | .pub-cache/
29 | .pub/
30 | /build/
31 | .flutter-plugins-dependencies
32 |
33 |
34 | # Android related
35 | **/android/**/gradle-wrapper.jar
36 | **/android/.gradle
37 | **/android/captures/
38 | **/android/gradlew
39 | **/android/gradlew.bat
40 | **/android/local.properties
41 | **/android/key.properties
42 | **/android/**/GeneratedPluginRegistrant.java
43 | **/android/key.properties
44 |
45 | # iOS/XCode related
46 | **/ios/**/*.mode1v3
47 | **/ios/**/*.mode2v3
48 | **/ios/**/*.moved-aside
49 | **/ios/**/*.pbxuser
50 | **/ios/**/*.perspectivev3
51 | **/ios/**/*sync/
52 | **/ios/**/.sconsign.dblite
53 | **/ios/**/.tags*
54 | **/ios/**/.vagrant/
55 | **/ios/**/DerivedData/
56 | **/ios/**/Icon?
57 | **/ios/**/Pods/
58 | **/ios/**/.symlinks/
59 | **/ios/**/profile
60 | **/ios/**/xcuserdata
61 | **/ios/.generated/
62 | **/ios/Flutter/App.framework
63 | **/ios/Flutter/Flutter.framework
64 | **/ios/Flutter/Generated.xcconfig
65 | **/ios/Flutter/app.flx
66 | **/ios/Flutter/app.zip
67 | **/ios/Flutter/flutter_assets/
68 | **/ios/ServiceDefinitions.json
69 | **/ios/Runner/GeneratedPluginRegistrant.*
70 | **/ios/Flutter/flutter_export_environment.sh
71 |
72 | # Exceptions to above rules.
73 | !**/ios/**/default.mode1v3
74 | !**/ios/**/default.mode2v3
75 | !**/ios/**/default.pbxuser
76 | !**/ios/**/default.perspectivev3
77 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages
78 |
79 | .env
80 |
--------------------------------------------------------------------------------
/assets/tutorial/notes/05 - Notes.md:
--------------------------------------------------------------------------------
1 | ---
2 | tags: [Basics, Notebooks/Tutorial]
3 | title: 05 - Notes
4 | created: '2019-04-30T21:17:06.073Z'
5 | modified: '2020-07-05T12:00:00.000Z'
6 | ---
7 |
8 | # 05 - Notes
9 |
10 | ## Syntax
11 |
12 | Notes are written in [GitHub-flavored Markdown](https://guides.github.com/features/mastering-markdown), so you can write emojis (`:joy:` -> :joy:), ~~strikethrough~~ text etc. in a familiar fashion.
13 |
14 | This also means that your notes aren't locked into any proprietary format.
15 |
16 | Notes can have some metadata: if they are favorited or not, which tags they have, which attachments they have, etc. These metadata are written as Markdown front matter. This is taken care of for you.
17 |
18 | ## Syntax Plugins
19 |
20 | Some syntax plugins for providing you [KaTeX](https://katex.org) and [mermaid](https://github.com/knsv/mermaid) support are built-in, check out this note's source.
21 |
22 | #### KaTeX
23 |
24 | Wrap a formula in `$$` to display it as a block:
25 |
26 | $$f{x} = \int_{-\infty}^\infty \hat f\xi\,e^{2 \pi i \xi x} \,d\xi$$
27 |
28 | Multi-line block formulas are supported too:
29 |
30 | $$
31 | \begin{pmatrix}
32 | f(\alpha) & b & c \\
33 | e & f(\beta) & g \\
34 | i & j & f(\gamma)
35 | \end{pmatrix}
36 | $$
37 |
38 | Wrap it in `$` to display it inline: $e^{iπ} + 1 = 0$.
39 |
40 | The [mhchem](https://mhchem.github.io/MathJax-mhchem) syntax for writing chemical expressions is supported too:
41 |
42 | $$\ce{ SO4^2- + Ba^2+ -> BaSO4 v }$$
43 |
44 | #### AsciiMath
45 |
46 | Wrap a formula in `&&` to display it as a block:
47 |
48 | &&sum_(i=1)^n i^3=((n(n+1))/2)^2&&
49 |
50 | Wrap it in `&` to display it inline: &e = mc^2&.
51 |
52 | #### mermaid
53 |
54 | ```mermaid
55 | graph TD
56 | Install --> Tutorial[Read the tutorial]
57 | Tutorial --> Star
58 | Tutorial --> Share
59 | ```
60 |
61 | ## Attachments
62 |
63 | Notes can have attachments, because sooner or later you'll want to save a file in a note, be it a boarding pass for your next trip or something else.
64 |
65 | Attachments can be added via the popup menu in the toolbar. Attachments are simply copied into your data directory, under the `attachments` sub-directory.
66 |
67 | You can open/remove them at any time.
68 |
--------------------------------------------------------------------------------
/lib/provider/theme.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:preferences/preference_service.dart';
3 |
4 | class ThemeNotifier with ChangeNotifier {
5 | ThemeNotifier() {
6 | _accentColor = Color(PrefService.getInt('theme_color') ?? 0xff21d885);
7 | updateTheme(PrefService.getString('theme') ?? 'light');
8 | }
9 |
10 | ThemeType currentTheme = ThemeType.light;
11 | ThemeData _currentThemeData;
12 |
13 | /* void switchTheme() => currentTheme == ThemeType.light
14 | ? currentTheme = ThemeType.dark
15 | : currentTheme = ThemeType.light; */
16 |
17 | updateTheme([String theme]) {
18 | switch (theme) {
19 | case 'light':
20 | currentTheme = ThemeType.light;
21 | break;
22 | case 'dark':
23 | currentTheme = ThemeType.dark;
24 | break;
25 | case 'black':
26 | currentTheme = ThemeType.dark;
27 | break;
28 | }
29 | _currentThemeData = ThemeData(
30 | brightness:
31 | currentTheme == ThemeType.light ? Brightness.light : Brightness.dark,
32 | scaffoldBackgroundColor: theme == 'black' ? Colors.black : null,
33 | backgroundColor: theme == 'black' ? Colors.black : null,
34 | dialogBackgroundColor: theme == 'black' ? Colors.black : null,
35 | canvasColor: theme == 'black' ? Colors.black : null,
36 | cardColor: theme == 'black' ? Colors.black : null,
37 | accentColor: _accentColor,
38 | primaryColor: _accentColor,
39 | toggleableActiveColor: _accentColor,
40 | highlightColor: _accentColor,
41 | buttonColor: _accentColor,
42 | floatingActionButtonTheme: FloatingActionButtonThemeData(
43 | backgroundColor: _accentColor,
44 | ),
45 | buttonTheme: ButtonThemeData(
46 | textTheme: ButtonTextTheme.primary,
47 | buttonColor: _accentColor,
48 | ),
49 | textTheme: TextTheme(
50 | button: TextStyle(color: _accentColor),
51 | ),
52 | );
53 | notifyListeners();
54 | }
55 |
56 | ThemeData get currentThemeData => _currentThemeData;
57 |
58 | Color _accentColor;
59 |
60 | get accentColor => _accentColor;
61 | set accentColor(Color color) {
62 | if (color != null) {
63 | _accentColor = color;
64 |
65 | updateTheme();
66 | }
67 | }
68 | }
69 |
70 | enum ThemeType { light, dark }
71 |
--------------------------------------------------------------------------------
/ios/Runner/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/android/app/build.gradle:
--------------------------------------------------------------------------------
1 | def localProperties = new Properties()
2 | def localPropertiesFile = rootProject.file('local.properties')
3 | if (localPropertiesFile.exists()) {
4 | localPropertiesFile.withReader('UTF-8') { reader ->
5 | localProperties.load(reader)
6 | }
7 | }
8 |
9 | def flutterRoot = localProperties.getProperty('flutter.sdk')
10 | if (flutterRoot == null) {
11 | throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
12 | }
13 |
14 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
15 | if (flutterVersionCode == null) {
16 | flutterVersionCode = '1'
17 | }
18 |
19 | def flutterVersionName = localProperties.getProperty('flutter.versionName')
20 | if (flutterVersionName == null) {
21 | flutterVersionName = '1.0'
22 | }
23 |
24 | apply plugin: 'com.android.application'
25 | apply plugin: 'kotlin-android'
26 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
27 |
28 |
29 | def keystorePropertiesFile = rootProject.file("key.properties")
30 | def keystoreProperties = new Properties()
31 | if (keystorePropertiesFile.exists()) {
32 | keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
33 | }
34 |
35 |
36 | android {
37 | ndkVersion "22.0.7026061"
38 | compileSdkVersion 29
39 |
40 | sourceSets {
41 | main.java.srcDirs += 'src/main/kotlin'
42 | }
43 |
44 | lintOptions {
45 | disable 'InvalidPackage'
46 | }
47 |
48 | defaultConfig {
49 | applicationId "net.redsolver.noteless"
50 | minSdkVersion 19
51 | targetSdkVersion 29
52 | versionCode flutterVersionCode.toInteger()
53 | versionName flutterVersionName
54 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
55 | }
56 |
57 | signingConfigs {
58 | release {
59 | keyAlias keystoreProperties['keyAlias']
60 | keyPassword keystoreProperties['keyPassword']
61 | storeFile file(keystoreProperties['storeFile'])
62 | storePassword keystoreProperties['storePassword']
63 | }
64 | }
65 |
66 | buildTypes {
67 | release {
68 | signingConfig signingConfigs.release
69 | }
70 | }
71 | }
72 |
73 | flutter {
74 | source '../..'
75 | }
76 |
77 | dependencies {
78 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
79 | testImplementation 'junit:junit:4.12'
80 | /* androidTestImplementation 'androidx.test:runner:1.0.2'
81 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.0.2' */
82 | }
83 |
--------------------------------------------------------------------------------
/android/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
18 |
22 |
29 |
33 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/lib/editor/pairer.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/services.dart';
2 |
3 | class CharacterPair implements TextInputFormatter {
4 |
5 | /// All the characters that can be paired, and their pairing character.
6 | static const PAIRED_CHARACTERS = {
7 | '"': '"',
8 | "'": "'",
9 | '(': ')',
10 | '{': '}',
11 | '[': ']',
12 | '`': '`'
13 | };
14 |
15 | final bool enablePairing;
16 |
17 | /// Creates a CharacterPair with the ability to toggle it on/off with
18 | /// [enablePairing] which should be derived from the settings. This is final
19 | /// as a new instance is created when the note is navigated to again.
20 | CharacterPair(this.enablePairing);
21 |
22 | @override
23 | TextEditingValue formatEditUpdate(
24 | TextEditingValue oldValue, TextEditingValue newValue) {
25 | if (enablePairing) {
26 | var keyPressed = KeyPressUtils.getPressedKey(oldValue, newValue).trim();
27 | if (PAIRED_CHARACTERS.containsKey(keyPressed)) {
28 | return pairCharacter(keyPressed, oldValue, newValue);
29 | }
30 | }
31 |
32 | return newValue;
33 | }
34 |
35 | /// Pairs a character with the first character being [char] and the second
36 | /// corresponding to its value in [PAIRED_CHARACTERS]. Takes in the same
37 | /// [oldValue] and [newValue] as [formatEditUpdate] does. Does not do
38 | /// any checking if the pairing _should_ happen, that is left to its invoker.
39 | TextEditingValue pairCharacter(
40 | String char, TextEditingValue oldValue, TextEditingValue newValue) {
41 | var oldSelection = oldValue.selection;
42 |
43 | final before = oldValue.text.substring(0, oldSelection.start);
44 | final content = oldValue.text.substring(oldSelection.start, oldSelection.end);
45 | final after = oldValue.text.substring(oldSelection.end);
46 |
47 | var newSelection = TextSelection(
48 | baseOffset: oldSelection.baseOffset + 1,
49 | extentOffset: oldSelection.extentOffset + 1,
50 | affinity: oldSelection.affinity,
51 | isDirectional: oldSelection.isDirectional);
52 |
53 | return TextEditingValue(
54 | text: '$before$char$content${PAIRED_CHARACTERS[char]}$after',
55 | selection: newSelection,
56 | composing: oldValue.composing);
57 | }
58 | }
59 |
60 | class KeyPressUtils {
61 | static const BACKSPACE = '\u0008';
62 |
63 | /// Gets the pressed key from the new and old values.
64 | /// Adapted from rich_editable_code's KeyboardUtilz.getPressedKey
65 | static String getPressedKey(
66 | TextEditingValue oldValue, TextEditingValue newValue) {
67 | if (newValue.text.length == 1 && newValue.text == '\n') {
68 | return '\n';
69 | }
70 |
71 | var newSelection = newValue.selection;
72 | var currentSelection = oldValue.selection;
73 |
74 | if (currentSelection.baseOffset > newSelection.baseOffset) {
75 | //backspace was pressed
76 | return BACKSPACE;
77 | }
78 |
79 | return newValue.text
80 | .substring(currentSelection.baseOffset, newSelection.baseOffset);
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/lib/utils/yaml.dart:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2015, Anders Holmgren. All rights reserved. Use of this source code
2 | // is governed by a BSD-style license that can be found in the LICENSE file.
3 |
4 | /// Serializes [node] into a String and returns it.
5 | String toYamlString(node) {
6 | var sb = new StringBuffer();
7 | writeYamlString(node, sb);
8 | return sb.toString();
9 | }
10 |
11 | /// Serializes [node] into a String and writes it to the [sink].
12 | void writeYamlString(node, StringSink sink) {
13 | _writeYamlString(node, 0, sink, true);
14 | }
15 |
16 | void _writeYamlString(node, int indent, StringSink ss, bool isTopLevel) {
17 | if (node is Map) {
18 | _mapToYamlString(node, indent, ss, isTopLevel);
19 | } else if (node is Iterable) {
20 | _listToYamlString(node, indent, ss, isTopLevel);
21 | } else if (node is String) {
22 | ss..writeln('"${_escapeString(node)}"');
23 | } else if (node is double) {
24 | ss.writeln("!!float $node");
25 | } else {
26 | ss.writeln(node);
27 | }
28 | }
29 |
30 | String _escapeString(String s) =>
31 | s.replaceAll('"', r'\"').replaceAll("\n", r"\n");
32 |
33 | void _mapToYamlString(Map node, int indent, StringSink ss, bool isTopLevel) {
34 | if (!isTopLevel) {
35 | ss.writeln();
36 | indent += 2;
37 | }
38 |
39 | final keys = _sortKeys(node);
40 |
41 | keys.forEach((k) {
42 | final v = node[k];
43 | _writeIndent(indent, ss);
44 | ss..write(k)..write(': ');
45 | _writeYamlString(v, indent, ss, false);
46 | });
47 | }
48 |
49 | Iterable _sortKeys(Map m) {
50 | final simple = [];
51 | final maps = [];
52 | final other = [];
53 |
54 | m.forEach((k, v) {
55 | if (v is String) {
56 | simple.add(k);
57 | } else if (v is Map) {
58 | maps.add(k);
59 | } else {
60 | other.add(k);
61 | }
62 | });
63 |
64 | return concat([simple..sort(), maps..sort(), other..sort()]).cast();
65 | }
66 |
67 | void _listToYamlString(
68 | Iterable node, int indent, StringSink ss, bool isTopLevel) {
69 | if (!isTopLevel) {
70 | ss.writeln();
71 | indent += 2;
72 | }
73 |
74 | node.forEach((v) {
75 | _writeIndent(indent, ss);
76 | ss.write('- ');
77 | _writeYamlString(v, indent, ss, false);
78 | });
79 | }
80 |
81 | void _writeIndent(int indent, StringSink ss) => ss.write(' ' * indent);
82 |
83 | // Copyright 2013 Google Inc. All Rights Reserved.
84 | //
85 | // Licensed under the Apache License, Version 2.0 (the "License");
86 | // you may not use this file except in compliance with the License.
87 | // You may obtain a copy of the License at
88 | //
89 | // http://www.apache.org/licenses/LICENSE-2.0
90 | //
91 | // Unless required by applicable law or agreed to in writing, software
92 | // distributed under the License is distributed on an "AS IS" BASIS,
93 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
94 | // See the License for the specific language governing permissions and
95 | // limitations under the License.
96 |
97 | Iterable concat(Iterable> iterables) =>
98 | iterables.expand((x) => x);
99 |
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "size" : "20x20",
5 | "idiom" : "iphone",
6 | "filename" : "Icon-App-20x20@2x.png",
7 | "scale" : "2x"
8 | },
9 | {
10 | "size" : "20x20",
11 | "idiom" : "iphone",
12 | "filename" : "Icon-App-20x20@3x.png",
13 | "scale" : "3x"
14 | },
15 | {
16 | "size" : "29x29",
17 | "idiom" : "iphone",
18 | "filename" : "Icon-App-29x29@1x.png",
19 | "scale" : "1x"
20 | },
21 | {
22 | "size" : "29x29",
23 | "idiom" : "iphone",
24 | "filename" : "Icon-App-29x29@2x.png",
25 | "scale" : "2x"
26 | },
27 | {
28 | "size" : "29x29",
29 | "idiom" : "iphone",
30 | "filename" : "Icon-App-29x29@3x.png",
31 | "scale" : "3x"
32 | },
33 | {
34 | "size" : "40x40",
35 | "idiom" : "iphone",
36 | "filename" : "Icon-App-40x40@2x.png",
37 | "scale" : "2x"
38 | },
39 | {
40 | "size" : "40x40",
41 | "idiom" : "iphone",
42 | "filename" : "Icon-App-40x40@3x.png",
43 | "scale" : "3x"
44 | },
45 | {
46 | "size" : "60x60",
47 | "idiom" : "iphone",
48 | "filename" : "Icon-App-60x60@2x.png",
49 | "scale" : "2x"
50 | },
51 | {
52 | "size" : "60x60",
53 | "idiom" : "iphone",
54 | "filename" : "Icon-App-60x60@3x.png",
55 | "scale" : "3x"
56 | },
57 | {
58 | "size" : "20x20",
59 | "idiom" : "ipad",
60 | "filename" : "Icon-App-20x20@1x.png",
61 | "scale" : "1x"
62 | },
63 | {
64 | "size" : "20x20",
65 | "idiom" : "ipad",
66 | "filename" : "Icon-App-20x20@2x.png",
67 | "scale" : "2x"
68 | },
69 | {
70 | "size" : "29x29",
71 | "idiom" : "ipad",
72 | "filename" : "Icon-App-29x29@1x.png",
73 | "scale" : "1x"
74 | },
75 | {
76 | "size" : "29x29",
77 | "idiom" : "ipad",
78 | "filename" : "Icon-App-29x29@2x.png",
79 | "scale" : "2x"
80 | },
81 | {
82 | "size" : "40x40",
83 | "idiom" : "ipad",
84 | "filename" : "Icon-App-40x40@1x.png",
85 | "scale" : "1x"
86 | },
87 | {
88 | "size" : "40x40",
89 | "idiom" : "ipad",
90 | "filename" : "Icon-App-40x40@2x.png",
91 | "scale" : "2x"
92 | },
93 | {
94 | "size" : "76x76",
95 | "idiom" : "ipad",
96 | "filename" : "Icon-App-76x76@1x.png",
97 | "scale" : "1x"
98 | },
99 | {
100 | "size" : "76x76",
101 | "idiom" : "ipad",
102 | "filename" : "Icon-App-76x76@2x.png",
103 | "scale" : "2x"
104 | },
105 | {
106 | "size" : "83.5x83.5",
107 | "idiom" : "ipad",
108 | "filename" : "Icon-App-83.5x83.5@2x.png",
109 | "scale" : "2x"
110 | },
111 | {
112 | "size" : "1024x1024",
113 | "idiom" : "ios-marketing",
114 | "filename" : "Icon-App-1024x1024@1x.png",
115 | "scale" : "1x"
116 | }
117 | ],
118 | "info" : {
119 | "version" : 1,
120 | "author" : "xcode"
121 | }
122 | }
123 |
--------------------------------------------------------------------------------
/assets/preview/katex.auto-render.min.js:
--------------------------------------------------------------------------------
1 | !function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t(require("katex")):"function"==typeof define&&define.amd?define(["katex"],t):"object"==typeof exports?exports.renderMathInElement=t(require("katex")):e.renderMathInElement=t(e.katex)}("undefined"!=typeof self?self:this,function(e){return function(e){var t={};function r(n){if(t[n])return t[n].exports;var o=t[n]={i:n,l:!1,exports:{}};return e[n].call(o.exports,o,o.exports,r),o.l=!0,o.exports}return r.m=e,r.c=t,r.d=function(e,t,n){r.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},r.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.t=function(e,t){if(1&t&&(e=r(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(r.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)r.d(n,o,function(t){return e[t]}.bind(null,o));return n},r.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return r.d(t,"a",t),t},r.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},r.p="",r(r.s=1)}([function(t,r){t.exports=e},function(e,t,r){"use strict";r.r(t);var n=r(0),o=r.n(n),a=function(e,t,r){for(var n=r,o=0,a=e.length;n
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
39 |
40 |
41 |
42 |
43 |
44 |
54 |
56 |
62 |
63 |
64 |
65 |
66 |
67 |
73 |
75 |
81 |
82 |
83 |
84 |
86 |
87 |
90 |
91 |
92 |
--------------------------------------------------------------------------------
/pubspec.yaml:
--------------------------------------------------------------------------------
1 | name: app
2 | description: A markdown note-taking app for mobile devices.
3 | publish_to: none
4 | # The following defines the version and build number for your application.
5 | # A version number is three numbers separated by dots, like 1.2.43
6 | # followed by an optional build number separated by a +.
7 | # Both the version and the builder number may be overridden in flutter
8 | # build by specifying --build-name and --build-number, respectively.
9 | # In Android, build-name is used as versionName while build-number used as versionCode.
10 | # Read more about Android versioning at https://developer.android.com/studio/publish/versioning
11 | # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
12 | # Read more about iOS versioning at
13 | # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
14 | version: 1.4.6+146
15 |
16 | environment:
17 | sdk: ">=2.5.0 <3.0.0"
18 |
19 | dependencies:
20 | flutter:
21 | sdk: flutter
22 | flutter_markdown: ^0.4.2
23 | path_provider: ^2.0.0
24 | yaml: ^2.2.0
25 | material_design_icons_flutter: ^4.0.5045
26 | markd:
27 | git: https://github.com/redsolver/markd.git
28 | # flutter_widget_from_html: ^0.3.3
29 | bsdiff: ^0.1.0
30 | webview_flutter: ^1.0.1
31 | # flutter_i18n: ^0.7.0
32 | preferences: ^5.2.0
33 | html: ^0.14.0+2
34 | url_launcher: ^6.0.2
35 | package_info: ^0.4.0+8
36 |
37 | provider: ^4.0.5+1
38 |
39 | front_matter: ^1.1.0
40 | flutter_slidable: ^0.5.4
41 | #time_machine: ^0.9.9
42 | file_picker: ^3.0.0
43 | rich_code_editor:
44 | git: https://github.com/bats64mgutsi/rich_code_editor.git
45 | device_info: ^2.0.0
46 | quick_actions: ^0.4.0+8
47 | receive_sharing_intent: ^1.4.1
48 | quiver: ^3.0.0
49 | intl: ^0.17.0
50 | permission_handler: ^6.1.0
51 | uuid: ^3.0.3
52 |
53 | dependency_overrides:
54 | shared_preferences: ^2.0.4
55 | # dev_dependencies:
56 | # flutter_launcher_icons: ^0.8.1
57 | flutter_icons:
58 | android: true
59 | ios: true
60 | image_path_android: "assets/icon/icon.png"
61 | image_path_ios: "assets/icon/icon_ios.png"
62 | adaptive_icon_background: "#ffffff"
63 | adaptive_icon_foreground: "assets/icon/adaptive_icon.png"
64 | # For information on the generic Dart part of this file, see the
65 | # following page: https://dart.dev/tools/pub/pubspec
66 | # The following section is specific to Flutter.
67 | flutter:
68 | generate: true
69 | # The following line ensures that the Material Icons font is
70 | # included with your application, so that you can use the icons in
71 | # the material Icons class.
72 | uses-material-design: true
73 |
74 | # To add assets to your application, add an assets section, like this:
75 | assets:
76 | - assets/tutorial/notes/
77 | - assets/tutorial/attachments/
78 | # - assets/i18n/
79 | - assets/preview/fonts/
80 | - assets/preview/
81 |
82 | # - images/a_dot_burr.jpeg
83 | # - images/a_dot_ham.jpeg
84 | # An image asset can refer to one or more resolution-specific "variants", see
85 | # https://flutter.dev/assets-and-images/#resolution-aware.
86 | # For details regarding adding assets from package dependencies, see
87 | # https://flutter.dev/assets-and-images/#from-packages
88 | # To add custom fonts to your application, add a fonts section here,
89 | # in this "flutter" section. Each entry in this list should have a
90 | # "family" key with the font family name, and a "fonts" key with a
91 | # list giving the asset and other descriptors for the font. For
92 | # example:
93 | fonts:
94 | - family: FiraMono
95 | fonts:
96 | - asset: assets/fonts/FiraMono-Regular.ttf
97 | # - asset: fonts/Schyler-Italic.ttf
98 | # style: italic
99 | # - family: Trajan Pro
100 | # fonts:
101 | # - asset: fonts/TrajanPro.ttf
102 | # - asset: fonts/TrajanPro_Bold.ttf
103 | # weight: 700
104 | #
105 | # For details regarding fonts from package dependencies,
106 | # see https://flutter.dev/custom-fonts/#from-packages
107 |
--------------------------------------------------------------------------------
/assets/preview/prism.css:
--------------------------------------------------------------------------------
1 | /* PrismJS 1.17.1
2 | https://prismjs.com/download.html#themes=prism&languages=markup+css+clike+javascript+abap+abnf+actionscript+ada+apacheconf+apl+applescript+c+arff+asciidoc+asm6502+csharp+autohotkey+autoit+bash+basic+batch+bison+bnf+brainfuck+bro+cpp+aspnet+arduino+cil+coffeescript+cmake+clojure+ruby+csp+css-extras+d+dart+diff+markup-templating+dns-zone-file+docker+ebnf+eiffel+ejs+elixir+elm+erb+erlang+fsharp+flow+fortran+gcode+gedcom+gherkin+git+glsl+gml+go+graphql+groovy+less+handlebars+haskell+haxe+hcl+http+hpkp+hsts+ichigojam+icon+inform7+ini+io+j+java+scala+php+javastacktrace+jolie+jq+javadoclike+n4js+markdown+json+jsonp+json5+julia+keyman+kotlin+latex+crystal+scheme+liquid+lisp+livescript+lolcode+lua+makefile+js-templates+django+matlab+mel+mizar+monkey+n1ql+typescript+nand2tetris-hdl+nasm+nginx+nim+nix+nsis+objectivec+ocaml+opencl+oz+parigp+parser+pascal+pascaligo+pcaxis+perl+jsdoc+phpdoc+php-extras+sql+powershell+processing+prolog+properties+protobuf+scss+puppet+pure+python+q+qore+r+js-extras+jsx+renpy+reason+vala+rest+rip+roboconf+textile+rust+sas+sass+stylus+javadoc+lilypond+shell-session+smalltalk+smarty+soy+splunk-spl+plsql+twig+swift+yaml+tcl+haml+toml+tt2+pug+tsx+t4-templating+visual-basic+t4-cs+regex+vbnet+velocity+verilog+vhdl+vim+t4-vb+wasm+wiki+xeora+xojo+xquery+tap */
3 | /**
4 | * prism.js default theme for JavaScript, CSS and HTML
5 | * Based on dabblet (http://dabblet.com)
6 | * @author Lea Verou
7 | */
8 |
9 | code[class*="language-"],
10 | pre[class*="language-"] {
11 | color: black;
12 | background: none;
13 | text-shadow: 0 1px white;
14 | font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
15 | font-size: 1em;
16 | text-align: left;
17 | white-space: pre;
18 | word-spacing: normal;
19 | word-break: normal;
20 | word-wrap: normal;
21 | line-height: 1.5;
22 |
23 | -moz-tab-size: 4;
24 | -o-tab-size: 4;
25 | tab-size: 4;
26 |
27 | -webkit-hyphens: none;
28 | -moz-hyphens: none;
29 | -ms-hyphens: none;
30 | hyphens: none;
31 | }
32 |
33 | pre[class*="language-"]::-moz-selection, pre[class*="language-"] ::-moz-selection,
34 | code[class*="language-"]::-moz-selection, code[class*="language-"] ::-moz-selection {
35 | text-shadow: none;
36 | background: #b3d4fc;
37 | }
38 |
39 | pre[class*="language-"]::selection, pre[class*="language-"] ::selection,
40 | code[class*="language-"]::selection, code[class*="language-"] ::selection {
41 | text-shadow: none;
42 | background: #b3d4fc;
43 | }
44 |
45 | @media print {
46 | code[class*="language-"],
47 | pre[class*="language-"] {
48 | text-shadow: none;
49 | }
50 | }
51 |
52 | /* Code blocks */
53 | pre[class*="language-"] {
54 | padding: 1em;
55 | margin: .5em 0;
56 | overflow: auto;
57 | }
58 |
59 | :not(pre) > code[class*="language-"],
60 | pre[class*="language-"] {
61 | background: #f5f2f0;
62 | }
63 |
64 | /* Inline code */
65 | :not(pre) > code[class*="language-"] {
66 | padding: .1em;
67 | border-radius: .3em;
68 | white-space: normal;
69 | }
70 |
71 | .token.comment,
72 | .token.prolog,
73 | .token.doctype,
74 | .token.cdata {
75 | color: slategray;
76 | }
77 |
78 | .token.punctuation {
79 | color: #999;
80 | }
81 |
82 | .namespace {
83 | opacity: .7;
84 | }
85 |
86 | .token.property,
87 | .token.tag,
88 | .token.boolean,
89 | .token.number,
90 | .token.constant,
91 | .token.symbol,
92 | .token.deleted {
93 | color: #905;
94 | }
95 |
96 | .token.selector,
97 | .token.attr-name,
98 | .token.string,
99 | .token.char,
100 | .token.builtin,
101 | .token.inserted {
102 | color: #690;
103 | }
104 |
105 | .token.operator,
106 | .token.entity,
107 | .token.url,
108 | .language-css .token.string,
109 | .style .token.string {
110 | color: #9a6e3a;
111 | background: hsla(0, 0%, 100%, .5);
112 | }
113 |
114 | .token.atrule,
115 | .token.attr-value,
116 | .token.keyword {
117 | color: #07a;
118 | }
119 |
120 | .token.function,
121 | .token.class-name {
122 | color: #DD4A68;
123 | }
124 |
125 | .token.regex,
126 | .token.important,
127 | .token.variable {
128 | color: #e90;
129 | }
130 |
131 | .token.important,
132 | .token.bold {
133 | font-weight: bold;
134 | }
135 | .token.italic {
136 | font-style: italic;
137 | }
138 |
139 | .token.entity {
140 | cursor: help;
141 | }
142 |
143 |
--------------------------------------------------------------------------------
/assets/fonts/LICENSE:
--------------------------------------------------------------------------------
1 | Digitized data copyright (c) 2012-2015, The Mozilla Foundation and Telefonica S.A.
2 |
3 | This Font Software is licensed under the SIL Open Font License, Version 1.1.
4 | This license is copied below, and is also available with a FAQ at:
5 | http://scripts.sil.org/OFL
6 |
7 |
8 | -----------------------------------------------------------
9 | SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
10 | -----------------------------------------------------------
11 |
12 | PREAMBLE
13 | The goals of the Open Font License (OFL) are to stimulate worldwide
14 | development of collaborative font projects, to support the font creation
15 | efforts of academic and linguistic communities, and to provide a free and
16 | open framework in which fonts may be shared and improved in partnership
17 | with others.
18 |
19 | The OFL allows the licensed fonts to be used, studied, modified and
20 | redistributed freely as long as they are not sold by themselves. The
21 | fonts, including any derivative works, can be bundled, embedded,
22 | redistributed and/or sold with any software provided that any reserved
23 | names are not used by derivative works. The fonts and derivatives,
24 | however, cannot be released under any other type of license. The
25 | requirement for fonts to remain under this license does not apply
26 | to any document created using the fonts or their derivatives.
27 |
28 | DEFINITIONS
29 | "Font Software" refers to the set of files released by the Copyright
30 | Holder(s) under this license and clearly marked as such. This may
31 | include source files, build scripts and documentation.
32 |
33 | "Reserved Font Name" refers to any names specified as such after the
34 | copyright statement(s).
35 |
36 | "Original Version" refers to the collection of Font Software components as
37 | distributed by the Copyright Holder(s).
38 |
39 | "Modified Version" refers to any derivative made by adding to, deleting,
40 | or substituting -- in part or in whole -- any of the components of the
41 | Original Version, by changing formats or by porting the Font Software to a
42 | new environment.
43 |
44 | "Author" refers to any designer, engineer, programmer, technical
45 | writer or other person who contributed to the Font Software.
46 |
47 | PERMISSION & CONDITIONS
48 | Permission is hereby granted, free of charge, to any person obtaining
49 | a copy of the Font Software, to use, study, copy, merge, embed, modify,
50 | redistribute, and sell modified and unmodified copies of the Font
51 | Software, subject to the following conditions:
52 |
53 | 1) Neither the Font Software nor any of its individual components,
54 | in Original or Modified Versions, may be sold by itself.
55 |
56 | 2) Original or Modified Versions of the Font Software may be bundled,
57 | redistributed and/or sold with any software, provided that each copy
58 | contains the above copyright notice and this license. These can be
59 | included either as stand-alone text files, human-readable headers or
60 | in the appropriate machine-readable metadata fields within text or
61 | binary files as long as those fields can be easily viewed by the user.
62 |
63 | 3) No Modified Version of the Font Software may use the Reserved Font
64 | Name(s) unless explicit written permission is granted by the corresponding
65 | Copyright Holder. This restriction only applies to the primary font name as
66 | presented to the users.
67 |
68 | 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
69 | Software shall not be used to promote, endorse or advertise any
70 | Modified Version, except to acknowledge the contribution(s) of the
71 | Copyright Holder(s) and the Author(s) or with their explicit written
72 | permission.
73 |
74 | 5) The Font Software, modified or unmodified, in part or in whole,
75 | must be distributed entirely under this license, and must not be
76 | distributed under any other license. The requirement for fonts to
77 | remain under this license does not apply to any document created
78 | using the Font Software.
79 |
80 | TERMINATION
81 | This license becomes null and void if any of the above conditions are
82 | not met.
83 |
84 | DISCLAIMER
85 | THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
86 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
87 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
88 | OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
89 | COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
90 | INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
91 | DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
92 | FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
93 | OTHER DEALINGS IN THE FONT SOFTWARE.
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 |
3 | ## 1.4.6
4 |
5 | - Added support for the Android 11 permission system
6 | - Added option to sort tags alphabetically in the sidebar
7 | - Improved compatibility with other Markdown-based note-taking tools (especially Dendron)
8 | - Some small bug and theme fixes
9 |
10 | ## 1.3.1
11 |
12 | - Added optional auto save option
13 | - Added optional auto pairing of brackets/quotes (thanks to @RubbaBoy)
14 | - Editor: Added option to move and restore note to/from trash
15 | - Improved table styling (thanks to @davidebersani)
16 | - Fixed some bugs
17 |
18 | ## 1.3.0
19 |
20 | - Added feature to create a new note by sharing text with Noteless (#42)
21 | - Adding an attachment to a note now automatically embeds it
22 | - Improved blockquote styling (#44)
23 | - Fixed some bugs
24 |
25 | ## 1.2.1
26 |
27 | - Added Android App Shortcut for creating a new note from the homescreen
28 | - Added proper table borders
29 | - Fixed some bugs
30 |
31 | ## 1.2.0
32 |
33 | - Added AsciiMath support
34 | - Added Black/AMOLED theme
35 | - Added experimental option: Automatic bullet points
36 | - Added optional single line break syntax
37 | - Increased height of editor toolbar
38 | - Changed behaviour of list-button in editor toolbar
39 | - Fixed image sizing in preview
40 | - Fixed text field submitting when adding a tag
41 |
42 | ## 1.1.1
43 |
44 | - Added support for spaces in links (#36)
45 |
46 | ## 1.1.0
47 |
48 | - Made checkboxes in preview mode toggleable (#37)
49 | - Added support for Wiki-style links like `[[My Note]]` (#38)
50 |
51 | ## 1.0.0
52 |
53 | - First stable release
54 | - Submitted the app to Google Play Store and F-Droid
55 | - Updated to Flutter 1.20 (Better Performance and some bug fixes in the editor)
56 |
57 | ## 0.3.2
58 |
59 | - Added F-Droid metadata
60 |
61 | ## 0.3.1
62 |
63 | - Fixed editor content not loading without front matter data
64 |
65 | ## 0.3.0
66 |
67 | - Fully reworked editor with syntax highlighting and a new keyboard toolbar to help with common Markdown operations
68 | - Added fallback to file metadata if front matter data is missing
69 |
70 | ## 0.2.1
71 |
72 | - Disabled the preview feature on Android 4.4 KitKat devices.
73 | - Removed WebDav sync
74 |
75 | ## Important Changes in Version 0.2.0
76 |
77 | The app has been renamed from `Notable Mobile` to `Noteless` on 02.07.2020.
78 |
79 | If you used an earlier Alpha Version, you need to uninstall the old one and install one of the new APKs (Don't forget to backup your notes!)
80 |
81 | This is because the app also has a new package name: `net.redsolver.noteless`.
82 |
83 | Also I decided to drop support for syncing notes directly via the app because there are alternative options which work a lot better.
84 |
85 | I recommend using an external data directory and a third-party sync app for Android like [Syncthing](https://syncthing.net/), Nextcloud Sync or FolderSync for other cloud services.
86 |
87 | ## 0.2.0
88 |
89 | - Renamed the app to "Noteless"
90 | - New app icon
91 | - Reworked tutorial notes
92 | - The Editor/Preview Mode Switcher is now the default option
93 | - New error handling: When an exception occurs while reading a note, the note is skipped and the errors are shown as "virtual notes".
94 | - Show loading dialog when changing external data directory
95 | - Fixed issue with using an external data directory on Android Q (10)
96 | - QOL Improvements (Autofocus, Small design improvements)
97 |
98 | ## 0.1.8
99 |
100 | - Added support for subdirectories
101 | - Added options to restore notes from trash
102 | - With the swipe actions of a note
103 | - With the "Restore from trash" button in the multi select options
104 | - Added option to create a logfile for sync
105 | - Added experimental option to enable virtual folder tags
106 | - Minor theme fixes
107 |
108 | ## 0.1.7
109 |
110 | - Fixed white flash when loading note preview
111 |
112 | ## 0.1.6
113 |
114 | - Added option to use a mode switcher for editor and preview
115 |
116 | ## 0.1.5
117 |
118 | - Added feature to add and remove attachments
119 | - Searching in content of notes
120 | - Enabled by default
121 | - Can be disabled in settings
122 | - Can get slow with more than 2000 notes
123 |
124 | ## 0.1.4
125 |
126 | - Added KaTeX and mhchem support
127 | - Added option to change accent color
128 | - Added note swipe actions (trash, delete, pin and favorite)
129 |
130 | ## 0.1.3
131 |
132 | - Fixed webdav sync
133 |
134 | ## 0.1.2
135 |
136 | - Fixed sync when using different data directory
137 |
138 | ## 0.1.1
139 |
140 | - Added option to select data directory on device
141 | - Moved multi select options to bottom app bar
142 | - Pressing back while being in select mode cancels it
143 | - Added option to recreate all tutorial notes and attachments in settings
144 | - Updated info page
145 | - Dark Theme now supports markdown preview
146 |
147 | ## 0.1.0
148 |
149 | - Select multiple notes by long pressing
150 | - After entering select mode, add notes to the selection by tapping them
151 | - Select or unselect all notes in the select menu
152 | - Favorite/Unfavorite multiple notes at once
153 | - Pin/Unpin multiple notes at once
154 | - Add and remove tags to multiple notes at once
155 | - Move to Trash and delete multiple notes at once
156 |
157 | ## 0.0.9
158 |
159 | - Dark Theme
160 | - Confirmation Dialogs
161 |
--------------------------------------------------------------------------------
/lib/sync/webdav.dart:
--------------------------------------------------------------------------------
1 | /* import 'dart:core' hide writeDebugLine;
2 | import 'dart:convert';
3 | import 'dart:io';
4 |
5 | import 'package:flutter/services.dart';
6 | import 'package:app/model/note.dart';
7 | import 'package:app/store/notes.dart';
8 | import 'package:app/store/persistent.dart';
9 | import 'package:preferences/preferences.dart';
10 | import 'package:webdav/webdav.dart';
11 | import 'package:webdav/src/client.dart';
12 | import 'package:intl/intl.dart';
13 |
14 | class WebdavSync {
15 | Future syncFiles(NotesStore store) async {
16 | debugOutput = '';
17 | var hostUri =
18 | Uri.parse('https://' + PrefService.getString('sync_webdav_host') ?? '');
19 | var hostPath = hostUri.path;
20 | if (hostPath.startsWith('/')) {
21 | hostPath = hostPath.substring(1);
22 | }
23 | if (hostPath.endsWith('/')) {
24 | hostPath = hostPath.substring(0, hostPath.length - 1);
25 | }
26 | Client client = Client(
27 | hostUri.host,
28 | PrefService.getString('sync_webdav_username') ?? '',
29 | PrefService.getString('sync_webdav_password') ?? '',
30 | hostPath,
31 | port: 443,
32 | protocol: 'https');
33 |
34 | try {
35 | var path = PrefService.getString('sync_webdav_path');
36 | client.mkdirs(path);
37 | await syncDirectory(client, '$path/notes/', 'notes');
38 | await syncDirectory(client, '$path/attachments/', 'attachments');
39 | } catch (e, st) {
40 | writeDebugLine(e);
41 | writeDebugLine(st);
42 | if (e is WebDavException) {
43 | return e.cause;
44 | } else {
45 | return e.toString();
46 | }
47 | }
48 |
49 | if (PrefService.getBool('debug_logs_sync') ?? false) {
50 | Note logNote = Note();
51 | logNote.title = '[DEBUG] Sync';
52 |
53 | logNote.created = DateTime.now();
54 | logNote.modified = logNote.created;
55 |
56 | logNote.tags.add('debug');
57 |
58 | logNote.file = File('${store.notesDir.path}/${logNote.title}.md');
59 |
60 | await PersistentStore.saveNote(
61 | logNote,
62 | '# ${logNote.title}\n\n${DateTime.now().toIso8601String()}\n\n' +
63 | debugOutput);
64 | }
65 | return null;
66 | }
67 |
68 | String debugOutput;
69 |
70 | writeDebugLine(var o) {
71 | if (PrefService.getBool('debug_logs_sync') ?? false) {
72 | debugOutput += o.toString() + '\n';
73 | }
74 | }
75 |
76 | Future syncDirectory(Client client, String path, String dir) async {
77 | await client.mkdir('$path');
78 |
79 | List noteFiles = await client.ls('$path');
80 |
81 | writeDebugLine('SYNC $path');
82 | writeDebugLine('${noteFiles.length} files');
83 |
84 | final directory = Directory(PrefService.getString('notable_directory'));
85 |
86 | final fileDir = Directory('${directory.path}/$dir');
87 |
88 | final timestampFile = File('${directory.path}/.$dir.sync');
89 | if (!timestampFile.existsSync()) {
90 | timestampFile.createSync();
91 | timestampFile.writeAsStringSync('{}');
92 | }
93 |
94 | Map localSyncTimestamps = json.decode(timestampFile.readAsStringSync());
95 | writeDebugLine('localSyncTimestamps: $localSyncTimestamps');
96 |
97 | List syncedNotes = [];
98 |
99 | for (FileInfo info in noteFiles) {
100 | if (info.isDict) {
101 | continue;
102 | }
103 |
104 | writeDebugLine('----');
105 |
106 | writeDebugLine(info.name);
107 | writeDebugLine(info.contentType);
108 | writeDebugLine(info.ctime);
109 | writeDebugLine(info.mtime);
110 |
111 | String name = Uri.decodeFull(info.name).split('/').last;
112 | writeDebugLine(name);
113 | if (name.trim().isEmpty) continue;
114 |
115 | syncedNotes.add(name);
116 |
117 | DateFormat format = new DateFormat("EEE, dd MMM yyyy hh:mm:ss zzz");
118 |
119 | String localFilePath = '${fileDir.path}/${name}';
120 | File localFile = File(localFilePath);
121 | DateTime lastModifiedServer = format.parse(info.mtime, true);
122 |
123 | writeDebugLine('LMS $lastModifiedServer');
124 |
125 | if (!localFile.existsSync()) {
126 | writeDebugLine('File does not exist locally -> DOWNLOAD');
127 | // DOWNLOAD
128 | client.download('$path${name}', localFilePath);
129 | localSyncTimestamps[name] = lastModifiedServer.toIso8601String();
130 | } else {
131 | DateTime lastModifiedClientSync =
132 | DateTime.tryParse(localSyncTimestamps[name] ?? '');
133 |
134 | if (lastModifiedClientSync == null)
135 | lastModifiedClientSync = DateTime.fromMillisecondsSinceEpoch(0);
136 | DateTime lastModifiedClientFile = localFile.lastModifiedSync().toUtc();
137 |
138 | DateTime lastModifiedClient;
139 |
140 | if (lastModifiedClientSync.isAfter(lastModifiedClientFile)) {
141 | lastModifiedClient = lastModifiedClientSync;
142 | } else {
143 | lastModifiedClient = lastModifiedClientFile;
144 | }
145 |
146 | writeDebugLine('lastModifiedServer');
147 | writeDebugLine(lastModifiedServer);
148 | writeDebugLine('lastModifiedClient');
149 | writeDebugLine(lastModifiedClient);
150 |
151 | writeDebugLine(lastModifiedClient.difference(lastModifiedServer));
152 | if (lastModifiedServer.difference(lastModifiedClient).abs().inSeconds <
153 | 3) {
154 | writeDebugLine('FILE MATCH!');
155 | } else if (lastModifiedServer.isBefore(lastModifiedClient)) {
156 | // UPLOAD
157 | writeDebugLine('UPLOAD');
158 | client.uploadFile(localFilePath, '$path${name}');
159 |
160 | localSyncTimestamps[name] = DateTime.now().toIso8601String();
161 | } else if (lastModifiedServer.isAfter(lastModifiedClient)) {
162 | // DOWNLOAD
163 | writeDebugLine('DOWNLOAD');
164 | client.download('$path${name}', localFilePath);
165 | localSyncTimestamps[name] = lastModifiedServer.toIso8601String();
166 | }
167 |
168 | // _upload();
169 | }
170 | }
171 | writeDebugLine(syncedNotes);
172 |
173 | for (var entity in fileDir.listSync()) {
174 | if (entity is! File) continue;
175 | String name = entity.uri.pathSegments.last;
176 | writeDebugLine(entity);
177 | if (!syncedNotes.contains(name)) {
178 | writeDebugLine('DOESNT EXIST ON SERVER $entity -> UPLOAD');
179 | client.uploadFile(entity.path, '$path${name}');
180 | localSyncTimestamps[name] = DateTime.now().toIso8601String();
181 | }
182 | }
183 |
184 | timestampFile.writeAsStringSync(json.encode(localSyncTimestamps));
185 | }
186 | }
187 | */
--------------------------------------------------------------------------------
/lib/store/persistent.dart:
--------------------------------------------------------------------------------
1 | import 'dart:io';
2 |
3 | import 'package:app/utils/yaml.dart';
4 | import 'package:preferences/preference_service.dart';
5 | import 'package:front_matter/front_matter.dart' as fm;
6 |
7 | import 'package:app/model/note.dart';
8 |
9 | const supportedFrontMatterKeys = [
10 | 'title',
11 | 'modified',
12 | 'created',
13 | 'tags',
14 | 'attachments',
15 | 'pinned',
16 | 'favorited',
17 | 'deleted',
18 | 'updated',
19 | ];
20 |
21 | class PersistentStore {
22 | static bool get isDendronModeEnabled =>
23 | (PrefService.getBool('dendron_mode') ?? false);
24 |
25 | static Future readContent(
26 | Note note,
27 | ) async {
28 | if (!note.file.existsSync()) return null;
29 |
30 | String fileContent = await note.file.readAsString();
31 |
32 | var content;
33 |
34 | if (fileContent.trimLeft().startsWith('---')) {
35 | var doc = fm.parse(fileContent);
36 | if (doc.content != null) {
37 | content = doc.content.trimLeft();
38 | } else {
39 | content = fileContent.trimLeft();
40 | }
41 | } else {
42 | content = fileContent.trimLeft();
43 | }
44 |
45 | if (isDendronModeEnabled) {
46 | if (!content.startsWith('# ')) {
47 | content = '# ${note.title}\n\n' + content;
48 | }
49 | }
50 |
51 | return content;
52 | }
53 |
54 | static Future saveNote(Note note, [String content]) async {
55 | // print('PersistentStore.saveNote');
56 |
57 | if (content == null) {
58 | content = await readContent(note);
59 | }
60 | if (isDendronModeEnabled) {
61 | final index = content.indexOf('\n');
62 | if (index != -1) content = content.substring(index).trimLeft();
63 | }
64 |
65 | String header = '---\n';
66 | Map data = {};
67 |
68 | data['title'] = note.title;
69 |
70 | if (PrefService.getBool('notes_list_virtual_tags') ?? false) {
71 | note.tags.removeWhere((s) => s.startsWith('#/'));
72 | }
73 |
74 | if (!isDendronModeEnabled) {
75 | if (note.tags.isNotEmpty) data['tags'] = note.tags;
76 | }
77 |
78 | if (note.attachments.isNotEmpty) data['attachments'] = note.attachments;
79 |
80 | if (note.usesMillis ?? false) {
81 | data['created'] = note.created.millisecondsSinceEpoch;
82 | data[note.usesUpdatedInsteadOfModified ? 'updated' : 'modified'] =
83 | note.modified.millisecondsSinceEpoch;
84 | } else {
85 | data['created'] = note.created.toIso8601String();
86 | data[note.usesUpdatedInsteadOfModified ? 'updated' : 'modified'] =
87 | note.modified.toIso8601String();
88 | }
89 |
90 | if (note.pinned) data['pinned'] = true;
91 | if (note.favorited) data['favorited'] = true;
92 | if (note.deleted) data['deleted'] = true;
93 |
94 | if (note.additionalFrontMatterKeys != null) {
95 | data.addAll(note.additionalFrontMatterKeys.cast());
96 | }
97 |
98 | header += toYamlString(data);
99 |
100 | if (!header.endsWith('\n')) header += '\n';
101 |
102 | header += '---\n\n';
103 |
104 | // print(header);
105 |
106 | note.file.writeAsStringSync(header + content);
107 | /* print(header + content); */
108 | }
109 |
110 | static Future readNote(File file) async {
111 | // print('PersistentStore.readNote');
112 |
113 | if (!file.existsSync()) return null;
114 |
115 | String fileContent = file.readAsStringSync();
116 |
117 | Map header;
118 |
119 | if (fileContent.trimLeft().startsWith('---')) {
120 | var doc = fm.parse(fileContent);
121 | /*
122 | String headerString = fileContent.split('---')[1]; */
123 |
124 | header = doc.data ?? {};
125 | } else {
126 | header = {};
127 | }
128 |
129 | /* for (String line in headerString.split('\n')) {
130 | if (line.trim().length == 0) continue;
131 | print(line);
132 | String key=line.split(':').first;
133 | header[key] = line.sub;
134 | } */
135 | //print(header);
136 | Note note = Note();
137 |
138 | note.file = file;
139 |
140 | note.title = header['title'].toString();
141 |
142 | if (note.title == null) {
143 | var title = file.path.split('/').last;
144 | if (title.endsWith('.md')) {
145 | title = title.substring(0, title.length - 3);
146 | }
147 | note.title = title;
148 | }
149 |
150 | if (header['modified'] != null && !isDendronModeEnabled) {
151 | if (header['modified'] is int) {
152 | note.usesMillis = true;
153 | note.modified = DateTime.fromMillisecondsSinceEpoch(header['modified']);
154 | } else {
155 | note.modified = DateTime.tryParse(header['modified']);
156 | }
157 | } else if (header['updated'] != null) {
158 | note.usesUpdatedInsteadOfModified = true;
159 | if (header['updated'] is int) {
160 | note.usesMillis = true;
161 | note.modified = DateTime.fromMillisecondsSinceEpoch(header['updated']);
162 | } else {
163 | note.modified = DateTime.tryParse(header['updated']);
164 | }
165 | } else {
166 | note.modified = file.lastModifiedSync();
167 | }
168 |
169 | if (header['created'] != null) {
170 | if (header['created'] is int) {
171 | note.usesMillis = true;
172 | note.created = DateTime.fromMillisecondsSinceEpoch(header['created']);
173 | } else {
174 | note.created = DateTime.tryParse(header['created']);
175 | }
176 | }
177 | if (note.created == null) {
178 | note.created = note.modified;
179 | }
180 |
181 | /*
182 | note.tags =
183 | (header['tags'] as YamlList).map((s) => s.toString()).toList(); */
184 | note.tags = List.from((header['tags'] ?? []).cast());
185 | note.attachments = List.from((header['attachments'] ?? []).cast());
186 |
187 | note.pinned = header['pinned'] ?? false;
188 | note.favorited = header['favorited'] ?? false;
189 | note.deleted = header['deleted'] ?? false;
190 |
191 | if (header.isNotEmpty) {
192 | note.additionalFrontMatterKeys = Map.from(header);
193 |
194 | note.additionalFrontMatterKeys
195 | .removeWhere((key, value) => supportedFrontMatterKeys.contains(key));
196 | }
197 |
198 | return note;
199 | }
200 |
201 | /* static Future readNoteMetadata(File file) async {
202 | // print('PersistentStore.readNote');
203 |
204 | if (!file.existsSync()) return null;
205 |
206 | var raf = await file.open();
207 |
208 | List bytes = [];
209 |
210 | bool equalBytes(List l1, List l2) {
211 | int i = -1;
212 | return l1.every((val) {
213 | i++;
214 | return l2[i] == val;
215 | });
216 | }
217 |
218 | while (true) {
219 | var byte = raf.readByteSync();
220 | if (byte == -1) break;
221 |
222 | bytes.add(byte);
223 |
224 | int length = bytes.length;
225 |
226 | if (length > 6 &&
227 | equalBytes(bytes.sublist(bytes.length - 4, bytes.length),
228 | [10, 45, 45, 45] /* == "\n---" */)) break;
229 | }
230 |
231 | String fileContent = utf8.decode(bytes);
232 |
233 | var doc = fm.parse(fileContent);
234 | /*
235 | String headerString = fileContent.split('---')[1]; */
236 |
237 | var header = doc.data /* loadYaml(headerString) */;
238 |
239 | if (header == null) return null;
240 |
241 | /* for (String line in headerString.split('\n')) {
242 | if (line.trim().length == 0) continue;
243 | print(line);
244 | String key=line.split(':').first;
245 | header[key] = line.sub;
246 | } */
247 | //print(header);
248 | Note note = Note();
249 |
250 | note.file = file;
251 |
252 | note.title = header['title'];
253 | note.created = DateTime.parse(header['created']);
254 | note.modified = DateTime.parse(header['modified']);
255 | /*
256 | note.tags =
257 | (header['tags'] as YamlList).map((s) => s.toString()).toList(); */
258 | note.tags = List.from((header['tags'] ?? []).cast());
259 | note.attachments = List.from((header['attachments'] ?? []).cast());
260 |
261 | note.pinned = header['pinned'] ?? false;
262 | note.favorited = header['favorited'] ?? false;
263 | note.deleted = header['deleted'] ?? false;
264 |
265 | return note;
266 | } */
267 |
268 | static Future deleteNote(Note note) async {
269 | await note.file.delete();
270 | }
271 | }
272 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # Noteless
4 |
5 | A markdown-based note-taking app for Android
6 |
7 | [](https://play.google.com/store/apps/details?id=net.redsolver.noteless)
8 | [](https://github.com/redsolver/noteless/releases)
9 | [](https://to.skydroid.app/noteless.redsolver)
10 | [](https://matrix.to/#/#noteless:matrix.org)
11 | 
12 |
13 | Compatible with notes saved in [Notable](https://notable.app/)
14 |
15 | ## Features
16 |
17 | - Markdown-optimized editor with syntax highlighting
18 | - Supports Github Flavored Markdown, AsciiMath, KaTeX and mermaidjs for diagrams
19 | - Tags for organizing your notes
20 | - Pin, Star and sort your notes by title or different dates
21 | - Very themable - dark/light mode and accent color
22 | - Full-text search
23 | - File Attachments that can be embedded into a note
24 | - Multi-Note Editing
25 | - Slide actions for easier editing
26 | - Tutorial notes which explain how to use the app
27 |
28 | ## Screenshots
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 | ## Download
55 |
56 | [https://github.com/redsolver/noteless/releases](https://github.com/redsolver/noteless/releases)
57 |
58 | ## Changelog
59 |
60 | ### 1.4.6
61 |
62 | - Added support for the Android 11 permission system
63 | - Added option to sort tags alphabetically in the sidebar
64 | - Improved compatibility with other Markdown-based note-taking tools (especially Dendron)
65 | - Some small bug and theme fixes
66 |
67 | ### 1.3.1
68 |
69 | - Added optional auto save option
70 | - Added optional auto pairing of brackets/quotes (thanks to @RubbaBoy)
71 | - Editor: Added option to move and restore note to/from trash
72 | - Improved table styling (thanks to @davidebersani)
73 | - Fixed some bugs
74 |
75 | ### 1.3.0
76 |
77 | - Added feature to create a new note by sharing text with Noteless (#42)
78 | - Adding an attachment to a note now automatically embeds it
79 | - Improved blockquote styling (#44)
80 | - Fixed some bugs
81 |
82 | ### 1.2.1
83 |
84 | - Added Android App Shortcut for creating a new note from the homescreen
85 | - Added proper table borders
86 | - Fixed some bugs
87 |
88 | ### 1.2.0
89 |
90 | - Added AsciiMath support
91 | - Added Black/AMOLED theme
92 | - Added experimental option: Automatic bullet points
93 | - Added optional single line break syntax
94 | - Increased height of editor toolbar
95 | - Changed behaviour of list-button in editor toolbar
96 | - Fixed image sizing in preview
97 | - Fixed text field submitting when adding a tag
98 |
99 | ### 1.1.1
100 |
101 | - Added support for spaces in links (#36)
102 |
103 | ### 1.1.0
104 |
105 | - Made checkboxes in preview mode toggleable (#37)
106 | - Added support for Wiki-style links like `[[My Note]]` (#38)
107 |
108 | ### 1.0.0
109 |
110 | - First stable release
111 | - Submitted the app to Google Play Store and F-Droid
112 | - Updated to Flutter 1.20 (Better Performance and some bug fixes in the editor)
113 |
114 | ### 0.3.2
115 |
116 | - Added F-Droid metadata
117 |
118 | ### 0.3.1
119 |
120 | - Fixed editor content not loading without front matter data
121 |
122 | ### 0.3.0
123 |
124 | - Fully reworked editor with syntax highlighting and a new keyboard toolbar to help with common Markdown operations
125 | - Added fallback to file metadata if front matter data is missing
126 |
127 | ### 0.2.1
128 |
129 | - Disabled the preview feature on Android 4.4 KitKat devices.
130 | - Removed WebDav sync
131 |
132 | ### Important Changes in Version 0.2.0
133 |
134 | The app has been renamed from `Notable Mobile` to `Noteless` on 02.07.2020.
135 |
136 | If you used an earlier Alpha Version, you need to uninstall the old one and install one of the new APKs (Don't forget to backup your notes!)
137 |
138 | This is because the app also has a new package name: `net.redsolver.noteless`.
139 |
140 | Also I decided to drop support for syncing notes directly via the app because there are alternative options which work a lot better.
141 |
142 | I recommend using an external data directory and a third-party sync app for Android like [Syncthing](https://syncthing.net/), Nextcloud Sync or FolderSync for other cloud services.
143 |
144 | ### 0.2.0
145 |
146 | - Renamed the app to "Noteless"
147 | - New app icon
148 | - Reworked tutorial notes
149 | - The Editor/Preview Mode Switcher is now the default option
150 | - New error handling: When an exception occurs while reading a note, the note is skipped and the errors are shown as "virtual notes".
151 | - Show loading dialog when changing external data directory
152 | - Fixed issue with using an external data directory on Android Q (10)
153 | - QOL Improvements (Autofocus, Small design improvements)
154 |
155 | ### 0.1.8
156 |
157 | - Added support for subdirectories
158 | - Added options to restore notes from trash
159 | - With the swipe actions of a note
160 | - With the "Restore from trash" button in the multi select options
161 | - Added option to create a logfile for sync
162 | - Added experimental option to enable virtual folder tags
163 | - Minor theme fixes
164 |
165 | ### 0.1.7
166 |
167 | - Fixed white flash when loading note preview
168 |
169 | ### 0.1.6
170 |
171 | - Added option to use a mode switcher for editor and preview
172 |
173 | ### 0.1.5
174 |
175 | - Added feature to add and remove attachments
176 | - Searching in content of notes
177 | - Enabled by default
178 | - Can be disabled in settings
179 | - Can get slow with more than 2000 notes
180 |
181 | ### 0.1.4
182 |
183 | - Added KaTeX and mhchem support
184 | - Added option to change accent color
185 | - Added note swipe actions (trash, delete, pin and favorite)
186 |
187 | ### 0.1.3
188 |
189 | - Fixed webdav sync
190 |
191 | ### 0.1.2
192 |
193 | - Fixed sync when using different data directory
194 |
195 | ### 0.1.1
196 |
197 | - Added option to select data directory on device
198 | - Moved multi select options to bottom app bar
199 | - Pressing back while being in select mode cancels it
200 | - Added option to recreate all tutorial notes and attachments in settings
201 | - Updated info page
202 | - Dark Theme now supports markdown preview
203 |
204 | ### 0.1.0
205 |
206 | - Select multiple notes by long pressing
207 | - After entering select mode, add notes to the selection by tapping them
208 | - Select or unselect all notes in the select menu
209 | - Favorite/Unfavorite multiple notes at once
210 | - Pin/Unpin multiple notes at once
211 | - Add and remove tags to multiple notes at once
212 | - Move to Trash and delete multiple notes at once
213 |
214 | ### 0.0.9
215 |
216 | - Dark Theme
217 | - Confirmation Dialogs
218 |
219 | ## License
220 |
221 | The app is MIT licensed.
222 |
--------------------------------------------------------------------------------
/lib/store/notes.dart:
--------------------------------------------------------------------------------
1 | import 'dart:io';
2 |
3 | import 'package:app/model/note.dart';
4 | import 'package:app/store/persistent.dart';
5 | import 'package:app/sync/webdav.dart';
6 | import 'package:path_provider/path_provider.dart';
7 | import 'package:preferences/preference_service.dart';
8 | import 'package:app/data/samples.dart';
9 | import 'package:flutter/services.dart' show rootBundle;
10 |
11 | class NotesStore {
12 | /* String subDirectoryNotes = ;
13 | String subDirectoryAttachments = ; */
14 |
15 | String get subDirectoryNotes => isDendronModeEnabled ? '' : '/notes';
16 | String get subDirectoryAttachments =>
17 | isDendronModeEnabled ? '/assets' : '/attachments';
18 |
19 | bool get isDendronModeEnabled => PrefService.getBool('dendron_mode') ?? false;
20 |
21 | Directory notesDir, attachmentsDir;
22 |
23 | String searchText;
24 |
25 | String syncMethod;
26 |
27 | get syncMethodName {
28 | switch (syncMethod) {
29 | case 'webdav':
30 | return 'WebDav';
31 | default:
32 | return 'No';
33 | }
34 | }
35 |
36 | void init() {
37 | syncMethod = PrefService.getString('sync') ?? '';
38 | }
39 |
40 | Future createTutorialNotes() async {
41 | for (String fileName in Samples.tutorialNotes) {
42 | File('${notesDir.path}/$fileName').writeAsStringSync(
43 | await rootBundle.loadString('assets/tutorial/notes/$fileName'));
44 | }
45 | }
46 |
47 | Future createTutorialAttachments() async {
48 | for (String fileName in Samples.tutorialAttachments) {
49 | File('${attachmentsDir.path}/$fileName').writeAsBytesSync(
50 | (await rootBundle.load('assets/tutorial/attachments/$fileName'))
51 | .buffer
52 | .asUint8List());
53 | }
54 | }
55 |
56 | Directory applicationDocumentsDirectory;
57 |
58 | Future listNotes() async {
59 | applicationDocumentsDirectory = await getApplicationDocumentsDirectory();
60 | Directory directory;
61 |
62 | if (PrefService.getBool('notable_external_directory_enabled') ?? false) {
63 | directory =
64 | Directory(PrefService.getString('notable_external_directory'));
65 | } else {
66 | directory = applicationDocumentsDirectory;
67 | }
68 | PrefService.setString('notable_directory', directory.path);
69 |
70 | // print(isDendronModeEnabled);
71 |
72 | notesDir = Directory('${directory.path}$subDirectoryNotes');
73 |
74 | PrefService.setString('notable_notes_directory', notesDir.path);
75 |
76 | if (!notesDir.existsSync()) {
77 | notesDir.createSync();
78 | if (!isDendronModeEnabled) await createTutorialNotes();
79 | }
80 |
81 | attachmentsDir = Directory('${directory.path}$subDirectoryAttachments');
82 | PrefService.setString('notable_attachments_directory', attachmentsDir.path);
83 |
84 | if (!attachmentsDir.existsSync()) {
85 | attachmentsDir.createSync();
86 | if (!isDendronModeEnabled) await createTutorialAttachments();
87 | }
88 |
89 | /* for (String fileName in Samples.tutorialNotes) {
90 | File('${notesDir.path}/$fileName').writeAsStringSync(
91 | await rootBundle.loadString('assets/tutorial/notes/$fileName'));
92 | } */
93 |
94 | allNotes = [];
95 |
96 | DateTime start = DateTime.now();
97 |
98 | await _listNotesInFolder('');
99 |
100 | print(DateTime.now().difference(start));
101 |
102 | // _updateTagList();
103 | }
104 |
105 | Future _listNotesInFolder(String dir, {bool isSubDirectory = false}) async {
106 | await for (var entity in Directory('${notesDir.path}$dir').list()) {
107 | if (entity is File) {
108 | try {
109 | if (isDendronModeEnabled) {
110 | if (!entity.path.endsWith('.md')) continue;
111 | }
112 | Note note = await PersistentStore.readNote(entity);
113 |
114 | if (note != null) {
115 | if (PrefService.getBool('notes_list_virtual_tags') ?? false) {
116 | if (isSubDirectory) note.tags.add('#$dir');
117 | }
118 | if (isDendronModeEnabled) {
119 | var path = entity.path
120 | .substring(notesDir.path.length, entity.path.length - 3);
121 | while (path.startsWith('/')) {
122 | path = path.substring(1);
123 | }
124 | note.tags.add('${path.replaceAll('.', '/')}');
125 | }
126 |
127 | allNotes.add(note);
128 | }
129 | } catch (e, st) {
130 | final note = Note();
131 | note.title =
132 | 'ERROR - "$e" on parsing "${entity.path.split('/notes/').last}"';
133 |
134 | note.created = DateTime.now();
135 | note.modified = note.created;
136 | note.tags = ['ERROR'];
137 | note.attachments = [];
138 |
139 | note.pinned = true;
140 | note.favorited = true;
141 | note.deleted = false;
142 |
143 | allNotes.add(note);
144 | }
145 | } else if (entity is Directory) {
146 | final dirName = entity.path.split('/').last;
147 |
148 | if (dirName.startsWith('.')) continue;
149 |
150 | if (entity.path.startsWith(attachmentsDir.path)) continue;
151 |
152 | await _listNotesInFolder(
153 | dir + '/' + dirName,
154 | isSubDirectory: true,
155 | );
156 | }
157 | }
158 | }
159 |
160 | updateTagList() {
161 | for (Note note in allNotes) {
162 | for (String tag in note.tags) {
163 | allTags.add(tag);
164 | }
165 | }
166 |
167 | final tmpRootTags = {};
168 |
169 | for (String tag in allTags) {
170 | tmpRootTags.add(tag.split('/').first);
171 | }
172 |
173 | rootTags = tmpRootTags.toList();
174 | rootTags.sort();
175 | }
176 |
177 | List getSubTags(String forTag) {
178 | Set subTags =
179 | allTags.where((tag) => tag.startsWith(forTag) && tag != forTag).toSet();
180 |
181 | subTags = subTags.map((String t) => t.replaceFirst('$forTag/', '')).toSet();
182 |
183 | subTags = subTags.map((String t) => t.split('/').first).toSet();
184 |
185 | final subTagsList = subTags.toList();
186 |
187 | if (PrefService.getBool('sort_tags_in_sidebar') ?? true) {
188 | subTagsList.sort();
189 | }
190 |
191 | return subTagsList;
192 | }
193 |
194 | filterAndSortNotes() {
195 | //shownNotes = List.from(allNotes);
196 |
197 | shownNotes = _filterByTag(allNotes, currentTag);
198 |
199 | if (searchText != null) {
200 | List keywords =
201 | searchText.split(' ').map((s) => s.toLowerCase()).toList();
202 |
203 | if (PrefService.getBool('search_content') ?? true) {
204 | List toRemove = [];
205 |
206 | for (Note note in shownNotes) {
207 | String content = note.file.readAsStringSync().toLowerCase();
208 |
209 | bool _contains = true;
210 | for (String keyword in keywords) {
211 | if (!content.contains(keyword)) {
212 | _contains = false;
213 | break;
214 | }
215 | }
216 | if (!_contains) {
217 | toRemove.add(note.title);
218 | }
219 | }
220 | shownNotes.removeWhere((n) => toRemove.contains(n.title));
221 | } else {
222 | shownNotes.retainWhere((note) {
223 | String noteTitle = note.title.toLowerCase();
224 | for (String keyword in keywords) {
225 | if (!noteTitle.contains(keyword)) return false;
226 | }
227 | return true;
228 | });
229 | }
230 | }
231 |
232 | shownNotes.sort((a, b) {
233 | if (a.pinned ^ b.pinned) {
234 | return a.pinned ? -1 : 1;
235 | } else {
236 | int value = 0;
237 |
238 | switch (PrefService.getString('sort_key') ?? 'title') {
239 | case 'title':
240 | value = a.title.compareTo(b.title);
241 | break;
242 | case 'date_created':
243 | value = a.created.compareTo(b.created);
244 | break;
245 | case 'date_modified':
246 | value = a.modified.compareTo(b.modified);
247 | break;
248 | }
249 | if (!(PrefService.getBool('sort_direction_asc') ?? true)) value *= -1;
250 |
251 | return value;
252 | }
253 | });
254 | }
255 |
256 | List _filterByTag(List notes, String cTag) {
257 | return notes.where((note) => note.hasTag(cTag)).toList();
258 | }
259 |
260 | int countNotesWithTag(List notes, String tag) {
261 | int count = 0;
262 | notes.forEach((note) {
263 | if (note.hasTag(tag)) count++;
264 | });
265 | return count;
266 | }
267 |
268 | List allNotes;
269 |
270 | List shownNotes;
271 |
272 | String currTag = '';
273 |
274 | set currentTag(String newTag) {
275 | currTag = newTag;
276 | PrefService.setString('current_tag', newTag);
277 | }
278 |
279 | String get currentTag => currTag;
280 |
281 | Set allTags = {};
282 |
283 | List rootTags = [];
284 |
285 | Future syncNow() async {
286 | /* switch (syncMethod) {
287 | case 'webdav':
288 | return await WebdavSync().syncFiles(this);
289 | } */
290 | return null;
291 | }
292 |
293 | Note getNote(String title) {
294 | return allNotes.firstWhere((n) => n.title == title);
295 | }
296 | }
297 |
--------------------------------------------------------------------------------
/lib/page/preview.dart:
--------------------------------------------------------------------------------
1 | import 'dart:io';
2 |
3 | import 'package:flutter/material.dart';
4 | import 'package:app/model/note.dart';
5 | import 'package:app/page/edit.dart';
6 | import 'package:app/page/note_list.dart';
7 | import 'package:app/provider/theme.dart';
8 | import 'package:app/store/notes.dart';
9 | import 'package:app/store/persistent.dart';
10 | import 'package:markd/markdown.dart';
11 | import 'package:preferences/preference_service.dart';
12 |
13 | import 'package:provider/provider.dart';
14 | import 'package:rich_code_editor/rich_code_controller.dart';
15 | import 'package:webview_flutter/webview_flutter.dart';
16 | import 'package:url_launcher/url_launcher.dart';
17 | import 'package:path_provider/path_provider.dart';
18 | import 'package:markd/markdown.dart' as markd;
19 |
20 | import 'package:markd/src/ast.dart' as markd_ast;
21 |
22 | class PreviewPage extends StatefulWidget {
23 | final NotesStore store;
24 | final String textContent;
25 | final RichCodeEditingController richCtrl;
26 |
27 | final ThemeData theme;
28 |
29 | PreviewPage(this.store, this.textContent, this.richCtrl, this.theme);
30 |
31 | @override
32 | _PreviewPageState createState() => _PreviewPageState();
33 | }
34 |
35 | class _PreviewPageState extends State {
36 | // BuildContext context;
37 |
38 | String currentTextContent;
39 |
40 | @override
41 | void initState() {
42 | _processContent();
43 | super.initState();
44 | }
45 |
46 | List checkboxPositions = [];
47 |
48 | File previewFile;
49 |
50 | _processContent() async {
51 | //this.context = context;
52 |
53 | final directory = widget.store.applicationDocumentsDirectory;
54 |
55 | final previewDir = Directory('${directory.path}/preview');
56 |
57 | const staticPreviewDir =
58 | 'file:///android_asset/flutter_assets/assets/preview';
59 |
60 | /* final previewAssetsDir =
61 | Directory('${directory.path}/preview/assets'); */
62 |
63 | previewFile = File('${previewDir.path}/index.html');
64 | previewFile.createSync(recursive: true);
65 |
66 | // TODO iOS Preview
67 |
68 | currentTextContent = widget.textContent;
69 |
70 | for (final match in RegExp(r'\[(x| )\]').allMatches(currentTextContent)) {
71 | // print(match);
72 | checkboxPositions.add(match.start + 1);
73 | }
74 |
75 | String content = widget.textContent;
76 |
77 | // Wiki-Style note links like [[Note]]
78 |
79 | content = content.replaceAllMapped(RegExp(r'\[\[[^\]]+\]\]'), (match) {
80 | var str = match.input.substring(match.start, match.end);
81 |
82 | String title = str.substring(2).split(']').first;
83 |
84 | return '[$title](@note/$title' +
85 | (title.endsWith('.md') ? '' : '.md') +
86 | ')';
87 | });
88 |
89 | content =
90 | content.replaceAllMapped(RegExp(r'(?<=\]\(@note\/).*(?=\))'), (match) {
91 | return content.substring(match.start, match.end).replaceAll(' ', '%20');
92 | });
93 |
94 | content = content.replaceAll(RegExp(r'\\\\'), '\\\\\\\\');
95 |
96 | ThemeData theme = widget.theme;
97 |
98 | String backgroundColor = theme.scaffoldBackgroundColor.value
99 | .toRadixString(16)
100 | .padLeft(8, '0')
101 | .substring(2);
102 |
103 | String textColor = theme.textTheme.body1.color.value
104 | .toRadixString(16)
105 | .padLeft(8, '0')
106 | .substring(2);
107 |
108 | String accentColor =
109 | theme.accentColor.value.toRadixString(16).padLeft(8, '0').substring(2);
110 |
111 | String generatedPreview = '''
112 |
113 |
114 |
115 | ''' +
116 | (Provider.of(context, listen: false).currentTheme ==
117 | ThemeType.light
118 | ? ''
119 | : '''
120 |
132 | ''') +
133 | '''
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
170 |
171 |
199 |
200 |
201 | ''' +
202 | markd.markdownToHtml(
203 | content,
204 | extensionSet: markd.ExtensionSet.gitHubWeb,
205 | inlineSyntaxes: [
206 | if (PrefService.getBool('single_line_break_syntax') ?? false)
207 | SingleLineBreakSyntax(),
208 | ],
209 | /* blockSyntaxes: [FencedCodeBlockSyntax()], */
210 | ) +
211 | '''
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
225 |
226 |
231 |
232 |
233 | ''';
234 |
235 | /* generatedPreview = generatedPreview.replaceAll('\\ ', ' '); */
236 | generatedPreview = generatedPreview
237 | .replaceAll(
238 | 'src="@attachment/',
239 | 'src="' +
240 | 'file://' +
241 | PrefService.getString('notable_attachments_directory') +
242 | '/')
243 | .replaceAll(
244 | 'src="/',
245 | 'src="' +
246 | 'file://' +
247 | PrefService.getString('notable_notes_directory') +
248 | '/');
249 |
250 | generatedPreview =
251 | generatedPreview.replaceAll('
')[1]);
254 |
255 | int checkboxIndex = -1;
256 |
257 | generatedPreview = generatedPreview.replaceAllMapped(
258 | 'disabled="disabled" class="todo" type="checkbox"', (match) {
259 | checkboxIndex++;
260 |
261 | return 'class="todo" type="checkbox" onclick="notelesscheckbox.postMessage( this.checked + \'-$checkboxIndex\');"';
262 | });
263 |
264 | await previewFile.writeAsString(generatedPreview);
265 |
266 | setState(() {
267 | _processingDone = true;
268 | });
269 | }
270 |
271 | bool _processingDone = false;
272 |
273 | bool _pageLoaded = false;
274 |
275 | @override
276 | Widget build(BuildContext context) {
277 | // print('BUILD');
278 |
279 | return StatefulBuilder(
280 | builder: (context, setState) {
281 | return !_processingDone
282 | ? Center(
283 | child: CircularProgressIndicator(),
284 | )
285 | : Stack(
286 | children: [
287 | WebView(
288 | initialUrl: 'file://' + previewFile.path,
289 | javascriptMode: JavascriptMode.unrestricted,
290 | onWebViewCreated: (ctrl) {},
291 | javascriptChannels: {
292 | JavascriptChannel(
293 | name: 'flutternotable',
294 | onMessageReceived: (_) async {
295 | setState(() {
296 | _pageLoaded = true;
297 | });
298 | }),
299 | JavascriptChannel(
300 | name: 'notelesscheckbox',
301 | onMessageReceived: (msg) async {
302 | final parts = msg.message.split('-');
303 |
304 | final bool checked = parts[0] == 'true';
305 |
306 | final int id = int.parse(parts[1]);
307 |
308 | final index = checkboxPositions[id];
309 |
310 | currentTextContent =
311 | currentTextContent.substring(0, index) +
312 | (checked ? 'x' : ' ') +
313 | currentTextContent.substring(index + 1);
314 |
315 | widget.richCtrl.text = currentTextContent;
316 |
317 | // textContent
318 | }),
319 | },
320 | navigationDelegate: (request) {
321 | print(request.url);
322 |
323 | if (request.url.startsWith('file://')) {
324 | String link = Uri.decodeFull(
325 | RegExp(r'@.*').stringMatch(request.url));
326 | print(link);
327 |
328 | String type =
329 | RegExp(r'(?<=@).*(?=/)').stringMatch(link);
330 |
331 | String data = RegExp(r'(?<=/).*').stringMatch(link);
332 | print(type);
333 | print(data);
334 | print(Theme.of(context).brightness);
335 | switch (type) {
336 | case 'note':
337 | _navigateToNote(data);
338 |
339 | break;
340 | case 'tag':
341 | _navigateToTag(data);
342 | break;
343 | case 'search':
344 | _navigateToSearch(data);
345 | break;
346 | case 'attachment':
347 | break;
348 | }
349 | } else {
350 | launch(
351 | request.url,
352 | );
353 | }
354 | return NavigationDecision.prevent;
355 | },
356 | ),
357 | if (!_pageLoaded)
358 | Container(
359 | color: Theme.of(context).scaffoldBackgroundColor,
360 | alignment: Alignment.center,
361 | child: CircularProgressIndicator(),
362 | ),
363 | ],
364 | );
365 | },
366 | );
367 | }
368 |
369 | void _navigateToNote(String title) async {
370 | if (!title.endsWith('.md')) title += '.md';
371 | Note newNote = await PersistentStore.readNote(
372 | File('${PrefService.getString('notable_notes_directory')}/${title}'));
373 | if (newNote == null) {
374 | // TODO Show Error
375 | } else {
376 | Navigator.of(context).push(MaterialPageRoute(
377 | builder: (context) => EditPage(newNote, widget.store)));
378 | }
379 | }
380 |
381 | void _navigateToTag(String tag) async {
382 | Navigator.of(context).push(MaterialPageRoute(
383 | builder: (context) => NoteListPage(
384 | filterTag: tag,
385 | isFirstPage: false,
386 | )));
387 | }
388 |
389 | void _navigateToSearch(String search) async {
390 | Navigator.of(context).push(MaterialPageRoute(
391 | builder: (context) => NoteListPage(
392 | searchText: search,
393 | isFirstPage: false,
394 | )));
395 | }
396 | }
397 |
398 | /// Represents a hard line break.
399 | class SingleLineBreakSyntax extends InlineSyntax {
400 | SingleLineBreakSyntax() : super(r'\n');
401 |
402 | /// Create a void
element.
403 | @override
404 | bool onMatch(InlineParser parser, Match match) {
405 | parser.addNode(markd_ast.Element.empty('br'));
406 | return true;
407 | }
408 | }
409 |
--------------------------------------------------------------------------------
/lib/editor/syntax_highlighter.dart:
--------------------------------------------------------------------------------
1 | import 'dart:ui';
2 |
3 | import 'package:flutter/material.dart';
4 | import 'package:rich_code_editor/exports.dart';
5 |
6 | class NotelessSyntaxHighlighter implements SyntaxHighlighterBase {
7 | Color accentColor;
8 |
9 | Map styles;
10 |
11 | init(Color accentColor) {
12 | this.accentColor = accentColor;
13 | styles = {
14 | '1': TextStyle(
15 | fontStyle: FontStyle.italic,
16 | ),
17 | '2': TextStyle(fontWeight: FontWeight.bold),
18 | '3': TextStyle(
19 | fontWeight: FontWeight.bold,
20 | fontStyle: FontStyle.italic,
21 | ),
22 | '4': TextStyle(
23 | color: Colors.blue,
24 | ),
25 | '5': TextStyle(
26 | color: Colors.purple,
27 | ),
28 | '6': TextStyle(
29 | decoration: TextDecoration.lineThrough,
30 | ),
31 | '7': TextStyle(
32 | color: accentColor,
33 | fontWeight: FontWeight.bold,
34 | ),
35 | };
36 | }
37 |
38 | NotelessSyntaxHighlighter({this.accentColor});
39 |
40 | @override
41 | TextEditingValue addTextRemotely(TextEditingValue oldValue, String newText) {
42 | return null;
43 | }
44 |
45 | @override
46 | TextEditingValue onBackSpacePress(
47 | TextEditingValue oldValue, TextSpan currentSpan) {
48 | return null;
49 | }
50 |
51 | @override
52 | TextEditingValue onEnterPress(TextEditingValue oldValue) {
53 | int oldStart = oldValue.selection.start;
54 |
55 | final bef = oldValue.text.substring(0, oldStart - 1);
56 |
57 | String befLine = bef.split('\n').last;
58 |
59 | int trimSpace = befLine.length;
60 |
61 | befLine = befLine.trimLeft();
62 |
63 | trimSpace = trimSpace - befLine.length;
64 |
65 | if (befLine.startsWith('- ') || befLine.startsWith('* ')) {
66 | if (befLine.length <= 2) {
67 | if (trimSpace == 0) {
68 | var newValue = oldValue.copyWith(
69 | text: bef.substring(0, oldStart - 3) +
70 | '\n\n' +
71 | oldValue.text.substring(oldStart + 1),
72 | composing: TextRange(start: -1, end: -1),
73 | selection: TextSelection.fromPosition(
74 | TextPosition(
75 | affinity: TextAffinity.upstream, offset: bef.length - 1),
76 | ),
77 | );
78 |
79 | return newValue;
80 | } else {
81 | var newValue = oldValue.copyWith(
82 | text: oldValue.text.substring(0, oldStart - 1 - 4) +
83 | oldValue.text.substring(oldStart - 3, oldStart) +
84 | oldValue.text.substring(oldStart + 1),
85 | composing: TextRange(start: -1, end: -1),
86 | selection: TextSelection.fromPosition(
87 | TextPosition(
88 | affinity: TextAffinity.upstream, offset: bef.length - 2),
89 | ),
90 | );
91 |
92 | return newValue;
93 | }
94 | }
95 |
96 | String sym = befLine.startsWith('* ') ? '*' : '-';
97 |
98 | for (int i = 0; i < trimSpace; i++) {
99 | sym = ' ' + sym;
100 | }
101 |
102 | var newValue = oldValue.copyWith(
103 | text: bef + '\n$sym \n' + oldValue.text.substring(oldStart + 1),
104 | composing: TextRange(start: -1, end: -1),
105 | selection: TextSelection.fromPosition(
106 | TextPosition(
107 | affinity: TextAffinity.upstream,
108 | offset: bef.length + 3 + trimSpace),
109 | ),
110 | );
111 |
112 | return newValue;
113 | }
114 |
115 | return null;
116 |
117 | int start = oldStart;
118 |
119 | int breakCount = 0;
120 |
121 | while (start > 0) {
122 | start--;
123 | if (oldValue.text[start] == '\n') {
124 | if (breakCount >= 1) break;
125 | breakCount++;
126 | }
127 | }
128 | if (start != 0) start++;
129 |
130 | String startOfLine = oldValue.text.substring(
131 | start,
132 | );
133 | final before = oldValue.text.substring(0, oldStart);
134 |
135 | print(startOfLine.substring(0, 10));
136 |
137 | if (startOfLine.startsWith('- ')) {
138 | int length = 1;
139 |
140 | if (startOfLine.startsWith('- ')) length++;
141 | /* _rec.text = before + startOfLine.substring(1).trimLeft();
142 | _rec.selection = TextSelection(
143 | baseOffset: oldStart - length, extentOffset: oldStart - length); */
144 | var newValue = oldValue.copyWith(
145 | text: before + '- \n' + oldValue.text,
146 | composing: TextRange(start: -1, end: -1),
147 | selection: TextSelection.fromPosition(
148 | TextPosition(
149 | affinity: TextAffinity.upstream, offset: before.length + 2),
150 | ),
151 | );
152 |
153 | return newValue;
154 | } else {}
155 | return oldValue;
156 | }
157 |
158 | @override
159 | List parseText(TextEditingValue tev) {
160 | var texts = tev.text.split('\n');
161 |
162 | var lsSpans = List();
163 |
164 | bool inCodeBlock = false;
165 |
166 | int i = 0;
167 | texts.forEach((text) {
168 | i++;
169 | // print('"$text"');
170 |
171 | if (text.startsWith('```')) {
172 | inCodeBlock = !inCodeBlock;
173 | lsSpans.add(TextSpan(text: text, style: styles['4']));
174 | /* if (text.endsWith(' ')) {
175 | lsSpans.add(TextSpan(text: ' '));
176 | } */
177 | lsSpans.add(TextSpan(text: '\n'));
178 | return;
179 | }
180 |
181 | if (inCodeBlock) {
182 | lsSpans.add(TextSpan(text: text));
183 | /* if (text.endsWith(' ')) {
184 | lsSpans.add(TextSpan(text: ' '));
185 | } */
186 | lsSpans.add(TextSpan(text: '\n'));
187 |
188 | return;
189 | }
190 |
191 | int lengthDiff = text.length;
192 |
193 | text = text.trimLeft();
194 |
195 | lengthDiff = lengthDiff - text.length;
196 |
197 | String lineStart = '';
198 |
199 | for (int i = 0; i < lengthDiff; i++) {
200 | lineStart += ' ';
201 | }
202 |
203 | if (lineStart != null)
204 | lsSpans.add(
205 | TextSpan(
206 | text: lineStart,
207 | ),
208 | );
209 |
210 | addPrefix(String prefix) {
211 | lsSpans.add(
212 | TextSpan(
213 | text: prefix,
214 | style: TextStyle(color: accentColor, fontWeight: FontWeight.bold),
215 | ),
216 | );
217 | }
218 |
219 | if (text.startsWith('# ')) {
220 | addPrefix('# ');
221 | text = text.substring(2);
222 | } else if (text.startsWith('## ')) {
223 | addPrefix('## ');
224 | text = text.substring(3);
225 | } else if (text.startsWith('### ')) {
226 | addPrefix('### ');
227 | text = text.substring(4);
228 | } else if (text.startsWith('#### ')) {
229 | addPrefix('#### ');
230 | text = text.substring(5);
231 | } else if (text.startsWith('##### ')) {
232 | addPrefix('##### ');
233 | text = text.substring(6);
234 | } else if (text.startsWith('###### ')) {
235 | addPrefix('###### ');
236 | text = text.substring(7);
237 | } else if (text.startsWith('- ')) {
238 | addPrefix('- ');
239 | text = text.substring(2);
240 | } else if (text.startsWith('> ')) {
241 | while (text.startsWith('> ')) {
242 | addPrefix('> ');
243 | text = text.substring(2);
244 | }
245 | } else if (text.startsWith('* ')) {
246 | addPrefix('* ');
247 | text = text.substring(2);
248 | } else {}
249 |
250 | /* String str = ''; */
251 |
252 | // Star
253 |
254 | String s = text.replaceAllMapped(
255 | RegExp(r'(?
257 | '1' +
258 | match.input.substring(match.start, match.end) +
259 | '0');
260 |
261 | s = s.replaceAllMapped(
262 | RegExp(r'(?
264 | '2' +
265 | match.input.substring(match.start, match.end) +
266 | '0');
267 |
268 | s = s.replaceAllMapped(
269 | RegExp(r'(?
271 | '3' +
272 | match.input.substring(match.start, match.end) +
273 | '0');
274 |
275 | // Underscore
276 |
277 | s = s.replaceAllMapped(
278 | RegExp(r'(?
280 | '1' +
281 | match.input.substring(match.start, match.end) +
282 | '0');
283 |
284 | s = s.replaceAllMapped(
285 | RegExp(r'(?
287 | '2' +
288 | match.input.substring(match.start, match.end) +
289 | '0');
290 |
291 | s = s.replaceAllMapped(
292 | RegExp(r'(?
294 | '3' +
295 | match.input.substring(match.start, match.end) +
296 | '0');
297 |
298 | // Strikethrough
299 |
300 | s = s.replaceAllMapped(
301 | RegExp(r'~~[^~]+~~'),
302 | (match) =>
303 | '6' +
304 | match.input.substring(match.start, match.end) +
305 | '0');
306 |
307 | // Inline Code
308 |
309 | s = s.replaceAllMapped(
310 | RegExp(r'\`[^\`]+\`'),
311 | (match) =>
312 | '4' +
313 | match.input.substring(match.start, match.end) +
314 | '0');
315 |
316 | // Divider ---
317 |
318 | s = s.replaceAllMapped(
319 | RegExp(r'^---$'),
320 | (match) =>
321 | '7' +
322 | match.input.substring(match.start, match.end) +
323 | '0');
324 |
325 | s = s.replaceAllMapped(
326 | RegExp(r'^\*\*\*$'),
327 | (match) =>
328 | '7' +
329 | match.input.substring(match.start, match.end) +
330 | '0');
331 |
332 | // KaTeX
333 |
334 | s = s.replaceAllMapped(
335 | RegExp(r'(?
337 | '4' +
338 | match.input.substring(match.start, match.end) +
339 | '0');
340 |
341 | s = s.replaceAllMapped(
342 | RegExp(r'\$\$[^\$]+\$\$'),
343 | (match) =>
344 | '4' +
345 | match.input.substring(match.start, match.end) +
346 | '0');
347 |
348 | // AsciiMath
349 |
350 | s = s.replaceAllMapped(
351 | RegExp(r'(?
353 | '4' +
354 | match.input.substring(match.start, match.end) +
355 | '0');
356 |
357 | s = s.replaceAllMapped(
358 | RegExp(r'&&[^&]+&&'),
359 | (match) =>
360 | '4' +
361 | match.input.substring(match.start, match.end) +
362 | '0');
363 |
364 | // Wiki-Style note links like [[Note]]
365 |
366 | s = s.replaceAllMapped(RegExp(r'\[\[[^\]]+\]\]'), (match) {
367 | var str = match.input.substring(match.start, match.end);
368 |
369 | String title = str.substring(2).split(']').first;
370 |
371 | return '7[[0$title7]]0';
372 | });
373 |
374 | // Emojis
375 |
376 | s = s.replaceAllMapped(
377 | RegExp(r'(?
379 | '4' +
380 | match.input.substring(match.start, match.end) +
381 | '0');
382 |
383 | // Links
384 |
385 | s = s.replaceAllMapped(RegExp(r'(!)?\[[^\]]*\]\([^\)]+\)'), (match) {
386 | var str = match.input.substring(match.start, match.end);
387 | String out = '';
388 | if (str.startsWith('!')) {
389 | str = str.substring(1);
390 | out += '4!';
391 | }
392 | String title = str.substring(1).split(']').first;
393 |
394 | out +=
395 | '7[0$title7]';
396 |
397 | str = str.substring(title.length + 2);
398 |
399 | out += '4' + str + '0';
400 |
401 | return out;
402 | });
403 |
404 | s = '0$s';
405 |
406 | for (var part in s.split('')) {
407 | TextStyle style = styles[part[0]];
408 |
409 | lsSpans.add(TextSpan(
410 | text: part.substring(1),
411 | style: style,
412 | ));
413 | /* if (part == '*') {
414 | lsSpans.add(TextSpan(
415 | text: str, style: TextStyle(fontWeight: FontWeight.bold)));
416 | str = '';
417 | } */
418 | }
419 |
420 |
421 | if (i < texts.length) {
422 | lsSpans.add(TextSpan(text: '\n'));
423 | }
424 | });
425 | return lsSpans;
426 | }
427 | }
428 |
--------------------------------------------------------------------------------
/lib/page/settings.dart:
--------------------------------------------------------------------------------
1 | import 'dart:io';
2 | import 'dart:math';
3 |
4 | import 'package:file_picker/file_picker.dart';
5 | import 'package:flutter/material.dart';
6 | import 'package:app/provider/theme.dart';
7 | import 'package:app/store/notes.dart';
8 | import 'package:permission_handler/permission_handler.dart';
9 | import 'package:path_provider/path_provider.dart';
10 | import 'package:preferences/preferences.dart';
11 | import 'package:preferences/radio_preference.dart';
12 | import 'package:provider/provider.dart';
13 |
14 | class SettingsPage extends StatefulWidget {
15 | final NotesStore store;
16 | SettingsPage(this.store);
17 | @override
18 | _SettingsPageState createState() => _SettingsPageState();
19 | }
20 |
21 | class _SettingsPageState extends State {
22 | NotesStore get store => widget.store;
23 | @override
24 | void initState() {
25 | PrefService.setDefaultValues({
26 | 'sync': '',
27 | 'sync_webdav_host': '',
28 | 'sync_webdav_path': '',
29 | 'sync_webdav_username': '',
30 | 'sync_webdav_password': '',
31 | 'theme': 'light',
32 | 'search_content': true,
33 | 'editor_mode_switcher': true,
34 | 'editor_pair_brackets': false,
35 | 'notes_list_virtual_tags': false,
36 | 'debug_logs_sync': false,
37 | 'editor_auto_save': false,
38 | 'dendron_mode': false,
39 | 'sort_tags_in_sidebar': true,
40 | });
41 | super.initState();
42 | }
43 |
44 | @override
45 | Widget build(BuildContext context) {
46 | return Scaffold(
47 | appBar: AppBar(
48 | title: Text('Settings'),
49 | ),
50 | body: ListView(children: [
51 | PreferenceTitle('Theme'),
52 | RadioPreference(
53 | 'Light',
54 | 'light',
55 | 'theme',
56 | isDefault: true,
57 | onSelect: () {
58 | Provider.of(context, listen: false)
59 | .updateTheme('light');
60 | },
61 | ),
62 | RadioPreference(
63 | 'Dark',
64 | 'dark',
65 | 'theme',
66 | onSelect: () {
67 | Provider.of(context, listen: false)
68 | .updateTheme('dark');
69 | },
70 | ),
71 | RadioPreference(
72 | 'Black / AMOLED',
73 | 'black',
74 | 'theme',
75 | onSelect: () {
76 | Provider.of(context, listen: false)
77 | .updateTheme('black');
78 | },
79 | ),
80 | ListTile(
81 | title: Text('Accent Color'),
82 | trailing: Padding(
83 | padding: const EdgeInsets.only(right: 9, left: 9),
84 | child: Container(
85 | decoration: BoxDecoration(
86 | border: Border.all(),
87 | color: Color(PrefService.getInt('theme_color') ?? 0xff21d885),
88 | ),
89 | child: SizedBox(
90 | width: 28,
91 | height: 28,
92 | ),
93 | ),
94 | ),
95 | onTap: () async {
96 | Color color = await showDialog(
97 | context: context,
98 | builder: (context) => AlertDialog(
99 | title: Text('Select accent color'),
100 | content: Container(
101 | child: GridView.count(
102 | crossAxisCount: 5,
103 | children: [
104 | for (Color color in [
105 | Color(0xff21d885),
106 | ...Colors.primaries,
107 | ...Colors.accents,
108 | ])
109 | InkWell(
110 | child: Container(
111 | margin: const EdgeInsets.all(5),
112 | color: color,
113 | ),
114 | onTap: () {
115 | Navigator.of(context).pop(color);
116 | },
117 | )
118 | ],
119 | ),
120 | width: MediaQuery.of(context).size.width * .7,
121 | ),
122 | actions: [
123 | FlatButton(
124 | child: Text('Cancel'),
125 | onPressed: () {
126 | Navigator.of(context).pop();
127 | },
128 | ),
129 | ],
130 | ));
131 | if (color != null) {
132 | PrefService.setInt('theme_color', color.value);
133 |
134 | Provider.of(context, listen: false).accentColor =
135 | color;
136 | }
137 | },
138 | ),
139 | if (Platform.isAndroid) ...[
140 | PreferenceTitle('Data Directory'),
141 | SwitchPreference(
142 | 'Use external storage',
143 | 'notable_external_directory_enabled',
144 | onChange: () async {
145 | if (PrefService.getString('notable_external_directory') == null) {
146 | PrefService.setString('notable_external_directory',
147 | (await getExternalStorageDirectory()).path);
148 | }
149 |
150 | await store.listNotes();
151 | await store.filterAndSortNotes();
152 | await store.updateTagList();
153 |
154 | if (mounted) setState(() {});
155 | },
156 | ),
157 | PreferenceHider([
158 | ListTile(
159 | title: Text('Location'),
160 | subtitle: Text(
161 | PrefService.getString('notable_external_directory') ?? '',
162 | ),
163 | onTap: () async {
164 | Directory dir;
165 |
166 | final dirStr = await _pickExternalDir();
167 |
168 | if (dirStr == null) {
169 | return;
170 | }
171 |
172 | dir = Directory(dirStr);
173 |
174 | if (dir != null) {
175 | showDialog(
176 | context: context,
177 | builder: (context) => AlertDialog(
178 | title: ListTile(
179 | leading: CircularProgressIndicator(),
180 | title: Text('Processing files...'),
181 | ),
182 | ),
183 | barrierDismissible: false,
184 | );
185 | PrefService.setString('notable_external_directory', dir.path);
186 |
187 | await store.listNotes();
188 | await store.filterAndSortNotes();
189 | await store.updateTagList();
190 | setState(() {});
191 | Navigator.of(context).pop();
192 | }
193 | },
194 | ),
195 | ], '!notable_external_directory_enabled'),
196 | ],
197 | PreferenceTitle('Editor'),
198 | SwitchPreference(
199 | 'Auto Save',
200 | 'editor_auto_save',
201 | ),
202 | SwitchPreference(
203 | 'Use Mode Switcher',
204 | 'editor_mode_switcher',
205 | ),
206 | SwitchPreference(
207 | 'Pair Brackets/Quotes',
208 | 'editor_pair_brackets',
209 | ),
210 | PreferenceTitle('Search'),
211 | SwitchPreference(
212 | 'Search content of notes',
213 | 'search_content',
214 | ),
215 | PreferenceTitle('Tags'),
216 | SwitchPreference(
217 | 'Sort tags alphabetically in the sidebar',
218 | 'sort_tags_in_sidebar',
219 | ),
220 | PreferenceTitle('Preview'),
221 | SwitchPreference(
222 | 'Enable single line break syntax',
223 | 'single_line_break_syntax',
224 | desc:
225 | 'When enabled, single line breaks are rendered as real line breaks',
226 | ),
227 | /* PreferenceTitle('Sync'),
228 | RadioPreference(
229 | 'No Sync',
230 | '',
231 | 'sync',
232 | isDefault: true,
233 | onSelect: () {
234 | setState(() {
235 | store.syncMethod = '';
236 | });
237 | },
238 | ),
239 | RadioPreference(
240 | 'WebDav Sync',
241 | 'webdav',
242 | 'sync',
243 | onSelect: () {
244 | setState(() {
245 | store.syncMethod = 'webdav';
246 | });
247 | },
248 | ),
249 | if (store.syncMethod == 'webdav')
250 | Column(
251 | children: [
252 | Padding(
253 | padding: const EdgeInsets.symmetric(horizontal: 16),
254 | child: Text(
255 | 'WARNING: WebDav Sync is not supported! Please use another app to sync if possible (Syncthing is recommended) and do NOT use it for important data or accounts! ',
256 | style: TextStyle(color: Colors.red),
257 | ),
258 | ),
259 | TextFieldPreference(
260 | 'Host',
261 | 'sync_webdav_host',
262 | hintText: 'mynextcloud.tld/remote.php/webdav/',
263 | ),
264 | TextFieldPreference(
265 | 'Path',
266 | 'sync_webdav_path',
267 | hintText: 'notable',
268 | ),
269 | TextFieldPreference('Username', 'sync_webdav_username'),
270 | TextFieldPreference(
271 | 'Password',
272 | 'sync_webdav_password',
273 | obscureText: true,
274 | ),
275 | ],
276 | ),
277 | */
278 | PreferenceTitle('More'),
279 | ListTile(
280 | title: Text('Recreate tutorial notes'),
281 | onTap: () async {
282 | if (await showDialog(
283 | context: context,
284 | builder: (context) => AlertDialog(
285 | title: Text(
286 | 'Do you want to recreate the tutorial notes and attachments?'),
287 | actions: [
288 | FlatButton(
289 | child: Text('Cancel'),
290 | onPressed: () {
291 | Navigator.of(context).pop(false);
292 | },
293 | ),
294 | FlatButton(
295 | child: Text('Recreate'),
296 | onPressed: () {
297 | Navigator.of(context).pop(true);
298 | },
299 | )
300 | ],
301 | )) ??
302 | false) {
303 | await store.createTutorialNotes();
304 | await store.createTutorialAttachments();
305 | await store.listNotes();
306 | await store.filterAndSortNotes();
307 | await store.updateTagList();
308 | }
309 | },
310 | ),
311 | /* PreferenceTitle('Debug'),
312 | SwitchPreference(
313 | 'Create sync logfile ',
314 | 'debug_logs_sync',
315 | ), */
316 | PreferenceTitle('Experimental'),
317 | SwitchPreference(
318 | 'Enable Dendron support',
319 | 'dendron_mode',
320 | desc: 'Dendron is a VSCode-based note-taking tool',
321 | onChange: () async {
322 | await store.listNotes();
323 | await store.filterAndSortNotes();
324 | await store.updateTagList();
325 |
326 | if (mounted) setState(() {});
327 | },
328 | ),
329 | SwitchPreference(
330 | 'Automatic bullet points',
331 | 'auto_bullet_points',
332 | desc:
333 | 'Adds a bullet point to a new line if the line before it had one',
334 | ),
335 | SwitchPreference(
336 | 'Show virtual tags',
337 | 'notes_list_virtual_tags',
338 | desc:
339 | 'Adds a virtual tag (#/path) to notes which are in a subdirectory',
340 | ),
341 | ]),
342 | );
343 | }
344 |
345 | Future _pickExternalDir() async {
346 | if (!await Permission.storage.request().isGranted) {
347 | return null;
348 | }
349 |
350 | var dir = await FilePicker.platform.getDirectoryPath();
351 | if ((dir ?? '').isNotEmpty) {
352 | if (await _checkIfDirectoryIsWritable(dir)) {
353 | return dir;
354 | }
355 | }
356 |
357 | if ((await Permission.storage.request()).isDenied) {
358 | return null;
359 | }
360 |
361 | var externalDir = await getExternalStorageDirectory();
362 | if (await _checkIfDirectoryIsWritable(externalDir.path)) {
363 | return externalDir.path;
364 | }
365 | return null;
366 | }
367 |
368 | Future _checkIfDirectoryIsWritable(String path) async {
369 | final testFile = File('$path/${Random().nextInt(1000000)}');
370 |
371 | try {
372 | await testFile.create(recursive: true);
373 | await testFile.writeAsString("This is only a test file, please ignore.");
374 | await testFile.delete();
375 | } catch (e) {
376 | return false;
377 | }
378 | return true;
379 | }
380 | }
381 |
--------------------------------------------------------------------------------
/pubspec.lock:
--------------------------------------------------------------------------------
1 | # Generated by pub
2 | # See https://dart.dev/tools/pub/glossary#lockfile
3 | packages:
4 | args:
5 | dependency: transitive
6 | description:
7 | name: args
8 | url: "https://pub.dartlang.org"
9 | source: hosted
10 | version: "1.6.0"
11 | bsdiff:
12 | dependency: "direct main"
13 | description:
14 | name: bsdiff
15 | url: "https://pub.dartlang.org"
16 | source: hosted
17 | version: "0.1.0"
18 | characters:
19 | dependency: transitive
20 | description:
21 | name: characters
22 | url: "https://pub.dartlang.org"
23 | source: hosted
24 | version: "1.1.0"
25 | charcode:
26 | dependency: transitive
27 | description:
28 | name: charcode
29 | url: "https://pub.dartlang.org"
30 | source: hosted
31 | version: "1.1.3"
32 | clock:
33 | dependency: transitive
34 | description:
35 | name: clock
36 | url: "https://pub.dartlang.org"
37 | source: hosted
38 | version: "1.1.0"
39 | collection:
40 | dependency: transitive
41 | description:
42 | name: collection
43 | url: "https://pub.dartlang.org"
44 | source: hosted
45 | version: "1.15.0"
46 | crypto:
47 | dependency: transitive
48 | description:
49 | name: crypto
50 | url: "https://pub.dartlang.org"
51 | source: hosted
52 | version: "3.0.0"
53 | csslib:
54 | dependency: transitive
55 | description:
56 | name: csslib
57 | url: "https://pub.dartlang.org"
58 | source: hosted
59 | version: "0.16.2"
60 | device_info:
61 | dependency: "direct main"
62 | description:
63 | name: device_info
64 | url: "https://pub.dartlang.org"
65 | source: hosted
66 | version: "2.0.0"
67 | device_info_platform_interface:
68 | dependency: transitive
69 | description:
70 | name: device_info_platform_interface
71 | url: "https://pub.dartlang.org"
72 | source: hosted
73 | version: "2.0.1"
74 | ffi:
75 | dependency: transitive
76 | description:
77 | name: ffi
78 | url: "https://pub.dartlang.org"
79 | source: hosted
80 | version: "1.0.0"
81 | file:
82 | dependency: transitive
83 | description:
84 | name: file
85 | url: "https://pub.dartlang.org"
86 | source: hosted
87 | version: "6.1.0"
88 | file_picker:
89 | dependency: "direct main"
90 | description:
91 | name: file_picker
92 | url: "https://pub.dartlang.org"
93 | source: hosted
94 | version: "3.0.0"
95 | flutter:
96 | dependency: "direct main"
97 | description: flutter
98 | source: sdk
99 | version: "0.0.0"
100 | flutter_markdown:
101 | dependency: "direct main"
102 | description:
103 | name: flutter_markdown
104 | url: "https://pub.dartlang.org"
105 | source: hosted
106 | version: "0.4.4"
107 | flutter_plugin_android_lifecycle:
108 | dependency: transitive
109 | description:
110 | name: flutter_plugin_android_lifecycle
111 | url: "https://pub.dartlang.org"
112 | source: hosted
113 | version: "2.0.0"
114 | flutter_slidable:
115 | dependency: "direct main"
116 | description:
117 | name: flutter_slidable
118 | url: "https://pub.dartlang.org"
119 | source: hosted
120 | version: "0.5.7"
121 | flutter_web_plugins:
122 | dependency: transitive
123 | description: flutter
124 | source: sdk
125 | version: "0.0.0"
126 | front_matter:
127 | dependency: "direct main"
128 | description:
129 | name: front_matter
130 | url: "https://pub.dartlang.org"
131 | source: hosted
132 | version: "1.1.0"
133 | html:
134 | dependency: "direct main"
135 | description:
136 | name: html
137 | url: "https://pub.dartlang.org"
138 | source: hosted
139 | version: "0.14.0+4"
140 | intl:
141 | dependency: "direct main"
142 | description:
143 | name: intl
144 | url: "https://pub.dartlang.org"
145 | source: hosted
146 | version: "0.17.0"
147 | js:
148 | dependency: transitive
149 | description:
150 | name: js
151 | url: "https://pub.dartlang.org"
152 | source: hosted
153 | version: "0.6.3"
154 | markd:
155 | dependency: "direct main"
156 | description:
157 | path: "."
158 | ref: HEAD
159 | resolved-ref: af66d9941323d68764c940ba29031f9eac32fda4
160 | url: "https://github.com/redsolver/markd.git"
161 | source: git
162 | version: "2.1.3+7"
163 | markdown:
164 | dependency: transitive
165 | description:
166 | name: markdown
167 | url: "https://pub.dartlang.org"
168 | source: hosted
169 | version: "2.1.8"
170 | matcher:
171 | dependency: transitive
172 | description:
173 | name: matcher
174 | url: "https://pub.dartlang.org"
175 | source: hosted
176 | version: "0.12.10"
177 | material_design_icons_flutter:
178 | dependency: "direct main"
179 | description:
180 | name: material_design_icons_flutter
181 | url: "https://pub.dartlang.org"
182 | source: hosted
183 | version: "4.0.5655"
184 | meta:
185 | dependency: transitive
186 | description:
187 | name: meta
188 | url: "https://pub.dartlang.org"
189 | source: hosted
190 | version: "1.3.0"
191 | nested:
192 | dependency: transitive
193 | description:
194 | name: nested
195 | url: "https://pub.dartlang.org"
196 | source: hosted
197 | version: "0.0.4"
198 | package_info:
199 | dependency: "direct main"
200 | description:
201 | name: package_info
202 | url: "https://pub.dartlang.org"
203 | source: hosted
204 | version: "0.4.3"
205 | path:
206 | dependency: transitive
207 | description:
208 | name: path
209 | url: "https://pub.dartlang.org"
210 | source: hosted
211 | version: "1.8.0"
212 | path_provider:
213 | dependency: "direct main"
214 | description:
215 | name: path_provider
216 | url: "https://pub.dartlang.org"
217 | source: hosted
218 | version: "2.0.1"
219 | path_provider_linux:
220 | dependency: transitive
221 | description:
222 | name: path_provider_linux
223 | url: "https://pub.dartlang.org"
224 | source: hosted
225 | version: "2.0.0"
226 | path_provider_macos:
227 | dependency: transitive
228 | description:
229 | name: path_provider_macos
230 | url: "https://pub.dartlang.org"
231 | source: hosted
232 | version: "2.0.0"
233 | path_provider_platform_interface:
234 | dependency: transitive
235 | description:
236 | name: path_provider_platform_interface
237 | url: "https://pub.dartlang.org"
238 | source: hosted
239 | version: "2.0.1"
240 | path_provider_windows:
241 | dependency: transitive
242 | description:
243 | name: path_provider_windows
244 | url: "https://pub.dartlang.org"
245 | source: hosted
246 | version: "2.0.0"
247 | permission_handler:
248 | dependency: "direct main"
249 | description:
250 | name: permission_handler
251 | url: "https://pub.dartlang.org"
252 | source: hosted
253 | version: "6.1.0"
254 | permission_handler_platform_interface:
255 | dependency: transitive
256 | description:
257 | name: permission_handler_platform_interface
258 | url: "https://pub.dartlang.org"
259 | source: hosted
260 | version: "3.1.0"
261 | platform:
262 | dependency: transitive
263 | description:
264 | name: platform
265 | url: "https://pub.dartlang.org"
266 | source: hosted
267 | version: "3.0.0"
268 | plugin_platform_interface:
269 | dependency: transitive
270 | description:
271 | name: plugin_platform_interface
272 | url: "https://pub.dartlang.org"
273 | source: hosted
274 | version: "2.0.0"
275 | preferences:
276 | dependency: "direct main"
277 | description:
278 | name: preferences
279 | url: "https://pub.dartlang.org"
280 | source: hosted
281 | version: "5.2.1"
282 | process:
283 | dependency: transitive
284 | description:
285 | name: process
286 | url: "https://pub.dartlang.org"
287 | source: hosted
288 | version: "4.1.0"
289 | provider:
290 | dependency: "direct main"
291 | description:
292 | name: provider
293 | url: "https://pub.dartlang.org"
294 | source: hosted
295 | version: "4.3.2+2"
296 | quick_actions:
297 | dependency: "direct main"
298 | description:
299 | name: quick_actions
300 | url: "https://pub.dartlang.org"
301 | source: hosted
302 | version: "0.4.0+9"
303 | quiver:
304 | dependency: "direct main"
305 | description:
306 | name: quiver
307 | url: "https://pub.dartlang.org"
308 | source: hosted
309 | version: "3.0.0"
310 | receive_sharing_intent:
311 | dependency: "direct main"
312 | description:
313 | name: receive_sharing_intent
314 | url: "https://pub.dartlang.org"
315 | source: hosted
316 | version: "1.4.1"
317 | rich_code_editor:
318 | dependency: "direct main"
319 | description:
320 | path: "."
321 | ref: HEAD
322 | resolved-ref: dd57cc6f808f2bb125c458eba016edb85f1ebaaa
323 | url: "https://github.com/bats64mgutsi/rich_code_editor.git"
324 | source: git
325 | version: "1.0.5"
326 | shared_preferences:
327 | dependency: "direct overridden"
328 | description:
329 | name: shared_preferences
330 | url: "https://pub.dartlang.org"
331 | source: hosted
332 | version: "2.0.4"
333 | shared_preferences_linux:
334 | dependency: transitive
335 | description:
336 | name: shared_preferences_linux
337 | url: "https://pub.dartlang.org"
338 | source: hosted
339 | version: "2.0.0"
340 | shared_preferences_macos:
341 | dependency: transitive
342 | description:
343 | name: shared_preferences_macos
344 | url: "https://pub.dartlang.org"
345 | source: hosted
346 | version: "2.0.0"
347 | shared_preferences_platform_interface:
348 | dependency: transitive
349 | description:
350 | name: shared_preferences_platform_interface
351 | url: "https://pub.dartlang.org"
352 | source: hosted
353 | version: "2.0.0"
354 | shared_preferences_web:
355 | dependency: transitive
356 | description:
357 | name: shared_preferences_web
358 | url: "https://pub.dartlang.org"
359 | source: hosted
360 | version: "2.0.0"
361 | shared_preferences_windows:
362 | dependency: transitive
363 | description:
364 | name: shared_preferences_windows
365 | url: "https://pub.dartlang.org"
366 | source: hosted
367 | version: "2.0.0"
368 | sky_engine:
369 | dependency: transitive
370 | description: flutter
371 | source: sdk
372 | version: "0.0.99"
373 | source_span:
374 | dependency: transitive
375 | description:
376 | name: source_span
377 | url: "https://pub.dartlang.org"
378 | source: hosted
379 | version: "1.7.0"
380 | stack_trace:
381 | dependency: transitive
382 | description:
383 | name: stack_trace
384 | url: "https://pub.dartlang.org"
385 | source: hosted
386 | version: "1.10.0"
387 | string_scanner:
388 | dependency: transitive
389 | description:
390 | name: string_scanner
391 | url: "https://pub.dartlang.org"
392 | source: hosted
393 | version: "1.0.5"
394 | term_glyph:
395 | dependency: transitive
396 | description:
397 | name: term_glyph
398 | url: "https://pub.dartlang.org"
399 | source: hosted
400 | version: "1.1.0"
401 | typed_data:
402 | dependency: transitive
403 | description:
404 | name: typed_data
405 | url: "https://pub.dartlang.org"
406 | source: hosted
407 | version: "1.3.0"
408 | url_launcher:
409 | dependency: "direct main"
410 | description:
411 | name: url_launcher
412 | url: "https://pub.dartlang.org"
413 | source: hosted
414 | version: "6.0.2"
415 | url_launcher_linux:
416 | dependency: transitive
417 | description:
418 | name: url_launcher_linux
419 | url: "https://pub.dartlang.org"
420 | source: hosted
421 | version: "2.0.0"
422 | url_launcher_macos:
423 | dependency: transitive
424 | description:
425 | name: url_launcher_macos
426 | url: "https://pub.dartlang.org"
427 | source: hosted
428 | version: "2.0.0"
429 | url_launcher_platform_interface:
430 | dependency: transitive
431 | description:
432 | name: url_launcher_platform_interface
433 | url: "https://pub.dartlang.org"
434 | source: hosted
435 | version: "2.0.2"
436 | url_launcher_web:
437 | dependency: transitive
438 | description:
439 | name: url_launcher_web
440 | url: "https://pub.dartlang.org"
441 | source: hosted
442 | version: "2.0.0"
443 | url_launcher_windows:
444 | dependency: transitive
445 | description:
446 | name: url_launcher_windows
447 | url: "https://pub.dartlang.org"
448 | source: hosted
449 | version: "2.0.0"
450 | uuid:
451 | dependency: "direct main"
452 | description:
453 | name: uuid
454 | url: "https://pub.dartlang.org"
455 | source: hosted
456 | version: "3.0.3"
457 | vector_math:
458 | dependency: transitive
459 | description:
460 | name: vector_math
461 | url: "https://pub.dartlang.org"
462 | source: hosted
463 | version: "2.1.0"
464 | webview_flutter:
465 | dependency: "direct main"
466 | description:
467 | name: webview_flutter
468 | url: "https://pub.dartlang.org"
469 | source: hosted
470 | version: "1.0.1"
471 | win32:
472 | dependency: transitive
473 | description:
474 | name: win32
475 | url: "https://pub.dartlang.org"
476 | source: hosted
477 | version: "2.0.4"
478 | xdg_directories:
479 | dependency: transitive
480 | description:
481 | name: xdg_directories
482 | url: "https://pub.dartlang.org"
483 | source: hosted
484 | version: "0.2.0"
485 | yaml:
486 | dependency: "direct main"
487 | description:
488 | name: yaml
489 | url: "https://pub.dartlang.org"
490 | source: hosted
491 | version: "2.2.1"
492 | sdks:
493 | dart: ">=2.12.0 <3.0.0"
494 | flutter: ">=1.22.0"
495 |
--------------------------------------------------------------------------------