Showing preview only (1,200K chars total). Download the full file or copy to clipboard to get everything.
Repository: tmaegel/ntodotxt
Branch: main
Commit: 8a3f0c0829bf
Files: 206
Total size: 1.1 MB
Directory structure:
gitextract_y8tbwi3d/
├── .devcontainer/
│ ├── Dockerfile
│ └── devcontainer.json
├── .github/
│ ├── dependabot.yml
│ └── workflows/
│ ├── ci.yaml
│ └── release.yaml
├── .gitignore
├── .gitmodules
├── .metadata
├── .pre-commit-config.yaml
├── .vscode/
│ └── tasks.json
├── .yamlfmt
├── CHANGELOG.md
├── Caddyfile
├── Dockerfile_fdroid
├── LICENSE
├── Makefile
├── README.md
├── analysis_options.yaml
├── android/
│ ├── .gitignore
│ ├── app/
│ │ ├── build.gradle
│ │ └── src/
│ │ ├── debug/
│ │ │ └── AndroidManifest.xml
│ │ ├── main/
│ │ │ ├── AndroidManifest.xml
│ │ │ ├── kotlin/
│ │ │ │ └── de/
│ │ │ │ └── tnmgl/
│ │ │ │ └── ntodotxt/
│ │ │ │ └── MainActivity.kt
│ │ │ └── res/
│ │ │ ├── drawable/
│ │ │ │ └── launch_background.xml
│ │ │ ├── drawable-v21/
│ │ │ │ └── launch_background.xml
│ │ │ ├── values/
│ │ │ │ └── styles.xml
│ │ │ └── values-night/
│ │ │ └── styles.xml
│ │ └── profile/
│ │ └── AndroidManifest.xml
│ ├── build.gradle
│ ├── gradle/
│ │ └── wrapper/
│ │ └── gradle-wrapper.properties
│ ├── gradle.properties
│ └── settings.gradle
├── docker-compose.yaml
├── emulatorctl
├── fonts/
│ └── LICENSE
├── integration_test/
│ ├── login/
│ │ └── login_integration_test.dart
│ ├── preview_app_integration_test.dart
│ ├── screenshot_integration_test.dart
│ └── webdav/
│ └── client/
│ └── webdav_client_test.dart
├── ios/
│ ├── .gitignore
│ ├── Flutter/
│ │ ├── AppFrameworkInfo.plist
│ │ ├── Debug.xcconfig
│ │ └── Release.xcconfig
│ ├── Runner/
│ │ ├── AppDelegate.swift
│ │ ├── Assets.xcassets/
│ │ │ ├── AppIcon.appiconset/
│ │ │ │ └── Contents.json
│ │ │ └── LaunchImage.imageset/
│ │ │ ├── Contents.json
│ │ │ └── README.md
│ │ ├── Base.lproj/
│ │ │ ├── LaunchScreen.storyboard
│ │ │ └── Main.storyboard
│ │ ├── Info.plist
│ │ └── Runner-Bridging-Header.h
│ ├── Runner.xcodeproj/
│ │ ├── project.pbxproj
│ │ ├── project.xcworkspace/
│ │ │ ├── contents.xcworkspacedata
│ │ │ └── xcshareddata/
│ │ │ ├── IDEWorkspaceChecks.plist
│ │ │ └── WorkspaceSettings.xcsettings
│ │ └── xcshareddata/
│ │ └── xcschemes/
│ │ └── Runner.xcscheme
│ ├── Runner.xcworkspace/
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata/
│ │ ├── IDEWorkspaceChecks.plist
│ │ └── WorkspaceSettings.xcsettings
│ └── RunnerTests/
│ └── RunnerTests.swift
├── lib/
│ ├── adaptive_layout/
│ │ └── widget/
│ │ └── adaptive_layout.dart
│ ├── app_info/
│ │ └── page/
│ │ └── app_details_page.dart
│ ├── common/
│ │ ├── bloc_observer.dart
│ │ ├── constants/
│ │ │ └── app.dart
│ │ ├── exception/
│ │ │ └── exceptions.dart
│ │ ├── misc.dart
│ │ ├── router/
│ │ │ └── router.dart
│ │ ├── theme/
│ │ │ └── theme.dart
│ │ └── widget/
│ │ ├── app_bar.dart
│ │ ├── chip.dart
│ │ ├── confirm_dialog.dart
│ │ ├── contexts_dialog.dart
│ │ ├── date_picker.dart
│ │ ├── filter_dialog.dart
│ │ ├── group_by_dialog.dart
│ │ ├── info_dialog.dart
│ │ ├── input_dialog.dart
│ │ ├── key_values_dialog.dart
│ │ ├── order_dialog.dart
│ │ ├── priorities_dialog.dart
│ │ ├── projects_dialog.dart
│ │ ├── scroll_to_top.dart
│ │ └── tag_dialog.dart
│ ├── database/
│ │ └── controller/
│ │ └── database.dart
│ ├── drawer/
│ │ ├── state/
│ │ │ ├── drawer_cubit.dart
│ │ │ └── drawer_state.dart
│ │ └── widget/
│ │ └── drawer.dart
│ ├── filter/
│ │ ├── controller/
│ │ │ ├── fake_filter_controller.dart
│ │ │ └── filter_controller.dart
│ │ ├── model/
│ │ │ └── filter_model.dart
│ │ ├── page/
│ │ │ ├── filter_create_edit_page.dart
│ │ │ └── filter_list_page.dart
│ │ ├── repository/
│ │ │ └── filter_repository.dart
│ │ ├── state/
│ │ │ ├── filter_cubit.dart
│ │ │ ├── filter_list_bloc.dart
│ │ │ ├── filter_list_event.dart
│ │ │ ├── filter_list_state.dart
│ │ │ └── filter_state.dart
│ │ └── widget/
│ │ └── filter_chip.dart
│ ├── intro/
│ │ └── page/
│ │ └── intro_page.dart
│ ├── licenses/
│ │ └── page/
│ │ └── licenses_page.dart
│ ├── login/
│ │ ├── page/
│ │ │ └── login_page.dart
│ │ └── state/
│ │ ├── login_cubit.dart
│ │ └── login_state.dart
│ ├── main.dart
│ ├── oss_licenses.dart
│ ├── setting/
│ │ ├── controller/
│ │ │ ├── fake_setting_controller.dart
│ │ │ └── setting_controller.dart
│ │ ├── model/
│ │ │ └── setting_model.dart
│ │ ├── page/
│ │ │ └── settings_page.dart
│ │ ├── repository/
│ │ │ └── setting_repository.dart
│ │ └── state/
│ │ ├── interaction_settings_cubit.dart
│ │ └── interaction_settings_state.dart
│ ├── todo/
│ │ ├── api/
│ │ │ └── todo_list_api.dart
│ │ ├── model/
│ │ │ └── todo_model.dart
│ │ ├── page/
│ │ │ ├── todo_create_edit_page.dart
│ │ │ ├── todo_list_page.dart
│ │ │ └── todo_search_page.dart
│ │ ├── repository/
│ │ │ └── todo_list_repository.dart
│ │ └── state/
│ │ ├── todo_cubit.dart
│ │ ├── todo_list_bloc.dart
│ │ ├── todo_list_event.dart
│ │ ├── todo_list_state.dart
│ │ └── todo_state.dart
│ ├── todo_file/
│ │ └── state/
│ │ ├── todo_file_cubit.dart
│ │ └── todo_file_state.dart
│ └── webdav/
│ └── client/
│ └── webdav_client.dart
├── linux/
│ ├── .gitignore
│ ├── CMakeLists.txt
│ ├── flutter/
│ │ └── CMakeLists.txt
│ ├── main.cc
│ ├── my_application.cc
│ └── my_application.h
├── macos/
│ ├── .gitignore
│ ├── Flutter/
│ │ ├── Flutter-Debug.xcconfig
│ │ └── Flutter-Release.xcconfig
│ ├── Runner/
│ │ ├── AppDelegate.swift
│ │ ├── Assets.xcassets/
│ │ │ └── AppIcon.appiconset/
│ │ │ └── Contents.json
│ │ ├── Base.lproj/
│ │ │ └── MainMenu.xib
│ │ ├── Configs/
│ │ │ ├── AppInfo.xcconfig
│ │ │ ├── Debug.xcconfig
│ │ │ ├── Release.xcconfig
│ │ │ └── Warnings.xcconfig
│ │ ├── DebugProfile.entitlements
│ │ ├── Info.plist
│ │ ├── MainFlutterWindow.swift
│ │ └── Release.entitlements
│ ├── Runner.xcodeproj/
│ │ ├── project.pbxproj
│ │ ├── project.xcworkspace/
│ │ │ └── xcshareddata/
│ │ │ └── IDEWorkspaceChecks.plist
│ │ └── xcshareddata/
│ │ └── xcschemes/
│ │ └── Runner.xcscheme
│ ├── Runner.xcworkspace/
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata/
│ │ └── IDEWorkspaceChecks.plist
│ └── RunnerTests/
│ └── RunnerTests.swift
├── metadata/
│ └── en-US/
│ ├── full_description.txt
│ ├── short_description.txt
│ └── title.txt
├── ntodotxt.yaml
├── pubspec.yaml
├── test/
│ ├── common/
│ │ └── widget/
│ │ ├── confirm_dialog_test.dart
│ │ ├── contexts_dialog_test.dart
│ │ ├── default_filter_state_filter_dialog_test.dart
│ │ ├── default_filter_state_group_dialog_test.dart
│ │ ├── default_filter_state_order_dialog_test.dart
│ │ ├── filter_state_filter_dialog_test.dart
│ │ ├── filter_state_group_dialog_test.dart
│ │ ├── filter_state_order_dialog_test.dart
│ │ ├── info_dialog_test.dart
│ │ ├── input_dialog_test.dart
│ │ ├── key_values_dialog_test.dart
│ │ ├── priorities_dialog_test.dart
│ │ └── projects_dialog_test.dart
│ ├── drawer/
│ │ └── state/
│ │ └── drawer_cubit_test.dart
│ ├── filter/
│ │ ├── controller/
│ │ │ └── filter_controller_test.dart
│ │ ├── page/
│ │ │ ├── filter_create_edit_page_test.dart
│ │ │ └── filter_list_page_test.dart
│ │ ├── state/
│ │ │ └── filter_cubit_test.dart
│ │ └── widget/
│ │ └── filter_chip_test.dart
│ ├── login/
│ │ └── page/
│ │ └── webdav_login_view_test.dart
│ ├── setting/
│ │ ├── controller/
│ │ │ └── setting_controller_test.dart
│ │ └── page/
│ │ └── settings_page_test.dart
│ ├── todo/
│ │ ├── api/
│ │ │ └── todo_list_api_test.dart
│ │ ├── model/
│ │ │ └── todo_model_test.dart
│ │ ├── page/
│ │ │ ├── todo_create_edit_page_test.dart
│ │ │ └── todo_list_page_test.dart
│ │ └── state/
│ │ ├── todo_cubit_test.dart
│ │ └── todo_list_bloc_test.dart
│ ├── todo_file/
│ │ └── state/
│ │ ├── todo_file_cubit_test.dart
│ │ └── todo_file_state_test.dart
│ └── webdav/
│ └── client/
│ └── webdav_client_test.dart
├── test_driver/
│ └── screenshot_integration_test.dart
├── web/
│ ├── index.html
│ └── manifest.json
└── windows/
├── .gitignore
├── CMakeLists.txt
├── flutter/
│ └── CMakeLists.txt
└── runner/
├── CMakeLists.txt
├── Runner.rc
├── flutter_window.cpp
├── flutter_window.h
├── main.cpp
├── resource.h
├── runner.exe.manifest
├── utils.cpp
├── utils.h
├── win32_window.cpp
└── win32_window.h
================================================
FILE CONTENTS
================================================
================================================
FILE: .devcontainer/Dockerfile
================================================
FROM mcr.microsoft.com/devcontainers/base:ubuntu-24.04
ENV FLUTTER_CHANNEL="stable"
ENV FLUTTER_VERSION="3.24.5"
ENV FLUTTER_HOME="/home/vscode/flutter"
ENV ANDROID_HOME="/home/vscode/.android-sdk"
ENV ANDROID_USER_HOME="/home/vscode/.android"
ENV ANDROID_PLATFORM_VERSION="36"
ENV ANDROID_BUILD_TOOLS_VERSION="36.0.0"
ENV ANDROID_SYSTEM_IMAGE="system-images;android-${ANDROID_PLATFORM_VERSION};google_apis;x86_64"
ENV DEBIAN_FRONTEND="noninteractive"
ENV PATH=${PATH}:${FLUTTER_HOME}/bin:${ANDROID_HOME}/cmdline-tools/latest/bin:${ANDROID_HOME}/platform-tools:${ANDROID_HOME}/emulator
RUN apt-get update && \
apt-get install -y --no-install-recommends \
clang \
cmake \
curl \
dconf-gsettings-backend \
dconf-service \
gsettings-desktop-schemas \
libcanberra-gtk-module \
libgl1-mesa-dri \
libglu1-mesa \
libgtk-3-dev \
liblzma-dev \
libpulse-dev \
libsecret-1-dev \
libsqlite3-dev \
libstdc++-12-dev \
libx11-xcb1 \
libxcb-cursor0 \
libxcb-xinerama0 \
libxkbcommon-x11-0 \
libxkbfile-dev \
ninja-build \
openjdk-17-jdk-headless \
pkg-config \
unzip \
vim \
wget \
xdg-user-dirs \
xz-utils \
zip && \
apt-get clean -y && \
rm -rf /var/lib/apt/lists/*
RUN mkdir -p ${ANDROID_USER_HOME} ${ANDROID_HOME}/cmdline-tools && \
wget "https://dl.google.com/android/repository/commandlinetools-linux-13114758_latest.zip" -O commandlinetools.zip && \
unzip commandlinetools.zip -d ${ANDROID_HOME}/cmdline-tools && \
mv ${ANDROID_HOME}/cmdline-tools/cmdline-tools ${ANDROID_HOME}/cmdline-tools/latest && \
rm commandlinetools.zip
RUN yes | sdkmanager --licenses && \
sdkmanager --update && \
sdkmanager platform-tools && \
sdkmanager emulator && \
sdkmanager "platforms;android-${ANDROID_PLATFORM_VERSION}" && \
sdkmanager "build-tools;${ANDROID_BUILD_TOOLS_VERSION}" && \
sdkmanager "${ANDROID_SYSTEM_IMAGE}" && \
echo | avdmanager create avd -n android-${ANDROID_PLATFORM_VERSION} -k "${ANDROID_SYSTEM_IMAGE}"
RUN chown -R vscode:vscode ${ANDROID_HOME} && \
chown -R vscode:vscode ${ANDROID_USER_HOME}
RUN mkdir -p ${FLUTTER_HOME} && \
wget "https://storage.googleapis.com/flutter_infra_release/releases/${FLUTTER_CHANNEL}/linux/flutter_linux_${FLUTTER_VERSION}-${FLUTTER_CHANNEL}.tar.xz" \
-O flutter.tar.xz && \
tar xf flutter.tar.xz -C ${FLUTTER_HOME} --strip-components=1 && \
rm flutter.tar.xz && \
chown -R vscode:vscode ${FLUTTER_HOME}
USER vscode
RUN dart --disable-analytics && flutter --disable-analytics
================================================
FILE: .devcontainer/devcontainer.json
================================================
{
"name": "Flutter",
"dockerFile": "Dockerfile",
"remoteUser": "vscode",
"updateRemoteUserUID": true,
"runArgs": ["--device=/dev/dri", "--device=/dev/kvm", "--group-add=video"],
"features": {
"ghcr.io/devcontainers-extra/features/shellcheck:1": {},
"ghcr.io/devcontainers-extra/features/shfmt:1": {},
"ghcr.io/prulloac/devcontainer-features/pre-commit:1": {}
},
"postCreateCommand": "flutter clean && flutter pub get",
"customizations": {
"vscode": {
"extensions": [
"Dart-Code.dart-code",
"Dart-Code.flutter",
"esbenp.prettier-vscode",
"mkhl.shfmt",
"redhat.vscode-yaml"
],
"settings": {
"[dart]": {
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.fixAll": "explicit",
"source.organizeImports": "explicit"
},
"editor.selectionHighlight": false,
"editor.tabCompletion": "onlySnippets",
"editor.wordBasedSuggestions": "off"
},
"[shellscript]": {
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.fixAll.shellcheck": "explicit"
}
},
"shfmt.executableArgs": ["-i", "2", "-s", "-bn", "-ci", "-sr"],
"shellcheck.customArgs": ["-o", "all"],
"shellcheck.enable": true,
"shellcheck.enableQuickFix": true,
"shellcheck.exclude": [],
"[markdown]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[json]": {
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.formatOnSave": true
},
"[jsonc]": {
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.formatOnSave": true
},
"[yaml]": {
"editor.defaultFormatter": "redhat.vscode-yaml",
"editor.formatOnSave": true
}
}
}
},
"containerEnv": {
"DISPLAY": "${localEnv:DISPLAY}",
"XDG_RUNTIME_DIR": "/tmp/vscode-wayland",
"WAYLAND_DISPLAY": "${localEnv:WAYLAND_DISPLAY}",
"GDK_BACKEND": "wayland",
"QT_QPA_PLATFORM": "xcb",
"QT_X11_NO_MITSHM": "1"
},
"mounts": [
"source=${localEnv:XDG_RUNTIME_DIR},target=/tmp/vscode-wayland,type=bind,consistency=cached",
"source=/tmp/.X11-unix,target=/tmp/.X11-unix,type=bind,consistency=cached"
]
}
================================================
FILE: .github/dependabot.yml
================================================
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
version: 2
updates:
- package-ecosystem: "pub"
directory: "/" # Location of package manifests
schedule:
interval: "weekly"
================================================
FILE: .github/workflows/ci.yaml
================================================
name: CI
on:
push:
branches:
- main
pull_request:
branches:
- main
jobs:
test:
name: CI
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install sqlite
run: sudo apt-get update && sudo apt-get -y install sqlite3 libsqlite3-dev
- name: Setup flutter
uses: subosito/flutter-action@v2
with:
flutter-version: '3.24.5'
channel: 'stable'
cache: true
cache-key: flutter-:os:-:channel:-:version:-:arch:-:hash:-${{ hashFiles('**/pubspec.lock') }}
- name: Flutter version
run: flutter --version
- name: Install dependencies
run: flutter pub get
- name: Check licenses
run: |
dart pub global activate very_good_cli
dart pub global run very_good_cli:very_good packages check licenses \
--dependency-type='direct-main,transitive' \
--allowed='MIT,BSD-3-Clause,BSD-2-Clause,Apache-2.0,Zlib'
- name: Analyze code (lint)
run: flutter analyze --fatal-infos --fatal-warnings
- name: Analyze code (format)
run: dart format --set-exit-if-changed .
- name: Run test
run: flutter test --coverage
- name: Check test coverage
uses: VeryGoodOpenSource/very_good_coverage@v2
with:
path: '${{ github.workspace }}/coverage/lcov.info'
min_coverage: 60
================================================
FILE: .github/workflows/release.yaml
================================================
name: Release
on:
push:
tags:
- 'v[0-9]+.[0-9]+.[0-9]+'
env:
PROPERTIES_PATH: "./android/key.properties"
jobs:
build:
name: Build
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install sqlite
run: sudo apt-get update && sudo apt-get -y install sqlite3 libsqlite3-dev
- name: Setup java
uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: '21'
- name: Setup signing environment
run: |
echo keyPassword=\${{ secrets.APP_SIGN_KEY_PASSWORD }} > ${{ env.PROPERTIES_PATH }}
echo storePassword=\${{ secrets.APP_SIGN_STORE_PASSWORD }} >> ${{ env.PROPERTIES_PATH }}
echo keyAlias=\${{ secrets.APP_SIGN_KEY_ALIAS }} >> ${{ env.PROPERTIES_PATH }}
echo storeFile=key.jks >> ${{ env.PROPERTIES_PATH }}
echo "${{ secrets.APP_SIGN_KEY_JKS }}" | base64 --decode > android/app/key.jks
- name: Setup flutter
uses: subosito/flutter-action@v2
with:
flutter-version: '3.24.5'
channel: 'stable'
cache: true
cache-key: flutter-:os:-:channel:-:version:-:arch:-:hash:-${{ hashFiles('**/pubspec.lock') }}
- name: Flutter version
run: flutter --version
- name: Install dependencies
run: flutter pub get
- name: Check licenses
run: |
dart pub global activate very_good_cli
dart pub global run very_good_cli:very_good packages check licenses \
--dependency-type='direct-main,transitive' \
--allowed='MIT,BSD-3-Clause,BSD-2-Clause,Apache-2.0,Zlib'
- name: Analyze code (lint)
run: flutter analyze --fatal-infos --fatal-warnings
- name: Analyze code (format)
run: dart format --set-exit-if-changed .
- name: Run test
run: flutter test --coverage
- name: Check test coverage
uses: VeryGoodOpenSource/very_good_coverage@v2
with:
path: '${{ github.workspace }}/coverage/lcov.info'
exclude: '**/*_observer.dart'
min_coverage: 60
- name: Build appbundle
run: flutter build appbundle --release
- name: Build apk
run: flutter build apk --release
- name: Build apk per ABI
run: flutter build apk --split-per-abi
- name: Release
uses: ncipollo/release-action@v1
with:
owner: ${{ github.repository_owner }}
body: 'See [CHANGELOG](https://github.com/tmaegel/ntodotxt/blob/main/CHANGELOG.md)'
artifacts: >
build/app/outputs/bundle/release/app-release.aab,
build/app/outputs/flutter-apk/app-release.apk,
build/app/outputs/flutter-apk/app-armeabi-v7a-release.apk,
build/app/outputs/flutter-apk/app-arm64-v8a-release.apk,
build/app/outputs/flutter-apk/app-x86_64-release.apk
token: ${{ secrets.PERSONAL_ACCESS_TOKEN }}
================================================
FILE: .gitignore
================================================
# Miscellaneous
*.class
*.lock
*.log
*.pyc
*.swp
.DS_Store
.atom/
.buildlog/
.history
.svn/
# IntelliJ related
*.iml
*.ipr
*.iws
.idea/
# Visual Studio Code related
.classpath
.project
.settings/
# Flutter repo-specific
/bin/cache/
/bin/internal/bootstrap.bat
/bin/internal/bootstrap.sh
/bin/mingit/
/dev/benchmarks/mega_gallery/
/dev/bots/.recipe_deps
/dev/bots/android_tools/
/dev/devicelab/ABresults*.json
/dev/docs/doc/
/dev/docs/flutter.docs.zip
/dev/docs/lib/
/dev/docs/pubspec.yaml
/dev/integration_tests/**/xcuserdata
/dev/integration_tests/**/Pods
/packages/flutter/coverage/
version
analysis_benchmark.json
# packages file containing multi-root paths
.packages.generated
# Flutter/Dart/Pub related
**/doc/api/
.dart_tool/
.flutter-plugins
.flutter-plugins-dependencies
**/generated_plugin_registrant.dart
.packages
.pub-preload-cache/
.pub/
build/
flutter_*.png
linked_*.ds
unlinked.ds
unlinked_spec.ds
# Android related
.android/
**/android/**/gradle-wrapper.jar
.gradle/
**/android/captures/
**/android/gradlew
**/android/gradlew.bat
**/android/local.properties
**/android/**/GeneratedPluginRegistrant.java
**/android/key.properties
*.jks
# iOS/XCode related
**/ios/**/*.mode1v3
**/ios/**/*.mode2v3
**/ios/**/*.moved-aside
**/ios/**/*.pbxuser
**/ios/**/*.perspectivev3
**/ios/**/*sync/
**/ios/**/.sconsign.dblite
**/ios/**/.tags*
**/ios/**/.vagrant/
**/ios/**/DerivedData/
**/ios/**/Icon?
**/ios/**/Pods/
**/ios/**/.symlinks/
**/ios/**/profile
**/ios/**/xcuserdata
**/ios/.generated/
**/ios/Flutter/.last_build_id
**/ios/Flutter/App.framework
**/ios/Flutter/Flutter.framework
**/ios/Flutter/Flutter.podspec
**/ios/Flutter/Generated.xcconfig
**/ios/Flutter/ephemeral
**/ios/Flutter/app.flx
**/ios/Flutter/app.zip
**/ios/Flutter/flutter_assets/
**/ios/Flutter/flutter_export_environment.sh
**/ios/ServiceDefinitions.json
**/ios/Runner/GeneratedPluginRegistrant.*
# macOS
**/Flutter/ephemeral/
**/Pods/
**/macos/Flutter/GeneratedPluginRegistrant.swift
**/macos/Flutter/ephemeral
**/xcuserdata/
# Windows
**/windows/flutter/generated_plugin_registrant.cc
**/windows/flutter/generated_plugin_registrant.h
**/windows/flutter/generated_plugins.cmake
# Linux
**/linux/flutter/generated_plugin_registrant.cc
**/linux/flutter/generated_plugin_registrant.h
**/linux/flutter/generated_plugins.cmake
# Coverage
coverage/
# Symbols
app.*.symbols
# Exceptions to above rules.
!**/ios/**/default.mode1v3
!**/ios/**/default.mode2v3
!**/ios/**/default.pbxuser
!**/ios/**/default.perspectivev3
!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages
!/dev/ci/**/Gemfile.lock
!.vscode/settings.json
docker-compose.yml
.scannerwork/
# devenv
.devenv*
devenv.local.nix
# direnv
.direnv
# nix
!flake.lock
local.properties
================================================
FILE: .gitmodules
================================================
[submodule ".flutter"]
path = .flutter
url = https://github.com/flutter/flutter
================================================
FILE: .metadata
================================================
# This file tracks properties of this Flutter project.
# Used by Flutter tool to assess capabilities and perform upgrades etc.
#
# This file should be version controlled and should not be manually edited.
version:
revision: "db7ef5bf9f59442b0e200a90587e8fa5e0c6336a"
channel: "stable"
project_type: app
# Tracks metadata for the flutter migrate command
migration:
platforms:
- platform: root
create_revision: db7ef5bf9f59442b0e200a90587e8fa5e0c6336a
base_revision: db7ef5bf9f59442b0e200a90587e8fa5e0c6336a
- platform: android
create_revision: db7ef5bf9f59442b0e200a90587e8fa5e0c6336a
base_revision: db7ef5bf9f59442b0e200a90587e8fa5e0c6336a
- platform: ios
create_revision: db7ef5bf9f59442b0e200a90587e8fa5e0c6336a
base_revision: db7ef5bf9f59442b0e200a90587e8fa5e0c6336a
- platform: linux
create_revision: db7ef5bf9f59442b0e200a90587e8fa5e0c6336a
base_revision: db7ef5bf9f59442b0e200a90587e8fa5e0c6336a
- platform: macos
create_revision: db7ef5bf9f59442b0e200a90587e8fa5e0c6336a
base_revision: db7ef5bf9f59442b0e200a90587e8fa5e0c6336a
- platform: web
create_revision: db7ef5bf9f59442b0e200a90587e8fa5e0c6336a
base_revision: db7ef5bf9f59442b0e200a90587e8fa5e0c6336a
- platform: windows
create_revision: db7ef5bf9f59442b0e200a90587e8fa5e0c6336a
base_revision: db7ef5bf9f59442b0e200a90587e8fa5e0c6336a
# User provided section
# List of Local paths (relative to this file) that should be
# ignored by the migrate tool.
#
# Files that are not part of the templates will be ignored by default.
unmanaged_files:
- 'lib/main.dart'
- 'ios/Runner.xcodeproj/project.pbxproj'
================================================
FILE: .pre-commit-config.yaml
================================================
exclude: (^android/|^build/|^coverage/|^ios/|^linux/|^macos/|^web/|^windows/)
fail_fast: true
default_install_hook_types: [pre-commit]
default_stages: [pre-commit]
repos:
- repo: "https://github.com/pre-commit/pre-commit-hooks"
rev: "v4.5.0"
hooks:
- id: check-added-large-files
args: ['--maxkb=1024']
- id: check-case-conflict
- id: pretty-format-json
args: ["--autofix", "--indent=4", "--no-sort-keys"]
- id: check-merge-conflict
- id: check-symlinks
- id: check-yaml
- id: check-json
- id: check-toml
- id: check-xml
- id: destroyed-symlinks
- id: detect-private-key
- id: trailing-whitespace
- id: double-quote-string-fixer
- repo: local
hooks:
- id: dart format
name: dart format
language: system
entry: dart format --set-exit-if-changed
files: \.dart$
- id: flutter analyze
name: flutter analyze
language: system
entry: flutter analyze --fatal-infos --fatal-warnings
files: \.dart$
- id: flutter test
name: flutter test
language: system
entry: flutter test --coverage
pass_filenames: false
- id: test coverage
name: test coverage
language: system
entry: dart run test_cov_console -l
pass_filenames: false
verbose: true
================================================
FILE: .vscode/tasks.json
================================================
{
"version": "2.0.0",
"tasks": [
{
"label": "flutter: run (Linux)",
"type": "shell",
"command": "flutter",
"args": ["run", "-d", "linux"],
"group": "build",
"problemMatcher": []
},
{
"label": "flutter: pub get",
"type": "shell",
"command": "flutter",
"args": ["pub", "get"],
"group": "build",
"problemMatcher": []
},
{
"label": "flutter: clean",
"type": "shell",
"command": "flutter",
"args": ["clean"],
"group": "build",
"problemMatcher": []
}
]
}
================================================
FILE: .yamlfmt
================================================
formatter:
type: basic
include_document_start: false
retain_line_breaks_single: true
trim_trailing_whitespace: true
pad_line_comments: 2
================================================
FILE: CHANGELOG.md
================================================
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased]
## [0.17.0] - 2026-03-13
### Added
- Option to enable or disable swipe-right and swipe-left actions for list items #107
- Option to delete filters via swipe-right action
## [0.16.1] - 2026-01-05
### Fixed
- 204 responses indicate no errors during the ping
## [0.16.0] - 2025-09-26
### Added
- Confirmation dialog when deleting a task with a swipe gesture #102
## [0.15.0] - 2025-09-12
### Added
- Mark todos as done/undone via swipe gesture #42 #80
- Delete todos via swipe gesture
## [0.14.2] - 2025-07-17
### Fixed
- Page rebuild when navigating between filter pages #97
## [0.14.1] - 2025-07-07
### Fixed
- Editing the filter name
- No longer push main routes to the navigator stack
### Added
- Add FloatingActionButton for easy marking of todos as done/undone #95
## [0.14.0] - 2025-06-22
### Added
- Donation link
### Changed
- Allow to choose completion date #83
### Fixed
- Displays initially an empty search result list if no search term has been entered
- Don't allow due dates in the past and completion dates in the future
## [0.13.1] - 2025-06-10
### Changed
- Improvement of the database handling
- No longer prevent landscape mode #88
### Removed
- Deprecated code for backwards compatibility
## [0.13.0] - 2025-05-22
### Changed
- Bump flutter version to 3.24.5
- Bump version of a bunch of dependencies
- Sets default localization to 'en' for date picker #90
## [0.12.4] - 2025-03-29
### Fixed
- Recognize whether a file already exists on the server side
### Changed
- Improvement of path handling
## [0.12.3] - 2025-03-15
### Fixed
- Migrate app data from cache directory to data directory #78 #84
## [0.12.2] - 2025-01-06
### Fixed
- Remove duplicate slash in file path #67, #79
### Added
- Add filter/todo save button to app bar
## [0.12.1] - 2024-12-11
### Fixed
- Deselecting priority
## [0.12.0] - 2024-12-02
### Added
- Checkbox to accept untrusted SSL certificates #72
### Changed
- Removes the save button and adds a save/discard dialog instead when leaving the todo/filter page #61
### Fixed
- Tag dialogs don't show all possible tags
## [0.11.0] - 2024-11-01
## Added
- Possibility to edit the due date without resetting it first #52
- Sort filters alphabetically #50
- Possibility to show and hide the password in the password field
### Changed
- Auto apply changes in priority, project, context and key-value dialogs #65
- Auto apply projects and contexts tags if a new todo is created within the filter page #44
- Context and project tags will no longer change to lower case #64
## [0.10.1] - 2024-09-22
### Changed
- Bump flutter version to 3.19.6
### Fixed
- First word not capitalized #63
- Allow single character key-value pairs #53
## [0.10.0] - 2024-06-09
## Added
- Possibility to configure the remote path and local/remote filename #56
## Removed
- BREAKING CHANGE: The username is no longer automatically appended to webdav base url (reinitialize your app if needed)
## [0.9.1] - 2024-05-23
### Fixed
- No auto-space is inserted after selecting a word from suggestion #36
## [0.9.0] - 2024-05-03
### Added
- Adds the full range of priorities from A to Z #48
### Fixed
- Removes id from the the todo key values #34
## [0.8.1] - 2024-04-25
### Fixed
- Fixes an issue that the file picker was not opened for android api versions lower than 28 #45
## [0.8.0] - 2024-04-01
### Added
- Custome file name of the local todo file while initialization of the app #35
### Changed
- File name and path can no longer be changed after initializing the app #35
- Update splash screen
## [0.7.1] - 2024-03-26
### Changed
- Adjusts configuration of textfield suggestions #36
## [0.7.0] - 2024-03-20
### Added
- Add an intro screen #31
- Highlights filter chip in a different color if filter has updated
- Tags can now also occur inline of a todo on the list view
- Long todos are displayed shortened on the list view
### Changed
- Update login screen #31
- Refactor initial loading and login routines
- Add hint if no tags are available on tag dialog
- Improve error handling and the resulting messages
### Fixed
- Trim whitespaces of filter name before updating
- Fix issue of todo textfield if todo is very long
- Fix small style issues
## [0.6.2] - 2024-03-13
### Fixed
- Requests folder permission on the initial setup screen #30
- Base url may also ends with the username #28
- Updates default filter directly if it has been changed in the settings
- Sorts todos by description only and completed todos come always at last
- Resets settings correctly if logout
## [0.6.1] - 2024-03-05
### Added
- Hide keyboard if tap outside of textfield
### Changed
- Bump file_picker to 6.2.0
- Bump flutter_bloc to 8.1.4
- Bump go_router to 13.2.0
- Bump sqflite_common_ffi to 2.3.2+1
- Bump sqlite3_flutter_libs to 0.5.20
- Bump url_launcher to 6.2.5
- Update style of drawer
- Update style of loading spinner
### Fixed
- Filter todo list on search page correctly
- Order todos for the different filters/groupings correctly
- Keep scroll position of todo list if todo was created or edited
- Solve error while initialization on desktop
## [0.6.0] - 2024-02-28
### Added
- Add new widget tests and refactor existing ones
### Changed
- Disable landscape mode
- Add a confirmation dialog when the app settings are reset
- Improve the appearance of the todo list page
- Make app bar transparent
- Hide floating action button if keyboard is open
- Hide floating action button (save) if todo or filter has not be changed
- Hide floating action button (save) if name todo or filter is empty
### Removed
- Remove the functionality to set the todo completion state by swiping
### Fixed
- Improved error handling on login screen
- Improved text field behavior when creating or editing todos #27
- Prevention of + and @ characters at the beginning of the tag when displayed in the tag dialog
## [0.5.1] - 2024-02-21
### Added
- Hide primary floating action button when scrolling down and show 'go to top' button instead
### Changed
- Remove bottom bar
- Transparent bottom system navigation bar and edge to edge view
- Small style adjustments of the snackbar and loading indicator
- Replace app launcher icon
### Fixed
- Dismiss dialogs on back button
- Resolve some build warnings
- Resolve some minor theme issues
## [0.5.0] - 2024-02-16
### Added
- Add possibility to customize the local path of the todo.txt file #7
- Tests the connection to the webdav before login
### Changed
- Improve the appearance of the login screen
### Fixed
- Activate the previous item in the drawer when navigating back
- Ignore empty lines in todo.txt file
## [0.4.7] - 2024-02-06
### Fixed
- Add missing permission android.permission.INTERNET #20
## [0.4.6] - 2024-02-04
### Fixed
- Pin tag/version of flutter submodule to v3.16.9
## [0.4.5] - 2024-02-03
### Changed
- Bump flutter version to 3.16.9
- Update some dialogs
### Fixed
- Server port for the webdav connection is optional #12 #17
- Sometimes the hamburger menu gets lost #18
- dense attribute is not neccessary for material3 themes
## [0.4.4] - 2024-01-16
### Changed
- Move drawer to appbar (mobile only)
- Redesign todo and filter detail page/view
### Fixed
- Disable allowBackup in AndroidManifest.xml
- Some dialogs are scrollable if the keyboad appears
- Fix regex for hostname validation #8
## [0.4.3] - 2024-01-08
### Changed
- Sign apks
### Fixed
- Add missing `flutter_launcher_icons` dependency
## [0.4.2] - 2024-01-05
### Added
- Add `flutter` as git submodule
## [0.4.1] - 2024-01-05
### Added
- Add metadata (`fastlane`) to get the app ready for deployment in the fdroid store
### Fixed
- Add version code to `pubspec.yaml`
## [0.4.0] - 2024-01-04
### Added
- App icon (made by @colebemis)
- Confirmation dialog for deleting todo or filter
### Changed
- Update drawer (mobile) style
- Disable 'Apply' button in dialogs if unnecessary (e.g. empty list)
- Bump `flutter` to 3.16.5
- Bump `go_router` to 13.0.1
- Bump `url_launcher` to 6.2.2
### Removed
- Remove `google_fonts`
## [0.3.0] - 2023-12-22
### Added
- Add functionality to save and manage filters
- Add database (`sqflite`) and controller to persist data (filter and settings)
- Add simple loading / splash screen while initialize the app
### Changed
- Save default filter settings in sqlite database instead of shared preferences
- Theme and UI improvements and some redesign (app bar, dialogs, ...)
- Replace navigation drawer with bottom sheet (for mobile) and navigation rail (desktop)
### Removed
- Remove dependencie shared_preferences
- Remove todo selection functionality
### Fixed
- Add error state to FilterState and handle/show errors
## [0.2.0] - 2023-12-11
### Added
- Add swipe (left/right) action to toggle the completion of todo
### Changed
- Minor style adjustments to the theme and layout
### Fixed
- Hide tags (projects, contexts, key values) in tag dialog if already present in todo
- Toggle filter/order/group by if tapping on the label
- Notification bars are floating
## [0.1.0] - 2023-12-08
### Added
- Intiial release
[unreleased]: https://github.com/tmaegel/ntodotxt/compare/v0.17.0...HEAD
[0.16.1]: https://github.com/tmaegel/ntodotxt/compare/v0.16.1...v0.17.0
[0.16.1]: https://github.com/tmaegel/ntodotxt/compare/v0.16.0...v0.16.1
[0.16.0]: https://github.com/tmaegel/ntodotxt/compare/v0.15.0...v0.16.0
[0.15.0]: https://github.com/tmaegel/ntodotxt/compare/v0.14.2...v0.15.0
[0.14.2]: https://github.com/tmaegel/ntodotxt/compare/v0.14.1...v0.14.2
[0.14.1]: https://github.com/tmaegel/ntodotxt/compare/v0.14.0...v0.14.1
[0.14.0]: https://github.com/tmaegel/ntodotxt/compare/v0.13.1...v0.14.0
[0.13.1]: https://github.com/tmaegel/ntodotxt/compare/v0.13.0...v0.13.1
[0.13.0]: https://github.com/tmaegel/ntodotxt/compare/v0.12.4...v0.13.0
[0.12.4]: https://github.com/tmaegel/ntodotxt/compare/v0.12.3...v0.12.4
[0.12.3]: https://github.com/tmaegel/ntodotxt/compare/v0.12.2...v0.12.3
[0.12.2]: https://github.com/tmaegel/ntodotxt/compare/v0.12.1...v0.12.2
[0.12.1]: https://github.com/tmaegel/ntodotxt/compare/v0.12.0...v0.12.1
[0.12.0]: https://github.com/tmaegel/ntodotxt/compare/v0.11.0...v0.12.0
[0.11.0]: https://github.com/tmaegel/ntodotxt/compare/v0.10.1...v0.11.0
[0.10.1]: https://github.com/tmaegel/ntodotxt/compare/v0.10.0...v0.10.1
[0.10.0]: https://github.com/tmaegel/ntodotxt/compare/v0.9.1...v0.10.0
[0.9.1]: https://github.com/tmaegel/ntodotxt/compare/v0.9.0...v0.9.1
[0.9.0]: https://github.com/tmaegel/ntodotxt/compare/v0.8.1...v0.9.0
[0.8.1]: https://github.com/tmaegel/ntodotxt/compare/v0.8.0...v0.8.1
[0.8.0]: https://github.com/tmaegel/ntodotxt/compare/v0.7.1...v0.8.0
[0.7.1]: https://github.com/tmaegel/ntodotxt/compare/v0.7.0...v0.7.1
[0.7.0]: https://github.com/tmaegel/ntodotxt/compare/v0.6.2...v0.7.0
[0.6.2]: https://github.com/tmaegel/ntodotxt/compare/v0.6.1...v0.6.2
[0.6.1]: https://github.com/tmaegel/ntodotxt/compare/v0.6.0...v0.6.1
[0.6.0]: https://github.com/tmaegel/ntodotxt/compare/v0.5.1...v0.6.0
[0.5.1]: https://github.com/tmaegel/ntodotxt/compare/v0.5.0...v0.5.1
[0.5.0]: https://github.com/tmaegel/ntodotxt/compare/v0.4.7...v0.5.0
[0.4.7]: https://github.com/tmaegel/ntodotxt/compare/v0.4.6...v0.4.7
[0.4.6]: https://github.com/tmaegel/ntodotxt/compare/v0.4.5...v0.4.6
[0.4.5]: https://github.com/tmaegel/ntodotxt/compare/v0.4.4...v0.4.5
[0.4.4]: https://github.com/tmaegel/ntodotxt/compare/v0.4.3...v0.4.4
[0.4.3]: https://github.com/tmaegel/ntodotxt/compare/v0.4.2...v0.4.3
[0.4.2]: https://github.com/tmaegel/ntodotxt/compare/v0.4.1...v0.4.2
[0.4.1]: https://github.com/tmaegel/ntodotxt/compare/v0.4.0...v0.4.1
[0.4.0]: https://github.com/tmaegel/ntodotxt/compare/v0.3.0...v0.4.0
[0.3.0]: https://github.com/tmaegel/ntodotxt/compare/v0.2.0...v0.3.0
[0.2.0]: https://github.com/tmaegel/ntodotxt/compare/v0.1.0...v0.2.0
[0.1.0]: https://github.com/tmaegel/ntodotxt/releases/tag/v0.1.0
================================================
FILE: Caddyfile
================================================
{
debug
}
localhost {
uri strip_prefix /nc
reverse_proxy nextcloud:80
}
10.0.2.2 {
tls internal
uri strip_prefix /nc
reverse_proxy nextcloud:80
}
================================================
FILE: Dockerfile_fdroid
================================================
FROM registry.gitlab.com/fdroid/docker-executable-fdroidserver:master
RUN apt-get update && apt-get install -y \
openjdk-17-jdk-headless \
&& rm -rf /var/lib/apt/lists/* \
&& update-java-alternatives -a
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) 2023 Toni Mägel
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: Makefile
================================================
.PHONY: screenshots
APP_ID = "de.tnmgl.ntodotxt"
FDROID_REPO = "${HOME}/Downloads/nosync/fdroiddata"
sonarqube:
docker run -d --name sonarqube -e SONAR_ES_BOOTSTRAP_CHECKS_DISABLE=true -p 127.0.0.1:9000:9000 sonarqube:10.4-community
scan:
docker run \
--rm --name sonar-scanner-cli \
-e SONAR_HOST_URL="http://sonarqube:9000" \
-e SONAR_SCANNER_OPTS="-Dsonar.projectKey=ntodotxt" \
-e SONAR_TOKEN="token" \
-v "$(shell pwd):/usr/src" \
--link sonarqube \
sonarsource/sonar-scanner-cli
licenses:
flutter pub run flutter_oss_licenses:generate.dart
icon:
flutter pub run flutter_launcher_icons
integration_env_configure:
docker exec -it -u www-data nextcloud_local php occ config:system:set trusted_domains 2 --value=10.0.2.2
screenshots:
flutter emulators --launch "Pixel_7_API_34_extension_level_7_x86_64" && sleep 10
flutter drive \
--driver=test_driver/screenshot_integration_test.dart \
--target=integration_test/screenshot_integration_test.dart || true
adb emu kill
preview_screenshots:
flutter emulators --launch "Pixel_7_API_34_extension_level_7_x86_64" && sleep 10
flutter drive \
--driver=test_driver/screenshot_integration_test.dart \
--target=integration_test/preview_app_integration_test.dart || true
adb emu kill
fdroid_lint:
cd $(FDROID_REPO) && docker run \
--rm \
--name fdroid \
-v "${HOME}/.android-sdk/":/opt/android-sdk \
-v $(FDROID_REPO):/repo \
-e ANDROID_HOME:/opt/android-sdk \
registry.gitlab.com/fdroid/docker-executable-fdroidserver:master lint -v $(APP_ID)
fdroid_signature:
apksigner verify --print-certs app.apk | grep SHA-256
cd $(FDROID_REPO) && docker run \
--rm \
--name fdroid \
-v "${HOME}/.android-sdk/":/opt/android-sdk \
-v $(FDROID_REPO):/repo \
-e ANDROID_HOME:/opt/android-sdk \
registry.gitlab.com/fdroid/docker-executable-fdroidserver:master signatures unsigned/app.apk
fdroid_build:
docker build -t fdroidserver -f Dockerfile_fdroid .
fdroid_run:
cd $(FDROID_REPO) && docker run \
--rm \
--name fdroid \
-v "${HOME}/.android-sdk/":/opt/android-sdk \
-v $(FDROID_REPO):/repo \
-e ANDROID_HOME:/opt/android-sdk \
fdroidserver build -v -l $(APP_ID)
================================================
FILE: README.md
================================================
# ntodotxt
[](https://github.com/tmaegel/ntodotxt/actions/workflows/ci.yaml)
[](https://github.com/tmaegel/ntodotxt/releases)
[](https://f-droid.org/packages/de.tnmgl.ntodotxt)
[](https://opensource.org/licenses/MIT)
[](https://github.com/flutter/flutter)
With `ntodotxt` you can manage your todos in a [todo.txt](https://github.com/todotxt/todo.txt) file (i.e. all information
is stored in a single file). You can save your todos locally on your device and/or synchronize the todo.txt file via webdav - for
example with a self-hosted nextcloud instance.
This application is under active development and will continue to be modified and improved over time.
## Screenshots
<a href="https://raw.githubusercontent.com/tmaegel/ntodotxt/HEAD/screenshots/preview/1.png"><img src="screenshots/preview/1.png" width="19.2%"/></a>
<a href="https://raw.githubusercontent.com/tmaegel/ntodotxt/HEAD/screenshots/preview/2.png"><img src="screenshots/preview/2.png" width="19.2%"/></a>
<a href="https://raw.githubusercontent.com/tmaegel/ntodotxt/HEAD/screenshots/preview/3.png"><img src="screenshots/preview/3.png" width="19.2%"/></a>
<a href="https://raw.githubusercontent.com/tmaegel/ntodotxt/HEAD/screenshots/preview/4.png"><img src="screenshots/preview/4.png" width="19.2%"/></a>
<a href="https://raw.githubusercontent.com/tmaegel/ntodotxt/HEAD/screenshots/preview/5.png"><img src="screenshots/preview/5.png" width="19.2%"/></a>
## Downloads
[<img src="https://fdroid.gitlab.io/artwork/badge/get-it-on.png" alt="Get it on F-Droid" height="80">](https://f-droid.org/packages/de.tnmgl.ntodotxt/)
## Features
### v1.0
- [x] Manage todos in [todo.txt](https://github.com/todotxt/todo.txt) format
- [x] Manage todos locally and/or synchronize todos via webdav with a server of your choice
- [x] Custom path and filename of todo files (local and remote)
- [x] Search todos
- [x] Create custom views of todos via filters
- [ ] Sort (ascending/descending) todos by criteria such as priority, creation date or due date
- [ ] Android widget
- [ ] Import/Export existing todos from/to file
- [ ] Import/Export filters and other settings
- [ ] Language localization (e.g. english, german)
- [ ] [Recurring](https://c306.net/t/topydo-docs/#Recurrence) tasks
- [ ] Archiving of completed todos (done.txt)
- [ ] ...
### Low priority
- [ ] Build and publish to Google Play (Android)
- [ ] Build and publish as `flatpak` to [flathub](https://flathub.org/) (Linux)
- [ ] Build and publish as `snap` to [snapcraft](https://snapcraft.io/) (Linux)
- [ ] Build and publish to Microsoft Store (Windows)
## Build
### General
[Flutter SDK](https://docs.flutter.dev/get-started/install) is required to build this project.
### Building on Linux
1. First you need to get the source code of `ntodotxt`.
```bash
git clone https://github.com/tmaegel/ntodotxt
```
2. Installing the dependencies for [sqflite](https://pub.dev/packages/sqflite_common_ffi#linux) and [flutter_secure_storage](https://pub.dev/packages/flutter_secure_storage#configure-linux-version).
```bash
dnf install sqlite-devel libsecret-devel1
```
3. Open project via [Android Studio](https://developer.android.com/studio).
4. Click the `Run` button and it will be built and run automatically.
5. Or you can build and run from command line.
```bash
flutter pub get
flutter run
# or
flutter build
```
If an error occurs during the build process, please follow these [steps](https://docs.flutter.dev/get-started/install/linux/desktop#development-tools).
## Sponsorship
`ntodotxt` is a free open source software that benefits from the open source community and every user can enjoy it's full functionality for free, so if you appreciate my current work, you can buy me a offee.
<a href='https://ko-fi.com/N4N41GAU03' target='_blank'><img height='36' style='border:0px;height:36px;' src='https://storage.ko-fi.com/cdn/kofi5.png?v=6' border='0' alt='Buy Me a Coffee at ko-fi.com' /></a>
Thanks for all the love and support.
## Alternatives
There are a bunch of other note taking apps with the WebDAV support. See them in [awesome-webdav](https://github.com/WebDAVDevs/awesome-webdav/blob/main/readme.md#android-other-apps) repository.
================================================
FILE: analysis_options.yaml
================================================
# This file configures the analyzer, which statically analyzes Dart code to
# check for errors, warnings, and lints.
#
# The issues identified by the analyzer are surfaced in the UI of Dart-enabled
# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
# invoked from the command line by running `flutter analyze`.
# The following line activates a set of recommended lints for Flutter apps,
# packages, and plugins designed to encourage good coding practices.
include: package:flutter_lints/flutter.yaml
linter:
# The lint rules applied to this project can be customized in the
# section below to disable rules from the `package:flutter_lints/flutter.yaml`
# included above or to enable additional rules. A list of all available lints
# and their documentation is published at https://dart.dev/lints.
#
# Instead of disabling a lint rule for the entire project in the
# section below, it can also be suppressed for a single line of code
# or a specific dart file by using the `// ignore: name_of_lint` and
# `// ignore_for_file: name_of_lint` syntax on the line or in the file
# producing the lint.
rules:
prefer_single_quotes: true
# Additional information about this file can be found at
# https://dart.dev/guides/language/analysis-options
================================================
FILE: android/.gitignore
================================================
gradle-wrapper.jar
/.gradle
/captures/
/gradlew
/gradlew.bat
/local.properties
GeneratedPluginRegistrant.java
# Remember to never publicly share your keystore.
# See https://flutter.dev/to/reference-keystore
key.properties
**/*.keystore
**/*.jks
================================================
FILE: android/app/build.gradle
================================================
plugins {
id "com.android.application"
id "kotlin-android"
// The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins.
id "dev.flutter.flutter-gradle-plugin"
}
def keystoreProperties = new Properties()
def keystorePropertiesFile = rootProject.file('key.properties')
if (keystorePropertiesFile.exists()) {
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
}
android {
namespace = "de.tnmgl.ntodotxt"
compileSdk = 35
ndkVersion = "25.1.8937393"
compileOptions {
sourceCompatibility = JavaVersion.VERSION_21
targetCompatibility = JavaVersion.VERSION_21
}
kotlinOptions {
jvmTarget = JavaVersion.VERSION_21
}
defaultConfig {
applicationId = "de.tnmgl.ntodotxt"
minSdk = flutter.minSdkVersion
targetSdk = flutter.targetSdkVersion
versionCode = flutter.versionCode
versionName = flutter.versionName
}
signingConfigs {
release {
keyAlias keystoreProperties['keyAlias']
keyPassword keystoreProperties['keyPassword']
storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null
storePassword keystoreProperties['storePassword']
}
}
buildTypes {
release {
signingConfig signingConfigs.release
}
}
// Removes DependencyInfoBlock for F-Droid.
dependenciesInfo {
// Disables dependency metadata when building APKs.
includeInApk = false
// Disables dependency metadata when building Android App Bundles.
includeInBundle = false
}
}
flutter {
source = "../.."
}
dependencies {}
ext.abiCodes = ["x86_64": 1, "armeabi-v7a": 2, "arm64-v8a": 3]
import com.android.build.OutputFile
android.applicationVariants.all { variant ->
variant.outputs.each { output ->
def abiVersionCode = project.ext.abiCodes.get(output.getFilter(OutputFile.ABI))
if (abiVersionCode != null) {
output.versionCodeOverride = variant.versionCode * 10 + abiVersionCode
}
}
}
================================================
FILE: android/app/src/debug/AndroidManifest.xml
================================================
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!-- The INTERNET permission is required for development. Specifically,
the Flutter tool needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
</manifest>
================================================
FILE: android/app/src/main/AndroidManifest.xml
================================================
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<application
android:label="ntodotxt"
android:name="${applicationName}"
android:icon="@mipmap/ic_launcher"
android:allowBackup="false"
android:requestLegacyExternalStorage="true"
android:enableOnBackInvokedCallback="true">
<activity
android:name=".MainActivity"
android:exported="true"
android:launchMode="singleTop"
android:taskAffinity=""
android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize">
<!-- Specifies an Android theme to apply to this Activity as soon as
the Android process has started. This theme is visible to the user
while the Flutter UI initializes. After that, this theme continues
to determine the Window background behind the Flutter UI. -->
<meta-data
android:name="io.flutter.embedding.android.NormalTheme"
android:resource="@style/NormalTheme"
/>
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<!-- Don't delete the meta-data below.
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
<meta-data
android:name="flutterEmbedding"
android:value="2" />
</application>
<!-- Required to query activities that can process text, see:
https://developer.android.com/training/package-visibility and
https://developer.android.com/reference/android/content/Intent#ACTION_PROCESS_TEXT.
In particular, this is used by the Flutter engine in io.flutter.plugin.text.ProcessTextPlugin. -->
<queries>
<intent>
<action android:name="android.intent.action.PROCESS_TEXT"/>
<data android:mimeType="text/plain"/>
</intent>
</queries>
</manifest>
================================================
FILE: android/app/src/main/kotlin/de/tnmgl/ntodotxt/MainActivity.kt
================================================
package de.tnmgl.ntodotxt
import io.flutter.embedding.android.FlutterActivity
class MainActivity: FlutterActivity() {
}
================================================
FILE: android/app/src/main/res/drawable/launch_background.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<!-- Modify this file to customize your launch splash screen -->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@android:color/white" />
<!-- You can insert your own image assets here -->
<!-- <item>
<bitmap
android:gravity="center"
android:src="@mipmap/launch_image" />
</item> -->
</layer-list>
================================================
FILE: android/app/src/main/res/drawable-v21/launch_background.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<!-- Modify this file to customize your launch splash screen -->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="?android:colorBackground" />
<!-- You can insert your own image assets here -->
<!-- <item>
<bitmap
android:gravity="center"
android:src="@mipmap/launch_image" />
</item> -->
</layer-list>
================================================
FILE: android/app/src/main/res/values/styles.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is off -->
<style name="LaunchTheme" parent="@android:style/Theme.Light.NoTitleBar">
<!-- Show a splash screen on the activity. Automatically removed when
the Flutter engine draws its first frame -->
<item name="android:windowBackground">@drawable/launch_background</item>
</style>
<!-- Theme applied to the Android Window as soon as the process has started.
This theme determines the color of the Android Window while your
Flutter UI initializes, as well as behind your Flutter UI while its
running.
This Theme is only used starting with V2 of Flutter's Android embedding. -->
<style name="NormalTheme" parent="@android:style/Theme.Light.NoTitleBar">
<item name="android:windowBackground">?android:colorBackground</item>
</style>
</resources>
================================================
FILE: android/app/src/main/res/values-night/styles.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is on -->
<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
<!-- Show a splash screen on the activity. Automatically removed when
the Flutter engine draws its first frame -->
<item name="android:windowBackground">@drawable/launch_background</item>
</style>
<!-- Theme applied to the Android Window as soon as the process has started.
This theme determines the color of the Android Window while your
Flutter UI initializes, as well as behind your Flutter UI while its
running.
This Theme is only used starting with V2 of Flutter's Android embedding. -->
<style name="NormalTheme" parent="@android:style/Theme.Black.NoTitleBar">
<item name="android:windowBackground">?android:colorBackground</item>
</style>
</resources>
================================================
FILE: android/app/src/profile/AndroidManifest.xml
================================================
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!-- The INTERNET permission is required for development. Specifically,
the Flutter tool needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
</manifest>
================================================
FILE: android/build.gradle
================================================
allprojects {
repositories {
google()
mavenCentral()
}
}
rootProject.buildDir = "../build"
subprojects {
project.buildDir = "${rootProject.buildDir}/${project.name}"
}
subprojects {
project.evaluationDependsOn(":app")
}
tasks.register("clean", Delete) {
delete rootProject.buildDir
}
================================================
FILE: android/gradle/wrapper/gradle-wrapper.properties
================================================
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-all.zip
================================================
FILE: android/gradle.properties
================================================
org.gradle.jvmargs=-Xmx4G -XX:MaxMetaspaceSize=2G -XX:+HeapDumpOnOutOfMemoryError
android.useAndroidX=true
android.enableJetifier=true
================================================
FILE: android/settings.gradle
================================================
pluginManagement {
def flutterSdkPath = {
def properties = new Properties()
file("local.properties").withInputStream { properties.load(it) }
def flutterSdkPath = properties.getProperty("flutter.sdk")
assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
return flutterSdkPath
}()
includeBuild("$flutterSdkPath/packages/flutter_tools/gradle")
repositories {
google()
mavenCentral()
gradlePluginPortal()
}
}
plugins {
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
id "com.android.application" version "8.3.2" apply false
id "org.jetbrains.kotlin.android" version "2.0.20" apply false
}
include ":app"
================================================
FILE: docker-compose.yaml
================================================
services:
nextcloud:
image: nextcloud:27
container_name: nextcloud
expose:
- 80
environment:
NEXTCLOUD_TRUSTED_DOMAINS: "127.0.0.1,10.0.2.2"
OVERWRITEHOST: "localhost:8443"
OVERWRITEPROTOCOL: "https"
volumes:
- nextcloud:/var/www/html
networks:
- caddy
caddy:
image: caddy:latest
container_name: reverse_proxy
ports:
- "127.0.0.1:8080:80"
- "127.0.0.1:8443:443"
- "127.0.0.1:8443:443/udp"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile:z
networks:
- caddy
volumes:
nextcloud:
caddy:
networks:
caddy:
================================================
FILE: emulatorctl
================================================
#!/usr/bin/env bash
function show_usage() {
echo "Usage:
$(basename "$") [options]"
echo ""
echo "Options:
-l List emulators / avds
-c [name] Create emulator / avd
-d Delete emulator / avd
-r Run emulator / avd
-e Exit emulator / avd
-v [api] Anroid API
-h Display this message"
}
if [[ $# -eq 0 ]]; then
show_usage
exit 1
fi
ACTION=0
ANDROID_API=36
EMULATOR_NAME=""
while getopts ":hldrec:v:" arg; do
case "${arg}" in
l)
avdmanager list avd
exit 0
;;
d)
avdmanager delete avd --name "$(avdmanager list avd -c | fzf)"
exit 0
;;
r)
echo "Starting emulator ..."
flutter emulators --launch "$(avdmanager list avd -c | fzf)"
exit 0
;;
e)
echo "Exiting emulator ..."
adb emu kill
exit 0
;;
c)
ACTION="create"
EMULATOR_NAME="${OPTARG}"
;;
v)
ANDROID_API="${OPTARG}"
;;
h | *)
show_usage
exit 0
;;
esac
done
if [[ ${ACTION} == "create" ]]; then
avdmanager create avd --name "${EMULATOR_NAME}-${ANDROID_API}" --package "system-images;android-${ANDROID_API};google_apis;x86_64"
fi
exit 0
================================================
FILE: fonts/LICENSE
================================================
Copyright 2020 The Open Sans Project Authors (https://github.com/googlefonts/opensans)
This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at:
http://scripts.sil.org/OFL
-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
-----------------------------------------------------------
PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide a free and
open framework in which fonts may be shared and improved in partnership
with others.
The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.
DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.
"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).
"Original Version" refers to the collection of Font Software components as
distributed by the Copyright Holder(s).
"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to a
new environment.
"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.
PERMISSION & CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:
1) Neither the Font Software nor any of its individual components,
in Original or Modified Versions, may be sold by itself.
2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.
3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the corresponding
Copyright Holder. This restriction only applies to the primary font name as
presented to the users.
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.
5) The Font Software, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created
using the Font Software.
TERMINATION
This license becomes null and void if any of the above conditions are
not met.
DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.
================================================
FILE: integration_test/login/login_integration_test.dart
================================================
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:ntodotxt/intro/page/intro_page.dart';
import 'package:ntodotxt/login/page/login_page.dart';
import 'package:ntodotxt/main.dart';
import 'package:path_provider/path_provider.dart';
void main() async {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge);
SystemChrome.setPreferredOrientations(
[DeviceOrientation.portraitUp, DeviceOrientation.portraitDown],
);
final String appDataDir =
'${(await getApplicationDocumentsDirectory()).path}/';
group('login', () {
group('initial', () {
testWidgets('screen is visible', (tester) async {
await tester.pumpWidget(
App(appDataDir: appDataDir),
);
await tester.pumpAndSettle(const Duration(milliseconds: 5000));
expect(find.byType(IntroPage), findsOneWidget);
});
});
group('local', () {
testWidgets('default local path', (tester) async {
await tester.pumpWidget(
App(appDataDir: appDataDir),
);
await tester.pumpAndSettle(const Duration(milliseconds: 5000));
expect(find.byType(IntroPage), findsOneWidget);
await tester.tap(find.byTooltip('Next page'));
await tester.pumpAndSettle();
await tester.tap(find.text('Use local mode'));
await tester.pumpAndSettle();
expect(find.byType(LocalLoginView), findsOneWidget);
expect(
find.byWidgetPredicate(
(Widget widget) =>
widget is ListTile &&
widget.title is Text &&
(widget.title as Text).data == 'Local path' &&
widget.subtitle != null &&
(widget.subtitle as Text).data == appDataDir,
),
findsOneWidget,
);
await tester.tap(find.text('Apply'));
await tester.pumpAndSettle();
expect(find.byType(App), findsOneWidget);
await tester.tap(find.byTooltip('Open drawer'));
await tester.pumpAndSettle();
await tester.drag(
find.byType(DraggableScrollableSheet), const Offset(0, -500));
await tester.pumpAndSettle();
await tester.tap(find.text('Settings'));
await tester.pumpAndSettle();
await tester.scrollUntilVisible(find.text('Reinitialization'), 500);
await tester.tap(find.text('Reinitialization'));
await tester.pumpAndSettle();
await tester.tap(
find.descendant(
of: find.byType(AlertDialog),
matching: find.text('Reninitialize'),
),
);
await tester.pumpAndSettle(const Duration(milliseconds: 5000));
expect(find.byType(IntroPage), findsOneWidget);
});
});
group('webdav', () {
testWidgets('default local path', (tester) async {
await tester.pumpWidget(
App(appDataDir: appDataDir),
);
await tester.pumpAndSettle(const Duration(milliseconds: 5000));
expect(find.byType(IntroPage), findsOneWidget);
await tester.tap(find.byTooltip('Next page'));
await tester.pumpAndSettle();
await tester.tap(find.byTooltip('Next page'));
await tester.pumpAndSettle();
await tester.tap(find.text('Use webdav mode'));
await tester.pumpAndSettle();
expect(find.byType(WebDAVLoginView), findsOneWidget);
expect(
find.byWidgetPredicate(
(Widget widget) =>
widget is ListTile &&
widget.title is Text &&
(widget.title as Text).data == 'Local path' &&
widget.subtitle != null &&
(widget.subtitle as Text).data == appDataDir,
),
findsOneWidget,
);
await tester.enterText(
find.ancestor(
of: find.text('Server'),
matching: find.byType(TextFormField),
),
'https://10.0.2.2:8443',
);
await tester.tap(find.byType(Checkbox));
await tester.enterText(
find.ancestor(
of: find.text('Path'),
matching: find.byType(TextFormField),
),
'/remote.php/dav/files/test',
);
await tester.enterText(
find.ancestor(
of: find.text('Username'),
matching: find.byType(TextFormField),
),
'test',
);
await tester.enterText(
find.ancestor(
of: find.text('Password'),
matching: find.byType(TextFormField),
),
'test',
);
await tester.pumpAndSettle();
await tester.tap(find.byType(AppBar));
await tester.pumpAndSettle();
await tester.tap(find.text('Apply'));
await tester.pumpAndSettle();
expect(find.byType(App), findsOneWidget);
await tester.tap(find.byTooltip('Open drawer'));
await tester.pumpAndSettle();
await tester.drag(
find.byType(DraggableScrollableSheet), const Offset(0, -500));
await tester.pumpAndSettle();
await tester.tap(find.text('Settings'));
await tester.pumpAndSettle();
await tester.scrollUntilVisible(find.text('Reinitialization'), 500);
await tester.tap(find.text('Reinitialization'));
await tester.pumpAndSettle();
await tester.tap(
find.descendant(
of: find.byType(AlertDialog),
matching: find.text('Reninitialize'),
),
);
await tester.pumpAndSettle(const Duration(milliseconds: 5000));
expect(find.byType(IntroPage), findsOneWidget);
});
});
});
}
================================================
FILE: integration_test/preview_app_integration_test.dart
================================================
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
class AppPreview extends StatelessWidget {
final String image;
final String message;
final Color foregroundColor = Colors.white;
final Color backgroundColor = Colors.lightBlue[100]!;
final Color deviceFrameColor = Colors.blueGrey;
AppPreview({
required this.image,
required this.message,
super.key,
});
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
backgroundColor: backgroundColor,
body: Container(
padding: const EdgeInsets.only(bottom: 24.0),
child: Column(
children: [
Flexible(
flex: 1,
child: Center(
child: Text(
message,
style: Theme.of(context).textTheme.titleLarge,
),
),
),
Flexible(
flex: 6,
child: Stack(
alignment: Alignment.topCenter,
children: [
Container(
decoration: BoxDecoration(
color: deviceFrameColor,
border: Border.all(
width: 12,
color: deviceFrameColor,
),
borderRadius: BorderRadius.circular(34),
),
child: Stack(
alignment: Alignment.topLeft,
children: [
Stack(
alignment: Alignment.topRight,
children: [
ClipRRect(
borderRadius: BorderRadius.circular(24),
child: Image.network(
image,
fit: BoxFit.cover,
),
),
Padding(
padding: const EdgeInsets.symmetric(
horizontal: 12.0, vertical: 8.0),
child: Row(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Icon(
Icons.signal_wifi_4_bar,
color: foregroundColor,
size: Theme.of(context)
.textTheme
.bodySmall
?.fontSize,
),
Icon(
Icons.signal_cellular_4_bar,
color: foregroundColor,
size: Theme.of(context)
.textTheme
.bodySmall
?.fontSize,
),
const SizedBox(width: 2.0),
Icon(
Icons.battery_full,
color: foregroundColor,
size: Theme.of(context)
.textTheme
.bodySmall
?.fontSize,
),
],
),
),
],
),
Padding(
padding: const EdgeInsets.symmetric(
horizontal: 12.0, vertical: 8.0),
child: Text(
'12:00',
style: TextStyle(
fontSize: Theme.of(context)
.textTheme
.bodySmall
?.fontSize,
color: foregroundColor,
),
),
),
],
),
),
],
),
),
],
),
),
),
);
}
}
void main() async {
const String repoUrl =
'https://raw.githubusercontent.com/tmaegel/ntodotxt/HEAD/';
final IntegrationTestWidgetsFlutterBinding binding =
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
WidgetsFlutterBinding.ensureInitialized();
// Hide android status bar.
SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersive);
group('dark mode', () {
group('create app store preview screenshots', () {
testWidgets('of todo list (default)', (tester) async {
await tester.pumpWidget(
AppPreview(
message: 'Compact overview of all todos',
image: '$repoUrl/screenshots/phone/1.png',
),
);
// Ensure the image is loaded/displayed.
await tester.pumpAndSettle(const Duration(milliseconds: 5000));
await binding.convertFlutterSurfaceToImage();
await tester.pumpAndSettle();
await binding.takeScreenshot('preview/1');
});
testWidgets('of todo list (with open drawer)', (tester) async {
await tester.pumpWidget(
AppPreview(
message: 'Custom filters',
image: '$repoUrl/screenshots/phone/2.png',
),
);
// Ensure the image is loaded/displayed.
await tester.pumpAndSettle(const Duration(milliseconds: 5000));
await binding.convertFlutterSurfaceToImage();
await tester.pumpAndSettle();
await binding.takeScreenshot('preview/2');
});
testWidgets('of todo edit page', (tester) async {
await tester.pumpWidget(
AppPreview(
message: 'Edit and create todos',
image: '$repoUrl/screenshots/phone/3.png',
),
);
// Ensure the image is loaded/displayed.
await tester.pumpAndSettle(const Duration(milliseconds: 5000));
await binding.convertFlutterSurfaceToImage();
await tester.pumpAndSettle();
await binding.takeScreenshot('preview/3');
});
testWidgets('of filter list (default)', (tester) async {
await tester.pumpWidget(
AppPreview(
message: 'Compact overview of all filters',
image: '$repoUrl/screenshots/phone/4.png',
),
);
// Ensure the image is loaded/displayed.
await tester.pumpAndSettle(const Duration(milliseconds: 5000));
await binding.convertFlutterSurfaceToImage();
await tester.pumpAndSettle();
await binding.takeScreenshot('preview/4');
});
testWidgets('of filter edit page', (tester) async {
await tester.pumpWidget(
AppPreview(
message: 'Edit and create filters',
image: '$repoUrl/screenshots/phone/5.png',
),
);
// Ensure the image is loaded/displayed.
await tester.pumpAndSettle(const Duration(milliseconds: 5000));
await binding.convertFlutterSurfaceToImage();
await tester.pumpAndSettle();
await binding.takeScreenshot('preview/5');
});
});
});
}
================================================
FILE: integration_test/screenshot_integration_test.dart
================================================
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:ntodotxt/database/controller/database.dart';
import 'package:ntodotxt/drawer/state/drawer_cubit.dart';
import 'package:ntodotxt/filter/controller/filter_controller.dart'
show FilterController;
import 'package:ntodotxt/filter/model/filter_model.dart'
show Filter, ListFilter, ListGroup, ListOrder;
import 'package:ntodotxt/filter/repository/filter_repository.dart';
import 'package:ntodotxt/filter/state/filter_cubit.dart';
import 'package:ntodotxt/filter/state/filter_list_bloc.dart';
import 'package:ntodotxt/filter/state/filter_list_event.dart';
import 'package:ntodotxt/login/state/login_cubit.dart';
import 'package:ntodotxt/login/state/login_state.dart'
show LoginLocal, LoginState, LoginWebDAV;
import 'package:ntodotxt/main.dart';
import 'package:ntodotxt/setting/controller/setting_controller.dart';
import 'package:ntodotxt/setting/repository/setting_repository.dart';
import 'package:ntodotxt/todo/model/todo_model.dart' show Priority, Todo;
import 'package:ntodotxt/todo_file/state/todo_file_cubit.dart';
import 'package:ntodotxt/webdav/client/webdav_client.dart';
import 'package:path_provider/path_provider.dart';
import 'package:sqflite_common_ffi/sqflite_ffi.dart';
// https://developer.android.com/studio/run/emulator-networking#networkaddresses
// Special alias to your host loopback interface (127.0.0.1 on your development machine)
const String server = 'https://10.0.2.2:8443';
const String path = '/remote.php/dav/files';
const String username = 'test';
const String password = 'test';
class FakeController extends Fake implements FilterController {
List<Filter> items = [
const Filter(
id: 1,
name: 'Agenda',
order: ListOrder.ascending,
filter: ListFilter.incompletedOnly,
group: ListGroup.upcoming,
),
const Filter(
id: 2,
name: 'Highly prioritized',
order: ListOrder.ascending,
filter: ListFilter.incompletedOnly,
group: ListGroup.project,
priorities: {Priority.A},
),
const Filter(
id: 3,
name: 'Projectideas',
order: ListOrder.ascending,
filter: ListFilter.incompletedOnly,
group: ListGroup.none,
projects: {'projectideas'},
),
const Filter(
id: 4,
name: 'Completed only',
order: ListOrder.ascending,
filter: ListFilter.completedOnly,
group: ListGroup.none,
),
];
@override
Future<List<Filter>> list() async {
return Future.value(items);
}
}
class AppTester extends StatelessWidget {
final DatabaseController dbController =
const DatabaseController(inMemoryDatabasePath);
final ThemeMode? themeMode;
final String appCacheDir;
const AppTester({
this.themeMode,
required this.appCacheDir,
super.key,
});
@override
Widget build(BuildContext context) {
return MultiRepositoryProvider(
providers: [
RepositoryProvider<SettingRepository>(
create: (BuildContext context) => SettingRepository(
SettingController(dbController),
),
),
RepositoryProvider<FilterRepository>(
create: (BuildContext context) => FilterRepository(
FakeController(),
),
),
],
child: MultiBlocProvider(
providers: [
BlocProvider<LoginCubit>(
create: (BuildContext context) => LoginCubit(
state: const LoginWebDAV(
server: server,
path: path,
username: username,
password: password,
acceptUntrustedCert: true,
),
),
),
BlocProvider<TodoFileCubit>(
create: (BuildContext context) => TodoFileCubit(
repository: context.read<SettingRepository>(),
localPath: appCacheDir,
)..load(),
),
BlocProvider<DrawerCubit>(
create: (BuildContext context) => DrawerCubit(),
),
// Default filter
BlocProvider<FilterCubit>(
create: (BuildContext context) => FilterCubit(
settingRepository: context.read<SettingRepository>(),
filterRepository: context.read<FilterRepository>(),
)..load(),
),
BlocProvider<FilterListBloc>(
create: (BuildContext context) => FilterListBloc(
repository: context.read<FilterRepository>(),
)
..add(const FilterListSubscriped())
..add(const FilterListSynchronizationRequested()),
),
],
child: Builder(
builder: (BuildContext context) {
return BlocBuilder<LoginCubit, LoginState>(
builder: (BuildContext context, LoginState state) {
if (state is LoginLocal || state is LoginWebDAV) {
return CoreApp(loginState: state);
} else {
return const InitialApp();
}
},
);
},
),
),
);
}
}
void main() async {
final IntegrationTestWidgetsFlutterBinding binding =
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge);
final DateTime today = DateTime.now();
final List<Todo> todoList = [
Todo(
creationDate: today.subtract(const Duration(days: 7)),
priority: Priority.A,
description:
'Automate the generation of +app screenshots +learnflutter @development @automation @productivity due:${Todo.date2Str(today.add(const Duration(days: 3)))!}',
),
Todo(
creationDate: today.subtract(const Duration(days: 14)),
priority: Priority.B,
description:
'Publish this +app +learnflutter @development due:${Todo.date2Str(today.add(const Duration(days: 7)))!}',
),
Todo(
creationDate: today.subtract(const Duration(days: 2)),
description:
'Increase test +coverage for this +app +learnflutter @development @testing @productivity',
),
Todo(
creationDate: today.subtract(const Duration(days: 2)),
completion: true,
completionDate: today.subtract(const Duration(days: 1)),
description:
'Write some tests for this +app +learnflutter @development @testing @productivity',
),
Todo(
creationDate: today.subtract(const Duration(days: 21)),
priority: Priority.C,
description:
'Setup a good project management tool @development @productivity',
)
];
setUp(() async {
// Setup todos.
WebDAVClient client = WebDAVClient(
server: server,
path: path,
username: username,
password: password,
);
try {
await client.upload(
content: todoList.join(Platform.lineTerminator),
filename: 'todo.txt');
} catch (e) {
fail('An exception was thrown: $e');
}
});
group('dark mode', () {
group('take screenshots', () {
testWidgets('of todo list (default)', (tester) async {
await tester.pumpWidget(
AppTester(
themeMode: ThemeMode.dark,
appCacheDir: (await getApplicationCacheDirectory()).path,
),
);
await tester.pumpAndSettle(const Duration(milliseconds: 5000));
await binding.convertFlutterSurfaceToImage();
await tester.pumpAndSettle();
await binding.takeScreenshot('phone/1');
});
testWidgets('of todo list (with open drawer)', (tester) async {
await tester.pumpWidget(
AppTester(
themeMode: ThemeMode.dark,
appCacheDir: (await getApplicationCacheDirectory()).path,
),
);
await tester.pumpAndSettle(const Duration(milliseconds: 5000));
await tester.tap(find.byTooltip('Open drawer'));
await tester.pumpAndSettle();
await tester.drag(
find.byType(DraggableScrollableSheet), const Offset(0, -500));
await tester.pumpAndSettle();
await binding.convertFlutterSurfaceToImage();
await tester.pumpAndSettle();
await binding.takeScreenshot('phone/2');
});
testWidgets('of todo edit page', (tester) async {
await tester.pumpWidget(
AppTester(
themeMode: ThemeMode.dark,
appCacheDir: (await getApplicationCacheDirectory()).path,
),
);
await tester.pumpAndSettle(const Duration(milliseconds: 5000));
await tester.tap(find.text(
'Publish this +app +learnflutter @development',
findRichText: true,
));
await tester.pumpAndSettle();
await binding.convertFlutterSurfaceToImage();
await tester.pumpAndSettle();
await binding.takeScreenshot('phone/3');
});
testWidgets('of filter list (default)', (tester) async {
await tester.pumpWidget(
AppTester(
themeMode: ThemeMode.dark,
appCacheDir: (await getApplicationCacheDirectory()).path,
),
);
await tester.pumpAndSettle(const Duration(milliseconds: 5000));
await tester.tap(find.byTooltip('Open drawer'));
await tester.pumpAndSettle();
await tester.drag(
find.byType(DraggableScrollableSheet), const Offset(0, -500));
await tester.pumpAndSettle();
await tester.tap(find.text('Filters'));
await tester.pumpAndSettle();
await binding.convertFlutterSurfaceToImage();
await tester.pumpAndSettle();
await binding.takeScreenshot('phone/4');
});
testWidgets('of filter edit page', (tester) async {
await tester.pumpWidget(
AppTester(
themeMode: ThemeMode.dark,
appCacheDir: (await getApplicationCacheDirectory()).path,
),
);
await tester.pumpAndSettle(const Duration(milliseconds: 5000));
await tester.tap(find.byTooltip('Open drawer'));
await tester.pumpAndSettle();
await tester.drag(
find.byType(DraggableScrollableSheet), const Offset(0, -500));
await tester.pumpAndSettle();
await tester.tap(find.text('Filters'));
await tester.pumpAndSettle();
await tester.tap(find.text('Projectideas'));
await tester.pumpAndSettle();
await binding.convertFlutterSurfaceToImage();
await tester.pumpAndSettle();
await binding.takeScreenshot('phone/5');
});
});
});
}
================================================
FILE: integration_test/webdav/client/webdav_client_test.dart
================================================
import 'dart:io' show Platform;
import 'dart:math';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:ntodotxt/webdav/client/webdav_client.dart';
import 'package:webdav_client/webdav_client.dart';
const String scheme = 'https';
const int port = 8443;
final String host = Platform.isAndroid ? '10.0.2.2' : 'localhost';
WebDAVClient createWebDAVClient({
String? server,
String? path,
String? username,
String? password,
}) {
return WebDAVClient(
server: server ?? '$scheme://$host:$port',
path: path ?? '/remote.php/dav/files/test',
username: username ?? 'test',
password: password ?? 'test',
acceptUntrustedCert: true,
);
}
String randomString({int len = 8}) {
final Random r = Random();
const chars =
'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz1234567890';
return List.generate(len, (index) => chars[r.nextInt(chars.length)]).join();
}
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
group('WebDAVClient', () {
group('ping()', () {
test('correct connection', () async {
final WebDAVClient client = createWebDAVClient();
try {
await client.ping();
} catch (e) {
fail('An exception was thrown: $e');
}
});
test('wrong host', () async {
final WebDAVClient client =
createWebDAVClient(server: '$scheme://webdav:$port');
expectLater(
() async => await client.ping(),
throwsA(
isA<WebDAVClientException>(),
),
);
});
test('wrong port', () async {
final WebDAVClient client =
createWebDAVClient(server: '$scheme://$host:9999');
expectLater(
() async => await client.ping(),
throwsA(
isA<WebDAVClientException>(),
),
);
});
});
group('listFiles()', () {
test('list', () async {
final WebDAVClient client = createWebDAVClient();
try {
await client.listFiles(path: '/');
} catch (e) {
fail('An exception was thrown: $e');
}
});
});
group('file create() & fileExists()', () {
test('file does exist (1)', () async {
final String filename = '${randomString()}.txt';
final WebDAVClient client = createWebDAVClient();
try {
await client.create(filename);
expectLater(
await client.fileExists(filename: filename),
true,
);
} catch (e) {
fail('An exception was thrown: $e');
}
});
test('file does exist (2)', () async {
final String directory = randomString();
final String filename = '${randomString()}.txt';
final WebDAVClient client = createWebDAVClient();
try {
await client.mkdir(directory: directory);
await client.create('$directory/$filename');
expectLater(
await client.fileExists(filename: '$directory/$filename'),
true,
);
} catch (e) {
fail('An exception was thrown: $e');
}
});
test('file doesn\'t exist (1)', () async {
final WebDAVClient client = createWebDAVClient();
try {
expectLater(
await client.fileExists(filename: 'abc.xyz'),
false,
);
} catch (e) {
fail('An exception was thrown: $e');
}
});
test('file doesn\'t exist (2)', () async {
final String directory = randomString();
final WebDAVClient client = createWebDAVClient();
try {
await client.mkdir(directory: directory);
expectLater(
await client.fileExists(filename: '/$directory/abc.xyz'),
false,
);
} catch (e) {
fail('An exception was thrown: $e');
}
});
test('directory/file doesn\'t exist in this path', () async {
final String directory = randomString();
final String filename = '${randomString()}.txt';
final WebDAVClient client = createWebDAVClient();
try {
await client.mkdir(directory: directory);
await client.create(filename);
expectLater(
await client.fileExists(filename: '$directory/$filename'),
false,
);
} catch (e) {
fail('An exception was thrown: $e');
}
});
});
group('upload()', () {
test('file upload', () async {
final String filename = '${randomString()}.txt';
final WebDAVClient client = createWebDAVClient();
try {
await client.upload(content: 'abc', filename: filename);
expectLater(await client.fileExists(filename: filename), true);
} catch (e) {
fail('An exception was thrown: $e');
}
});
test('file upload within already existing directory', () async {
final String directory = randomString();
final String filename = '${randomString()}.txt';
final WebDAVClient client = createWebDAVClient();
try {
await client.mkdir(directory: directory);
await client.upload(content: 'abc', filename: '$directory/$filename');
expectLater(
await client.fileExists(filename: '$directory/$filename'),
true,
);
} catch (e) {
fail('An exception was thrown: $e');
}
});
test('file upload within non existing directory', () async {
final String directory = randomString();
final String filename = '${randomString()}.txt';
final WebDAVClient client = createWebDAVClient();
try {
await client.upload(content: 'abc', filename: '$directory/$filename');
expectLater(
await client.fileExists(filename: '$directory/$filename'),
true,
);
} catch (e) {
fail('An exception was thrown: $e');
}
});
test('exception', () async {
final WebDAVClient client = createWebDAVClient(password: 'wrong');
expectLater(
() async => await client.upload(content: 'abc', filename: 'todo.txt'),
throwsA(
isA<WebDAVClientException>(),
),
);
});
});
group('download()', () {
test('file download', () async {
final String filename = '${randomString()}.txt';
final WebDAVClient client = createWebDAVClient();
try {
await client.upload(content: 'abc', filename: filename);
expectLater(await client.download(filename: filename), 'abc');
} catch (e) {
fail('An exception was thrown: $e');
}
});
test('file download within directory', () async {
final String directory = randomString();
final String filename = '${randomString()}.txt';
final WebDAVClient client = createWebDAVClient();
try {
await client.upload(content: 'abc', filename: '$directory/$filename');
expectLater(
await client.download(filename: '$directory/$filename'),
'abc',
);
} catch (e) {
fail('An exception was thrown: $e');
}
});
test('exception', () async {
final WebDAVClient client = createWebDAVClient(password: 'wrong');
expectLater(
() async => await client.download(filename: 'todo.txt'),
throwsA(
isA<WebDAVClientException>(),
),
);
});
});
group('getFile()', () {
test('valid', () async {
final String filename = '${randomString()}.txt';
final WebDAVClient client = createWebDAVClient();
try {
await client.upload(content: 'abc', filename: filename);
File f = await client.getFile(filename: filename);
expect(f.mTime is DateTime, true);
} catch (e) {
fail('An exception was thrown: $e');
}
});
test('exception', () async {
final WebDAVClient client = createWebDAVClient();
expectLater(
() async => await client.getFile(filename: 'unknown.txt'),
throwsA(
isA<WebDAVClientException>(),
),
);
});
});
});
}
================================================
FILE: ios/.gitignore
================================================
**/dgph
*.mode1v3
*.mode2v3
*.moved-aside
*.pbxuser
*.perspectivev3
**/*sync/
.sconsign.dblite
.tags*
**/.vagrant/
**/DerivedData/
Icon?
**/Pods/
**/.symlinks/
profile
xcuserdata
**/.generated/
Flutter/App.framework
Flutter/Flutter.framework
Flutter/Flutter.podspec
Flutter/Generated.xcconfig
Flutter/ephemeral/
Flutter/app.flx
Flutter/app.zip
Flutter/flutter_assets/
Flutter/flutter_export_environment.sh
ServiceDefinitions.json
Runner/GeneratedPluginRegistrant.*
# Exceptions to above rules.
!default.mode1v3
!default.mode2v3
!default.pbxuser
!default.perspectivev3
================================================
FILE: ios/Flutter/AppFrameworkInfo.plist
================================================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>App</string>
<key>CFBundleIdentifier</key>
<string>io.flutter.flutter.app</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>App</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1.0</string>
<key>MinimumOSVersion</key>
<string>12.0</string>
</dict>
</plist>
================================================
FILE: ios/Flutter/Debug.xcconfig
================================================
#include "Generated.xcconfig"
================================================
FILE: ios/Flutter/Release.xcconfig
================================================
#include "Generated.xcconfig"
================================================
FILE: ios/Runner/AppDelegate.swift
================================================
import Flutter
import UIKit
@main
@objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}
================================================
FILE: ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json
================================================
{
"images" : [
{
"size" : "20x20",
"idiom" : "iphone",
"filename" : "Icon-App-20x20@2x.png",
"scale" : "2x"
},
{
"size" : "20x20",
"idiom" : "iphone",
"filename" : "Icon-App-20x20@3x.png",
"scale" : "3x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-App-29x29@1x.png",
"scale" : "1x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-App-29x29@2x.png",
"scale" : "2x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-App-29x29@3x.png",
"scale" : "3x"
},
{
"size" : "40x40",
"idiom" : "iphone",
"filename" : "Icon-App-40x40@2x.png",
"scale" : "2x"
},
{
"size" : "40x40",
"idiom" : "iphone",
"filename" : "Icon-App-40x40@3x.png",
"scale" : "3x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "Icon-App-60x60@2x.png",
"scale" : "2x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "Icon-App-60x60@3x.png",
"scale" : "3x"
},
{
"size" : "20x20",
"idiom" : "ipad",
"filename" : "Icon-App-20x20@1x.png",
"scale" : "1x"
},
{
"size" : "20x20",
"idiom" : "ipad",
"filename" : "Icon-App-20x20@2x.png",
"scale" : "2x"
},
{
"size" : "29x29",
"idiom" : "ipad",
"filename" : "Icon-App-29x29@1x.png",
"scale" : "1x"
},
{
"size" : "29x29",
"idiom" : "ipad",
"filename" : "Icon-App-29x29@2x.png",
"scale" : "2x"
},
{
"size" : "40x40",
"idiom" : "ipad",
"filename" : "Icon-App-40x40@1x.png",
"scale" : "1x"
},
{
"size" : "40x40",
"idiom" : "ipad",
"filename" : "Icon-App-40x40@2x.png",
"scale" : "2x"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "Icon-App-76x76@1x.png",
"scale" : "1x"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "Icon-App-76x76@2x.png",
"scale" : "2x"
},
{
"size" : "83.5x83.5",
"idiom" : "ipad",
"filename" : "Icon-App-83.5x83.5@2x.png",
"scale" : "2x"
},
{
"size" : "1024x1024",
"idiom" : "ios-marketing",
"filename" : "Icon-App-1024x1024@1x.png",
"scale" : "1x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json
================================================
{
"images" : [
{
"idiom" : "universal",
"filename" : "LaunchImage.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "LaunchImage@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "LaunchImage@3x.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md
================================================
# Launch Screen Assets
You can customize the launch screen with your own desired assets by replacing the image files in this directory.
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.
================================================
FILE: ios/Runner/Base.lproj/LaunchScreen.storyboard
================================================
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="12121" systemVersion="16G29" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12089"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="EHf-IW-A2E">
<objects>
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="Ydg-fD-yQy"/>
<viewControllerLayoutGuide type="bottom" id="xbc-2k-c8Z"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<imageView opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" image="LaunchImage" translatesAutoresizingMaskIntoConstraints="NO" id="YRO-k0-Ey4">
</imageView>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="YRO-k0-Ey4" firstAttribute="centerX" secondItem="Ze5-6b-2t3" secondAttribute="centerX" id="1a2-6s-vTC"/>
<constraint firstItem="YRO-k0-Ey4" firstAttribute="centerY" secondItem="Ze5-6b-2t3" secondAttribute="centerY" id="4X2-HB-R7a"/>
</constraints>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="53" y="375"/>
</scene>
</scenes>
<resources>
<image name="LaunchImage" width="168" height="185"/>
</resources>
</document>
================================================
FILE: ios/Runner/Base.lproj/Main.storyboard
================================================
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="10117" systemVersion="15F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="BYZ-38-t0r">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10085"/>
</dependencies>
<scenes>
<!--Flutter View Controller-->
<scene sceneID="tne-QT-ifu">
<objects>
<viewController id="BYZ-38-t0r" customClass="FlutterViewController" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/>
<viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
</objects>
</scene>
</scenes>
</document>
================================================
FILE: ios/Runner/Info.plist
================================================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key>
<string>Ntodotxt</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>ntodotxt</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>$(FLUTTER_BUILD_NAME)</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>$(FLUTTER_BUILD_NUMBER)</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
<string>Main</string>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>CADisableMinimumFrameDurationOnPhone</key>
<true/>
<key>UIApplicationSupportsIndirectInputEvents</key>
<true/>
</dict>
</plist>
================================================
FILE: ios/Runner/Runner-Bridging-Header.h
================================================
#import "GeneratedPluginRegistrant.h"
================================================
FILE: ios/Runner.xcodeproj/project.pbxproj
================================================
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 54;
objects = {
/* Begin PBXBuildFile section */
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; };
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
331C8085294A63A400263BE5 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 97C146E61CF9000F007C117D /* Project object */;
proxyType = 1;
remoteGlobalIDString = 97C146ED1CF9000F007C117D;
remoteInfo = Runner;
};
/* End PBXContainerItemProxy section */
/* Begin PBXCopyFilesBuildPhase section */
9705A1C41CF9048500538489 /* Embed Frameworks */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "";
dstSubfolderSpec = 10;
files = (
);
name = "Embed Frameworks";
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = "<group>"; };
331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
97C146EB1CF9000F007C117D /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
331C8082294A63A400263BE5 /* RunnerTests */ = {
isa = PBXGroup;
children = (
331C807B294A618700263BE5 /* RunnerTests.swift */,
);
path = RunnerTests;
sourceTree = "<group>";
};
9740EEB11CF90186004384FC /* Flutter */ = {
isa = PBXGroup;
children = (
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
9740EEB21CF90195004384FC /* Debug.xcconfig */,
7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
9740EEB31CF90195004384FC /* Generated.xcconfig */,
);
name = Flutter;
sourceTree = "<group>";
};
97C146E51CF9000F007C117D = {
isa = PBXGroup;
children = (
9740EEB11CF90186004384FC /* Flutter */,
97C146F01CF9000F007C117D /* Runner */,
97C146EF1CF9000F007C117D /* Products */,
331C8082294A63A400263BE5 /* RunnerTests */,
);
sourceTree = "<group>";
};
97C146EF1CF9000F007C117D /* Products */ = {
isa = PBXGroup;
children = (
97C146EE1CF9000F007C117D /* Runner.app */,
331C8081294A63A400263BE5 /* RunnerTests.xctest */,
);
name = Products;
sourceTree = "<group>";
};
97C146F01CF9000F007C117D /* Runner */ = {
isa = PBXGroup;
children = (
97C146FA1CF9000F007C117D /* Main.storyboard */,
97C146FD1CF9000F007C117D /* Assets.xcassets */,
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
97C147021CF9000F007C117D /* Info.plist */,
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */,
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
74858FAE1ED2DC5600515810 /* AppDelegate.swift */,
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */,
);
path = Runner;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
331C8080294A63A400263BE5 /* RunnerTests */ = {
isa = PBXNativeTarget;
buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */;
buildPhases = (
331C807D294A63A400263BE5 /* Sources */,
331C807F294A63A400263BE5 /* Resources */,
);
buildRules = (
);
dependencies = (
331C8086294A63A400263BE5 /* PBXTargetDependency */,
);
name = RunnerTests;
productName = RunnerTests;
productReference = 331C8081294A63A400263BE5 /* RunnerTests.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
97C146ED1CF9000F007C117D /* Runner */ = {
isa = PBXNativeTarget;
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
buildPhases = (
9740EEB61CF901F6004384FC /* Run Script */,
97C146EA1CF9000F007C117D /* Sources */,
97C146EB1CF9000F007C117D /* Frameworks */,
97C146EC1CF9000F007C117D /* Resources */,
9705A1C41CF9048500538489 /* Embed Frameworks */,
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
);
buildRules = (
);
dependencies = (
);
name = Runner;
productName = Runner;
productReference = 97C146EE1CF9000F007C117D /* Runner.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
97C146E61CF9000F007C117D /* Project object */ = {
isa = PBXProject;
attributes = {
BuildIndependentTargetsInParallel = YES;
LastUpgradeCheck = 1510;
ORGANIZATIONNAME = "";
TargetAttributes = {
331C8080294A63A400263BE5 = {
CreatedOnToolsVersion = 14.0;
TestTargetID = 97C146ED1CF9000F007C117D;
};
97C146ED1CF9000F007C117D = {
CreatedOnToolsVersion = 7.3.1;
LastSwiftMigration = 1100;
};
};
};
buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
compatibilityVersion = "Xcode 9.3";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = 97C146E51CF9000F007C117D;
productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
97C146ED1CF9000F007C117D /* Runner */,
331C8080294A63A400263BE5 /* RunnerTests */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
331C807F294A63A400263BE5 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
97C146EC1CF9000F007C117D /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
"${TARGET_BUILD_DIR}/${INFOPLIST_PATH}",
);
name = "Thin Binary";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
};
9740EEB61CF901F6004384FC /* Run Script */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "Run Script";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
331C807D294A63A400263BE5 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
97C146EA1CF9000F007C117D /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */,
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
331C8086294A63A400263BE5 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 97C146ED1CF9000F007C117D /* Runner */;
targetProxy = 331C8085294A63A400263BE5 /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
/* Begin PBXVariantGroup section */
97C146FA1CF9000F007C117D /* Main.storyboard */ = {
isa = PBXVariantGroup;
children = (
97C146FB1CF9000F007C117D /* Base */,
);
name = Main.storyboard;
sourceTree = "<group>";
};
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = {
isa = PBXVariantGroup;
children = (
97C147001CF9000F007C117D /* Base */,
);
name = LaunchScreen.storyboard;
sourceTree = "<group>";
};
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
249021D3217E4FDB00AE95B9 /* Profile */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_USER_SCRIPT_SANDBOXING = NO;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
};
name = Profile;
};
249021D4217E4FDB00AE95B9 /* Profile */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = de.tnmgl.ntodotxt;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic";
};
name = Profile;
};
331C8088294A63A400263BE5 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = de.tnmgl.ntodotxt.RunnerTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
};
name = Debug;
};
331C8089294A63A400263BE5 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = de.tnmgl.ntodotxt.RunnerTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
};
name = Release;
};
331C808A294A63A400263BE5 /* Profile */ = {
isa = XCBuildConfiguration;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = de.tnmgl.ntodotxt.RunnerTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
};
name = Profile;
};
97C147031CF9000F007C117D /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
ENABLE_USER_SCRIPT_SANDBOXING = NO;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
97C147041CF9000F007C117D /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_USER_SCRIPT_SANDBOXING = NO;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos;
SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_OPTIMIZATION_LEVEL = "-O";
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
};
name = Release;
};
97C147061CF9000F007C117D /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = de.tnmgl.ntodotxt;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic";
};
name = Debug;
};
97C147071CF9000F007C117D /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = de.tnmgl.ntodotxt;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
331C8088294A63A400263BE5 /* Debug */,
331C8089294A63A400263BE5 /* Release */,
331C808A294A63A400263BE5 /* Profile */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = {
isa = XCConfigurationList;
buildConfigurations = (
97C147031CF9000F007C117D /* Debug */,
97C147041CF9000F007C117D /* Release */,
249021D3217E4FDB00AE95B9 /* Profile */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = {
isa = XCConfigurationList;
buildConfigurations = (
97C147061CF9000F007C117D /* Debug */,
97C147071CF9000F007C117D /* Release */,
249021D4217E4FDB00AE95B9 /* Profile */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 97C146E61CF9000F007C117D /* Project object */;
}
================================================
FILE: ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata
================================================
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:">
</FileRef>
</Workspace>
================================================
FILE: ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
================================================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>
================================================
FILE: ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings
================================================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>PreviewsEnabled</key>
<false/>
</dict>
</plist>
================================================
FILE: ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
================================================
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1510"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</MacroExpansion>
<Testables>
<TestableReference
skipped = "NO"
parallelizable = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "331C8080294A63A400263BE5"
BuildableName = "RunnerTests.xctest"
BlueprintName = "RunnerTests"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</LaunchAction>
<ProfileAction
buildConfiguration = "Profile"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
================================================
FILE: ios/Runner.xcworkspace/contents.xcworkspacedata
================================================
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:Runner.xcodeproj">
</FileRef>
</Workspace>
================================================
FILE: ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
================================================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>
================================================
FILE: ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings
================================================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>PreviewsEnabled</key>
<false/>
</dict>
</plist>
================================================
FILE: ios/RunnerTests/RunnerTests.swift
================================================
import Flutter
import UIKit
import XCTest
class RunnerTests: XCTestCase {
func testExample() {
// If you add code to the Runner application, consider adding tests here.
// See https://developer.apple.com/documentation/xctest for more information about using XCTest.
}
}
================================================
FILE: lib/adaptive_layout/widget/adaptive_layout.dart
================================================
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:ntodotxt/common/misc.dart';
import 'package:ntodotxt/drawer/widget/drawer.dart';
import 'package:ntodotxt/filter/state/filter_cubit.dart';
import 'package:ntodotxt/filter/state/filter_list_bloc.dart';
import 'package:ntodotxt/filter/state/filter_list_state.dart';
import 'package:ntodotxt/filter/state/filter_state.dart';
import 'package:ntodotxt/login/state/login_cubit.dart';
import 'package:ntodotxt/login/state/login_state.dart';
import 'package:ntodotxt/todo/state/todo_list_bloc.dart';
import 'package:ntodotxt/todo/state/todo_list_state.dart';
import 'package:ntodotxt/todo_file/state/todo_file_cubit.dart';
import 'package:ntodotxt/todo_file/state/todo_file_state.dart';
class AdaptiveLayout extends StatelessWidget {
final Widget child;
const AdaptiveLayout({
required this.child,
super.key,
});
@override
Widget build(BuildContext context) {
// if (MediaQuery.of(context).size.width < maxScreenWidthCompact) {
// @todo: Activate WideLayout later!
return NotificationWrapper(
child: NarrowLayout(child: child),
);
// } else {
// return NotificationWrapper(
// child: WideLayout(child: child),
// );
// }
}
}
class NotificationWrapper extends StatelessWidget {
final Widget child;
const NotificationWrapper({
required this.child,
super.key,
});
@override
Widget build(BuildContext context) {
return MultiBlocListener(
listeners: [
BlocListener<LoginCubit, LoginState>(
listener: (BuildContext context, LoginState state) {
if (state is LoginError) {
SnackBarHandler.error(context, state.message);
}
},
),
BlocListener<TodoFileCubit, TodoFileState>(
listener: (BuildContext context, TodoFileState state) {
if (state is TodoFileError) {
SnackBarHandler.error(context, state.message);
}
},
),
BlocListener<FilterListBloc, FilterListState>(
listener: (BuildContext context, FilterListState state) {
if (state is FilterListError) {
SnackBarHandler.error(context, state.message);
}
},
),
BlocListener<FilterCubit, FilterState>(
listener: (BuildContext context, FilterState state) {
if (state is FilterError) {
SnackBarHandler.error(context, state.message);
}
},
),
BlocListener<TodoListBloc, TodoListState>(
listener: (BuildContext context, TodoListState state) {
if (state is TodoListError) {
SnackBarHandler.error(context, state.message);
}
},
),
],
child: child,
);
}
}
class NarrowLayout extends StatelessWidget {
final Widget child;
const NarrowLayout({
required this.child,
super.key,
});
@override
Widget build(BuildContext context) => child;
}
class WideLayout extends StatelessWidget {
final Widget child;
const WideLayout({
required this.child,
super.key,
});
@override
Widget build(BuildContext context) {
return Row(
children: [
const NavigationRailDrawer(),
const VerticalDivider(width: 2),
Expanded(child: child),
],
);
}
}
================================================
FILE: lib/app_info/page/app_details_page.dart
================================================
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:ntodotxt/common/constants/app.dart';
import 'package:ntodotxt/common/widget/app_bar.dart';
import 'package:url_launcher/url_launcher.dart';
class AppInfoPage extends StatelessWidget {
const AppInfoPage({super.key});
@override
Widget build(BuildContext context) {
return const Scaffold(
appBar: MainAppBar(title: 'About'),
body: AppInfoView(),
);
}
}
class AppInfoView extends StatelessWidget {
static const String repoUrl = 'https://github.com/tmaegel/ntodotxt';
const AppInfoView({super.key});
@override
Widget build(BuildContext context) {
return ListView(
padding: const EdgeInsets.symmetric(horizontal: 8.0),
children: [
ListTile(
contentPadding: const EdgeInsets.symmetric(horizontal: 8.0),
leading: const Icon(Icons.update),
title: const Text('Version'),
subtitle: const Text('v$version'),
onTap: () => _openUrl('$repoUrl/blob/main/CHANGELOG.md'),
),
ListTile(
contentPadding: const EdgeInsets.symmetric(horizontal: 8.0),
leading: const Icon(Icons.code),
title: const Text('Source code'),
subtitle: const Text(repoUrl),
onTap: () => _openUrl(repoUrl),
),
ListTile(
contentPadding: const EdgeInsets.symmetric(horizontal: 8.0),
leading: const Icon(Icons.bug_report_outlined),
title: const Text('Issue tracker'),
subtitle: const Text('$repoUrl/issues'),
onTap: () => _openUrl('$repoUrl/issues'),
),
ListTile(
contentPadding: const EdgeInsets.symmetric(horizontal: 8.0),
leading: const Icon(Icons.email_outlined),
title: const Text('Contact me'),
subtitle: const Text('tnmgl@posteo.de'),
onTap: () => _openUrl('mailto:tnmgl@posteo.de'),
),
ListTile(
contentPadding: const EdgeInsets.symmetric(horizontal: 8.0),
leading: const Icon(Icons.volunteer_activism),
title: const Text('Donation'),
subtitle: const Text('Support this app'),
onTap: () => _openUrl('https://ko-fi.com/tnmgl'),
),
ListTile(
contentPadding: const EdgeInsets.symmetric(horizontal: 8.0),
leading: const Icon(Icons.shield_outlined),
title: const Text('Licence'),
subtitle: const Text('MIT License'),
onTap: () => context.pushNamed('licenses'),
),
],
);
}
Future<void> _openUrl(String urlStr) async {
final Uri url = Uri.parse(urlStr);
if (!await launchUrl(url)) {
throw Exception('Could not open $urlStr');
}
}
}
================================================
FILE: lib/common/bloc_observer.dart
================================================
// coverage:ignore-file
import 'package:flutter_bloc/flutter_bloc.dart'
show Bloc, BlocBase, BlocObserver, Change, Transition;
import 'package:ntodotxt/main.dart' show log;
class GenericBlocObserver extends BlocObserver {
@override
void onChange(BlocBase bloc, Change change) {
super.onChange(bloc, change);
log.fine(
'STATE CHANGE: ${change.currentState.runtimeType} > ${change.nextState.runtimeType}');
log.finer('${bloc.runtimeType} $change');
}
@override
void onTransition(Bloc bloc, Transition transition) {
super.onTransition(bloc, transition);
log.finest('${bloc.runtimeType} $transition');
}
@override
void onError(BlocBase bloc, Object error, StackTrace stackTrace) {
log.fine('${bloc.runtimeType} $error $stackTrace');
super.onError(bloc, error, stackTrace);
}
}
================================================
FILE: lib/common/constants/app.dart
================================================
// coverage:ignore-file
const String version = '0.17.0';
/// https://m3.material.io/foundations/layout/applying-layout/window-size-classes
const int maxScreenWidthCompact = 600;
const String defaultLocalTodoPath = '/';
const String defaultRemoteTodoPath = '/';
const String defaultTodoFilename = 'todo.txt';
const String defaultDoneFilename = 'done.txt';
================================================
FILE: lib/common/exception/exceptions.dart
================================================
// coverage:ignore-file
sealed class TodoException implements Exception {
final String message;
const TodoException(this.message);
@override
String toString() => message;
}
class TodoNotFound extends TodoException {
final String? id;
const TodoNotFound({
this.id,
}) : super('Todo with id $id could not be found');
}
class TodoMissingId extends TodoException {
const TodoMissingId() : super('Todo has no id key');
}
class TodoStringMalformed extends TodoException {
final String str;
const TodoStringMalformed({
required this.str,
}) : super('Todo string is malformed: "$str"');
}
class TodoInvalidProjectTag extends TodoException {
final String tag;
const TodoInvalidProjectTag({
required this.tag,
}) : super('Invalid project tag: $tag');
}
class TodoInvalidContextTag extends TodoException {
final String tag;
const TodoInvalidContextTag({
required this.tag,
}) : super('Invalid context tag: $tag');
}
class TodoInvalidKeyValueTag extends TodoException {
final String tag;
const TodoInvalidKeyValueTag({
required this.tag,
}) : super('Invalid key value tag: $tag');
}
class TodoForbiddenCompletionDate extends TodoException {
const TodoForbiddenCompletionDate()
: super('Completion date is forbidden if todo is incompleted');
}
class TodoMissingCompletionDate extends TodoException {
const TodoMissingCompletionDate()
: super('Completed todo requires a completion date');
}
================================================
FILE: lib/common/misc.dart
================================================
// coverage:ignore-file
import 'dart:async';
import 'dart:io' show Platform;
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:ntodotxt/drawer/state/drawer_cubit.dart';
class PlatformInfo {
static bool get isDesktopOS {
return Platform.isMacOS || Platform.isLinux || Platform.isWindows;
}
static bool get isAppOS {
return Platform.isIOS || Platform.isAndroid;
}
}
enum MessageType { success, info, error }
class SnackBarHandler {
static void _call(BuildContext context, MessageType type, String message) {
Color backgroundColor = Theme.of(context).colorScheme.primaryContainer;
Color foregroundColor = Theme.of(context).colorScheme.onPrimaryContainer;
switch (type) {
case MessageType.success:
backgroundColor = Theme.of(context).colorScheme.primaryContainer;
foregroundColor = Theme.of(context).colorScheme.onPrimaryContainer;
break;
case MessageType.info:
backgroundColor = Theme.of(context).colorScheme.primaryContainer;
foregroundColor = Theme.of(context).colorScheme.onPrimaryContainer;
break;
case MessageType.error:
backgroundColor = Theme.of(context).colorScheme.error;
foregroundColor = Theme.of(context).colorScheme.onError;
break;
}
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
backgroundColor: backgroundColor,
duration: type == MessageType.error
? const Duration(seconds: 10)
: const Duration(seconds: 4),
content: Text(
message,
style: TextStyle(color: foregroundColor),
),
),
);
}
static void success(BuildContext context, String message) =>
_call(context, MessageType.success, message);
static void info(BuildContext context, String message) =>
_call(context, MessageType.info, message);
static void error(BuildContext context, String message) =>
_call(context, MessageType.error, message);
}
class CustomScrollBehavior extends MaterialScrollBehavior {
@override
Set<PointerDeviceKind> get dragDevices => {
PointerDeviceKind.touch,
PointerDeviceKind.mouse,
PointerDeviceKind.stylus,
PointerDeviceKind.unknown,
};
}
class Debouncer {
Timer? _timer;
final int milliseconds;
Debouncer({required this.milliseconds});
void run(VoidCallback action) {
_timer?.cancel();
_timer = Timer(Duration(milliseconds: milliseconds), action);
}
void dispose() {
_timer?.cancel();
_timer = null;
}
}
class PopScopeDrawer extends StatelessWidget {
final Widget child;
const PopScopeDrawer({
required this.child,
super.key,
});
@override
Widget build(BuildContext context) {
return PopScope(
canPop: false,
onPopInvokedWithResult: <T>(bool didPop, T? result) {
if (didPop) {
return;
}
context.read<DrawerCubit>().back();
Navigator.of(context).pop();
},
child: child,
);
}
}
================================================
FILE: lib/common/router/router.dart
================================================
// coverage:ignore-file
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:go_router/go_router.dart';
import 'package:ntodotxt/adaptive_layout/widget/adaptive_layout.dart';
import 'package:ntodotxt/app_info/page/app_details_page.dart';
import 'package:ntodotxt/filter/model/filter_model.dart';
import 'package:ntodotxt/filter/page/filter_create_edit_page.dart';
import 'package:ntodotxt/filter/page/filter_list_page.dart';
import 'package:ntodotxt/licenses/page/licenses_page.dart';
import 'package:ntodotxt/setting/page/settings_page.dart';
import 'package:ntodotxt/todo/model/todo_model.dart';
import 'package:ntodotxt/todo/page/todo_create_edit_page.dart';
import 'package:ntodotxt/todo/page/todo_list_page.dart';
import 'package:ntodotxt/todo/page/todo_search_page.dart';
import 'package:ntodotxt/todo/state/todo_list_bloc.dart';
class AppRouter {
final GlobalKey<NavigatorState> _rootNavigatorKey =
GlobalKey<NavigatorState>(debugLabel: 'root');
final GlobalKey<NavigatorState> _shellNavigatorKey =
GlobalKey<NavigatorState>(debugLabel: 'shell');
AppRouter();
late final GoRouter config = GoRouter(
navigatorKey: _rootNavigatorKey,
initialLocation: '/todo',
debugLogDiagnostics: false,
routes: <RouteBase>[
ShellRoute(
navigatorKey: _shellNavigatorKey,
builder: (context, state, child) {
return AdaptiveLayout(child: child);
},
routes: [
GoRoute(
path: '/settings',
name: 'settings',
builder: (BuildContext context, GoRouterState state) {
return const SettingsPage();
},
routes: <RouteBase>[
GoRoute(
path: 'settings/app-info',
name: 'app-info',
builder: (BuildContext context, GoRouterState state) {
return const AppInfoPage();
},
routes: <RouteBase>[
GoRoute(
path: 'settings/app-info/licenses',
name: 'licenses',
builder: (BuildContext context, GoRouterState state) {
return const LicenceListPage();
},
),
],
),
],
),
GoRoute(
path: '/todo',
name: 'todo-list',
builder: (BuildContext context, GoRouterState state) {
Filter? filter = state.extra as Filter?;
return TodoListPage(
filter: filter,
key: ValueKey(filter?.id ?? 'default'),
);
},
routes: <RouteBase>[
GoRoute(
path: 'todo/create',
name: 'todo-create',
builder: (BuildContext context, GoRouterState state) {
Todo todo = state.extra as Todo;
return TodoCreateEditPage(
initTodo: todo,
newTodo: true,
projects: context.read<TodoListBloc>().state.projects,
contexts: context.read<TodoListBloc>().state.contexts,
keyValues: context.read<TodoListBloc>().state.keyValues,
);
},
),
GoRoute(
path: 'todo/edit',
name: 'todo-edit',
builder: (BuildContext context, GoRouterState state) {
Todo todo = state.extra as Todo;
return TodoCreateEditPage(
initTodo: todo,
newTodo: false,
projects: context.read<TodoListBloc>().state.projects,
contexts: context.read<TodoListBloc>().state.contexts,
keyValues: context.read<TodoListBloc>().state.keyValues,
);
},
),
GoRoute(
path: 'todo/search',
name: 'todo-search',
builder: (BuildContext context, GoRouterState state) {
Filter? filter = state.extra as Filter?;
return TodoSearchPage(filter: filter);
},
),
],
),
GoRoute(
path: '/filter',
name: 'filter-list',
builder: (BuildContext context, GoRouterState state) {
return const FilterListPage();
},
routes: <RouteBase>[
GoRoute(
path: 'filter/create',
name: 'filter-create',
builder: (BuildContext context, GoRouterState state) {
return FilterCreateEditPage(
projects: context.read<TodoListBloc>().state.projects,
contexts: context.read<TodoListBloc>().state.contexts,
);
},
),
GoRoute(
path: 'filter/edit',
name: 'filter-edit',
builder: (BuildContext context, GoRouterState state) {
Filter filter = state.extra as Filter;
return FilterCreateEditPage(
initFilter: filter,
projects: context.read<TodoListBloc>().state.projects,
contexts: context.read<TodoListBloc>().state.contexts,
);
},
),
],
),
],
),
],
);
}
================================================
FILE: lib/common/theme/theme.dart
================================================
// coverage:ignore-file
import 'package:flex_color_scheme/flex_color_scheme.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:ntodotxt/common/misc.dart';
final ThemeData light = CustomTheme.light;
final ThemeData dark = CustomTheme.dark;
/// Customize versions of the theme data.
final ThemeData lightTheme = light.copyWith(
appBarTheme: light.appBarTheme.copyWith(
backgroundColor: Colors.transparent,
systemOverlayStyle: const SystemUiOverlayStyle(
statusBarColor: Colors.transparent,
statusBarBrightness: Brightness.dark,
statusBarIconBrightness: Brightness.dark,
systemNavigationBarColor: Colors.transparent,
systemNavigationBarIconBrightness: Brightness.dark,
),
),
snackBarTheme: light.snackBarTheme.copyWith(
elevation: 0.0,
),
splashColor: PlatformInfo.isAppOS ? Colors.transparent : null,
chipTheme: light.chipTheme.copyWith(),
expansionTileTheme: light.expansionTileTheme.copyWith(
shape: const Border(),
collapsedBackgroundColor: light.appBarTheme.backgroundColor,
textColor: light.colorScheme.primary,
),
listTileTheme: light.listTileTheme.copyWith(
selectedColor: light.textTheme.bodySmall?.color,
selectedTileColor: light.hoverColor,
contentPadding: const EdgeInsets.symmetric(horizontal: 12.0),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
),
),
scrollbarTheme: light.scrollbarTheme.copyWith(
thickness: WidgetStateProperty.all(5.0),
),
bottomAppBarTheme: light.bottomAppBarTheme.copyWith(),
floatingActionButtonTheme: light.floatingActionButtonTheme.copyWith(
elevation: 0.0,
focusElevation: 0.0,
hoverElevation: 0.0,
),
inputDecorationTheme: light.inputDecorationTheme.copyWith(
filled: false,
isDense: true,
border: InputBorder.none,
enabledBorder: InputBorder.none,
focusedBorder: InputBorder.none,
focusedErrorBorder: InputBorder.none,
errorBorder: InputBorder.none,
disabledBorder: InputBorder.none,
),
progressIndicatorTheme: light.progressIndicatorTheme.copyWith(
color: light.colorScheme.primary,
circularTrackColor: light.colorScheme.primaryContainer,
refreshBackgroundColor: light.colorScheme.primaryContainer,
),
);
final ThemeData darkTheme = dark.copyWith(
appBarTheme: dark.appBarTheme.copyWith(
backgroundColor: Colors.transparent,
systemOverlayStyle: const SystemUiOverlayStyle(
statusBarColor: Colors.transparent,
statusBarBrightness: Brightness.light,
statusBarIconBrightness: Brightness.light,
systemNavigationBarColor: Colors.transparent,
systemNavigationBarIconBrightness: Brightness.light,
),
),
snackBarTheme: dark.snackBarTheme.copyWith(
elevation: 0.0,
),
splashColor: PlatformInfo.isAppOS ? Colors.transparent : null,
chipTheme: dark.chipTheme.copyWith(),
expansionTileTheme: dark.expansionTileTheme.copyWith(
shape: const Border(),
collapsedBackgroundColor: dark.appBarTheme.backgroundColor,
textColor: dark.colorScheme.primary,
),
listTileTheme: dark.listTileTheme.copyWith(
selectedColor: dark.textTheme.bodySmall?.color,
selectedTileColor: dark.hoverColor,
contentPadding: const EdgeInsets.symmetric(horizontal: 12.0),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
),
),
scrollbarTheme: dark.scrollbarTheme.copyWith(
thickness: WidgetStateProperty.all(5.0),
),
bottomAppBarTheme: dark.bottomAppBarTheme.copyWith(),
floatingActionButtonTheme: dark.floatingActionButtonTheme.copyWith(
elevation: 0.0,
focusElevation: 0.0,
hoverElevation: 0.0,
),
inputDecorationTheme: dark.inputDecorationTheme.copyWith(
filled: false,
isDense: true,
border: InputBorder.none,
enabledBorder: InputBorder.none,
focusedBorder: InputBorder.none,
focusedErrorBorder: InputBorder.none,
errorBorder: InputBorder.none,
disabledBorder: InputBorder.none,
),
progressIndicatorTheme: dark.progressIndicatorTheme.copyWith(
color: dark.colorScheme.primary,
circularTrackColor: dark.colorScheme.primaryContainer,
refreshBackgroundColor: dark.colorScheme.primaryContainer,
),
);
// Theme config for FlexColorScheme version 7.3.x. Make sure you use
// same or higher package version, but still same major version. If you
// use a lower package version, some properties may not be supported.
// In that case remove them after copying this theme to your app.
class CustomTheme {
static ThemeData get light {
return FlexThemeData.light(
scheme: FlexScheme.bahamaBlue,
surfaceMode: FlexSurfaceMode.levelSurfacesLowScaffold,
blendLevel: 7,
subThemesData: const FlexSubThemesData(
blendOnLevel: 10,
blendOnColors: false,
useM2StyleDividerInM3: true,
alignedDropdown: true,
useInputDecoratorThemeInDialogs: true,
),
visualDensity: FlexColorScheme.comfortablePlatformDensity,
useMaterial3: true,
swapLegacyOnMaterial3: true,
fontFamily: 'OpenSans',
);
}
static ThemeData get dark {
return FlexThemeData.dark(
scheme: FlexScheme.bahamaBlue,
surfaceMode: FlexSurfaceMode.levelSurfacesLowScaffold,
blendLevel: 13,
subThemesData: const FlexSubThemesData(
blendOnLevel: 20,
useM2StyleDividerInM3: true,
alignedDropdown: true,
useInputDecoratorThemeInDialogs: true,
),
visualDensity: FlexColorScheme.comfortablePlatformDensity,
useMaterial3: true,
swapLegacyOnMaterial3: true,
fontFamily: 'OpenSans',
);
}
}
================================================
FILE: lib/common/widget/app_bar.dart
================================================
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:ntodotxt/common/misc.dart' show CustomScrollBehavior;
import 'package:ntodotxt/drawer/widget/drawer.dart';
import 'package:ntodotxt/filter/widget/filter_chip.dart';
import 'package:ntodotxt/todo/state/todo_list_bloc.dart';
import 'package:ntodotxt/todo/state/todo_list_state.dart';
class MainAppBar extends StatelessWidget implements PreferredSizeWidget {
final String title;
final Widget? toolbar;
final Widget? bottom;
const MainAppBar({
required this.title,
this.toolbar,
this.bottom,
super.key,
});
@override
Widget build(BuildContext context) {
// @todo: Activate WideLayout later!
// final bool narrowView =
// MediaQuery.of(context).size.width < maxScreenWidthCompact;
return AppBar(
// titleSpacing: narrowView ? 0.0 : null,
titleSpacing: 0.0,
title: Text(title),
// leading: narrowView && Scaffold.of(context).hasDrawer
leading: Scaffold.of(context).hasDrawer
? Builder(
builder: (BuildContext context) {
return IconButton(
tooltip: 'Open drawer',
icon: const Icon(Icons.menu),
onPressed: () async {
await showModalBottomSheet(
context: context,
isScrollControlled: true,
builder: (BuildContext context) =>
const BottomSheetNavigationDrawer(),
);
},
);
},
)
: null,
actions: toolbar == null
? null
: <Widget>[
toolbar!,
const SizedBox(width: 8),
],
bottom: bottom == null
? null
: PreferredSize(
preferredSize: Size.zero,
child: Padding(
padding: const EdgeInsets.only(bottom: 8.0),
child: bottom!,
),
),
);
}
// Scaffold requires as appbar a class that implements PreferredSizeWidget.
@override
Size get preferredSize =>
Size.fromHeight(bottom == null ? kToolbarHeight : 110);
}
class AppBarFilterList extends StatelessWidget {
const AppBarFilterList({super.key});
@override
Widget build(BuildContext context) {
final ScrollController controller = ScrollController();
return BlocBuilder<TodoListBloc, TodoListState>(
builder: (BuildContext context, TodoListState todoListState) {
return ScrollConfiguration(
behavior: CustomScrollBehavior(),
child: SingleChildScrollView(
controller: controller,
scrollDirection: Axis.horizontal,
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const FilterOrderChip(),
const SizedBox(width: 4),
const FilterFilterChip(),
const SizedBox(width: 4),
const FilterGroupChip(),
const SizedBox(width: 4),
const FilterPrioritiesChip(),
const SizedBox(width: 4),
FilterProjectsChip(availableTags: todoListState.projects),
const SizedBox(width: 4),
FilterContextsChip(availableTags: todoListState.contexts),
],
),
),
),
);
},
);
}
}
================================================
FILE: lib/common/widget/chip.dart
================================================
import 'package:flutter/material.dart';
class BasicIconChip extends StatelessWidget {
final String label;
final IconData iconData;
final bool mono;
const BasicIconChip({
required this.label,
required this.iconData,
this.mono = false,
super.key,
});
@override
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.symmetric(horizontal: 4.0, vertical: 0.0),
decoration: BoxDecoration(
color: mono
? Theme.of(context).colorScheme.surfaceContainerHigh
: Theme.of(context).colorScheme.secondaryContainer,
borderRadius: BorderRadius.circular(4),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Icon(iconData, size: 14.0),
const SizedBox(width: 2.0),
Text(
label,
style: TextStyle(
color: mono
? Theme.of(context).colorScheme.onSurfaceVariant
: Theme.of(context).colorScheme.onSecondaryContainer,
),
)
],
),
);
}
}
class BasicChip extends StatelessWidget {
final String label;
final bool mono;
const BasicChip({
required this.label,
this.mono = false,
super.key,
});
@override
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.symmetric(horizontal: 4.0, vertical: 0.0),
decoration: BoxDecoration(
color: mono
? Theme.of(context).colorScheme.surfaceContainerHigh
: Theme.of(context).colorScheme.secondaryContainer,
borderRadius: BorderRadius.circular(4),
),
child: Text(
label,
style: TextStyle(
color: mono
? Theme.of(context).colorScheme.onSurfaceVariant
: Theme.of(context).colorScheme.onSecondaryContainer,
),
),
);
}
}
class GenericActionChip extends StatelessWidget {
final Widget label;
final Widget avatar;
final Function() onPressed;
final bool selected;
const GenericActionChip({
required this.label,
required this.avatar,
required this.onPressed,
this.selected = false,
super.key,
});
@override
Widget build(BuildContext context) {
return ActionChip(
avatar: avatar,
label: label,
padding: EdgeInsets.zero,
side: selected == true
? BorderSide(color: Theme.of(context).colorScheme.primary)
: null,
labelPadding: const EdgeInsets.only(right: 8.0),
onPressed: () async => onPressed(),
);
}
}
class GenericChoiceChip extends StatelessWidget {
final Widget label;
final bool selected;
final bool showCheckmark;
final Function(bool selected) onSelected;
const GenericChoiceChip({
required this.label,
this.selected = false,
this.showCheckmark = false,
required this.onSelected,
super.key,
});
@override
Widget build(BuildContext context) {
return ChoiceChip(
label: label,
selected: selected,
showCheckmark: showCheckmark,
// Workaround: https://github.com/flutter/flutter/issues/67797
visualDensity: const VisualDensity(
horizontal: -4.0,
vertical: -4.0,
),
onSelected: (bool selected) => onSelected(selected),
);
}
}
class GenericChipGroup extends StatelessWidget {
final List<Widget> children;
final WrapAlignment alignment;
const GenericChipGroup({
required this.children,
this.alignment = WrapAlignment.start,
super.key,
});
@override
Widget build(BuildContext context) {
return Wrap(
spacing: 4.0, // gap between adjacent chips
alignment: alignment,
runSpacing: 4.0, // gap between lines
runAlignment: WrapAlignment.center,
crossAxisAlignment: WrapCrossAlignment.start,
children: children,
);
}
}
================================================
FILE: lib/common/widget/confirm_dialog.dart
================================================
import 'package:flutter/material.dart';
class ConfirmationDialog extends StatelessWidget {
final String title;
final String message;
final String actionLabel;
final String cancelLabel;
const ConfirmationDialog({
required this.title,
required this.message,
required this.actionLabel,
required this.cancelLabel,
super.key,
});
static Future<bool> dialog({
required BuildContext context,
required String title,
required String message,
required String actionLabel,
required String cancelLabel,
}) async {
bool? result = await showDialog<bool>(
useRootNavigator: false,
context: context,
barrierDismissible: false, // User must tap button.
builder: (BuildContext context) => ConfirmationDialog(
title: title,
message: message,
actionLabel: actionLabel,
cancelLabel: cancelLabel,
),
);
return result ?? false;
}
@override
Widget build(BuildContext context) {
return AlertDialog(
title: Text(title),
content: Text(message),
actions: <Widget>[
TextButton(
child: Text(cancelLabel),
onPressed: () => Navigator.pop(context, false),
),
TextButton(
child: Text(actionLabel),
onPressed: () => Navigator.pop(context, true),
),
],
);
}
}
================================================
FILE: lib/common/widget/contexts_dialog.dart
================================================
import 'package:flutter/material.dart';
import 'package:ntodotxt/common/widget/tag_dialog.dart';
import 'package:ntodotxt/filter/state/filter_cubit.dart' show FilterCubit;
import 'package:ntodotxt/todo/state/todo_cubit.dart';
class FilterContextTagDialog extends TagDialog {
final FilterCubit cubit;
const FilterContextTagDialog({
required this.cubit,
super.title = 'Contexts',
super.tagName = 'context',
super.availableTags,
super.addTags = false,
super.key = const Key('FilterContextTagDialog'),
});
@override
RegExp get regex => RegExp(r'^\S+$');
static Future<void> dialog({
required BuildContext context,
required FilterCubit cubit,
required Set<String> availableTags,
}) async {
showModalBottomSheet<void>(
context: context,
isScrollControlled: true,
builder: (BuildContext context) => FilterContextTagDialog(
cubit: cubit,
availableTags: availableTags,
),
);
}
@override
State<FilterContextTagDialog> createState() => _FilterContextTagDialogState();
}
class _FilterContextTagDialogState
extends TagDialogState<FilterContextTagDialog> {
@override
void initState() {
super.initState();
super.tags = {
...widget.availableTags.map(
(String t) => Tag(
name: t,
selected: widget.cubit.state.filter.contexts.contains(t),
),
),
};
}
@override
void onUpdate() {
widget.cubit.updateContexts({
for (Tag t in tags)
if (t.selected) t.name
});
}
}
class TodoContextTagDialog extends TagDialog {
final TodoCubit cubit;
const TodoContextTagDialog({
required this.cubit,
super.title = 'Contexts',
super.tagName = 'context',
super.availableTags,
super.addTags = true,
super.key = const Key('TodoContextTagDialog'),
});
@override
RegExp get regex => RegExp(r'^\S+$');
static Future<void> dialog({
required BuildContext context,
required TodoCubit cubit,
required Set<String> availableTags,
}) async {
showModalBottomSheet<void>(
context: context,
isScrollControlled: true,
builder: (BuildContext context) => TodoContextTagDialog(
cubit: cubit,
availableTags: availableTags,
),
);
}
@override
State<TodoContextTagDialog> createState() => _TodoContextTagDialogState();
}
class _TodoContextTagDialogState extends TagDialogState<TodoContextTagDialog> {
@override
void initState() {
super.initState();
super.tags = {
...widget.availableTags.map(
(String t) => Tag(
name: t,
selected: widget.cubit.state.todo.contexts.contains(t),
),
),
// Overwrites contexts of todo with selected=true
...widget.cubit.state.todo.contexts.map(
(String t) => Tag(name: t, selected: true),
),
};
}
@override
void onUpdate() {
widget.cubit.updateContexts({
for (Tag t in tags)
if (t.selected) t.name
});
}
}
================================================
FILE: lib/common/widget/date_picker.dart
================================================
import 'package:flutter/material.dart';
class TodoDatePicker {
static final int defaultDaysOffset = 3650;
const TodoDatePicker();
static Future<DateTime?> pickDate({
required BuildContext context,
required DateTime? initialDate,
int? startDateDaysOffset,
int? endDateDaysOffset,
}) async {
final DateTime initial = initialDate ?? DateTime.now();
return await showDatePicker(
useRootNavigator: false,
context: context,
firstDate: initial.subtract(
Duration(days: startDateDaysOffset ?? defaultDaysOffset),
),
initialDate: initial,
lastDate: initial.add(
Duration(days: endDateDaysOffset ?? defaultDaysOffset),
),
locale: const Locale('en', 'GB'),
);
}
}
================================================
FILE: lib/common/widget/filter_dialog.dart
================================================
import 'package:flutter/material.dart';
import 'package:ntodotxt/filter/model/filter_model.dart' show ListFilter;
import 'package:ntodotxt/filter/state/filter_cubit.dart' show FilterCubit;
class FilterStateFilterDialog extends StatelessWidget {
final FilterCubit cubit;
final Map<String, ListFilter> items;
const FilterStateFilterDialog({
required this.cubit,
super.key,
}) : items = const {
'All': ListFilter.all,
'Completed only': ListFilter.completedOnly,
'Incompleted only': ListFilter.incompletedOnly,
};
static Future<void> dialog({
required BuildContext context,
required FilterCubit cubit,
}) async {
return await showDialog<Future<void>>(
useRootNavigator: false,
context: context,
builder: (BuildContext context) => FilterStateFilterDialog(cubit: cubit),
);
}
@override
Widget build(BuildContext context) {
return Dialog(
child: ListView.builder(
shrinkWrap: true,
padding: const EdgeInsets.all(16.0),
itemCount: items.length,
itemBuilder: (BuildContext context, int index) {
String key = items.keys.elementAt(index);
ListFilter value = items[key]!;
return RadioListTile<ListFilter>(
key: Key('${value.name}DialogRadioButton'),
contentPadding: EdgeInsets.zero,
title: Text(key),
value: value,
groupValue: cubit.state.filter.filter,
onChanged: (ListFilter? value) {
if (value != null) {
cubit.updateFilter(value);
}
Navigator.pop(context);
},
);
},
),
);
}
}
class DefaultFilterStateFilterDialog extends StatelessWidget {
final FilterCubit cubit;
final Map<String, ListFilter> items;
const DefaultFilterStateFilterDialog({
required this.cubit,
super.key,
}) : items = const {
'All': ListFilter.all,
'Completed only': ListFilter.completedOnly,
'Incompleted only': ListFilter.incompletedOnly,
};
static Future<void> dialog({
required BuildContext context,
required FilterCubit cubit,
}) async {
return await showDialog<Future<void>>(
useRootNavigator: false,
context: context,
builder: (BuildContext context) =>
DefaultFilterStateFilterDialog(cubit: cubit),
);
}
@override
Widget build(BuildContext context) {
return Dialog(
child: ListView.builder(
shrinkWrap: true,
padding: const EdgeInsets.all(16.0),
itemCount: items.length,
itemBuilder: (BuildContext context, int index) {
String key = items.keys.elementAt(index);
ListFilter value = items[key]!;
return RadioListTile<ListFilter>(
key: Key('${value.name}DialogRadioButton'),
contentPadding: EdgeInsets.zero,
value: value,
title: Text(key),
groupValue: cubit.state.filter.filter,
onChanged: (ListFilter? value) {
if (value != null) {
cubit.updateDefaultFilter(value);
}
Navigator.pop(context);
},
);
},
),
);
}
}
================================================
FILE: lib/common/widget/group_by_dialog.dart
================================================
import 'package:flutter/material.dart';
import 'package:ntodotxt/filter/model/filter_model.dart' show ListGroup;
import 'package:ntodotxt/filter/state/filter_cubit.dart' show FilterCubit;
class FilterStateGroupDialog extends StatelessWidget {
final FilterCubit cubit;
final Map<String, ListGroup> items;
const FilterStateGroupDialog({
required this.cubit,
super.key,
}) : items = const {
'None': ListGroup.none,
'Upcoming': ListGroup.upcoming,
'Priority': ListGroup.priority,
'Project': ListGroup.project,
'Context': ListGroup.context,
};
static Future<void> dialog({
required BuildContext context,
required FilterCubit cubit,
}) async {
return await showDialog<Future<void>>(
useRootNavigator: false,
context: context,
builder: (BuildContext context) => FilterStateGroupDialog(cubit: cubit),
);
}
@override
Widget build(BuildContext context) {
return Dialog(
child: ListView.builder(
shrinkWrap: true,
padding: const EdgeInsets.all(16.0),
itemCount: items.length,
itemBuilder: (BuildContext context, int index) {
String key = items.keys.elementAt(index);
ListGroup value = items[key]!;
return RadioListTile<ListGroup>(
key: Key('${value.name}DialogRadioButton'),
contentPadding: EdgeInsets.zero,
title: Text(key),
value: value,
groupValue: cubit.state.filter.group,
onChanged: (ListGroup? value) {
if (value != null) {
cubit.updateGroup(value);
}
Navigator.pop(context);
},
);
},
),
);
}
}
class DefaultFilterStateGroupDialog extends StatelessWidget {
final FilterCubit cubit;
final Map<String, ListGroup> items;
const DefaultFilterStateGroupDialog({
required this.cubit,
super.key,
}) : items = const {
'None': ListGroup.none,
'Upcoming': ListGroup.upcoming,
'Priority': ListGroup.priority,
'Project': ListGroup.project,
'Context': ListGroup.context,
};
static Future<void> dialog({
required BuildContext context,
required FilterCubit cubit,
}) async {
return await showDialog<Future<void>>(
useRootNavigator: false,
context: context,
builder: (BuildContext context) =>
DefaultFilterStateGroupDialog(cubit: cubit),
);
}
@override
Widget build(BuildContext context) {
return Dialog(
child: ListView.builder(
shrinkWrap: true,
padding: const EdgeInsets.all(16.0),
itemCount: items.length,
itemBuilder: (BuildContext context, int index) {
String key = items.keys.elementAt(index);
ListGroup value = items[key]!;
return RadioListTile<ListGroup>(
key: Key('${value.name}DialogRadioButton'),
contentPadding: EdgeInsets.zero,
value: value,
title: Text(key),
groupValue: cubit.state.filter.group,
onChanged: (ListGroup? value) {
if (value != null) {
cubit.updateDefaultGroup(value);
}
Navigator.pop(context);
});
},
),
);
}
}
================================================
FILE: lib/common/widget/info_dialog.dart
================================================
import 'package:flutter/material.dart';
class InfoDialog extends StatelessWidget {
final String title;
final String message;
const InfoDialog({
required this.title,
required this.message,
super.key,
});
static Future<void> dialog({
required BuildContext context,
required String title,
required String message,
}) async {
return await showDialog<void>(
useRootNavigator: false,
context: context,
barrierDismissible: true,
builder: (BuildContext context) => InfoDialog(
title: title,
message: message,
),
);
}
@override
Widget build(BuildContext context) {
return AlertDialog(
title: Text(title),
titleTextStyle: Theme.of(context).textTheme.titleMedium,
content: Text(message),
);
}
}
================================================
FILE: lib/common/widget/input_dialog.dart
================================================
import 'package:flutter/material.dart';
class InputDialog extends StatelessWidget {
final String title;
final String label;
final String? value;
const InputDialog({
required this.title,
required this.label,
this.value,
super.key,
});
static Future<String?> dialog({
required BuildContext context,
required String title,
required String label,
String? value,
}) async {
return await showDialog<String?>(
useRootNavigator: false,
context: context,
barrierDismissible: false, // User must tap button.
builder: (BuildContext context) =>
InputDialog(title: title, label: label, value: value),
);
}
@override
Widget build(BuildContext context) {
final TextEditingController controller = TextEditingController();
controller.text = value ?? '';
return AlertDialog(
title: Text(title),
content: TextField(
controller: controller,
decoration: InputDecoration(hintText: label),
),
actions: <Widget>[
TextButton(
child: const Text('Cancel'),
onPressed: () => Navigator.pop(context),
),
TextButton(
child: const Text('Ok'),
onPressed: () => Navigator.pop(context, controller.text),
),
],
);
}
}
================================================
FILE: lib/common/widget/key_values_dialog.dart
================================================
import 'package:flutter/material.dart';
import 'package:ntodotxt/common/widget/tag_dialog.dart';
import 'package:ntodotxt/todo/model/todo_model.dart';
import 'package:ntodotxt/todo/state/todo_cubit.dart';
class TodoKeyValueTagDialog extends TagDialog {
final TodoCubit cubit;
const TodoKeyValueTagDialog({
required this.cubit,
super.title = 'Key values',
super.tagName = 'key:value',
super.availableTags,
super.addTags = true,
super.key = const Key('TodoKeyValueTagDialog'),
});
@override
RegExp get regex => Todo.patternKeyValue;
static Future<void> dialog({
required BuildContext context,
required TodoCubit cubit,
required Set<String> availableTags,
}) async {
showModalBottomSheet<void>(
context: context,
isScrollControlled: true,
builder: (BuildContext context) => TodoKeyValueTagDialog(
cubit: cubit,
availableTags: availableTags,
),
);
}
@override
State<TodoKeyValueTagDialog> createState() => _TodoKeyValueTagDialogState();
}
class _TodoKeyValueTagDialogState
extends TagDialogState<TodoKeyValueTagDialog> {
@override
void initState() {
super.initState();
super.tags = {
...widget.availableTags.map(
(String t) => Tag(
name: t,
selected: widget.cubit.state.todo.fmtKeyValues.contains(t),
),
),
// Overwrites key values of todo with selected=true
...widget.cubit.state.todo.fmtKeyValues.map(
(String t) => Tag(name: t, selected: true),
),
};
}
@override
void onUpdate() {
widget.cubit.updateKeyValues({
for (Tag t in tags)
if (t.selected) t.name
});
}
}
================================================
FILE: lib/common/widget/order_dialog.dart
================================================
import 'package:flutter/material.dart';
import 'package:ntodotxt/filter/model/filter_model.dart' show ListOrder;
import 'package:ntodotxt/filter/state/filter_cubit.dart' show FilterCubit;
class FilterStateOrderDialog extends StatelessWidget {
final FilterCubit cubit;
final Map<String, ListOrder> items;
const FilterStateOrderDialog({
required this.cubit,
super.key,
}) : items = const {
'Ascending': ListOrder.ascending,
'Descending': ListOrder.descending,
};
static Future<void> dialog({
required BuildContext context,
required FilterCubit cubit,
}) async {
return await showDialog<Future<void>>(
useRootNavigator: false,
context: context,
builder: (BuildContext context) => FilterStateOrderDialog(cubit: cubit),
);
}
@override
Widget build(BuildContext context) {
return Dialog(
child: ListView.builder(
shrinkWrap: true,
padding: const EdgeInsets.all(16.0),
itemCount: items.length,
itemBuilder: (BuildContext context, int index) {
String key = items.keys.elementAt(index);
ListOrder value = items[key]!;
return RadioListTile<ListOrder>(
key: Key('${value.name}DialogRadioButton'),
contentPadding: EdgeInsets.zero,
title: Text(key),
value: value,
groupValue: cubit.state.filter.order,
onChanged: (ListOrder? value) {
if (value != null) {
cubit.updateOrder(value);
}
Navigator.pop(context);
},
);
},
),
);
}
}
class DefaultFilterStateOrderDialog extends StatelessWidget {
final FilterCubit cubit;
final Map<String, ListOrder> items;
const DefaultFilterStateOrderDialog({
required this.cubit,
super.key,
}) : items = const {
'Ascending': ListOrder.ascending,
'Descending': ListOrder.descending,
};
static Future<void> dialog({
required BuildContext context,
required FilterCubit cubit,
}) async {
return await showDialog<Future<void>>(
useRootNavigator: false,
context: context,
builder: (BuildContext context) =>
DefaultFilterStateOrderDialog(cubit: cubit),
);
}
@override
Widget build(BuildContext context) {
return Dialog(
child: ListView.builder(
shrinkWrap: true,
padding: const EdgeInsets.all(16.0),
itemCount: items.length,
itemBuilder: (BuildContext context, int index) {
String key = items.keys.elementAt(index);
ListOrder value = items[key]!;
return RadioListTile<ListOrder>(
key: Key('${value.name}DialogRadioButton'),
contentPadding: EdgeInsets.zero,
value: value,
title: Text(key),
groupValue: cubit.state.filter.order,
onChanged: (ListOrder? value) {
if (value != null) {
cubit.updateDefaultOrder(value);
}
Navigator.pop(context);
},
);
},
),
);
}
}
================================================
FILE: lib/common/widget/priorities_dialog.dart
================================================
import 'package:flutter/material.dart';
import 'package:ntodotxt/common/misc.dart';
import 'package:ntodotxt/common/widget/chip.dart';
import 'package:ntodotxt/filter/state/filter_cubit.dart' show FilterCubit;
import 'package:ntodotxt/todo/model/todo_model.dart' show Priority;
import 'package:ntodotxt/todo/state/todo_cubit.dart';
class PriorityTag {
Priority priority;
bool selected;
PriorityTag({
required this.priority,
required this.selected,
});
@override
String toString() => priority.name;
}
class PriorityTagDialog extends StatefulWidget {
final String title;
final Set<Priority> availableTags;
const PriorityTagDialog({
required this.title,
this.availableTags = const {},
super.key,
});
@override
State<PriorityTagDialog> createState() => PriorityTagDialogState();
}
class PriorityTagDialogState<T extends PriorityTagDialog> extends State<T> {
// Holds the selected tags before adding to the regular state.
Set<PriorityTag> tags = {};
late TextEditingController _controller;
@override
void initState() {
super.initState();
_controller = TextEditingController();
}
@override
void dispose() {
// Clean up the controller when the widget is disposed.
_controller.dispose();
super.dispose();
}
Set<PriorityTag> get sortedTags {
List<PriorityTag> t = tags.toList()
..sort(
(PriorityTag a, PriorityTag b) => a.toString().compareTo(b.toString()),
);
return t.toSet();
}
void onUpdate(PriorityTag value, bool selected) {}
@override
Widget build(BuildContext context) {
return DraggableScrollableSheet(
initialChildSize: 0.5,
minChildSize: 0.15,
maxChildSize: 0.9,
expand: false,
builder: (BuildContext context, ScrollController scrollController) {
return ScrollConfiguration(
behavior: CustomScrollBehavior(),
child: ListView(
controller: scrollController,
children: [
Padding(
padding: const EdgeInsets.fromLTRB(16.0, 12.0, 16.0, 8.0),
child: ListTile(
contentPadding: const EdgeInsets.symmetric(horizontal: 8.0),
title: Text(
widget.title,
style: Theme.of(context).textTheme.titleLarge,
),
),
),
if (tags.isNotEmpty) const Divider(),
if (tags.isNotEmpty)
Padding(
padding: const EdgeInsets.symmetric(
horizontal: 16.0, vertical: 8.0),
child: ListTile(
contentPadding: const EdgeInsets.symmetric(horizontal: 8.0),
title: GenericChipGroup(
children: [
for (var t in sortedTags)
GenericChoiceChip(
label: Text(t.priority.name),
selected: t.selected,
onSelected: (bool selected) =>
onUpdate(t, selected),
),
],
),
),
),
],
),
);
},
);
}
}
class FilterPriorityTagDialog extends PriorityTagDialog {
final FilterCubit cubit;
const FilterPriorityTagDialog({
required this.cubit,
super.title = 'Priorities',
super.availableTags,
super.key = const Key('FilterPriorityTagDialog'),
});
static Future<void> dialog({
required BuildContext context,
required FilterCubit cubit,
required Set<Priority> availableTags,
}) async {
showModalBottomSheet<void>(
context: context,
isScrollControlled: true,
builder: (BuildContext context) => FilterPriorityTagDialog(
cubit: cubit,
availableTags: availableTags,
),
);
}
@override
State<FilterPriorityTagDialog> createState() =>
_FilterPriorityTagDialogState();
}
class _FilterPriorityTagDialogState
extends PriorityTagDialogState<FilterPriorityTagDialog> {
@override
void initState() {
super.initState();
super.tags = {
...widget.availableTags.map(
(Priority t) => PriorityTag(
priority: t,
selected: widget.cubit.state.filter.priorities.contains(t),
),
),
};
}
@override
void onUpdate(PriorityTag value, bool selected) {
setState(() {
value.selected = selected;
});
widget.cubit.updatePriorities({
for (PriorityTag t in tags)
if (t.selected) t.priority
});
}
}
class TodoPriorityTagDialog extends PriorityTagDialog {
final TodoCubit cubit;
const TodoPriorityTagDialog({
required this.cubit,
super.title = 'Priorities',
super.availableTags,
super.key = const Key('TodoPriorityTagDialog'),
});
static Future<void> dialog({
required BuildContext context,
required TodoCubit cubit,
required Set<Priority> availableTags,
}) async {
showModalBottomSheet<void>(
context: context,
isScrollControlled: true,
builder: (BuildContext context) => TodoPriorityTagDialog(
cubit: cubit,
availableTags: availableTags,
),
);
}
@override
State<TodoPriorityTagDialog> createState() => _TodoPriorityTagDialogState();
}
class _TodoPriorityTagDialogState
extends PriorityTagDialogState<TodoPriorityTagDialog> {
@override
void initState() {
super.initState();
super.tags = {
...widget.availableTags.map(
(Priority t) => PriorityTag(
priority: t,
selected: widget.cubit.state.todo.priority == t,
),
),
};
}
@override
void onUpdate(PriorityTag value, bool selected) {
setState(() {
// Unset priorities first.
for (PriorityTag tag in tags) {
tag.selected = false;
}
value.selected = selected;
});
if (selected) {
widget.cubit.setPriority(value.priority);
} else {
widget.cubit.unsetPriority();
}
}
}
================================================
FILE: lib/common/widget/projects_dialog.dart
================================================
import 'package:flutter/material.dart';
import 'package:ntodotxt/common/widget/tag_dialog.dart';
import 'package:ntodotxt/filter/state/filter_cubit.dart' show FilterCubit;
import 'package:ntodotxt/todo/state/todo_cubit.dart';
class FilterProjectTagDialog extends TagDialog {
final FilterCubit cubit;
const FilterProjectTagDialog({
required this.cubit,
super.title = 'Projects',
super.tagName = 'project',
super.availableTags,
super.addTags = false,
super.key = const Key('FilterProjectTagDialog'),
});
@override
RegExp get regex => RegExp(r'^\S+$');
static Future<void> dialog({
required BuildContext context,
required FilterCubit cubit,
required Set<String> availableTags,
}) async {
showModalBottomSheet<void>(
context: context,
isScrollControlled: true,
builder: (BuildContext context) => FilterProjectTagDialog(
cubit: cubit,
availableTags: availableTags,
),
);
}
@override
State<FilterProjectTagDialog> createState() => _FilterProjectTagDialogState();
}
class _FilterProjectTagDialogState
extends TagDialogState<FilterProjectTagDialog> {
@override
void initState() {
super.initState();
super.tags = {
...widget.availableTags.map(
(String t) => Tag(
name: t,
selected: widget.cubit.state.filter.projects.contains(t),
),
),
};
}
@override
void onUpdate() {
widget.cubit.updateProjects({
for (Tag t in tags)
if (t.selected) t.name
});
}
}
class TodoProjectTagDialog extends TagDialog {
final TodoCubit cubit;
const TodoProjectTagDialog({
required this.cubit,
super.title = 'Projects',
super.tagName = 'project',
super.availableTags,
super.addTags = true,
super.key = const Key('TodoProjectTagDialog'),
});
@override
RegExp get regex => RegExp(r'^\S+$');
static Future<void> dialog({
required BuildContext context,
required TodoCubit cubit,
required Set<String> availableTags,
}) async {
showModalBottomSheet<void>(
context: context,
isScrollControlled: true,
builder: (BuildContext context) => TodoProjectTagDialog(
cubit: cubit,
availableTags: availableTags,
),
);
}
@override
State<TodoProjectTagDialog> createState() => _TodoProjectTagDialogState();
}
class _TodoProjectTagDialogState extends TagDialogState<TodoProjectTagDialog> {
@override
void initState() {
super.initState();
super.tags = {
...widget.availableTags.map(
(String t) => Tag(
name: t,
selected: widget.cubit.state.todo.projects.contains(t),
),
),
// Overwrites projects of todo with selected=true
...widget.cubit.state.todo.projects.map(
(String t) => Tag(name: t, selected: true),
),
};
}
@override
void onUpdate() {
widget.cubit.updateProjects({
for (Tag t in tags)
if (t.selected) t.name
});
}
}
================================================
FILE: lib/common/widget/scroll_to_top.dart
================================================
import 'package:flutter/material.dart';
class ScollToTopView extends StatefulWidget {
const ScollToTopView({super.key});
@override
State<ScollToTopView> createState() => ScollToTopViewState();
}
class ScollToTopViewState<T extends ScollToTopView> extends State<T> {
bool scrolledDown = false;
late ScrollController scrollController;
@override
void initState() {
scrollController = ScrollController()
..addListener(
() {
setState(() {
if (scrollController.offset >= 50) {
scrolledDown = true;
} else {
scrolledDown = false;
}
});
},
);
super.initState();
}
@override
void dispose() {
scrollController.dispose();
super.dispose();
}
void scrollToTop() {
scrollController.animateTo(0,
duration: const Duration(milliseconds: 250), curve: Curves.linear);
}
@override
Widget build(BuildContext context) {
return Container();
}
}
================================================
FILE: lib/common/widget/tag_dialog.dart
================================================
import 'package:flutter/material.dart';
import 'package:ntodotxt/common/misc.dart';
import 'package:ntodotxt/common/widget/chip.dart';
class Tag {
final String name;
bool selected;
Tag({
required this.name,
required this.selected,
});
// Makes overwriting possible if 'selected' is different.
@override
bool operator ==(Object other) => other is Tag && name == other.name;
@override
int get hashCode => name.hashCode;
@override
String toString() => '$name ($selected)';
}
class TagDialog extends StatefulWidget {
final String title;
final String tagName;
final Set<String> availableTags;
final bool addTags;
const TagDialog({
required this.title,
required this.tagName,
this.availableTags = const {},
this.addTags = true,
super.key,
});
RegExp get regex => RegExp(r'^\S+$');
@ove
gitextract_y8tbwi3d/
├── .devcontainer/
│ ├── Dockerfile
│ └── devcontainer.json
├── .github/
│ ├── dependabot.yml
│ └── workflows/
│ ├── ci.yaml
│ └── release.yaml
├── .gitignore
├── .gitmodules
├── .metadata
├── .pre-commit-config.yaml
├── .vscode/
│ └── tasks.json
├── .yamlfmt
├── CHANGELOG.md
├── Caddyfile
├── Dockerfile_fdroid
├── LICENSE
├── Makefile
├── README.md
├── analysis_options.yaml
├── android/
│ ├── .gitignore
│ ├── app/
│ │ ├── build.gradle
│ │ └── src/
│ │ ├── debug/
│ │ │ └── AndroidManifest.xml
│ │ ├── main/
│ │ │ ├── AndroidManifest.xml
│ │ │ ├── kotlin/
│ │ │ │ └── de/
│ │ │ │ └── tnmgl/
│ │ │ │ └── ntodotxt/
│ │ │ │ └── MainActivity.kt
│ │ │ └── res/
│ │ │ ├── drawable/
│ │ │ │ └── launch_background.xml
│ │ │ ├── drawable-v21/
│ │ │ │ └── launch_background.xml
│ │ │ ├── values/
│ │ │ │ └── styles.xml
│ │ │ └── values-night/
│ │ │ └── styles.xml
│ │ └── profile/
│ │ └── AndroidManifest.xml
│ ├── build.gradle
│ ├── gradle/
│ │ └── wrapper/
│ │ └── gradle-wrapper.properties
│ ├── gradle.properties
│ └── settings.gradle
├── docker-compose.yaml
├── emulatorctl
├── fonts/
│ └── LICENSE
├── integration_test/
│ ├── login/
│ │ └── login_integration_test.dart
│ ├── preview_app_integration_test.dart
│ ├── screenshot_integration_test.dart
│ └── webdav/
│ └── client/
│ └── webdav_client_test.dart
├── ios/
│ ├── .gitignore
│ ├── Flutter/
│ │ ├── AppFrameworkInfo.plist
│ │ ├── Debug.xcconfig
│ │ └── Release.xcconfig
│ ├── Runner/
│ │ ├── AppDelegate.swift
│ │ ├── Assets.xcassets/
│ │ │ ├── AppIcon.appiconset/
│ │ │ │ └── Contents.json
│ │ │ └── LaunchImage.imageset/
│ │ │ ├── Contents.json
│ │ │ └── README.md
│ │ ├── Base.lproj/
│ │ │ ├── LaunchScreen.storyboard
│ │ │ └── Main.storyboard
│ │ ├── Info.plist
│ │ └── Runner-Bridging-Header.h
│ ├── Runner.xcodeproj/
│ │ ├── project.pbxproj
│ │ ├── project.xcworkspace/
│ │ │ ├── contents.xcworkspacedata
│ │ │ └── xcshareddata/
│ │ │ ├── IDEWorkspaceChecks.plist
│ │ │ └── WorkspaceSettings.xcsettings
│ │ └── xcshareddata/
│ │ └── xcschemes/
│ │ └── Runner.xcscheme
│ ├── Runner.xcworkspace/
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata/
│ │ ├── IDEWorkspaceChecks.plist
│ │ └── WorkspaceSettings.xcsettings
│ └── RunnerTests/
│ └── RunnerTests.swift
├── lib/
│ ├── adaptive_layout/
│ │ └── widget/
│ │ └── adaptive_layout.dart
│ ├── app_info/
│ │ └── page/
│ │ └── app_details_page.dart
│ ├── common/
│ │ ├── bloc_observer.dart
│ │ ├── constants/
│ │ │ └── app.dart
│ │ ├── exception/
│ │ │ └── exceptions.dart
│ │ ├── misc.dart
│ │ ├── router/
│ │ │ └── router.dart
│ │ ├── theme/
│ │ │ └── theme.dart
│ │ └── widget/
│ │ ├── app_bar.dart
│ │ ├── chip.dart
│ │ ├── confirm_dialog.dart
│ │ ├── contexts_dialog.dart
│ │ ├── date_picker.dart
│ │ ├── filter_dialog.dart
│ │ ├── group_by_dialog.dart
│ │ ├── info_dialog.dart
│ │ ├── input_dialog.dart
│ │ ├── key_values_dialog.dart
│ │ ├── order_dialog.dart
│ │ ├── priorities_dialog.dart
│ │ ├── projects_dialog.dart
│ │ ├── scroll_to_top.dart
│ │ └── tag_dialog.dart
│ ├── database/
│ │ └── controller/
│ │ └── database.dart
│ ├── drawer/
│ │ ├── state/
│ │ │ ├── drawer_cubit.dart
│ │ │ └── drawer_state.dart
│ │ └── widget/
│ │ └── drawer.dart
│ ├── filter/
│ │ ├── controller/
│ │ │ ├── fake_filter_controller.dart
│ │ │ └── filter_controller.dart
│ │ ├── model/
│ │ │ └── filter_model.dart
│ │ ├── page/
│ │ │ ├── filter_create_edit_page.dart
│ │ │ └── filter_list_page.dart
│ │ ├── repository/
│ │ │ └── filter_repository.dart
│ │ ├── state/
│ │ │ ├── filter_cubit.dart
│ │ │ ├── filter_list_bloc.dart
│ │ │ ├── filter_list_event.dart
│ │ │ ├── filter_list_state.dart
│ │ │ └── filter_state.dart
│ │ └── widget/
│ │ └── filter_chip.dart
│ ├── intro/
│ │ └── page/
│ │ └── intro_page.dart
│ ├── licenses/
│ │ └── page/
│ │ └── licenses_page.dart
│ ├── login/
│ │ ├── page/
│ │ │ └── login_page.dart
│ │ └── state/
│ │ ├── login_cubit.dart
│ │ └── login_state.dart
│ ├── main.dart
│ ├── oss_licenses.dart
│ ├── setting/
│ │ ├── controller/
│ │ │ ├── fake_setting_controller.dart
│ │ │ └── setting_controller.dart
│ │ ├── model/
│ │ │ └── setting_model.dart
│ │ ├── page/
│ │ │ └── settings_page.dart
│ │ ├── repository/
│ │ │ └── setting_repository.dart
│ │ └── state/
│ │ ├── interaction_settings_cubit.dart
│ │ └── interaction_settings_state.dart
│ ├── todo/
│ │ ├── api/
│ │ │ └── todo_list_api.dart
│ │ ├── model/
│ │ │ └── todo_model.dart
│ │ ├── page/
│ │ │ ├── todo_create_edit_page.dart
│ │ │ ├── todo_list_page.dart
│ │ │ └── todo_search_page.dart
│ │ ├── repository/
│ │ │ └── todo_list_repository.dart
│ │ └── state/
│ │ ├── todo_cubit.dart
│ │ ├── todo_list_bloc.dart
│ │ ├── todo_list_event.dart
│ │ ├── todo_list_state.dart
│ │ └── todo_state.dart
│ ├── todo_file/
│ │ └── state/
│ │ ├── todo_file_cubit.dart
│ │ └── todo_file_state.dart
│ └── webdav/
│ └── client/
│ └── webdav_client.dart
├── linux/
│ ├── .gitignore
│ ├── CMakeLists.txt
│ ├── flutter/
│ │ └── CMakeLists.txt
│ ├── main.cc
│ ├── my_application.cc
│ └── my_application.h
├── macos/
│ ├── .gitignore
│ ├── Flutter/
│ │ ├── Flutter-Debug.xcconfig
│ │ └── Flutter-Release.xcconfig
│ ├── Runner/
│ │ ├── AppDelegate.swift
│ │ ├── Assets.xcassets/
│ │ │ └── AppIcon.appiconset/
│ │ │ └── Contents.json
│ │ ├── Base.lproj/
│ │ │ └── MainMenu.xib
│ │ ├── Configs/
│ │ │ ├── AppInfo.xcconfig
│ │ │ ├── Debug.xcconfig
│ │ │ ├── Release.xcconfig
│ │ │ └── Warnings.xcconfig
│ │ ├── DebugProfile.entitlements
│ │ ├── Info.plist
│ │ ├── MainFlutterWindow.swift
│ │ └── Release.entitlements
│ ├── Runner.xcodeproj/
│ │ ├── project.pbxproj
│ │ ├── project.xcworkspace/
│ │ │ └── xcshareddata/
│ │ │ └── IDEWorkspaceChecks.plist
│ │ └── xcshareddata/
│ │ └── xcschemes/
│ │ └── Runner.xcscheme
│ ├── Runner.xcworkspace/
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata/
│ │ └── IDEWorkspaceChecks.plist
│ └── RunnerTests/
│ └── RunnerTests.swift
├── metadata/
│ └── en-US/
│ ├── full_description.txt
│ ├── short_description.txt
│ └── title.txt
├── ntodotxt.yaml
├── pubspec.yaml
├── test/
│ ├── common/
│ │ └── widget/
│ │ ├── confirm_dialog_test.dart
│ │ ├── contexts_dialog_test.dart
│ │ ├── default_filter_state_filter_dialog_test.dart
│ │ ├── default_filter_state_group_dialog_test.dart
│ │ ├── default_filter_state_order_dialog_test.dart
│ │ ├── filter_state_filter_dialog_test.dart
│ │ ├── filter_state_group_dialog_test.dart
│ │ ├── filter_state_order_dialog_test.dart
│ │ ├── info_dialog_test.dart
│ │ ├── input_dialog_test.dart
│ │ ├── key_values_dialog_test.dart
│ │ ├── priorities_dialog_test.dart
│ │ └── projects_dialog_test.dart
│ ├── drawer/
│ │ └── state/
│ │ └── drawer_cubit_test.dart
│ ├── filter/
│ │ ├── controller/
│ │ │ └── filter_controller_test.dart
│ │ ├── page/
│ │ │ ├── filter_create_edit_page_test.dart
│ │ │ └── filter_list_page_test.dart
│ │ ├── state/
│ │ │ └── filter_cubit_test.dart
│ │ └── widget/
│ │ └── filter_chip_test.dart
│ ├── login/
│ │ └── page/
│ │ └── webdav_login_view_test.dart
│ ├── setting/
│ │ ├── controller/
│ │ │ └── setting_controller_test.dart
│ │ └── page/
│ │ └── settings_page_test.dart
│ ├── todo/
│ │ ├── api/
│ │ │ └── todo_list_api_test.dart
│ │ ├── model/
│ │ │ └── todo_model_test.dart
│ │ ├── page/
│ │ │ ├── todo_create_edit_page_test.dart
│ │ │ └── todo_list_page_test.dart
│ │ └── state/
│ │ ├── todo_cubit_test.dart
│ │ └── todo_list_bloc_test.dart
│ ├── todo_file/
│ │ └── state/
│ │ ├── todo_file_cubit_test.dart
│ │ └── todo_file_state_test.dart
│ └── webdav/
│ └── client/
│ └── webdav_client_test.dart
├── test_driver/
│ └── screenshot_integration_test.dart
├── web/
│ ├── index.html
│ └── manifest.json
└── windows/
├── .gitignore
├── CMakeLists.txt
├── flutter/
│ └── CMakeLists.txt
└── runner/
├── CMakeLists.txt
├── Runner.rc
├── flutter_window.cpp
├── flutter_window.h
├── main.cpp
├── resource.h
├── runner.exe.manifest
├── utils.cpp
├── utils.h
├── win32_window.cpp
└── win32_window.h
SYMBOL INDEX (896 symbols across 110 files)
FILE: integration_test/login/login_integration_test.dart
function main (line 10) | void main()
FILE: integration_test/preview_app_integration_test.dart
class AppPreview (line 6) | class AppPreview extends StatelessWidget {
method build (line 20) | Widget build(BuildContext context)
function main (line 130) | void main()
FILE: integration_test/screenshot_integration_test.dart
class FakeController (line 37) | class FakeController extends Fake implements FilterController {
method list (line 72) | Future<List<Filter>> list()
class AppTester (line 77) | class AppTester extends StatelessWidget {
method build (line 90) | Widget build(BuildContext context)
function main (line 159) | void main()
FILE: integration_test/webdav/client/webdav_client_test.dart
function createWebDAVClient (line 13) | WebDAVClient createWebDAVClient({
function randomString (line 28) | String randomString({int len = 8})
function main (line 35) | void main()
FILE: lib/adaptive_layout/widget/adaptive_layout.dart
class AdaptiveLayout (line 16) | class AdaptiveLayout extends StatelessWidget {
method build (line 25) | Widget build(BuildContext context)
class NotificationWrapper (line 39) | class NotificationWrapper extends StatelessWidget {
method build (line 48) | Widget build(BuildContext context)
class NarrowLayout (line 92) | class NarrowLayout extends StatelessWidget {
method build (line 101) | Widget build(BuildContext context)
class WideLayout (line 104) | class WideLayout extends StatelessWidget {
method build (line 113) | Widget build(BuildContext context)
FILE: lib/app_info/page/app_details_page.dart
class AppInfoPage (line 7) | class AppInfoPage extends StatelessWidget {
method build (line 11) | Widget build(BuildContext context)
class AppInfoView (line 19) | class AppInfoView extends StatelessWidget {
method build (line 25) | Widget build(BuildContext context)
method _openUrl (line 75) | Future<void> _openUrl(String urlStr)
FILE: lib/common/bloc_observer.dart
class GenericBlocObserver (line 7) | class GenericBlocObserver extends BlocObserver {
method onChange (line 9) | void onChange(BlocBase bloc, Change change)
method onTransition (line 17) | void onTransition(Bloc bloc, Transition transition)
method onError (line 23) | void onError(BlocBase bloc, Object error, StackTrace stackTrace)
FILE: lib/common/exception/exceptions.dart
class TodoException (line 3) | sealed class TodoException implements Exception {
method toString (line 9) | String toString()
class TodoNotFound (line 12) | class TodoNotFound extends TodoException {
class TodoMissingId (line 19) | class TodoMissingId extends TodoException {
class TodoStringMalformed (line 23) | class TodoStringMalformed extends TodoException {
class TodoInvalidProjectTag (line 30) | class TodoInvalidProjectTag extends TodoException {
class TodoInvalidContextTag (line 37) | class TodoInvalidContextTag extends TodoException {
class TodoInvalidKeyValueTag (line 44) | class TodoInvalidKeyValueTag extends TodoException {
class TodoForbiddenCompletionDate (line 51) | class TodoForbiddenCompletionDate extends TodoException {
class TodoMissingCompletionDate (line 56) | class TodoMissingCompletionDate extends TodoException {
FILE: lib/common/misc.dart
class PlatformInfo (line 11) | class PlatformInfo {
type MessageType (line 21) | enum MessageType { success, info, error }
class SnackBarHandler (line 23) | class SnackBarHandler {
method _call (line 24) | void _call(BuildContext context, MessageType type, String message)
method success (line 55) | void success(BuildContext context, String message)
method info (line 58) | void info(BuildContext context, String message)
method error (line 61) | void error(BuildContext context, String message)
class CustomScrollBehavior (line 65) | class CustomScrollBehavior extends MaterialScrollBehavior {
class Debouncer (line 75) | class Debouncer {
method run (line 81) | void run(VoidCallback action)
method dispose (line 86) | void dispose()
class PopScopeDrawer (line 92) | class PopScopeDrawer extends StatelessWidget {
method build (line 101) | Widget build(BuildContext context)
FILE: lib/common/router/router.dart
class AppRouter (line 19) | class AppRouter {
FILE: lib/common/theme/theme.dart
class CustomTheme (line 125) | class CustomTheme {
FILE: lib/common/widget/app_bar.dart
class MainAppBar (line 9) | class MainAppBar extends StatelessWidget implements PreferredSizeWidget {
method build (line 22) | Widget build(BuildContext context)
class AppBarFilterList (line 73) | class AppBarFilterList extends StatelessWidget {
method build (line 77) | Widget build(BuildContext context)
FILE: lib/common/widget/chip.dart
class BasicIconChip (line 3) | class BasicIconChip extends StatelessWidget {
method build (line 16) | Widget build(BuildContext context)
class BasicChip (line 44) | class BasicChip extends StatelessWidget {
method build (line 55) | Widget build(BuildContext context)
class GenericActionChip (line 76) | class GenericActionChip extends StatelessWidget {
method build (line 91) | Widget build(BuildContext context)
class GenericChoiceChip (line 105) | class GenericChoiceChip extends StatelessWidget {
method build (line 120) | Widget build(BuildContext context)
class GenericChipGroup (line 135) | class GenericChipGroup extends StatelessWidget {
method build (line 146) | Widget build(BuildContext context)
FILE: lib/common/widget/confirm_dialog.dart
class ConfirmationDialog (line 3) | class ConfirmationDialog extends StatelessWidget {
method dialog (line 17) | Future<bool> dialog({
method build (line 40) | Widget build(BuildContext context)
FILE: lib/common/widget/contexts_dialog.dart
class FilterContextTagDialog (line 6) | class FilterContextTagDialog extends TagDialog {
method dialog (line 21) | Future<void> dialog({
method createState (line 37) | State<FilterContextTagDialog> createState()
class _FilterContextTagDialogState (line 40) | class _FilterContextTagDialogState
method initState (line 43) | void initState()
method onUpdate (line 56) | void onUpdate()
class TodoContextTagDialog (line 64) | class TodoContextTagDialog extends TagDialog {
method dialog (line 79) | Future<void> dialog({
method createState (line 95) | State<TodoContextTagDialog> createState()
class _TodoContextTagDialogState (line 98) | class _TodoContextTagDialogState extends TagDialogState<TodoContextTagDi...
method initState (line 100) | void initState()
method onUpdate (line 117) | void onUpdate()
FILE: lib/common/widget/date_picker.dart
class TodoDatePicker (line 3) | class TodoDatePicker {
method pickDate (line 8) | Future<DateTime?> pickDate({
FILE: lib/common/widget/filter_dialog.dart
class FilterStateFilterDialog (line 5) | class FilterStateFilterDialog extends StatelessWidget {
method dialog (line 18) | Future<void> dialog({
method build (line 30) | Widget build(BuildContext context)
class DefaultFilterStateFilterDialog (line 58) | class DefaultFilterStateFilterDialog extends StatelessWidget {
method dialog (line 71) | Future<void> dialog({
method build (line 84) | Widget build(BuildContext context)
FILE: lib/common/widget/group_by_dialog.dart
class FilterStateGroupDialog (line 5) | class FilterStateGroupDialog extends StatelessWidget {
method dialog (line 20) | Future<void> dialog({
method build (line 32) | Widget build(BuildContext context)
class DefaultFilterStateGroupDialog (line 60) | class DefaultFilterStateGroupDialog extends StatelessWidget {
method dialog (line 75) | Future<void> dialog({
method build (line 88) | Widget build(BuildContext context)
FILE: lib/common/widget/info_dialog.dart
class InfoDialog (line 3) | class InfoDialog extends StatelessWidget {
method dialog (line 13) | Future<void> dialog({
method build (line 30) | Widget build(BuildContext context)
FILE: lib/common/widget/input_dialog.dart
class InputDialog (line 3) | class InputDialog extends StatelessWidget {
method dialog (line 15) | Future<String?> dialog({
method build (line 31) | Widget build(BuildContext context)
FILE: lib/common/widget/key_values_dialog.dart
class TodoKeyValueTagDialog (line 6) | class TodoKeyValueTagDialog extends TagDialog {
method dialog (line 21) | Future<void> dialog({
method createState (line 37) | State<TodoKeyValueTagDialog> createState()
class _TodoKeyValueTagDialogState (line 40) | class _TodoKeyValueTagDialogState
method initState (line 43) | void initState()
method onUpdate (line 60) | void onUpdate()
FILE: lib/common/widget/order_dialog.dart
class FilterStateOrderDialog (line 5) | class FilterStateOrderDialog extends StatelessWidget {
method dialog (line 17) | Future<void> dialog({
method build (line 29) | Widget build(BuildContext context)
class DefaultFilterStateOrderDialog (line 57) | class DefaultFilterStateOrderDialog extends StatelessWidget {
method dialog (line 69) | Future<void> dialog({
method build (line 82) | Widget build(BuildContext context)
FILE: lib/common/widget/priorities_dialog.dart
class PriorityTag (line 8) | class PriorityTag {
method toString (line 18) | String toString()
class PriorityTagDialog (line 21) | class PriorityTagDialog extends StatefulWidget {
method createState (line 32) | State<PriorityTagDialog> createState()
class PriorityTagDialogState (line 35) | class PriorityTagDialogState<T extends PriorityTagDialog> extends State<...
method initState (line 42) | void initState()
method dispose (line 48) | void dispose()
method onUpdate (line 62) | void onUpdate(PriorityTag value, bool selected)
method build (line 65) | Widget build(BuildContext context)
class FilterPriorityTagDialog (line 115) | class FilterPriorityTagDialog extends PriorityTagDialog {
method dialog (line 125) | Future<void> dialog({
method createState (line 141) | State<FilterPriorityTagDialog> createState()
class _FilterPriorityTagDialogState (line 145) | class _FilterPriorityTagDialogState
method initState (line 148) | void initState()
method onUpdate (line 161) | void onUpdate(PriorityTag value, bool selected)
class TodoPriorityTagDialog (line 172) | class TodoPriorityTagDialog extends PriorityTagDialog {
method dialog (line 182) | Future<void> dialog({
method createState (line 198) | State<TodoPriorityTagDialog> createState()
class _TodoPriorityTagDialogState (line 201) | class _TodoPriorityTagDialogState
method initState (line 204) | void initState()
method onUpdate (line 217) | void onUpdate(PriorityTag value, bool selected)
FILE: lib/common/widget/projects_dialog.dart
class FilterProjectTagDialog (line 6) | class FilterProjectTagDialog extends TagDialog {
method dialog (line 21) | Future<void> dialog({
method createState (line 37) | State<FilterProjectTagDialog> createState()
class _FilterProjectTagDialogState (line 40) | class _FilterProjectTagDialogState
method initState (line 43) | void initState()
method onUpdate (line 56) | void onUpdate()
class TodoProjectTagDialog (line 64) | class TodoProjectTagDialog extends TagDialog {
method dialog (line 79) | Future<void> dialog({
method createState (line 95) | State<TodoProjectTagDialog> createState()
class _TodoProjectTagDialogState (line 98) | class _TodoProjectTagDialogState extends TagDialogState<TodoProjectTagDi...
method initState (line 100) | void initState()
method onUpdate (line 117) | void onUpdate()
FILE: lib/common/widget/scroll_to_top.dart
class ScollToTopView (line 3) | class ScollToTopView extends StatefulWidget {
method createState (line 7) | State<ScollToTopView> createState()
class ScollToTopViewState (line 10) | class ScollToTopViewState<T extends ScollToTopView> extends State<T> {
method initState (line 15) | void initState()
method dispose (line 32) | void dispose()
method scrollToTop (line 37) | void scrollToTop()
method build (line 43) | Widget build(BuildContext context)
FILE: lib/common/widget/tag_dialog.dart
class Tag (line 5) | class Tag {
method toString (line 22) | String toString()
class TagDialog (line 25) | class TagDialog extends StatefulWidget {
method createState (line 42) | State<TagDialog> createState()
class TagDialogState (line 45) | class TagDialogState<T extends TagDialog> extends State<T> {
method initState (line 53) | void initState()
method dispose (line 60) | void dispose()
method onUpdate (line 74) | void onUpdate()
method build (line 77) | Widget build(BuildContext context)
FILE: lib/database/controller/database.dart
class ModelControllerInterface (line 6) | abstract class ModelControllerInterface<T> {
method list (line 7) | Future<List<T>> list()
method get (line 9) | Future<T?> get(dynamic identifier)
method insert (line 11) | Future<int> insert(T model)
method update (line 13) | Future<int> update(T model)
method delete (line 15) | Future<int> delete(dynamic identifier)
class DatabaseController (line 18) | class DatabaseController {
method close (line 33) | Future<void> close()
method _open (line 40) | Future<Database> _open()
FILE: lib/drawer/state/drawer_cubit.dart
class DrawerCubit (line 5) | class DrawerCubit extends Cubit<DrawerState> {
method reset (line 8) | void reset()
method next (line 10) | void next(int index)
method back (line 19) | void back()
FILE: lib/drawer/state/drawer_state.dart
class DrawerState (line 3) | final class DrawerState extends Equatable {
method toString (line 19) | String toString()
FILE: lib/drawer/widget/drawer.dart
class DrawerDestination (line 11) | class DrawerDestination {
class NavigationRailDrawer (line 25) | class NavigationRailDrawer extends StatelessWidget {
method build (line 29) | Widget build(BuildContext context)
class BottomSheetNavigationDrawer (line 96) | class BottomSheetNavigationDrawer extends StatelessWidget {
method build (line 100) | Widget build(BuildContext context)
FILE: lib/filter/controller/fake_filter_controller.dart
class FakeFilterController (line 7) | class FakeFilterController implements FilterControllerInterface {
method list (line 13) | Future<List<Filter>> list()
method get (line 16) | Future<Filter?> get(dynamic identifier)
method insert (line 26) | Future<int> insert(Filter model)
method update (line 32) | Future<int> update(Filter model)
method delete (line 43) | Future<int> delete(dynamic identifier)
FILE: lib/filter/controller/filter_controller.dart
class FilterControllerInterface (line 5) | abstract class FilterControllerInterface
class FilterController (line 8) | class FilterController implements FilterControllerInterface {
method list (line 14) | Future<List<Filter>> list()
method get (line 27) | Future<Filter?> get(dynamic identifier)
method insert (line 54) | Future<int> insert(Filter model)
method update (line 68) | Future<int> update(Filter model)
method delete (line 87) | Future<int> delete(dynamic identifier)
FILE: lib/filter/model/filter_model.dart
type ListOrder (line 5) | enum ListOrder {
type ListFilter (line 10) | enum ListFilter {
type ListGroup (line 16) | enum ListGroup {
function byName (line 29) | ListOrder byName(String? name)
function _sort (line 44) | int _sort<T>(T a, T b)
function ascending (line 57) | int ascending<T>(T a, T b)
function descending (line 71) | int descending<T>(T a, T b)
function sort (line 85) | Iterable<T> sort<T>(Iterable<T> list)
function byName (line 93) | ListFilter byName(String? name)
function _apply (line 105) | bool _apply(Todo todo)
function apply (line 119) | Iterable<Todo> apply(Iterable<Todo> todoList)
function byName (line 127) | ListGroup byName(String? name)
function groupByNone (line 139) | Map<String, Iterable<Todo>> groupByNone({
function groupByUpcoming (line 148) | Map<String, Iterable<Todo>> groupByUpcoming({
function groupByPriority (line 179) | Map<String, Iterable<Todo>> groupByPriority({
function groupByProject (line 197) | Map<String, Iterable<Todo>> groupByProject({
function groupByContext (line 219) | Map<String, Iterable<Todo>> groupByContext({
class Filter (line 242) | class Filter extends Equatable {
method apply (line 298) | Iterable<Todo> apply(List<Todo> todoList)
method _applyPriority (line 316) | bool _applyPriority(Todo todo)
method _applyProject (line 318) | bool _applyProject(Todo todo)
method _applyContext (line 327) | bool _applyContext(Todo todo)
method grouped (line 336) | Map<String, Iterable<Todo>> grouped(Iterable<Todo> todoList)
method copyWith (line 377) | Filter copyWith({
method copyWithUnsaved (line 403) | Filter copyWithUnsaved({
method toMap (line 424) | Map<String, dynamic> toMap()
method toString (line 438) | String toString()
FILE: lib/filter/page/filter_create_edit_page.dart
class FilterCreateEditPage (line 22) | class FilterCreateEditPage extends StatelessWidget {
method build (line 35) | Widget build(BuildContext context)
class FilterDialogWrapper (line 100) | class FilterDialogWrapper extends StatelessWidget {
method build (line 111) | Widget build(BuildContext context)
class SaveFilterIconButton (line 168) | class SaveFilterIconButton extends StatelessWidget {
method build (line 176) | Widget build(BuildContext context)
class DeleteFilterIconButton (line 202) | class DeleteFilterIconButton extends StatelessWidget {
method build (line 206) | Widget build(BuildContext context)
class FilterNameTextField (line 234) | class FilterNameTextField extends StatefulWidget {
method createState (line 238) | State<FilterNameTextField> createState()
class _FilterNameTextFieldState (line 241) | class _FilterNameTextFieldState extends State<FilterNameTextField> {
method initState (line 246) | void initState()
method dispose (line 253) | void dispose()
method build (line 260) | Widget build(BuildContext context)
class FilterOrderItem (line 304) | class FilterOrderItem extends StatelessWidget {
method build (line 308) | Widget build(BuildContext context)
class FilterFilterItem (line 337) | class FilterFilterItem extends StatelessWidget {
method build (line 341) | Widget build(BuildContext context)
class FilterGroupItem (line 370) | class FilterGroupItem extends StatelessWidget {
method build (line 374) | Widget build(BuildContext context)
class FilterPrioritiesItem (line 405) | class FilterPrioritiesItem extends StatelessWidget {
method build (line 409) | Widget build(BuildContext context)
class FilterProjectTagsItem (line 442) | class FilterProjectTagsItem extends StatelessWidget {
method build (line 451) | Widget build(BuildContext context)
class FilterContextTagsItem (line 483) | class FilterContextTagsItem extends StatelessWidget {
method build (line 492) | Widget build(BuildContext context)
FILE: lib/filter/page/filter_list_page.dart
class FilterListPage (line 17) | class FilterListPage extends StatelessWidget {
method build (line 21) | Widget build(BuildContext context)
class FilterListViewNarrow (line 36) | class FilterListViewNarrow extends ScollToTopView {
method createState (line 40) | State<FilterListViewNarrow> createState()
class _FilterListViewNarrowState (line 43) | class _FilterListViewNarrowState
method build (line 46) | Widget build(BuildContext context)
class FilterListViewWide (line 83) | class FilterListViewWide extends ScollToTopView {
method createState (line 87) | State<FilterListViewWide> createState()
class _FilterListViewWideState (line 90) | class _FilterListViewWideState extends ScollToTopViewState<FilterListVie...
method build (line 92) | Widget build(BuildContext context)
class FilterListTile (line 128) | class FilterListTile extends StatelessWidget {
method build (line 137) | Widget build(BuildContext context)
method _buildSubtitle (line 196) | Widget? _buildSubtitle()
FILE: lib/filter/repository/filter_repository.dart
class FilterRepository (line 6) | class FilterRepository {
method refresh (line 15) | Future<void> refresh()
method dispose (line 19) | void dispose()
method list (line 23) | Future<List<Filter>> list()
method get (line 25) | Future<Filter?> get({required int id})
method insert (line 27) | Future<int> insert(Filter model)
method update (line 33) | Future<int> update(Filter model)
method delete (line 39) | Future<int> delete({required int id})
FILE: lib/filter/state/filter_cubit.dart
class FilterCubit (line 11) | class FilterCubit extends Cubit<FilterState> {
method load (line 27) | Future<void> load()
method create (line 52) | Future<void> create(Filter f)
method update (line 64) | Future<void> update(Filter f)
method delete (line 76) | Future<void> delete(Filter filter)
method updateName (line 87) | void updateName(String name)
method updateOrder (line 99) | void updateOrder(ListOrder order)
method updateFilter (line 109) | void updateFilter(ListFilter filter)
method updateGroup (line 119) | void updateGroup(ListGroup group)
method addPriority (line 129) | void addPriority(Priority priority)
method removePriority (line 143) | void removePriority(Priority priority)
method updatePriorities (line 157) | void updatePriorities(Set<Priority> priorities)
method addProject (line 171) | void addProject(String project)
method removeProject (line 185) | void removeProject(String project)
method updateProjects (line 199) | void updateProjects(Set<String> projects)
method addContext (line 213) | void addContext(String context)
method removeContext (line 227) | void removeContext(String context)
method updateContexts (line 241) | void updateContexts(Set<String> contexts)
method resetToDefaults (line 259) | Future<void> resetToDefaults()
method updateDefaultOrder (line 271) | Future<void> updateDefaultOrder(ListOrder? value)
method updateDefaultFilter (line 288) | Future<void> updateDefaultFilter(ListFilter? value)
method updateDefaultGroup (line 305) | Future<void> updateDefaultGroup(ListGroup? value)
FILE: lib/filter/state/filter_list_bloc.dart
class FilterListBloc (line 7) | class FilterListBloc extends Bloc<FilterListEvent, FilterListState> {
method _onFilterListSubscriped (line 18) | Future<void> _onFilterListSubscriped(
method _onFilterSynchronizationRequested (line 31) | Future<void> _onFilterSynchronizationRequested(
method _onFilterDeleted (line 44) | Future<void> _onFilterDeleted(
FILE: lib/filter/state/filter_list_event.dart
class FilterListEvent (line 4) | sealed class FilterListEvent extends Equatable {
class FilterListSubscriped (line 11) | final class FilterListSubscriped extends FilterListEvent {
class FilterListSynchronizationRequested (line 15) | final class FilterListSynchronizationRequested extends FilterListEvent {
class FilterListFilterDeleted (line 19) | final class FilterListFilterDeleted extends FilterListEvent {
FILE: lib/filter/state/filter_list_state.dart
class FilterListState (line 4) | sealed class FilterListState extends Equatable {
method copyWith (line 11) | FilterListState copyWith({
method loading (line 15) | FilterListLoading loading({
method success (line 23) | FilterListSuccess success({
method error (line 31) | FilterListError error({
method toString (line 47) | String toString()
class FilterListLoading (line 50) | final class FilterListLoading extends FilterListState {
method copyWith (line 56) | FilterListLoading copyWith({List<Filter>? filterList})
method toString (line 60) | String toString()
class FilterListSuccess (line 63) | final class FilterListSuccess extends FilterListState {
method copyWith (line 69) | FilterListSuccess copyWith({List<Filter>? filterList})
method toString (line 73) | String toString()
class FilterListError (line 76) | final class FilterListError extends FilterListState {
method copyWith (line 85) | FilterListError copyWith({
method toString (line 101) | String toString()
FILE: lib/filter/state/filter_state.dart
class FilterState (line 5) | sealed class FilterState extends Equatable {
method loading (line 14) | FilterLoading loading({
method update (line 23) | FilterChanged update({
method save (line 32) | FilterSaved save({
method error (line 40) | FilterError error({
method toString (line 108) | String toString()
class FilterLoading (line 111) | final class FilterLoading extends FilterState {
method copyWith (line 117) | FilterLoading copyWith({
method toString (line 123) | String toString()
class FilterChanged (line 126) | final class FilterChanged extends FilterState {
method copyWith (line 132) | FilterChanged copyWith({
method toString (line 138) | String toString()
class FilterSaved (line 141) | final class FilterSaved extends FilterState {
method copyWith (line 147) | FilterSaved copyWith({
method toString (line 153) | String toString()
class FilterError (line 156) | final class FilterError extends FilterState {
method copyWith (line 165) | FilterError copyWith({
method toString (line 180) | String toString()
FILE: lib/filter/widget/filter_chip.dart
class FilterOrderChip (line 16) | class FilterOrderChip extends StatelessWidget {
method build (line 20) | Widget build(BuildContext context)
class FilterFilterChip (line 51) | class FilterFilterChip extends StatelessWidget {
method build (line 55) | Widget build(BuildContext context)
class FilterGroupChip (line 92) | class FilterGroupChip extends StatelessWidget {
method build (line 96) | Widget build(BuildContext context)
class FilterPrioritiesChip (line 116) | class FilterPrioritiesChip extends StatelessWidget {
method build (line 120) | Widget build(BuildContext context)
class FilterProjectsChip (line 141) | class FilterProjectsChip extends StatelessWidget {
method build (line 150) | Widget build(BuildContext context)
class FilterContextsChip (line 172) | class FilterContextsChip extends StatelessWidget {
method build (line 181) | Widget build(BuildContext context)
FILE: lib/intro/page/intro_page.dart
class IntroPage (line 5) | class IntroPage extends StatefulWidget {
method createState (line 9) | State<IntroPage> createState()
class _IntroPageState (line 12) | class _IntroPageState extends State<IntroPage> {
method build (line 24) | Widget build(BuildContext context)
class IntroPageWelcome (line 89) | class IntroPageWelcome extends StatelessWidget {
method build (line 93) | Widget build(BuildContext context)
class IntroPageLocal (line 131) | class IntroPageLocal extends StatelessWidget {
method build (line 151) | Widget build(BuildContext context)
class IntroPageWebDav (line 189) | class IntroPageWebDav extends StatelessWidget {
method build (line 205) | Widget build(BuildContext context)
FILE: lib/licenses/page/licenses_page.dart
class LicenceListPage (line 5) | class LicenceListPage extends StatelessWidget {
method build (line 9) | Widget build(BuildContext context)
class LicenseListView (line 17) | class LicenseListView extends StatelessWidget {
method build (line 21) | Widget build(BuildContext context)
class LicenceDetailPage (line 48) | class LicenceDetailPage extends StatelessWidget {
method build (line 59) | Widget build(BuildContext context)
FILE: lib/login/page/login_page.dart
class LocalLoginView (line 13) | class LocalLoginView extends StatefulWidget {
method createState (line 17) | State<LocalLoginView> createState()
class _LocalLoginViewState (line 20) | class _LocalLoginViewState extends State<LocalLoginView> {
method build (line 24) | Widget build(BuildContext context)
class WebDAVLoginView (line 81) | class WebDAVLoginView extends StatefulWidget {
method createState (line 85) | State<WebDAVLoginView> createState()
class _WebDAVLoginViewState (line 88) | class _WebDAVLoginViewState extends State<WebDAVLoginView> {
method initState (line 99) | void initState()
method dispose (line 105) | void dispose()
method setServerAddr (line 109) | void setServerAddr(String value)
method setAcceptUntrustedCert (line 111) | void setAcceptUntrustedCert(bool value)
method setBaseUrl (line 114) | void setBaseUrl(String value)
method setUsername (line 116) | void setUsername(String value)
method setPassword (line 118) | void setPassword(String value)
method build (line 121) | Widget build(BuildContext context)
class ServerAddrField (line 222) | class ServerAddrField extends StatefulWidget {
method createState (line 231) | State<ServerAddrField> createState()
class _ServerAddrFieldState (line 234) | class _ServerAddrFieldState extends State<ServerAddrField> {
method initState (line 238) | void initState()
method dispose (line 244) | void dispose()
method build (line 250) | Widget build(BuildContext context)
class AcceptUntrustedCertField (line 281) | class AcceptUntrustedCertField extends StatefulWidget {
method createState (line 290) | State<AcceptUntrustedCertField> createState()
class _AcceptUntrustedCertFieldState (line 294) | class _AcceptUntrustedCertFieldState extends State<AcceptUntrustedCertFi...
method build (line 298) | Widget build(BuildContext context)
class BaseUrlField (line 314) | class BaseUrlField extends StatefulWidget {
method createState (line 323) | State<BaseUrlField> createState()
class _BaseUrlFieldState (line 326) | class _BaseUrlFieldState extends State<BaseUrlField> {
method initState (line 330) | void initState()
method dispose (line 336) | void dispose()
method build (line 342) | Widget build(BuildContext context)
class UsernameField (line 376) | class UsernameField extends StatefulWidget {
method createState (line 385) | State<UsernameField> createState()
class _UsernameFieldState (line 388) | class _UsernameFieldState extends State<UsernameField> {
method initState (line 392) | void initState()
method dispose (line 398) | void dispose()
method build (line 404) | Widget build(BuildContext context)
class PasswordField (line 427) | class PasswordField extends StatefulWidget {
method createState (line 436) | State<PasswordField> createState()
class _PasswordFieldState (line 439) | class _PasswordFieldState extends State<PasswordField> {
method initState (line 445) | void initState()
method dispose (line 451) | void dispose()
method build (line 457) | Widget build(BuildContext context)
class LocalPathInput (line 487) | class LocalPathInput extends StatelessWidget {
method build (line 491) | Widget build(BuildContext context)
class RemotePathInput (line 533) | class RemotePathInput extends StatefulWidget {
method createState (line 537) | State<RemotePathInput> createState()
class _RemotePathInputState (line 540) | class _RemotePathInputState extends State<RemotePathInput> {
method initState (line 545) | void initState()
method dispose (line 550) | void dispose()
method build (line 557) | Widget build(BuildContext context)
method _save (line 589) | Future<void> _save(BuildContext context, String value)
class TodoFilenameInput (line 611) | class TodoFilenameInput extends StatefulWidget {
method createState (line 615) | State<TodoFilenameInput> createState()
class _TodoFilenameInputState (line 618) | class _TodoFilenameInputState extends State<TodoFilenameInput> {
method initState (line 623) | void initState()
method dispose (line 628) | void dispose()
method build (line 635) | Widget build(BuildContext context)
method _save (line 659) | Future<void> _save(BuildContext context, String value)
FILE: lib/login/state/login_cubit.dart
class LoginCubit (line 7) | class LoginCubit extends Cubit<LoginState> {
method login (line 12) | Future<void> login()
method logout (line 65) | Future<void> logout()
method loginLocal (line 74) | Future<void> loginLocal({
method loginWebDAV (line 88) | Future<void> loginWebDAV({
method resetSecureStorage (line 134) | Future<void> resetSecureStorage()
FILE: lib/login/state/login_state.dart
type Backend (line 5) | enum Backend { none, local, webdav }
class LoginState (line 7) | sealed class LoginState extends Equatable {
method copyWith (line 14) | LoginState copyWith()
method loading (line 16) | LoginLoading loading()
method logout (line 18) | Logout logout()
method loginLocal (line 20) | LoginLocal loginLocal()
method loginWebDAV (line 22) | LoginWebDAV loginWebDAV({
method error (line 37) | LoginError error({
method toString (line 48) | String toString()
class LoginLoading (line 51) | final class LoginLoading extends LoginState {
method copyWith (line 57) | LoginLoading copyWith()
method toString (line 65) | String toString()
class Logout (line 68) | final class Logout extends LoginState {
method copyWith (line 74) | Logout copyWith()
method toString (line 82) | String toString()
class LoginLocal (line 85) | final class LoginLocal extends LoginState {
method copyWith (line 91) | LoginLocal copyWith()
method toString (line 99) | String toString()
class LoginWebDAV (line 102) | final class LoginWebDAV extends LoginState {
method copyWith (line 128) | LoginWebDAV copyWith({
method toString (line 154) | String toString()
class LoginError (line 157) | final class LoginError extends LoginState {
method copyWith (line 171) | LoginError copyWith({
method toString (line 184) | String toString()
FILE: lib/main.dart
function main (line 49) | void main()
class App (line 78) | class App extends StatefulWidget {
method createState (line 87) | State<App> createState()
class _AppState (line 90) | class _AppState extends State<App> {
method initState (line 94) | void initState()
method dispose (line 100) | void dispose()
method build (line 106) | Widget build(BuildContext context)
class InitialApp (line 174) | class InitialApp extends StatelessWidget {
method _initialize (line 182) | Future<bool> _initialize(BuildContext context)
method build (line 205) | Widget build(BuildContext context)
method _loadingScreen (line 278) | Widget _loadingScreen()
method _errorScreen (line 290) | Widget _errorScreen()
class CoreApp (line 299) | class CoreApp extends StatelessWidget {
method build (line 310) | Widget build(BuildContext context)
method _createTodoListRepository (line 351) | TodoListRepository _createTodoListRepository(
FILE: lib/oss_licenses.dart
class Package (line 153) | class Package {
class PackageRef (line 198) | class PackageRef {
method resolve (line 203) | Package resolve()
FILE: lib/setting/controller/fake_setting_controller.dart
class FakeSettingController (line 7) | class FakeSettingController implements SettingControllerInterface {
method list (line 13) | Future<List<Setting>> list()
method get (line 16) | Future<Setting?> get(dynamic identifier)
method insert (line 26) | Future<int> insert(Setting model)
method getOrInsert (line 32) | Future<Setting> getOrInsert(
method update (line 45) | Future<int> update(Setting model)
method updateOrInsert (line 56) | Future<int> updateOrInsert(Setting model)
method delete (line 65) | Future<int> delete(dynamic identifier)
FILE: lib/setting/controller/setting_controller.dart
class SettingControllerInterface (line 5) | abstract class SettingControllerInterface
method getOrInsert (line 7) | Future<Setting> getOrInsert(
method updateOrInsert (line 10) | Future<int> updateOrInsert(Setting model)
class SettingController (line 13) | class SettingController implements SettingControllerInterface {
method list (line 19) | Future<List<Setting>> list()
method get (line 29) | Future<Setting?> get(dynamic identifier)
method insert (line 47) | Future<int> insert(Setting model)
method getOrInsert (line 59) | Future<Setting> getOrInsert(
method update (line 72) | Future<int> update(Setting model)
method updateOrInsert (line 87) | Future<int> updateOrInsert(Setting model)
method delete (line 96) | Future<int> delete(dynamic identifier)
FILE: lib/setting/model/setting_model.dart
class Setting (line 3) | class Setting extends Equatable {
method copyWith (line 24) | Setting copyWith({
method toMap (line 37) | Map<String, dynamic> toMap()
method toString (line 45) | String toString()
FILE: lib/setting/page/settings_page.dart
class SettingsPage (line 21) | class SettingsPage extends StatelessWidget {
method build (line 25) | Widget build(BuildContext context)
class SettingsView (line 35) | class SettingsView extends StatelessWidget {
method build (line 39) | Widget build(BuildContext context)
class DefaultListOrderSettingsItem (line 134) | class DefaultListOrderSettingsItem extends StatelessWidget {
method build (line 138) | Widget build(BuildContext context)
class DefaultListFilterSettingsItem (line 161) | class DefaultListFilterSettingsItem extends StatelessWidget {
method build (line 165) | Widget build(BuildContext context)
class DefaultListGroupSettingsItem (line 188) | class DefaultListGroupSettingsItem extends StatelessWidget {
method build (line 192) | Widget build(BuildContext context)
class SwipeLeftActionEnabledSettingsItem (line 215) | class SwipeLeftActionEnabledSettingsItem extends StatelessWidget {
method build (line 219) | Widget build(BuildContext context)
class SwipeRightActionEnabledSettingsItem (line 245) | class SwipeRightActionEnabledSettingsItem extends StatelessWidget {
method build (line 249) | Widget build(BuildContext context)
class LocalPathSettingsItem (line 276) | class LocalPathSettingsItem extends StatelessWidget {
method build (line 280) | Widget build(BuildContext context)
class RemotePathSettingsItem (line 303) | class RemotePathSettingsItem extends StatelessWidget {
method build (line 307) | Widget build(BuildContext context)
class TodoFilenameSettingsItem (line 338) | class TodoFilenameSettingsItem extends StatelessWidget {
method build (line 342) | Widget build(BuildContext context)
FILE: lib/setting/repository/setting_repository.dart
class SettingRepository (line 5) | class SettingRepository {
method list (line 10) | Future<List<Setting>> list()
method get (line 12) | Future<Setting?> get({required String key})
method getOrInsert (line 15) | Future<Setting> getOrInsert(
method insert (line 19) | Future<int> insert(Setting model)
method update (line 21) | Future<int> update(Setting model)
method delete (line 23) | Future<int> delete({required String key})
method updateOrInsert (line 26) | Future<int> updateOrInsert(Setting model)
FILE: lib/setting/state/interaction_settings_cubit.dart
class InteractionSettingsCubit (line 6) | class InteractionSettingsCubit extends Cubit<InteractionSettingsState> {
method parseBoolOrFalse (line 18) | bool parseBoolOrFalse(String? value)
method load (line 22) | Future<void> load()
method setSwipeLeftActionEnabled (line 39) | Future<void> setSwipeLeftActionEnabled(bool value)
method setSwipeRightActionEnabled (line 50) | Future<void> setSwipeRightActionEnabled(bool value)
FILE: lib/setting/state/interaction_settings_state.dart
class InteractionSettingsState (line 3) | sealed class InteractionSettingsState extends Equatable {
method loading (line 12) | InteractionSettingsLoading loading({
method save (line 24) | InteractionSettingsSaved save({
method error (line 36) | InteractionSettingsError error({
method toString (line 57) | String toString()
class InteractionSettingsLoading (line 61) | final class InteractionSettingsLoading extends InteractionSettingsState {
method copyWith (line 67) | InteractionSettingsLoading copyWith({
method toString (line 79) | String toString()
class InteractionSettingsSaved (line 83) | final class InteractionSettingsSaved extends InteractionSettingsState {
method copyWith (line 89) | InteractionSettingsSaved copyWith({
method toString (line 101) | String toString()
class InteractionSettingsError (line 105) | final class InteractionSettingsError extends InteractionSettingsState {
method copyWith (line 114) | InteractionSettingsError copyWith({
method toString (line 134) | String toString()
FILE: lib/todo/api/todo_list_api.dart
class LocalFile (line 11) | class LocalFile {
class WebDAVFile (line 24) | class WebDAVFile {
class TodoListApi (line 36) | abstract class TodoListApi {
method getTodoList (line 38) | Stream<List<Todo>> getTodoList()
method initSource (line 40) | Future<void> initSource()
method readFromSource (line 43) | Future<void> readFromSource()
method writeToSource (line 46) | Future<void> writeToSource()
method existsTodo (line 48) | bool existsTodo(Todo todo)
method saveTodo (line 53) | void saveTodo(Todo todo)
method saveMultipleTodos (line 56) | void saveMultipleTodos(List<Todo> todos)
method deleteTodo (line 59) | void deleteTodo(Todo todo)
method deleteMultipleTodos (line 62) | void deleteMultipleTodos(List<Todo> todos)
class LocalTodoListApi (line 65) | class LocalTodoListApi extends TodoListApi {
method updateList (line 94) | void updateList(List<Todo> todoList)
method _dispatch (line 104) | void _dispatch(List<Todo> todoList)
method dispose (line 111) | void dispose()
method _read (line 115) | List<Todo> _read(List<String> rawTodoList)
method read (line 122) | Future<List<Todo>> read()
method readSync (line 127) | List<Todo> readSync()
method write (line 132) | Future<void> write(String content)
method getTodoList (line 138) | Stream<List<Todo>> getTodoList()
method initSource (line 141) | Future<void> initSource()
method readFromSource (line 149) | Future<void> readFromSource()
method writeToSource (line 152) | Future<void> writeToSource()
method existsTodo (line 157) | bool existsTodo(Todo todo)
method _save (line 160) | List<Todo> _save(List<Todo> todoList, Todo todo)
method saveTodo (line 176) | void saveTodo(Todo todo)
method saveMultipleTodos (line 183) | void saveMultipleTodos(List<Todo> todos)
method _delete (line 192) | List<Todo> _delete(List<Todo> todoList, Todo todo)
method deleteTodo (line 198) | void deleteTodo(Todo todo)
method deleteMultipleTodos (line 205) | void deleteMultipleTodos(List<Todo> todos)
class WebDAVTodoListApi (line 215) | class WebDAVTodoListApi extends LocalTodoListApi {
method initSource (line 236) | Future<void> initSource()
method readFromSource (line 247) | Future<void> readFromSource()
method writeToSource (line 253) | Future<void> writeToSource()
method downloadFromSource (line 258) | Future<String> downloadFromSource()
method uploadToSource (line 263) | Future<void> uploadToSource()
FILE: lib/todo/model/todo_model.dart
type Priority (line 8) | enum Priority {
function byName (line 49) | Priority byName(String name)
function sort (line 59) | Set<Priority> sort(Set<Priority> priorities)
class Todo (line 101) | class Todo extends Equatable {
method fmtProject (line 194) | fmtProject(String p)
method containsProject (line 196) | bool containsProject(String project)
method matchProject (line 204) | bool matchProject(String project)
method fmtContext (line 221) | fmtContext(String c)
method containsContext (line 223) | bool containsContext(String context)
method matchContext (line 231) | bool matchContext(String context)
method fmtKeyValue (line 250) | fmtKeyValue(String keyValue)
method containsKeyValue (line 253) | bool containsKeyValue(String keyValue)
method matchKeyValue (line 263) | bool matchKeyValue(String kv)
method copyWith (line 427) | Todo copyWith({
method copyDiff (line 447) | Todo copyDiff({
method copyMerge (line 469) | Todo copyMerge(Todo todo)
method toString (line 490) | String toString()
method genId (line 502) | String genId({int len = 32})
method str2date (line 511) | DateTime? str2date(String value)
method date2Str (line 519) | String? date2Str(DateTime? date)
method compareToToday (line 526) | int compareToToday(DateTime date)
method differenceToToday (line 532) | String differenceToToday(DateTime date)
method _todoStringElementAt (line 558) | String _todoStringElementAt(String value, int index)
method _str2completion (line 567) | bool _str2completion(String value)
method _str2priority (line 572) | Priority _str2priority(String value)
FILE: lib/todo/page/todo_create_edit_page.dart
class TodoCreateEditPage (line 20) | class TodoCreateEditPage extends StatelessWidget {
method build (line 37) | Widget build(BuildContext context)
class TodoDialogWrapper (line 111) | class TodoDialogWrapper extends StatelessWidget {
method build (line 124) | Widget build(BuildContext context)
class DoneUndonePrimaryButton (line 182) | class DoneUndonePrimaryButton extends StatelessWidget {
method build (line 186) | Widget build(BuildContext context)
method setCompletionDate (line 206) | void setCompletionDate(BuildContext context, TodoState state)
method unsetCompletionDate (line 213) | void unsetCompletionDate(BuildContext context)
class SaveTodoIconButton (line 220) | class SaveTodoIconButton extends StatelessWidget {
method build (line 228) | Widget build(BuildContext context)
class DeleteTodoIconButton (line 252) | class DeleteTodoIconButton extends StatelessWidget {
method build (line 256) | Widget build(BuildContext context)
class TodoDescriptionTextField (line 286) | class TodoDescriptionTextField extends StatefulWidget {
method createState (line 290) | State<TodoDescriptionTextField> createState()
class _TodoDescriptionTextFieldState (line 294) | class _TodoDescriptionTextFieldState extends State<TodoDescriptionTextFi...
method initState (line 299) | void initState()
method dispose (line 306) | void dispose()
method build (line 313) | Widget build(BuildContext context)
class TodoPriorityItem (line 354) | class TodoPriorityItem extends StatelessWidget {
method build (line 360) | Widget build(BuildContext context)
class TodoProjectTagsItem (line 385) | class TodoProjectTagsItem extends StatelessWidget {
method build (line 394) | Widget build(BuildContext context)
class TodoContextTagsItem (line 425) | class TodoContextTagsItem extends StatelessWidget {
method build (line 434) | Widget build(BuildContext context)
class TodoKeyValueTagsItem (line 465) | class TodoKeyValueTagsItem extends StatelessWidget {
method build (line 474) | Widget build(BuildContext context)
class TodoCreationDateItem (line 506) | class TodoCreationDateItem extends StatelessWidget {
method build (line 510) | Widget build(BuildContext context)
class TodoCompletionDateItem (line 534) | class TodoCompletionDateItem extends StatelessWidget {
method build (line 538) | Widget build(BuildContext context)
method setCompletionDate (line 562) | Future<void> setCompletionDate(BuildContext context, TodoState state)
class TodoDueDateItem (line 582) | class TodoDueDateItem extends StatelessWidget {
method build (line 586) | Widget build(BuildContext context)
method setDueDate (line 613) | Future<void> setDueDate(BuildContext context, TodoState state)
method unsetDueDate (line 629) | void unsetDueDate(BuildContext context, String dueDate)
FILE: lib/todo/page/todo_list_page.dart
class TodoListPage (line 22) | class TodoListPage extends StatelessWidget {
method build (line 31) | Widget build(BuildContext context)
method _build (line 34) | Widget _build(BuildContext context)
method _buildWithFilter (line 44) | Widget _buildWithFilter(BuildContext context)
class TodoListViewNarrow (line 62) | class TodoListViewNarrow extends ScollToTopView {
method createState (line 66) | State<TodoListViewNarrow> createState()
class _TodoListViewNarrowState (line 69) | class _TodoListViewNarrowState extends ScollToTopViewState<TodoListViewN...
method build (line 71) | Widget build(BuildContext context)
class TodoListViewWide (line 157) | class TodoListViewWide extends ScollToTopView {
method createState (line 161) | State<TodoListViewWide> createState()
class _TodoListViewWideState (line 164) | class _TodoListViewWideState extends ScollToTopViewState<TodoListViewWid...
method build (line 166) | Widget build(BuildContext context)
class LoadingIndicatorWrapper (line 251) | class LoadingIndicatorWrapper extends StatelessWidget {
method build (line 262) | Widget build(BuildContext context)
class TodoList (line 294) | class TodoList extends StatelessWidget {
method build (line 303) | Widget build(BuildContext context)
class TodoListTile (line 349) | class TodoListTile extends StatelessWidget {
method build (line 358) | Widget build(BuildContext context)
method _buildTitle (line 444) | Widget _buildTitle(BuildContext context)
method _buildSubtitle (line 475) | Widget? _buildSubtitle()
class TodoListDeleteFilter (line 510) | class TodoListDeleteFilter extends StatelessWidget {
method build (line 514) | Widget build(BuildContext context)
class TodoListSaveFilter (line 545) | class TodoListSaveFilter extends StatelessWidget {
method build (line 549) | Widget build(BuildContext context)
FILE: lib/todo/page/todo_search_page.dart
class TodoSearchPage (line 15) | class TodoSearchPage extends StatelessWidget {
method build (line 24) | Widget build(BuildContext context)
class TodoSearchView (line 38) | class TodoSearchView extends StatefulWidget {
method createState (line 42) | State<TodoSearchView> createState()
class _TodoSearchViewState (line 45) | class _TodoSearchViewState extends State<TodoSearchView> {
method initState (line 50) | void initState()
method dispose (line 57) | void dispose()
method _getResults (line 62) | Iterable<Todo> _getResults(Iterable<Todo> todoList)
method _buildSearchField (line 72) | Widget _buildSearchField(BuildContext context)
method _buildActions (line 86) | List<Widget> _buildActions(BuildContext context)
method build (line 102) | Widget build(BuildContext context)
class TodoSearchTile (line 145) | class TodoSearchTile extends StatelessWidget {
method build (line 154) | Widget build(BuildContext context)
method _buildTitle (line 169) | Widget _buildTitle(BuildContext context)
method _buildSubtitle (line 200) | Widget? _buildSubtitle()
method _onTapAction (line 234) | void _onTapAction(BuildContext context)
FILE: lib/todo/repository/todo_list_repository.dart
class TodoListRepository (line 5) | class TodoListRepository {
method getTodoList (line 11) | Stream<List<Todo>> getTodoList()
method initSource (line 13) | Future<void> initSource()
method readFromSource (line 16) | Future<void> readFromSource()
method writeToSource (line 19) | Future<void> writeToSource()
method existsTodo (line 21) | bool existsTodo(Todo todo)
method saveTodo (line 26) | void saveTodo(Todo todo)
method saveMultipleTodos (line 29) | void saveMultipleTodos(List<Todo> todos)
method deleteTodo (line 32) | void deleteTodo(Todo todo)
method deleteMultipleTodos (line 35) | void deleteMultipleTodos(List<Todo> todos)
FILE: lib/todo/state/todo_cubit.dart
class TodoCubit (line 6) | class TodoCubit extends Cubit<TodoState> {
method updateTodo (line 11) | void updateTodo(Todo todo)
method toggleCompletion (line 21) | void toggleCompletion({bool? completion, DateTime? completionDate})
method updateDescription (line 34) | void updateDescription(String description)
method setPriority (line 44) | void setPriority(Priority priority)
method unsetPriority (line 54) | void unsetPriority()
method addProject (line 64) | void addProject(String project)
method updateProjects (line 88) | void updateProjects(Set<String> projects)
method removeProject (line 120) | void removeProject(String project)
method addContext (line 139) | void addContext(String context)
method updateContexts (line 163) | void updateContexts(Set<String> contexts)
method removeContext (line 195) | void removeContext(String context)
method addKeyValue (line 214) | void addKeyValue(String kv)
method updateKeyValues (line 244) | void updateKeyValues(Set<String> keyValues)
method removeKeyValue (line 290) | void removeKeyValue(String kv)
FILE: lib/todo/state/todo_list_bloc.dart
class TodoListBloc (line 8) | class TodoListBloc extends Bloc<TodoListEvent, TodoListState> {
method _onTodoListSubscriptionRequested (line 22) | Future<void> _onTodoListSubscriptionRequested(
method _onTodoListSynchronizationRequested (line 36) | void _onTodoListSynchronizationRequested(
method _onTodoSubmitted (line 57) | void _onTodoSubmitted(
method _onTodoDeleted (line 72) | void _onTodoDeleted(
method _onTodoCompletionToggled (line 87) | void _onTodoCompletionToggled(
FILE: lib/todo/state/todo_list_event.dart
class TodoListEvent (line 4) | sealed class TodoListEvent extends Equatable {
class TodoListSubscriptionRequested (line 11) | final class TodoListSubscriptionRequested extends TodoListEvent {
class TodoListSynchronizationRequested (line 15) | final class TodoListSynchronizationRequested extends TodoListEvent {
class TodoListTodoSubmitted (line 19) | final class TodoListTodoSubmitted extends TodoListEvent {
class TodoListTodoDeleted (line 30) | final class TodoListTodoDeleted extends TodoListEvent {
class TodoListTodoCompletionToggled (line 41) | final class TodoListTodoCompletionToggled extends TodoListEvent {
FILE: lib/todo/state/todo_list_state.dart
class TodoListState (line 5) | sealed class TodoListState extends Equatable {
method filteredTodoList (line 42) | Iterable<Todo> filteredTodoList(Filter filter)
method groupedTodoList (line 44) | Map<String, Iterable<Todo>> groupedTodoList(Filter filter)
method copyWith (line 47) | TodoListState copyWith({
method loading (line 51) | TodoListState loading({
method success (line 59) | TodoListState success({
method error (line 67) | TodoListState error({
method toString (line 83) | String toString()
class TodoListLoading (line 86) | final class TodoListLoading extends TodoListState {
method copyWith (line 92) | TodoListLoading copyWith({
method toString (line 101) | String toString()
class TodoListSuccess (line 105) | final class TodoListSuccess extends TodoListState {
method copyWith (line 111) | TodoListSuccess copyWith({
method toString (line 120) | String toString()
class TodoListError (line 124) | final class TodoListError extends TodoListState {
method copyWith (line 133) | TodoListError copyWith({
method toString (line 150) | String toString()
FILE: lib/todo/state/todo_state.dart
class TodoState (line 4) | sealed class TodoState extends Equatable {
method success (line 11) | TodoSuccess success({
method error (line 19) | TodoError error({
method toString (line 35) | String toString()
class TodoSuccess (line 38) | final class TodoSuccess extends TodoState {
method copyWith (line 43) | TodoSuccess copyWith({
method toString (line 57) | String toString()
class TodoError (line 60) | final class TodoError extends TodoState {
method copyWith (line 68) | TodoError copyWith({
method toString (line 85) | String toString()
FILE: lib/todo_file/state/todo_file_cubit.dart
class TodoFileCubit (line 11) | class TodoFileCubit extends Cubit<TodoFileState> {
method checkLocalPermission (line 31) | Future<void> checkLocalPermission(String filename)
method load (line 39) | Future<void> load()
method saveLocalPath (line 74) | Future<void> saveLocalPath(String? value)
method saveLocalFilename (line 94) | Future<void> saveLocalFilename(String? value)
method saveRemotePath (line 114) | Future<void> saveRemotePath(String? value)
method resetToDefaults (line 129) | Future<void> resetToDefaults()
method resetTodoFileSettings (line 147) | Future<void> resetTodoFileSettings()
FILE: lib/todo_file/state/todo_file_state.dart
class TodoFileState (line 6) | sealed class TodoFileState extends Equatable {
method load (line 28) | TodoFileLoading load({
method ready (line 42) | TodoFileReady ready({
method error (line 56) | TodoFileError error({
method toString (line 81) | String toString()
class TodoFileLoading (line 85) | final class TodoFileLoading extends TodoFileState {
method copyWith (line 93) | TodoFileLoading copyWith({
method toString (line 108) | String toString()
class TodoFileReady (line 112) | final class TodoFileReady extends TodoFileState {
method copyWith (line 120) | TodoFileReady copyWith({
method toString (line 135) | String toString()
class TodoFileError (line 139) | final class TodoFileError extends TodoFileState {
method copyWith (line 150) | TodoFileError copyWith({
method toString (line 176) | String toString()
FILE: lib/webdav/client/webdav_client.dart
class WebDAVClientException (line 10) | class WebDAVClientException implements Exception {
method toString (line 16) | String toString()
class WebDAVClient (line 19) | class WebDAVClient {
method _open (line 75) | Future<webdav.Client> _open()
method _handleDioError (line 116) | (String, String) _handleDioError(DioException error)
method ping (line 202) | Future<void> ping()
method _exists (line 223) | Future<bool> _exists({
method fileExists (line 241) | Future<bool> fileExists({
method getFile (line 257) | Future<webdav.File> getFile({
method listFiles (line 272) | Future<List<webdav.File>> listFiles({
method create (line 287) | Future<void> create(String filename)
method mkdir (line 308) | Future<void> mkdir(
method download (line 332) | Future<String> download({
method upload (line 348) | Future<void> upload({
FILE: linux/main.cc
function main (line 3) | int main(int argc, char** argv) {
FILE: linux/my_application.cc
type _MyApplication (line 10) | struct _MyApplication {
function my_application_activate (line 18) | static void my_application_activate(GApplication* application) {
function gboolean (line 66) | static gboolean my_application_local_command_line(GApplication* applicat...
function my_application_startup (line 85) | static void my_application_startup(GApplication* application) {
function my_application_shutdown (line 94) | static void my_application_shutdown(GApplication* application) {
function my_application_dispose (line 103) | static void my_application_dispose(GObject* object) {
function my_application_class_init (line 109) | static void my_application_class_init(MyApplicationClass* klass) {
function my_application_init (line 117) | static void my_application_init(MyApplication* self) {}
function MyApplication (line 119) | MyApplication* my_application_new() {
FILE: test/common/widget/confirm_dialog_test.dart
class MaterialAppConfirmationDialog (line 5) | class MaterialAppConfirmationDialog extends StatefulWidget {
method createState (line 9) | State<MaterialAppConfirmationDialog> createState()
class _MaterialAppConfirmationDialogState (line 13) | class _MaterialAppConfirmationDialogState
method build (line 18) | Widget build(BuildContext context)
function main (line 51) | void main()
FILE: test/common/widget/contexts_dialog_test.dart
class MaterialAppFilterContextTagDialog (line 18) | class MaterialAppFilterContextTagDialog extends StatelessWidget {
method build (line 27) | Widget build(BuildContext context)
class MaterialAppTodoContextTagDialog (line 89) | class MaterialAppTodoContextTagDialog extends StatelessWidget {
method build (line 93) | Widget build(BuildContext context)
function safeTapByFinder (line 139) | Future safeTapByFinder(WidgetTester tester, Finder finder)
function main (line 145) | void main()
FILE: test/common/widget/default_filter_state_filter_dialog_test.dart
class MaterialAppDefaultFilterStateFilterDialog (line 15) | class MaterialAppDefaultFilterStateFilterDialog extends StatelessWidget {
method build (line 24) | Widget build(BuildContext context)
function main (line 79) | void main()
FILE: test/common/widget/default_filter_state_group_dialog_test.dart
class MaterialAppDefaultFilterStateGroupDialog (line 15) | class MaterialAppDefaultFilterStateGroupDialog extends StatelessWidget {
method build (line 24) | Widget build(BuildContext context)
function main (line 79) | void main()
FILE: test/common/widget/default_filter_state_order_dialog_test.dart
class MaterialAppDefaultFilterStateOrderDialog (line 15) | class MaterialAppDefaultFilterStateOrderDialog extends StatelessWidget {
method build (line 24) | Widget build(BuildContext context)
function main (line 79) | void main()
FILE: test/common/widget/filter_state_filter_dialog_test.dart
class MaterialAppFilterStateFilterDialog (line 15) | class MaterialAppFilterStateFilterDialog extends StatelessWidget {
method build (line 24) | Widget build(BuildContext context)
function main (line 79) | void main()
FILE: test/common/widget/filter_state_group_dialog_test.dart
class MaterialAppFilterStateGroupDialog (line 15) | class MaterialAppFilterStateGroupDialog extends StatelessWidget {
method build (line 24) | Widget build(BuildContext context)
function main (line 79) | void main()
FILE: test/common/widget/filter_state_order_dialog_test.dart
class MaterialAppFilterStateOrderDialog (line 15) | class MaterialAppFilterStateOrderDialog extends StatelessWidget {
method build (line 24) | Widget build(BuildContext context)
function main (line 79) | void main()
FILE: test/common/widget/info_dialog_test.dart
class MaterialAppInfoDialog (line 5) | class MaterialAppInfoDialog extends StatelessWidget {
method build (line 9) | Widget build(BuildContext context)
function main (line 35) | void main()
FILE: test/common/widget/input_dialog_test.dart
class MaterialAppInputDialog (line 5) | class MaterialAppInputDialog extends StatefulWidget {
method createState (line 9) | State<MaterialAppInputDialog> createState()
class _MaterialAppInputDialogState (line 12) | class _MaterialAppInputDialogState extends State<MaterialAppInputDialog> {
method build (line 16) | Widget build(BuildContext context)
function main (line 47) | void main()
FILE: test/common/widget/key_values_dialog_test.dart
class MaterialAppTodoKeyValueTagDialog (line 9) | class MaterialAppTodoKeyValueTagDialog extends StatelessWidget {
method build (line 13) | Widget build(BuildContext context)
function safeTapByFinder (line 59) | Future safeTapByFinder(WidgetTester tester, Finder finder)
function main (line 65) | void main()
FILE: test/common/widget/priorities_dialog_test.dart
class MaterialAppFilterPriorityTagDialog (line 18) | class MaterialAppFilterPriorityTagDialog extends StatelessWidget {
method build (line 27) | Widget build(BuildContext context)
class MaterialAppTodoPriorityTagDialog (line 89) | class MaterialAppTodoPriorityTagDialog extends StatelessWidget {
method build (line 98) | Widget build(BuildContext context)
function safeTapByFinder (line 158) | Future safeTapByFinder(WidgetTester tester, Finder finder)
function main (line 164) | void main()
FILE: test/common/widget/projects_dialog_test.dart
class MaterialAppFilterProjectTagDialog (line 18) | class MaterialAppFilterProjectTagDialog extends StatelessWidget {
method build (line 27) | Widget build(BuildContext context)
class MaterialAppTodoProjectTagDialog (line 89) | class MaterialAppTodoProjectTagDialog extends StatelessWidget {
method build (line 93) | Widget build(BuildContext context)
function safeTapByFinder (line 139) | Future safeTapByFinder(WidgetTester tester, Finder finder)
function main (line 145) | void main()
FILE: test/drawer/state/drawer_cubit_test.dart
function main (line 5) | void main()
FILE: test/filter/controller/filter_controller_test.dart
function main (line 12) | void main()
FILE: test/filter/page/filter_create_edit_page_test.dart
class BlocRepositoryWrapper (line 21) | class BlocRepositoryWrapper extends StatelessWidget {
method build (line 34) | Widget build(BuildContext context)
function main (line 62) | void main()
FILE: test/filter/page/filter_list_page_test.dart
class FakeController (line 18) | class FakeController extends Fake implements FilterController {
method list (line 26) | Future<List<Filter>> list()
class FilterListPageMaterialApp (line 31) | class FilterListPageMaterialApp extends StatelessWidget {
method build (line 42) | Widget build(BuildContext context)
function main (line 82) | void main()
FILE: test/filter/state/filter_cubit_test.dart
function main (line 14) | void main()
FILE: test/filter/widget/filter_chip_test.dart
class BlocAppWrapper (line 23) | class BlocAppWrapper extends StatelessWidget {
method build (line 36) | Widget build(BuildContext context)
function main (line 70) | void main()
FILE: test/login/page/webdav_login_view_test.dart
class MaterialAppWebDAVLoginView (line 12) | class MaterialAppWebDAVLoginView extends StatelessWidget {
method build (line 21) | Widget build(BuildContext context)
function main (line 48) | void main()
FILE: test/setting/controller/setting_controller_test.dart
function main (line 11) | void main()
FILE: test/setting/page/settings_page_test.dart
class SettingsPageBlocProvider (line 20) | class SettingsPageBlocProvider extends StatelessWidget {
method build (line 31) | Widget build(BuildContext context)
function main (line 80) | void main()
FILE: test/todo/api/todo_list_api_test.dart
function mockTodoListFile (line 9) | File mockTodoListFile(List<String> rawTodoList)
function mockLocalTodoListRepository (line 21) | TodoListRepository mockLocalTodoListRepository(File todoFile)
function main (line 28) | void main()
FILE: test/todo/model/todo_model_test.dart
function main (line 4) | void main()
FILE: test/todo/page/todo_create_edit_page_test.dart
class MaterialAppWrapper (line 11) | class MaterialAppWrapper extends StatelessWidget {
method build (line 26) | Widget build(BuildContext context)
function main (line 39) | void main()
FILE: test/todo/page/todo_list_page_test.dart
class TodoListPageMaterialApp (line 27) | class TodoListPageMaterialApp extends StatelessWidget {
method build (line 40) | Widget build(BuildContext context)
function main (line 100) | void main()
FILE: test/todo/state/todo_cubit_test.dart
function main (line 6) | void main()
FILE: test/todo/state/todo_list_bloc_test.dart
function mockTodoListFile (line 12) | File mockTodoListFile(List<String> rawTodoList)
function mockLocalTodoListRepository (line 24) | TodoListRepository mockLocalTodoListRepository(File todoFile)
function main (line 31) | void main()
FILE: test/todo_file/state/todo_file_cubit_test.dart
function main (line 9) | void main()
FILE: test/todo_file/state/todo_file_state_test.dart
function main (line 4) | void main()
FILE: test/webdav/client/webdav_client_test.dart
function main (line 4) | void main()
FILE: test_driver/screenshot_integration_test.dart
function main (line 4) | Future<void> main()
FILE: windows/runner/flutter_window.cpp
function LRESULT (line 50) | LRESULT
FILE: windows/runner/flutter_window.h
function class (line 12) | class FlutterWindow : public Win32Window {
FILE: windows/runner/main.cpp
function wWinMain (line 8) | int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev,
FILE: windows/runner/utils.cpp
function CreateAndAttachConsole (line 10) | void CreateAndAttachConsole() {
function GetCommandLineArguments (line 24) | std::vector<std::string> GetCommandLineArguments() {
function Utf8FromUtf16 (line 44) | std::string Utf8FromUtf16(const wchar_t* utf16_string) {
FILE: windows/runner/win32_window.cpp
function Scale (line 36) | int Scale(int source, double scale_factor) {
function EnableFullDpiSupportIfAvailable (line 42) | void EnableFullDpiSupportIfAvailable(HWND hwnd) {
class WindowClassRegistrar (line 59) | class WindowClassRegistrar {
method WindowClassRegistrar (line 64) | static WindowClassRegistrar* GetInstance() {
method WindowClassRegistrar (line 80) | WindowClassRegistrar() = default;
function wchar_t (line 89) | const wchar_t* WindowClassRegistrar::GetWindowClass() {
function LRESULT (line 157) | LRESULT CALLBACK Win32Window::WndProc(HWND const window,
function LRESULT (line 176) | LRESULT
function Win32Window (line 236) | Win32Window* Win32Window::GetThisFromHandle(HWND const window) noexcept {
function RECT (line 252) | RECT Win32Window::GetClientArea() {
function HWND (line 258) | HWND Win32Window::GetHandle() {
FILE: windows/runner/win32_window.h
type Size (line 21) | struct Size {
Condensed preview — 206 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (1,213K chars).
[
{
"path": ".devcontainer/Dockerfile",
"chars": 2470,
"preview": "FROM mcr.microsoft.com/devcontainers/base:ubuntu-24.04\n\nENV FLUTTER_CHANNEL=\"stable\"\nENV FLUTTER_VERSION=\"3.24.5\"\nENV FL"
},
{
"path": ".devcontainer/devcontainer.json",
"chars": 2410,
"preview": "{\n \"name\": \"Flutter\",\n \"dockerFile\": \"Dockerfile\",\n \"remoteUser\": \"vscode\",\n \"updateRemoteUserUID\": true,\n \"runArgs"
},
{
"path": ".github/dependabot.yml",
"chars": 462,
"preview": "# To get started with Dependabot version updates, you'll need to specify which\n# package ecosystems to update and where "
},
{
"path": ".github/workflows/ci.yaml",
"chars": 1464,
"preview": "name: CI\n\non:\n push:\n branches:\n - main\n pull_request:\n branches:\n - main\n\njobs:\n test:\n name: CI\n"
},
{
"path": ".github/workflows/release.yaml",
"chars": 3052,
"preview": "name: Release\n\non:\n push:\n tags:\n - 'v[0-9]+.[0-9]+.[0-9]+'\n\nenv:\n PROPERTIES_PATH: \"./android/key.properties\""
},
{
"path": ".gitignore",
"chars": 2743,
"preview": "# Miscellaneous\n*.class\n*.lock\n*.log\n*.pyc\n*.swp\n.DS_Store\n.atom/\n.buildlog/\n.history\n.svn/\n\n# IntelliJ related\n*.iml\n*."
},
{
"path": ".gitmodules",
"chars": 82,
"preview": "[submodule \".flutter\"]\n\tpath = .flutter\n\turl = https://github.com/flutter/flutter\n"
},
{
"path": ".metadata",
"chars": 1706,
"preview": "# This file tracks properties of this Flutter project.\n# Used by Flutter tool to assess capabilities and perform upgrade"
},
{
"path": ".pre-commit-config.yaml",
"chars": 1400,
"preview": "exclude: (^android/|^build/|^coverage/|^ios/|^linux/|^macos/|^web/|^windows/)\nfail_fast: true\ndefault_install_hook_types"
},
{
"path": ".vscode/tasks.json",
"chars": 587,
"preview": "{\n \"version\": \"2.0.0\",\n \"tasks\": [\n {\n \"label\": \"flutter: run (Linux)\",\n \"type\": \"shell\",\n \"command\""
},
{
"path": ".yamlfmt",
"chars": 147,
"preview": "formatter:\n type: basic\n include_document_start: false\n retain_line_breaks_single: true\n trim_trailing_whitespace: t"
},
{
"path": "CHANGELOG.md",
"chars": 12231,
"preview": "# Changelog\n\nAll notable changes to this project will be documented in this file.\n\nThe format is based on [Keep a Change"
},
{
"path": "Caddyfile",
"chars": 160,
"preview": "{\n debug\n}\n\nlocalhost {\n uri strip_prefix /nc\n reverse_proxy nextcloud:80\n}\n\n10.0.2.2 {\n tls internal\n uri strip_pr"
},
{
"path": "Dockerfile_fdroid",
"chars": 210,
"preview": "FROM registry.gitlab.com/fdroid/docker-executable-fdroidserver:master\n\nRUN apt-get update && apt-get install -y \\\n open"
},
{
"path": "LICENSE",
"chars": 1067,
"preview": "MIT License\n\nCopyright (c) 2023 Toni Mägel\n\nPermission is hereby granted, free of charge, to any person obtaining a copy"
},
{
"path": "Makefile",
"chars": 2188,
"preview": ".PHONY: screenshots\n\nAPP_ID = \"de.tnmgl.ntodotxt\"\nFDROID_REPO = \"${HOME}/Downloads/nosync/fdroiddata\"\n\nsonarqube:\n\tdocke"
},
{
"path": "README.md",
"chars": 4582,
"preview": "# ntodotxt\n\n[](https://github.com/tmaegel/"
},
{
"path": "analysis_options.yaml",
"chars": 1290,
"preview": "# This file configures the analyzer, which statically analyzes Dart code to\n# check for errors, warnings, and lints.\n#\n#"
},
{
"path": "android/.gitignore",
"chars": 247,
"preview": "gradle-wrapper.jar\n/.gradle\n/captures/\n/gradlew\n/gradlew.bat\n/local.properties\nGeneratedPluginRegistrant.java\n\n# Remembe"
},
{
"path": "android/app/build.gradle",
"chars": 2113,
"preview": "plugins {\n id \"com.android.application\"\n id \"kotlin-android\"\n // The Flutter Gradle Plugin must be applied afte"
},
{
"path": "android/app/src/debug/AndroidManifest.xml",
"chars": 618,
"preview": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\">\n <!-- The INTERNET permission is required for d"
},
{
"path": "android/app/src/main/AndroidManifest.xml",
"chars": 2641,
"preview": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\">\n <uses-permission android:name=\"android.permiss"
},
{
"path": "android/app/src/main/kotlin/de/tnmgl/ntodotxt/MainActivity.kt",
"chars": 122,
"preview": "package de.tnmgl.ntodotxt\n\nimport io.flutter.embedding.android.FlutterActivity\n\nclass MainActivity: FlutterActivity() {\n"
},
{
"path": "android/app/src/main/res/drawable/launch_background.xml",
"chars": 434,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- Modify this file to customize your launch splash screen -->\n<layer-list xmln"
},
{
"path": "android/app/src/main/res/drawable-v21/launch_background.xml",
"chars": 438,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- Modify this file to customize your launch splash screen -->\n<layer-list xmln"
},
{
"path": "android/app/src/main/res/values/styles.xml",
"chars": 996,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n <!-- Theme applied to the Android Window while the process is sta"
},
{
"path": "android/app/src/main/res/values-night/styles.xml",
"chars": 995,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n <!-- Theme applied to the Android Window while the process is sta"
},
{
"path": "android/app/src/profile/AndroidManifest.xml",
"chars": 618,
"preview": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\">\n <!-- The INTERNET permission is required for d"
},
{
"path": "android/build.gradle",
"chars": 322,
"preview": "allprojects {\n repositories {\n google()\n mavenCentral()\n }\n}\n\nrootProject.buildDir = \"../build\"\nsubp"
},
{
"path": "android/gradle/wrapper/gradle-wrapper.properties",
"chars": 200,
"preview": "distributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dist"
},
{
"path": "android/gradle.properties",
"chars": 135,
"preview": "org.gradle.jvmargs=-Xmx4G -XX:MaxMetaspaceSize=2G -XX:+HeapDumpOnOutOfMemoryError\nandroid.useAndroidX=true\nandroid.enabl"
},
{
"path": "android/settings.gradle",
"chars": 727,
"preview": "pluginManagement {\n def flutterSdkPath = {\n def properties = new Properties()\n file(\"local.properties\")"
},
{
"path": "docker-compose.yaml",
"chars": 620,
"preview": "services:\n nextcloud:\n image: nextcloud:27\n container_name: nextcloud\n expose:\n - 80\n environment:\n "
},
{
"path": "emulatorctl",
"chars": 1229,
"preview": "#!/usr/bin/env bash\n\nfunction show_usage() {\n echo \"Usage:\n $(basename \"$\") [options]\"\n echo \"\"\n echo \"Options:\n "
},
{
"path": "fonts/LICENSE",
"chars": 4482,
"preview": "Copyright 2020 The Open Sans Project Authors (https://github.com/googlefonts/opensans)\r\n\r\nThis Font Software is licensed"
},
{
"path": "integration_test/login/login_integration_test.dart",
"chars": 5850,
"preview": "import 'package:flutter/material.dart';\nimport 'package:flutter/services.dart';\nimport 'package:flutter_test/flutter_tes"
},
{
"path": "integration_test/preview_app_integration_test.dart",
"chars": 8045,
"preview": "import 'package:flutter/material.dart';\nimport 'package:flutter/services.dart';\nimport 'package:flutter_test/flutter_tes"
},
{
"path": "integration_test/screenshot_integration_test.dart",
"chars": 10786,
"preview": "import 'dart:io';\n\nimport 'package:flutter/material.dart';\nimport 'package:flutter/services.dart';\nimport 'package:flutt"
},
{
"path": "integration_test/webdav/client/webdav_client_test.dart",
"chars": 8411,
"preview": "import 'dart:io' show Platform;\nimport 'dart:math';\n\nimport 'package:flutter_test/flutter_test.dart';\nimport 'package:in"
},
{
"path": "ios/.gitignore",
"chars": 569,
"preview": "**/dgph\n*.mode1v3\n*.mode2v3\n*.moved-aside\n*.pbxuser\n*.perspectivev3\n**/*sync/\n.sconsign.dblite\n.tags*\n**/.vagrant/\n**/De"
},
{
"path": "ios/Flutter/AppFrameworkInfo.plist",
"chars": 774,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "ios/Flutter/Debug.xcconfig",
"chars": 30,
"preview": "#include \"Generated.xcconfig\"\n"
},
{
"path": "ios/Flutter/Release.xcconfig",
"chars": 30,
"preview": "#include \"Generated.xcconfig\"\n"
},
{
"path": "ios/Runner/AppDelegate.swift",
"chars": 391,
"preview": "import Flutter\nimport UIKit\n\n@main\n@objc class AppDelegate: FlutterAppDelegate {\n override func application(\n _ appl"
},
{
"path": "ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json",
"chars": 2519,
"preview": "{\n \"images\" : [\n {\n \"size\" : \"20x20\",\n \"idiom\" : \"iphone\",\n \"filename\" : \"Icon-App-20x20@2x.png\",\n "
},
{
"path": "ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json",
"chars": 391,
"preview": "{\n \"images\" : [\n {\n \"idiom\" : \"universal\",\n \"filename\" : \"LaunchImage.png\",\n \"scale\" : \"1x\"\n },\n "
},
{
"path": "ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md",
"chars": 336,
"preview": "# Launch Screen Assets\n\nYou can customize the launch screen with your own desired assets by replacing the image files in"
},
{
"path": "ios/Runner/Base.lproj/LaunchScreen.storyboard",
"chars": 2377,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard"
},
{
"path": "ios/Runner/Base.lproj/Main.storyboard",
"chars": 1605,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard"
},
{
"path": "ios/Runner/Info.plist",
"chars": 1643,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "ios/Runner/Runner-Bridging-Header.h",
"chars": 38,
"preview": "#import \"GeneratedPluginRegistrant.h\"\n"
},
{
"path": "ios/Runner.xcodeproj/project.pbxproj",
"chars": 23636,
"preview": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 54;\n\tobjects = {\n\n/* Begin PBXBuildFile section *"
},
{
"path": "ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata",
"chars": 135,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n version = \"1.0\">\n <FileRef\n location = \"self:\">\n </FileRef"
},
{
"path": "ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist",
"chars": 238,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings",
"chars": 226,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme",
"chars": 3647,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n LastUpgradeVersion = \"1510\"\n version = \"1.3\">\n <BuildAction\n "
},
{
"path": "ios/Runner.xcworkspace/contents.xcworkspacedata",
"chars": 152,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n version = \"1.0\">\n <FileRef\n location = \"group:Runner.xcodepr"
},
{
"path": "ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist",
"chars": 238,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings",
"chars": 226,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "ios/RunnerTests/RunnerTests.swift",
"chars": 285,
"preview": "import Flutter\nimport UIKit\nimport XCTest\n\nclass RunnerTests: XCTestCase {\n\n func testExample() {\n // If you add cod"
},
{
"path": "lib/adaptive_layout/widget/adaptive_layout.dart",
"chars": 3424,
"preview": "import 'package:flutter/material.dart';\nimport 'package:flutter_bloc/flutter_bloc.dart';\nimport 'package:ntodotxt/common"
},
{
"path": "lib/app_info/page/app_details_page.dart",
"chars": 2768,
"preview": "import 'package:flutter/material.dart';\nimport 'package:go_router/go_router.dart';\nimport 'package:ntodotxt/common/const"
},
{
"path": "lib/common/bloc_observer.dart",
"chars": 835,
"preview": "// coverage:ignore-file\n\nimport 'package:flutter_bloc/flutter_bloc.dart'\n show Bloc, BlocBase, BlocObserver, Change, "
},
{
"path": "lib/common/constants/app.dart",
"chars": 358,
"preview": "// coverage:ignore-file\n\nconst String version = '0.17.0';\n\n/// https://m3.material.io/foundations/layout/applying-layout"
},
{
"path": "lib/common/exception/exceptions.dart",
"chars": 1464,
"preview": "// coverage:ignore-file\n\nsealed class TodoException implements Exception {\n final String message;\n\n const TodoExceptio"
},
{
"path": "lib/common/misc.dart",
"chars": 3102,
"preview": "// coverage:ignore-file\n\nimport 'dart:async';\nimport 'dart:io' show Platform;\n\nimport 'package:flutter/gestures.dart';\ni"
},
{
"path": "lib/common/router/router.dart",
"chars": 5572,
"preview": "// coverage:ignore-file\n\nimport 'package:flutter/material.dart';\nimport 'package:flutter_bloc/flutter_bloc.dart';\nimport"
},
{
"path": "lib/common/theme/theme.dart",
"chars": 5684,
"preview": "// coverage:ignore-file\n\nimport 'package:flex_color_scheme/flex_color_scheme.dart';\nimport 'package:flutter/material.dar"
},
{
"path": "lib/common/widget/app_bar.dart",
"chars": 3657,
"preview": "import 'package:flutter/material.dart';\nimport 'package:flutter_bloc/flutter_bloc.dart';\nimport 'package:ntodotxt/common"
},
{
"path": "lib/common/widget/chip.dart",
"chars": 3894,
"preview": "import 'package:flutter/material.dart';\n\nclass BasicIconChip extends StatelessWidget {\n final String label;\n final Ico"
},
{
"path": "lib/common/widget/confirm_dialog.dart",
"chars": 1371,
"preview": "import 'package:flutter/material.dart';\n\nclass ConfirmationDialog extends StatelessWidget {\n final String title;\n fina"
},
{
"path": "lib/common/widget/contexts_dialog.dart",
"chars": 3011,
"preview": "import 'package:flutter/material.dart';\nimport 'package:ntodotxt/common/widget/tag_dialog.dart';\nimport 'package:ntodotx"
},
{
"path": "lib/common/widget/date_picker.dart",
"chars": 759,
"preview": "import 'package:flutter/material.dart';\n\nclass TodoDatePicker {\n static final int defaultDaysOffset = 3650;\n\n const To"
},
{
"path": "lib/common/widget/filter_dialog.dart",
"chars": 3277,
"preview": "import 'package:flutter/material.dart';\nimport 'package:ntodotxt/filter/model/filter_model.dart' show ListFilter;\nimport"
},
{
"path": "lib/common/widget/group_by_dialog.dart",
"chars": 3374,
"preview": "import 'package:flutter/material.dart';\nimport 'package:ntodotxt/filter/model/filter_model.dart' show ListGroup;\nimport "
},
{
"path": "lib/common/widget/info_dialog.dart",
"chars": 812,
"preview": "import 'package:flutter/material.dart';\n\nclass InfoDialog extends StatelessWidget {\n final String title;\n final String"
},
{
"path": "lib/common/widget/input_dialog.dart",
"chars": 1316,
"preview": "import 'package:flutter/material.dart';\n\nclass InputDialog extends StatelessWidget {\n final String title;\n final Strin"
},
{
"path": "lib/common/widget/key_values_dialog.dart",
"chars": 1697,
"preview": "import 'package:flutter/material.dart';\nimport 'package:ntodotxt/common/widget/tag_dialog.dart';\nimport 'package:ntodotx"
},
{
"path": "lib/common/widget/order_dialog.dart",
"chars": 3148,
"preview": "import 'package:flutter/material.dart';\nimport 'package:ntodotxt/filter/model/filter_model.dart' show ListOrder;\nimport "
},
{
"path": "lib/common/widget/priorities_dialog.dart",
"chars": 6119,
"preview": "import 'package:flutter/material.dart';\nimport 'package:ntodotxt/common/misc.dart';\nimport 'package:ntodotxt/common/widg"
},
{
"path": "lib/common/widget/projects_dialog.dart",
"chars": 3011,
"preview": "import 'package:flutter/material.dart';\nimport 'package:ntodotxt/common/widget/tag_dialog.dart';\nimport 'package:ntodotx"
},
{
"path": "lib/common/widget/scroll_to_top.dart",
"chars": 1005,
"preview": "import 'package:flutter/material.dart';\n\nclass ScollToTopView extends StatefulWidget {\n const ScollToTopView({super.key"
},
{
"path": "lib/common/widget/tag_dialog.dart",
"chars": 6219,
"preview": "import 'package:flutter/material.dart';\nimport 'package:ntodotxt/common/misc.dart';\nimport 'package:ntodotxt/common/widg"
},
{
"path": "lib/database/controller/database.dart",
"chars": 1771,
"preview": "import 'package:ntodotxt/filter/model/filter_model.dart' show Filter;\nimport 'package:ntodotxt/main.dart' show log;\nimpo"
},
{
"path": "lib/drawer/state/drawer_cubit.dart",
"chars": 581,
"preview": "import 'package:flutter_bloc/flutter_bloc.dart';\nimport 'package:ntodotxt/drawer/state/drawer_state.dart';\n\n/// Keep the"
},
{
"path": "lib/drawer/state/drawer_state.dart",
"chars": 385,
"preview": "import 'package:equatable/equatable.dart';\n\nfinal class DrawerState extends Equatable {\n final int index;\n final int? "
},
{
"path": "lib/drawer/widget/drawer.dart",
"chars": 7824,
"preview": "import 'package:flutter/material.dart';\nimport 'package:flutter_bloc/flutter_bloc.dart';\nimport 'package:go_router/go_ro"
},
{
"path": "lib/filter/controller/fake_filter_controller.dart",
"chars": 1169,
"preview": "// coverage:ignore-file\n\nimport 'package:ntodotxt/filter/controller/filter_controller.dart'\n show FilterControllerInt"
},
{
"path": "lib/filter/controller/filter_controller.dart",
"chars": 2492,
"preview": "import 'package:ntodotxt/database/controller/database.dart';\nimport 'package:ntodotxt/filter/model/filter_model.dart' sh"
},
{
"path": "lib/filter/model/filter_model.dart",
"chars": 11748,
"preview": "import 'package:equatable/equatable.dart';\nimport 'package:ntodotxt/todo/model/todo_model.dart'\n show Priorities, Pri"
},
{
"path": "lib/filter/page/filter_create_edit_page.dart",
"chars": 16869,
"preview": "import 'package:flutter/material.dart';\nimport 'package:flutter/services.dart';\nimport 'package:flutter_bloc/flutter_blo"
},
{
"path": "lib/filter/page/filter_list_page.dart",
"chars": 7611,
"preview": "import 'package:flutter/material.dart';\nimport 'package:flutter_bloc/flutter_bloc.dart';\nimport 'package:go_router/go_ro"
},
{
"path": "lib/filter/repository/filter_repository.dart",
"chars": 1216,
"preview": "import 'package:ntodotxt/filter/controller/filter_controller.dart'\n show FilterController;\nimport 'package:ntodotxt/f"
},
{
"path": "lib/filter/state/filter_cubit.dart",
"chars": 8048,
"preview": "import 'package:flutter_bloc/flutter_bloc.dart';\nimport 'package:ntodotxt/filter/model/filter_model.dart'\n show Filte"
},
{
"path": "lib/filter/state/filter_list_bloc.dart",
"chars": 2169,
"preview": "import 'package:flutter_bloc/flutter_bloc.dart';\nimport 'package:ntodotxt/filter/model/filter_model.dart';\nimport 'packa"
},
{
"path": "lib/filter/state/filter_list_event.dart",
"chars": 649,
"preview": "import 'package:equatable/equatable.dart';\nimport 'package:ntodotxt/filter/model/filter_model.dart';\n\nsealed class Filte"
},
{
"path": "lib/filter/state/filter_list_state.dart",
"chars": 2236,
"preview": "import 'package:equatable/equatable.dart';\nimport 'package:ntodotxt/filter/model/filter_model.dart';\n\nsealed class Filte"
},
{
"path": "lib/filter/state/filter_state.dart",
"chars": 3546,
"preview": "import 'package:collection/collection.dart';\nimport 'package:equatable/equatable.dart';\nimport 'package:ntodotxt/filter/"
},
{
"path": "lib/filter/widget/filter_chip.dart",
"chars": 6248,
"preview": "import 'package:flutter/material.dart';\nimport 'package:flutter_bloc/flutter_bloc.dart';\nimport 'package:ntodotxt/common"
},
{
"path": "lib/intro/page/intro_page.dart",
"chars": 7280,
"preview": "import 'package:flutter/material.dart';\nimport 'package:ntodotxt/login/page/login_page.dart';\nimport 'package:url_launch"
},
{
"path": "lib/licenses/page/licenses_page.dart",
"chars": 1980,
"preview": "import 'package:flutter/material.dart';\nimport 'package:ntodotxt/common/widget/app_bar.dart';\nimport 'package:ntodotxt/o"
},
{
"path": "lib/login/page/login_page.dart",
"chars": 20641,
"preview": "import 'package:file_picker/file_picker.dart';\nimport 'package:flutter/material.dart';\nimport 'package:flutter_bloc/flut"
},
{
"path": "lib/login/state/login_cubit.dart",
"chars": 4626,
"preview": "import 'package:flutter_bloc/flutter_bloc.dart';\nimport 'package:ntodotxt/login/state/login_state.dart';\nimport 'package"
},
{
"path": "lib/login/state/login_state.dart",
"chars": 3607,
"preview": "import 'dart:math';\n\nimport 'package:equatable/equatable.dart';\n\nenum Backend { none, local, webdav }\n\nsealed class Logi"
},
{
"path": "lib/main.dart",
"chars": 12680,
"preview": "import 'dart:io';\n\nimport 'package:flutter/material.dart';\nimport 'package:flutter/services.dart';\nimport 'package:flutt"
},
{
"path": "lib/oss_licenses.dart",
"chars": 258181,
"preview": "// coverage:ignore-file\n\n// cSpell:disable\n// ignore_for_file: always_put_required_named_parameters_first\n// ignore_for_"
},
{
"path": "lib/setting/controller/fake_setting_controller.dart",
"chars": 1733,
"preview": "// coverage:ignore-file\n\nimport 'package:ntodotxt/setting/controller/setting_controller.dart'\n show SettingController"
},
{
"path": "lib/setting/controller/setting_controller.dart",
"chars": 2790,
"preview": "import 'package:ntodotxt/database/controller/database.dart';\nimport 'package:ntodotxt/setting/model/setting_model.dart' "
},
{
"path": "lib/setting/model/setting_model.dart",
"chars": 1039,
"preview": "import 'package:equatable/equatable.dart';\n\nclass Setting extends Equatable {\n final String key;\n final String value;\n"
},
{
"path": "lib/setting/page/settings_page.dart",
"chars": 12674,
"preview": "import 'package:flutter/material.dart';\nimport 'package:flutter_bloc/flutter_bloc.dart';\nimport 'package:go_router/go_ro"
},
{
"path": "lib/setting/repository/setting_repository.dart",
"chars": 980,
"preview": "import 'package:ntodotxt/setting/controller/setting_controller.dart'\n show SettingControllerInterface;\nimport 'packag"
},
{
"path": "lib/setting/state/interaction_settings_cubit.dart",
"chars": 1877,
"preview": "import 'package:flutter_bloc/flutter_bloc.dart';\nimport 'package:ntodotxt/setting/model/setting_model.dart';\nimport 'pac"
},
{
"path": "lib/setting/state/interaction_settings_state.dart",
"chars": 4157,
"preview": "import 'package:equatable/equatable.dart';\n\nsealed class InteractionSettingsState extends Equatable {\n final bool swipe"
},
{
"path": "lib/todo/api/todo_list_api.dart",
"chars": 7184,
"preview": "import 'dart:async';\nimport 'dart:io';\n\nimport 'package:collection/collection.dart';\nimport 'package:ntodotxt/main.dart'"
},
{
"path": "lib/todo/model/todo_model.dart",
"chars": 16370,
"preview": "import 'dart:convert';\nimport 'dart:math';\n\nimport 'package:crypto/crypto.dart';\nimport 'package:equatable/equatable.dar"
},
{
"path": "lib/todo/page/todo_create_edit_page.dart",
"chars": 20051,
"preview": "import 'package:flutter/material.dart';\nimport 'package:flutter/services.dart';\nimport 'package:flutter_bloc/flutter_blo"
},
{
"path": "lib/todo/page/todo_list_page.dart",
"chars": 20809,
"preview": "import 'package:flutter/material.dart';\nimport 'package:flutter_bloc/flutter_bloc.dart';\nimport 'package:go_router/go_ro"
},
{
"path": "lib/todo/page/todo_search_page.dart",
"chars": 7119,
"preview": "import 'package:flutter/material.dart';\nimport 'package:flutter/services.dart';\nimport 'package:flutter_bloc/flutter_blo"
},
{
"path": "lib/todo/repository/todo_list_repository.dart",
"chars": 1216,
"preview": "import 'package:ntodotxt/todo/api/todo_list_api.dart';\nimport 'package:ntodotxt/todo/model/todo_model.dart';\n\n/// A repo"
},
{
"path": "lib/todo/state/todo_cubit.dart",
"chars": 8650,
"preview": "import 'package:flutter_bloc/flutter_bloc.dart';\nimport 'package:ntodotxt/common/exception/exceptions.dart';\nimport 'pac"
},
{
"path": "lib/todo/state/todo_list_bloc.dart",
"chars": 3299,
"preview": "import 'package:flutter_bloc/flutter_bloc.dart';\nimport 'package:ntodotxt/todo/model/todo_model.dart';\nimport 'package:n"
},
{
"path": "lib/todo/state/todo_list_event.dart",
"chars": 1102,
"preview": "import 'package:equatable/equatable.dart';\nimport 'package:ntodotxt/todo/model/todo_model.dart';\n\nsealed class TodoListE"
},
{
"path": "lib/todo/state/todo_list_state.dart",
"chars": 3297,
"preview": "import 'package:equatable/equatable.dart';\nimport 'package:ntodotxt/filter/model/filter_model.dart';\nimport 'package:nto"
},
{
"path": "lib/todo/state/todo_state.dart",
"chars": 1457,
"preview": "import 'package:equatable/equatable.dart';\nimport 'package:ntodotxt/todo/model/todo_model.dart';\n\nsealed class TodoState"
},
{
"path": "lib/todo_file/state/todo_file_cubit.dart",
"chars": 4543,
"preview": "import 'dart:io';\n\nimport 'package:flutter_bloc/flutter_bloc.dart';\nimport 'package:ntodotxt/common/constants/app.dart';"
},
{
"path": "lib/todo_file/state/todo_file_state.dart",
"chars": 4618,
"preview": "import 'dart:io';\n\nimport 'package:equatable/equatable.dart';\nimport 'package:ntodotxt/common/constants/app.dart';\n\nseal"
},
{
"path": "lib/webdav/client/webdav_client.dart",
"chars": 10411,
"preview": "import 'dart:convert' show utf8;\nimport 'dart:io';\n\nimport 'package:dio/dio.dart';\nimport 'package:dio/io.dart';\nimport "
},
{
"path": "linux/.gitignore",
"chars": 18,
"preview": "flutter/ephemeral\n"
},
{
"path": "linux/CMakeLists.txt",
"chars": 5426,
"preview": "# Project-level configuration.\ncmake_minimum_required(VERSION 3.10)\nproject(runner LANGUAGES CXX)\n\n# The name of the exe"
},
{
"path": "linux/flutter/CMakeLists.txt",
"chars": 2815,
"preview": "# This file controls Flutter-level build steps. It should not be edited.\ncmake_minimum_required(VERSION 3.10)\n\nset(EPHEM"
},
{
"path": "linux/main.cc",
"chars": 180,
"preview": "#include \"my_application.h\"\n\nint main(int argc, char** argv) {\n g_autoptr(MyApplication) app = my_application_new();\n "
},
{
"path": "linux/my_application.cc",
"chars": 4424,
"preview": "#include \"my_application.h\"\n\n#include <flutter_linux/flutter_linux.h>\n#ifdef GDK_WINDOWING_X11\n#include <gdk/gdkx.h>\n#en"
},
{
"path": "linux/my_application.h",
"chars": 388,
"preview": "#ifndef FLUTTER_MY_APPLICATION_H_\n#define FLUTTER_MY_APPLICATION_H_\n\n#include <gtk/gtk.h>\n\nG_DECLARE_FINAL_TYPE(MyApplic"
},
{
"path": "macos/.gitignore",
"chars": 89,
"preview": "# Flutter-related\n**/Flutter/ephemeral/\n**/Pods/\n\n# Xcode-related\n**/dgph\n**/xcuserdata/\n"
},
{
"path": "macos/Flutter/Flutter-Debug.xcconfig",
"chars": 48,
"preview": "#include \"ephemeral/Flutter-Generated.xcconfig\"\n"
},
{
"path": "macos/Flutter/Flutter-Release.xcconfig",
"chars": 48,
"preview": "#include \"ephemeral/Flutter-Generated.xcconfig\"\n"
},
{
"path": "macos/Runner/AppDelegate.swift",
"chars": 201,
"preview": "import Cocoa\nimport FlutterMacOS\n\n@main\nclass AppDelegate: FlutterAppDelegate {\n override func applicationShouldTermina"
},
{
"path": "macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json",
"chars": 1291,
"preview": "{\n \"images\" : [\n {\n \"size\" : \"16x16\",\n \"idiom\" : \"mac\",\n \"filename\" : \"app_icon_16.png\",\n \"scale"
},
{
"path": "macos/Runner/Base.lproj/MainMenu.xib",
"chars": 23723,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.XIB\" version=\"3.0\" toolsVersion"
},
{
"path": "macos/Runner/Configs/AppInfo.xcconfig",
"chars": 596,
"preview": "// Application-level settings for the Runner target.\n//\n// This may be replaced with something auto-generated from metad"
},
{
"path": "macos/Runner/Configs/Debug.xcconfig",
"chars": 77,
"preview": "#include \"../../Flutter/Flutter-Debug.xcconfig\"\n#include \"Warnings.xcconfig\"\n"
},
{
"path": "macos/Runner/Configs/Release.xcconfig",
"chars": 79,
"preview": "#include \"../../Flutter/Flutter-Release.xcconfig\"\n#include \"Warnings.xcconfig\"\n"
},
{
"path": "macos/Runner/Configs/Warnings.xcconfig",
"chars": 580,
"preview": "WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverl"
},
{
"path": "macos/Runner/DebugProfile.entitlements",
"chars": 348,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "macos/Runner/Info.plist",
"chars": 1060,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "macos/Runner/MainFlutterWindow.swift",
"chars": 388,
"preview": "import Cocoa\nimport FlutterMacOS\n\nclass MainFlutterWindow: NSWindow {\n override func awakeFromNib() {\n let flutterVi"
},
{
"path": "macos/Runner/Release.entitlements",
"chars": 240,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "macos/Runner.xcodeproj/project.pbxproj",
"chars": 26350,
"preview": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 54;\n\tobjects = {\n\n/* Begin PBXAggregateTarget sec"
},
{
"path": "macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist",
"chars": 238,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme",
"chars": 3655,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n LastUpgradeVersion = \"1510\"\n version = \"1.3\">\n <BuildAction\n "
},
{
"path": "macos/Runner.xcworkspace/contents.xcworkspacedata",
"chars": 152,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n version = \"1.0\">\n <FileRef\n location = \"group:Runner.xcodepr"
},
{
"path": "macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist",
"chars": 238,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "macos/RunnerTests/RunnerTests.swift",
"chars": 290,
"preview": "import Cocoa\nimport FlutterMacOS\nimport XCTest\n\nclass RunnerTests: XCTestCase {\n\n func testExample() {\n // If you ad"
},
{
"path": "metadata/en-US/full_description.txt",
"chars": 258,
"preview": "With ntodotxt you can manage your todos in a todo.txt file (i.e. all information is stored in a single file). You can sa"
},
{
"path": "metadata/en-US/short_description.txt",
"chars": 37,
"preview": "Manage your todos in a todo.txt file\n"
},
{
"path": "metadata/en-US/title.txt",
"chars": 9,
"preview": "ntodotxt\n"
},
{
"path": "ntodotxt.yaml",
"chars": 145,
"preview": "session: ntodotxt\n\nroot: ~/Projekte/dart/flutter/ntodotxt/\n\nwindows:\n - name: git\n - name: neovim\n - name: flutter ru"
},
{
"path": "pubspec.yaml",
"chars": 1332,
"preview": "name: ntodotxt\n\ndescription: App for managing your todos within a todo.txt file locally or via webdav (e.g. Nextcloud)\np"
},
{
"path": "test/common/widget/confirm_dialog_test.dart",
"chars": 2525,
"preview": "import 'package:flutter/material.dart';\nimport 'package:flutter_test/flutter_test.dart';\nimport 'package:ntodotxt/common"
},
{
"path": "test/common/widget/contexts_dialog_test.dart",
"chars": 9762,
"preview": "import 'package:flutter/material.dart';\nimport 'package:flutter_bloc/flutter_bloc.dart';\nimport 'package:flutter_test/fl"
},
{
"path": "test/common/widget/default_filter_state_filter_dialog_test.dart",
"chars": 3963,
"preview": "import 'package:flutter/material.dart';\nimport 'package:flutter_bloc/flutter_bloc.dart';\nimport 'package:flutter_test/fl"
},
{
"path": "test/common/widget/default_filter_state_group_dialog_test.dart",
"chars": 3940,
"preview": "import 'package:flutter/material.dart';\nimport 'package:flutter_bloc/flutter_bloc.dart';\nimport 'package:flutter_test/fl"
},
{
"path": "test/common/widget/default_filter_state_order_dialog_test.dart",
"chars": 3951,
"preview": "import 'package:flutter/material.dart';\nimport 'package:flutter_bloc/flutter_bloc.dart';\nimport 'package:flutter_test/fl"
},
{
"path": "test/common/widget/filter_state_filter_dialog_test.dart",
"chars": 3918,
"preview": "import 'package:flutter/material.dart';\nimport 'package:flutter_bloc/flutter_bloc.dart';\nimport 'package:flutter_test/fl"
},
{
"path": "test/common/widget/filter_state_group_dialog_test.dart",
"chars": 3905,
"preview": "import 'package:flutter/material.dart';\nimport 'package:flutter_bloc/flutter_bloc.dart';\nimport 'package:flutter_test/fl"
},
{
"path": "test/common/widget/filter_state_order_dialog_test.dart",
"chars": 3916,
"preview": "import 'package:flutter/material.dart';\nimport 'package:flutter_bloc/flutter_bloc.dart';\nimport 'package:flutter_test/fl"
},
{
"path": "test/common/widget/info_dialog_test.dart",
"chars": 1613,
"preview": "import 'package:flutter/material.dart';\nimport 'package:flutter_test/flutter_test.dart';\nimport 'package:ntodotxt/common"
},
{
"path": "test/common/widget/input_dialog_test.dart",
"chars": 2524,
"preview": "import 'package:flutter/material.dart';\nimport 'package:flutter_test/flutter_test.dart';\nimport 'package:ntodotxt/common"
},
{
"path": "test/common/widget/key_values_dialog_test.dart",
"chars": 3701,
"preview": "import 'package:flutter/material.dart';\nimport 'package:flutter_bloc/flutter_bloc.dart';\nimport 'package:flutter_test/fl"
},
{
"path": "test/common/widget/priorities_dialog_test.dart",
"chars": 9307,
"preview": "import 'package:flutter/material.dart';\nimport 'package:flutter_bloc/flutter_bloc.dart';\nimport 'package:flutter_test/fl"
},
{
"path": "test/common/widget/projects_dialog_test.dart",
"chars": 9762,
"preview": "import 'package:flutter/material.dart';\nimport 'package:flutter_bloc/flutter_bloc.dart';\nimport 'package:flutter_test/fl"
},
{
"path": "test/drawer/state/drawer_cubit_test.dart",
"chars": 1913,
"preview": "import 'package:flutter_test/flutter_test.dart';\nimport 'package:ntodotxt/drawer/state/drawer_cubit.dart';\nimport 'packa"
},
{
"path": "test/filter/controller/filter_controller_test.dart",
"chars": 5853,
"preview": "import 'package:flutter/widgets.dart';\nimport 'package:flutter_test/flutter_test.dart';\nimport 'package:ntodotxt/databas"
},
{
"path": "test/filter/page/filter_create_edit_page_test.dart",
"chars": 31720,
"preview": "import 'package:flutter/material.dart';\nimport 'package:flutter_bloc/flutter_bloc.dart';\nimport 'package:flutter_test/fl"
},
{
"path": "test/filter/page/filter_list_page_test.dart",
"chars": 4679,
"preview": "import 'package:flutter/material.dart';\nimport 'package:flutter_bloc/flutter_bloc.dart';\nimport 'package:flutter_test/fl"
},
{
"path": "test/filter/state/filter_cubit_test.dart",
"chars": 17120,
"preview": "import 'package:flutter_test/flutter_test.dart';\nimport 'package:ntodotxt/database/controller/database.dart';\nimport 'pa"
},
{
"path": "test/filter/widget/filter_chip_test.dart",
"chars": 16654,
"preview": "import 'package:flutter/material.dart';\nimport 'package:flutter_bloc/flutter_bloc.dart';\nimport 'package:flutter_test/fl"
},
{
"path": "test/login/page/webdav_login_view_test.dart",
"chars": 9055,
"preview": "import 'package:flutter/material.dart';\nimport 'package:flutter_bloc/flutter_bloc.dart';\nimport 'package:flutter_test/fl"
},
{
"path": "test/setting/controller/setting_controller_test.dart",
"chars": 3692,
"preview": "import 'package:flutter/widgets.dart';\nimport 'package:flutter_test/flutter_test.dart';\nimport 'package:ntodotxt/databas"
},
{
"path": "test/setting/page/settings_page_test.dart",
"chars": 7495,
"preview": "import 'package:flutter/material.dart';\nimport 'package:flutter_bloc/flutter_bloc.dart';\nimport 'package:flutter_test/fl"
},
{
"path": "test/todo/api/todo_list_api_test.dart",
"chars": 9864,
"preview": "import 'dart:io';\n\nimport 'package:file/memory.dart';\nimport 'package:flutter_test/flutter_test.dart';\nimport 'package:n"
},
{
"path": "test/todo/model/todo_model_test.dart",
"chars": 33458,
"preview": "import 'package:flutter_test/flutter_test.dart';\nimport 'package:ntodotxt/todo/model/todo_model.dart';\n\nvoid main() {\n "
},
{
"path": "test/todo/page/todo_create_edit_page_test.dart",
"chars": 48398,
"preview": "import 'package:flutter/material.dart';\nimport 'package:flutter_test/flutter_test.dart';\nimport 'package:ntodotxt/common"
},
{
"path": "test/todo/page/todo_list_page_test.dart",
"chars": 24843,
"preview": "import 'dart:io';\n\nimport 'package:file/memory.dart';\nimport 'package:flutter/material.dart';\nimport 'package:flutter_bl"
},
{
"path": "test/todo/state/todo_cubit_test.dart",
"chars": 23428,
"preview": "import 'package:flutter_test/flutter_test.dart';\nimport 'package:ntodotxt/todo/model/todo_model.dart';\nimport 'package:n"
},
{
"path": "test/todo/state/todo_list_bloc_test.dart",
"chars": 15402,
"preview": "import 'dart:io';\n\nimport 'package:file/memory.dart';\nimport 'package:flutter_test/flutter_test.dart';\nimport 'package:n"
},
{
"path": "test/todo_file/state/todo_file_cubit_test.dart",
"chars": 3718,
"preview": "import 'package:flutter_test/flutter_test.dart';\nimport 'package:ntodotxt/setting/controller/fake_setting_controller.dar"
},
{
"path": "test/todo_file/state/todo_file_state_test.dart",
"chars": 8924,
"preview": "import 'package:flutter_test/flutter_test.dart';\nimport 'package:ntodotxt/todo_file/state/todo_file_state.dart';\n\nvoid m"
},
{
"path": "test/webdav/client/webdav_client_test.dart",
"chars": 5409,
"preview": "import 'package:flutter_test/flutter_test.dart';\nimport 'package:ntodotxt/webdav/client/webdav_client.dart';\n\nvoid main("
},
{
"path": "test_driver/screenshot_integration_test.dart",
"chars": 554,
"preview": "import 'dart:io';\nimport 'package:integration_test/integration_test_driver_extended.dart';\n\nFuture<void> main() async {\n"
},
{
"path": "web/index.html",
"chars": 1220,
"preview": "<!DOCTYPE html>\n<html>\n<head>\n <!--\n If you are serving your web app in a path other than the root, change the\n h"
},
{
"path": "web/manifest.json",
"chars": 912,
"preview": "{\n \"name\": \"ntodotxt\",\n \"short_name\": \"ntodotxt\",\n \"start_url\": \".\",\n \"display\": \"standalone\",\n \"backgrou"
},
{
"path": "windows/.gitignore",
"chars": 291,
"preview": "flutter/ephemeral/\n\n# Visual Studio user-specific files.\n*.suo\n*.user\n*.userosscache\n*.sln.docstates\n\n# Visual Studio bu"
},
{
"path": "windows/CMakeLists.txt",
"chars": 4152,
"preview": "# Project-level configuration.\ncmake_minimum_required(VERSION 3.14)\nproject(ntodotxt LANGUAGES CXX)\n\n# The name of the e"
},
{
"path": "windows/flutter/CMakeLists.txt",
"chars": 3742,
"preview": "# This file controls Flutter-level build steps. It should not be edited.\ncmake_minimum_required(VERSION 3.14)\n\nset(EPHEM"
},
{
"path": "windows/runner/CMakeLists.txt",
"chars": 1796,
"preview": "cmake_minimum_required(VERSION 3.14)\nproject(runner LANGUAGES CXX)\n\n# Define the application target. To change its name,"
},
{
"path": "windows/runner/Runner.rc",
"chars": 3023,
"preview": "// Microsoft Visual C++ generated resource script.\n//\n#pragma code_page(65001)\n#include \"resource.h\"\n\n#define APSTUDIO_R"
},
{
"path": "windows/runner/flutter_window.cpp",
"chars": 2122,
"preview": "#include \"flutter_window.h\"\n\n#include <optional>\n\n#include \"flutter/generated_plugin_registrant.h\"\n\nFlutterWindow::Flutt"
},
{
"path": "windows/runner/flutter_window.h",
"chars": 928,
"preview": "#ifndef RUNNER_FLUTTER_WINDOW_H_\n#define RUNNER_FLUTTER_WINDOW_H_\n\n#include <flutter/dart_project.h>\n#include <flutter/f"
},
{
"path": "windows/runner/main.cpp",
"chars": 1261,
"preview": "#include <flutter/dart_project.h>\n#include <flutter/flutter_view_controller.h>\n#include <windows.h>\n\n#include \"flutter_w"
}
]
// ... and 6 more files (download for full content)
About this extraction
This page contains the full source code of the tmaegel/ntodotxt GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 206 files (1.1 MB), approximately 262.0k tokens, and a symbol index with 896 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.