├── .devcontainer
├── Dockerfile
├── build-in-container.sh
└── devcontainer.json
├── .github
├── FUNDING.yml
├── release.yml
└── workflows
│ ├── build-android.yml
│ ├── build-linux.yml
│ ├── build-website.yml
│ ├── build-windows.yml
│ ├── flatpak.yml
│ ├── pre-release.yml
│ ├── pull_request.yml
│ ├── release-android.yml
│ ├── release-windows-store.yml
│ ├── release.yml
│ └── tests.yml
├── .gitignore
├── .metadata
├── .vscode
├── launch.json
├── settings.json
└── tasks.json
├── BUILDING.md
├── LICENSE
├── PRIVACY_POLICY.md
├── README.md
├── analysis_options.yaml
├── android
├── .gitignore
├── app
│ ├── build.gradle.kts
│ ├── google-services.json
│ ├── proguard-rules.pro
│ └── src
│ │ ├── debug
│ │ └── AndroidManifest.xml
│ │ ├── main
│ │ ├── AndroidManifest.xml
│ │ ├── kotlin
│ │ │ └── com
│ │ │ │ └── example
│ │ │ │ └── adventure_list
│ │ │ │ └── MainActivity.kt
│ │ └── res
│ │ │ ├── drawable-v21
│ │ │ ├── app_widget_background.xml
│ │ │ ├── app_widget_inner_view_background.xml
│ │ │ └── launch_background.xml
│ │ │ ├── drawable
│ │ │ ├── app_icon.png
│ │ │ ├── launch_background.xml
│ │ │ └── widget_background.xml
│ │ │ ├── layout
│ │ │ └── example_layout.xml
│ │ │ ├── mipmap-hdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-mdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xhdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xxhdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xxxhdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── raw
│ │ │ └── keep.xml
│ │ │ ├── values-night-v31
│ │ │ └── themes.xml
│ │ │ ├── values-night
│ │ │ └── styles.xml
│ │ │ ├── values-v21
│ │ │ └── styles.xml
│ │ │ ├── values-v31
│ │ │ ├── styles.xml
│ │ │ └── themes.xml
│ │ │ ├── values
│ │ │ ├── attrs.xml
│ │ │ ├── colors.xml
│ │ │ ├── dimens.xml
│ │ │ ├── strings.xml
│ │ │ ├── styles.xml
│ │ │ └── themes.xml
│ │ │ └── xml
│ │ │ └── home_widget_example.xml
│ │ └── profile
│ │ └── AndroidManifest.xml
├── build.gradle.kts
├── gradle.properties
├── gradle
│ └── wrapper
│ │ └── gradle-wrapper.properties
└── settings.gradle.kts
├── assets
├── fonts
│ ├── NotoSans-Regular.ttf
│ └── OFL.txt
└── icons
│ ├── codes.merritt.adventurelist-symbolic-with-notification-badge.ico
│ ├── codes.merritt.adventurelist-symbolic-with-notification-badge.svg
│ ├── codes.merritt.adventurelist-symbolic.ico
│ ├── codes.merritt.adventurelist-symbolic.svg
│ ├── codes.merritt.adventurelist-with-notification-badge.ico
│ ├── codes.merritt.adventurelist-with-notification-badge.svg
│ ├── codes.merritt.adventurelist.Source.svg
│ ├── codes.merritt.adventurelist.ico
│ ├── codes.merritt.adventurelist.png
│ └── codes.merritt.adventurelist.svg
├── build.yaml
├── devtools_options.yaml
├── lib
├── firebase_options.dart
├── main.dart
└── src
│ ├── app.dart
│ ├── app
│ ├── app.dart
│ └── cubit
│ │ ├── app_cubit.dart
│ │ ├── app_state.dart
│ │ └── cubit.dart
│ ├── authentication
│ ├── authentication.dart
│ ├── cubit
│ │ ├── authentication_cubit.dart
│ │ └── authentication_state.dart
│ ├── google_auth.dart
│ └── sign_in_page.dart
│ ├── autostart
│ └── autostart_service.dart
│ ├── background_tasks
│ ├── background_tasks.dart
│ └── background_tasks_service.dart
│ ├── core
│ ├── constants.dart
│ ├── core.dart
│ ├── helpers
│ │ ├── date_time.dart
│ │ ├── error_handler.dart
│ │ └── helpers.dart
│ └── widgets
│ │ ├── border.dart
│ │ ├── input_dialog.dart
│ │ ├── measure_size.dart
│ │ └── widgets.dart
│ ├── home_widget
│ ├── home_widget.dart
│ ├── home_widget_manager.dart
│ └── widgets
│ │ ├── home_screen_widget.dart
│ │ ├── home_widget_config_page.dart
│ │ └── widgets.dart
│ ├── logs
│ ├── logging_manager.dart
│ └── src
│ │ ├── log_file_service.dart
│ │ └── src.dart
│ ├── notifications
│ ├── cubit
│ │ ├── notifications_cubit.dart
│ │ └── notifications_state.dart
│ ├── models
│ │ ├── models.dart
│ │ └── notification.dart
│ └── notifications.dart
│ ├── settings
│ ├── cubit
│ │ ├── cubit.dart
│ │ ├── settings_cubit.dart
│ │ └── settings_state.dart
│ ├── models
│ │ ├── desktop_widget_settings.dart
│ │ └── models.dart
│ ├── settings.dart
│ └── widgets
│ │ ├── export_data_page.dart
│ │ ├── settings_page.dart
│ │ └── widgets.dart
│ ├── shortcuts
│ ├── app_shortcuts.dart
│ └── shortcuts_manager.dart
│ ├── storage
│ ├── helpers.dart
│ ├── storage.dart
│ └── storage_repository.dart
│ ├── system_tray
│ └── system_tray_manager.dart
│ ├── tasks
│ ├── commands
│ │ ├── command.dart
│ │ ├── commands.dart
│ │ ├── delete_completed_tasks_command.dart
│ │ ├── delete_task_command.dart
│ │ └── set_task_completed_command.dart
│ ├── cubit
│ │ ├── tasks_cubit.dart
│ │ └── tasks_state.dart
│ ├── enums
│ │ ├── enums.dart
│ │ └── recurrence_end_type.dart
│ ├── helpers
│ │ ├── date_time.dart
│ │ ├── frequency.dart
│ │ ├── helpers.dart
│ │ ├── recurrence_rule.dart
│ │ └── weekdays.dart
│ ├── models
│ │ ├── models.dart
│ │ ├── task.dart
│ │ └── task_list.dart
│ ├── repository
│ │ ├── repository.dart
│ │ ├── src
│ │ │ ├── google_calendar.dart
│ │ │ └── src.dart
│ │ └── tasks_repository.dart
│ ├── services
│ │ ├── recurrence_rule_service.dart
│ │ └── services.dart
│ ├── tasks.dart
│ ├── validators
│ │ ├── task_list_validator.dart
│ │ └── validators.dart
│ └── widgets
│ │ ├── navigation_area.dart
│ │ ├── task_details
│ │ ├── recurrence_widget.dart
│ │ ├── sub_tasks_list_widget.dart
│ │ ├── task_details.dart
│ │ └── task_details_widget.dart
│ │ ├── task_tile.dart
│ │ ├── tasks_page.dart
│ │ ├── tasks_view.dart
│ │ └── widgets.dart
│ ├── theme
│ ├── app_theme.dart
│ └── theme.dart
│ ├── updates
│ ├── models
│ │ ├── models.dart
│ │ └── version_info.dart
│ ├── update_service.dart
│ └── updates.dart
│ └── window
│ ├── app_window.dart
│ ├── cubit
│ ├── cubit.dart
│ ├── window_cubit.dart
│ └── window_state.dart
│ └── window.dart
├── linux
├── .gitignore
├── CMakeLists.txt
├── flutter
│ └── CMakeLists.txt
├── main.cc
├── my_application.cc
└── my_application.h
├── packaging
├── linux
│ ├── codes.merritt.adventurelist.desktop
│ └── codes.merritt.adventurelist.metainfo.xml
└── windows
│ └── inno_setup.iss
├── pubspec.lock
├── pubspec.yaml
├── test
└── src
│ ├── background_tasks
│ └── background_tasks_service_test.dart
│ └── tasks
│ ├── cubit
│ └── tasks_cubit_test.dart
│ ├── helpers
│ └── recurrence_rule_test.dart
│ ├── models
│ ├── task_list_test.dart
│ └── task_test.dart
│ ├── repository
│ └── src
│ │ └── google_calendar_test.dart
│ ├── validators
│ └── task_list_validator_test.dart
│ └── widgets
│ └── task_details
│ ├── recurrence_widget_test.dart
│ └── task_details_widget_test.dart
├── translations
├── de.json
├── en.json
├── it.json
└── pt-BR.json
├── web
├── favicon.png
├── icons
│ ├── Icon-192.png
│ ├── Icon-512.png
│ ├── Icon-maskable-192.png
│ └── Icon-maskable-512.png
├── index.html
└── manifest.json
├── website
├── .gitignore
├── README.md
├── analysis_options.yaml
├── l10n.yaml
├── lib
│ ├── main.dart
│ └── src
│ │ ├── app.dart
│ │ ├── localization
│ │ └── app_en.arb
│ │ ├── pages
│ │ ├── home_page.dart
│ │ └── privacy_policy.dart
│ │ ├── sample_feature
│ │ ├── sample_item.dart
│ │ ├── sample_item_details_view.dart
│ │ └── sample_item_list_view.dart
│ │ ├── settings
│ │ ├── settings_controller.dart
│ │ ├── settings_service.dart
│ │ └── settings_view.dart
│ │ └── widgets
│ │ └── custom_app_bar.dart
├── linux
│ ├── .gitignore
│ ├── CMakeLists.txt
│ ├── flutter
│ │ └── CMakeLists.txt
│ ├── main.cc
│ ├── my_application.cc
│ └── my_application.h
├── pubspec.lock
├── pubspec.yaml
├── static
│ ├── index.html
│ └── privacy_policy.html
└── web
│ ├── favicon.png
│ ├── icons
│ ├── Icon-192.png
│ ├── Icon-512.png
│ ├── Icon-maskable-192.png
│ └── Icon-maskable-512.png
│ ├── 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
├── resources
└── app_icon.ico
├── runner.exe.manifest
├── utils.cpp
├── utils.h
├── win32_window.cpp
└── win32_window.h
/.devcontainer/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM mcr.microsoft.com/devcontainers/base:ubuntu-20.04
2 |
3 | ENV DEBIAN_FRONTEND=noninteractive
4 |
5 |
6 | # ------------------------ Prepare docker environment ------------------------ #
7 |
8 | RUN apt-get update && \
9 | # Install general utilities
10 | apt-get -y install tree && \
11 | # Install Flutter dependencies
12 | apt-get -y install curl file git unzip xz-utils zip clang cmake ninja-build pkg-config libgtk-3-dev liblzma-dev && \
13 | # Install app-specific dependencies
14 | apt-get -y install keybinder-3.0 appindicator3-0.1 libappindicator3-1 libappindicator3-dev libnotify-dev
15 |
16 |
17 | # ------------------------------ Install Flutter ----------------------------- #
18 |
19 | RUN git clone https://github.com/flutter/flutter.git -b stable /home/vscode/flutter
20 | RUN git config --global --add safe.directory /home/vscode/flutter
21 | ENV PATH="$PATH:/home/vscode/flutter/bin"
22 | RUN flutter upgrade
23 | RUN chown -R vscode:vscode /home/vscode/flutter
24 |
25 |
26 | # ------------------------------ Install Flatpak ----------------------------- #
27 |
28 | RUN apt-get install -y flatpak flatpak-builder
29 | RUN flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo
30 | RUN flatpak install -y org.freedesktop.Sdk/x86_64/21.08
31 | RUN flatpak install -y org.freedesktop.Platform/x86_64/21.08
32 | RUN flatpak install -y flathub org.freedesktop.appstream-glib
33 |
--------------------------------------------------------------------------------
/.devcontainer/build-in-container.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 |
4 | # When run from the vscode dev container this will build and package the app.
5 |
6 |
7 | set -x
8 |
9 |
10 | projectName=AdventureList
11 | archiveName=$projectName-Linux-Portable.tar.gz
12 |
13 | # ----------------------------- Build Flutter app ---------------------------- #
14 |
15 | flutter pub get
16 | flutter build linux
17 |
18 | workspace=$PWD
19 | cd build/linux/x64/release/bundle || exit
20 | touch PORTABLE
21 | tar -czaf $archiveName ./*
22 | cp -r $archiveName "$workspace"/
23 | cd "$workspace" || exit
24 |
--------------------------------------------------------------------------------
/.devcontainer/devcontainer.json:
--------------------------------------------------------------------------------
1 | // For format details, see https://aka.ms/devcontainer.json. For config options, see the
2 | // README at: https://github.com/devcontainers/templates/tree/main/src/ubuntu
3 | {
4 | "name": "Ubuntu",
5 |
6 | // "image": "mcr.microsoft.com/devcontainers/base:focal",
7 | // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
8 | "build": {
9 | "dockerfile": "Dockerfile"
10 | },
11 |
12 | // Features to add to the dev container. More info: https://containers.dev/features.
13 | "features": {
14 | "ghcr.io/rocker-org/devcontainer-features/apt-packages:1": {}
15 | },
16 |
17 | // Use 'forwardPorts' to make a list of ports inside the container available locally.
18 | // "forwardPorts": [],
19 |
20 | // Use 'postCreateCommand' to run commands after the container is created.
21 | // "postCreateCommand": "",
22 |
23 | // Configure tool-specific properties.
24 | // "customizations": {},
25 |
26 | // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
27 | // "remoteUser": "root"
28 |
29 | "mounts": [
30 | "source=/home/merritt/Development,target=/development,type=bind,consistency=cached"
31 | ],
32 |
33 | "privileged": true,
34 |
35 | "remoteEnv": {
36 | // Add Flutter to the PATH variable.
37 | "PATH": "${containerEnv:PATH}:/home/vscode/flutter/bin"
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | github: Merrit
2 | ko_fi: merrit
3 | custom: ["https://paypal.me/KristenMcWilliam", "https://www.buymeacoffee.com/Merritt"]
4 |
--------------------------------------------------------------------------------
/.github/release.yml:
--------------------------------------------------------------------------------
1 | changelog:
2 | exclude:
3 | labels:
4 | - ignore-for-release
5 | categories:
6 | - title: Breaking Changes 🛠
7 | labels:
8 | - Semver-Major
9 | - breaking-change
10 | - title: New Features 🎉
11 | labels:
12 | - Semver-Minor
13 | - enhancement
14 | - title: Fixes ✨
15 | labels:
16 | - bugfix
17 | - title: Code Cleanup 🪥
18 | labels:
19 | - cleanup
20 | - title: Other Changes
21 | labels:
22 | - "*"
23 |
--------------------------------------------------------------------------------
/.github/workflows/build-android.yml:
--------------------------------------------------------------------------------
1 | name: Build Android
2 | on:
3 | # Enable manual run
4 | workflow_dispatch:
5 | # Allow being called by other workflows
6 | workflow_call:
7 | inputs:
8 | pre-release:
9 | description: "Whether the build is for a pre-release"
10 | required: false
11 | default: false
12 | type: boolean
13 |
14 | env:
15 | app-display-name: "Adventure List"
16 | author: "Merritt Codes"
17 | identifier: "codes.merritt.adventurelist"
18 |
19 | jobs:
20 | build-android:
21 | name: Build Android
22 | runs-on: ubuntu-latest
23 |
24 | # ----------------------------------- Setup ------------------------------ #
25 |
26 | steps:
27 | - name: Setup Flutter
28 | uses: subosito/flutter-action@v2
29 |
30 | - name: Install Android dependencies
31 | uses: actions/setup-java@v4
32 | with:
33 | distribution: 'zulu'
34 | java-version: '17'
35 |
36 | - name: Checkout code
37 | uses: actions/checkout@v4
38 |
39 | - name: Configure Keystore for Android
40 | run: |
41 | echo "$PLAY_STORE_UPLOAD_KEY" | base64 --decode > app/upload-keystore.jks
42 | echo "storeFile=upload-keystore.jks" >> key.properties
43 | echo "keyAlias=$KEYSTORE_KEY_ALIAS" >> key.properties
44 | echo "storePassword=$KEYSTORE_STORE_PASSWORD" >> key.properties
45 | echo "keyPassword=$KEYSTORE_KEY_PASSWORD" >> key.properties
46 | env:
47 | PLAY_STORE_UPLOAD_KEY: ${{ secrets.PLAY_STORE_UPLOAD_KEY }}
48 | KEYSTORE_KEY_ALIAS: ${{ secrets.KEYSTORE_KEY_ALIAS }}
49 | KEYSTORE_KEY_PASSWORD: ${{ secrets.KEYSTORE_KEY_PASSWORD }}
50 | KEYSTORE_STORE_PASSWORD: ${{ secrets.KEYSTORE_STORE_PASSWORD }}
51 | working-directory: android
52 |
53 | - name: Prepare for build
54 | run: |
55 | flutter pub get
56 |
57 | # ----------------------------------- Build ---------------------------- #
58 |
59 | - name: Generate localizations
60 | run: dart run easy_localization:generate --source-dir translations --output-dir lib/generated --output-file locale_keys.g.dart --format keys --skip-unnecessary-keys
61 |
62 | - name: Run build script
63 | env:
64 | GITHUB_TOKEN: ${{ secrets.RELEASES_TOKEN }}
65 | run: flutter pub run flutter_app_builder -v --platforms=android
66 |
67 | # ---------------------------------- Upload ---------------------------- #
68 |
69 | - name: Upload artifacts to workflow
70 | uses: actions/upload-artifact@v4
71 | with:
72 | name: android-artifacts
73 | path: output/*
74 |
--------------------------------------------------------------------------------
/.github/workflows/build-linux.yml:
--------------------------------------------------------------------------------
1 | name: Build Linux
2 | on:
3 | # Enable manual run
4 | workflow_dispatch:
5 | # Allow being called by other workflows
6 | workflow_call:
7 | inputs:
8 | pre-release:
9 | description: "Whether the build is for a pre-release"
10 | required: false
11 | default: false
12 | type: boolean
13 |
14 | env:
15 | app-display-name: "Adventure List"
16 | author: "Merritt Codes"
17 | identifier: "codes.merritt.adventurelist"
18 |
19 | jobs:
20 | build-linux:
21 | name: Build Linux
22 | runs-on: ubuntu-20.04
23 |
24 | # ----------------------------------- Setup ------------------------------ #
25 |
26 | steps:
27 | - name: Setup Linux build requirements
28 | run: |
29 | sudo apt-get update
30 | # libappindicator required for tray_manager
31 | sudo apt-get install appindicator3-0.1 libappindicator3-dev
32 | # libnotify-dev required for notifications, only until the
33 | # following issue is resolved:
34 | # https://github.com/MaikuB/flutter_local_notifications/issues/746
35 | sudo apt-get install libnotify-dev
36 | # keybinder required for global hotkeys
37 | sudo apt-get install keybinder-3.0
38 |
39 | - name: Set pre-release environment variable
40 | if: inputs.pre-release == true
41 | run: echo "prerelease=true" >> $GITHUB_ENV
42 |
43 | - name: Setup Flutter
44 | uses: subosito/flutter-action@v2
45 |
46 | - name: Checkout code
47 | uses: actions/checkout@v4
48 |
49 | - name: Prepare for build
50 | run: |
51 | flutter config --enable-linux-desktop
52 | flutter pub get
53 |
54 | # ----------------------------------- Build ---------------------------- #
55 |
56 | - name: Generate localizations
57 | run: dart run easy_localization:generate --source-dir translations --output-dir lib/generated --output-file locale_keys.g.dart --format keys --skip-unnecessary-keys
58 |
59 | - name: Run build script
60 | env:
61 | GITHUB_TOKEN: ${{ secrets.RELEASES_TOKEN }}
62 | run: flutter pub run flutter_app_builder -v --platforms=linux
63 |
64 | # ---------------------------------- Upload ---------------------------- #
65 |
66 | - name: Upload artifacts to workflow
67 | uses: actions/upload-artifact@v4
68 | with:
69 | name: linux-artifacts
70 | path: output/*
71 |
--------------------------------------------------------------------------------
/.github/workflows/build-website.yml:
--------------------------------------------------------------------------------
1 | on:
2 | push:
3 | branches:
4 | - disabledworkflow
5 |
6 | jobs:
7 | nonejob:
8 | runs-on: ubuntu-20.04
9 | steps:
10 | - run: donothingdisabled
11 | # Currently resides in and manages by the `website` branch.
12 |
13 | # # Automatically build and deploy website to GitHub Pages.
14 |
15 | # name: Build Website
16 |
17 | # on:
18 | # push:
19 | # branches:
20 | # - main
21 | # pull_request:
22 |
23 | # jobs:
24 | # deploy:
25 | # runs-on: ubuntu-20.04
26 | # permissions:
27 | # contents: write
28 | # concurrency:
29 | # group: ${{ github.workflow }}-${{ github.ref }}
30 | # steps:
31 | # - uses: actions/checkout@v4
32 |
33 | # # Using static site for now as it seems required to verify with Google
34 | # # Cloud Console. ¯\_(ツ)_/¯
35 | # - name: Deploy
36 | # uses: peaceiris/actions-gh-pages@v3
37 | # if: ${{ github.ref == 'refs/heads/main' }}
38 | # with:
39 | # github_token: ${{ secrets.GITHUB_TOKEN }}
40 | # publish_dir: ${{ github.workspace }}/website/static
41 | # cname: adventurelist.merritt.codes
42 |
43 | # # - name: Setup Flutter
44 | # # run: |
45 | # # git clone https://github.com/flutter/flutter.git --depth 1 -b stable _flutter
46 | # # echo "${GITHUB_WORKSPACE}/_flutter/bin" >> ${GITHUB_PATH}
47 |
48 | # # - name: Install
49 | # # run: |
50 | # # flutter config --enable-web
51 | # # flutter pub get
52 |
53 | # # - name: Build
54 | # # run: flutter build web
55 | # # working-directory: ${{ github.workspace }}/website
56 |
57 | # # - name: Deploy
58 | # # uses: peaceiris/actions-gh-pages@v3
59 | # # if: ${{ github.ref == 'refs/heads/main' }}
60 | # # with:
61 | # # github_token: ${{ secrets.GITHUB_TOKEN }}
62 | # # publish_dir: ${{ github.workspace }}/website/build/web
63 | # # cname: adventurelist.merritt.codes
64 |
--------------------------------------------------------------------------------
/.github/workflows/build-windows.yml:
--------------------------------------------------------------------------------
1 | name: Build Windows
2 | on:
3 | # Enable manual run
4 | workflow_dispatch:
5 | # Allow being called by other workflows
6 | workflow_call:
7 | inputs:
8 | pre-release:
9 | description: "Whether the build is for a pre-release"
10 | required: false
11 | default: false
12 | type: boolean
13 |
14 | env:
15 | app-display-name: "Adventure List"
16 | author: "Merritt Codes"
17 | identifier: "codes.merritt.adventurelist"
18 | msix-icon-path: "assets\\icons\\codes.merritt.adventurelist.png"
19 |
20 | jobs:
21 | build-windows:
22 | name: Build Windows
23 | runs-on: windows-latest
24 |
25 | # ----------------------------------- Setup ------------------------------ #
26 |
27 | steps:
28 | - name: Set pre-release environment variable
29 | if: inputs.pre-release == true
30 | run: echo "prerelease=true" >> $GITHUB_ENV
31 |
32 | - name: Setup Flutter
33 | uses: subosito/flutter-action@v2
34 |
35 | - name: Checkout code
36 | uses: actions/checkout@v4
37 |
38 | - name: Prepare for build
39 | run: |
40 | # Fix error for git packages with long names
41 | git config --system core.longpaths true
42 | # Setup Flutter
43 | flutter config --enable-windows-desktop
44 | flutter pub get
45 |
46 | # ----------------------------------- Build ---------------------------- #
47 |
48 | - name: Generate localizations
49 | run: dart run easy_localization:generate --source-dir translations --output-dir lib/generated --output-file locale_keys.g.dart --format keys --skip-unnecessary-keys
50 |
51 | - name: Run build script
52 | env:
53 | GITHUB_TOKEN: ${{ secrets.RELEASES_TOKEN }}
54 | run: flutter pub run flutter_app_builder -v --platforms=windows
55 |
56 | # ---------------------------------- Upload ---------------------------- #
57 |
58 | - name: Upload Windows Store MSIX artifact to workflow
59 | uses: actions/upload-artifact@v4
60 | with:
61 | name: windows-store-artifact
62 | path: output/*.msix
63 |
64 | # MSIX is only for publishing to the Windows Store.
65 | - name: Remove Windows Store artifact from release files
66 | run: rm output/*.msix
67 |
68 | - name: Upload artifacts to workflow
69 | uses: actions/upload-artifact@v4
70 | with:
71 | name: windows-artifacts
72 | path: output/*
73 |
--------------------------------------------------------------------------------
/.github/workflows/pre-release.yml:
--------------------------------------------------------------------------------
1 | # Create a new prerelease with every push on main
2 |
3 | name: Pre-Release
4 |
5 | on:
6 | push:
7 | branches:
8 | - "main"
9 | tags-ignore:
10 | - "*"
11 |
12 | concurrency:
13 | group: ci-pre-release-${{ github.ref }}-1
14 | cancel-in-progress: true
15 |
16 | jobs:
17 | call-tests:
18 | uses: ./.github/workflows/tests.yml
19 |
20 | call-build-linux:
21 | needs: call-tests
22 | uses: ./.github/workflows/build-linux.yml
23 | with:
24 | pre-release: true
25 | secrets: inherit
26 | call-build-windows:
27 | needs: call-tests
28 | uses: ./.github/workflows/build-windows.yml
29 | with:
30 | pre-release: true
31 | secrets: inherit
32 | call-build-android:
33 | needs: call-tests
34 | uses: ./.github/workflows/build-android.yml
35 | secrets: inherit
36 |
37 | pre-release:
38 | name: "Pre Release"
39 | needs: [call-build-linux, call-build-windows, call-build-android]
40 | runs-on: "ubuntu-latest"
41 |
42 | steps:
43 | - uses: actions/checkout@v4
44 |
45 | - name: Download artifacts
46 | uses: actions/download-artifact@v4
47 | with:
48 | path: artifacts
49 |
50 | - name: Create Development Release & Upload artifacts
51 | uses: marvinpinto/action-automatic-releases@v1.2.1
52 | with:
53 | repo_token: "${{ secrets.GITHUB_TOKEN }}"
54 | automatic_release_tag: "latest"
55 | prerelease: true
56 | title: "Development Build"
57 | files: |
58 | ${{ github.workspace }}/artifacts/linux-artifacts/*
59 | ${{ github.workspace }}/artifacts/windows-artifacts/*
60 | ${{ github.workspace }}/artifacts/android-artifacts/*
61 |
--------------------------------------------------------------------------------
/.github/workflows/pull_request.yml:
--------------------------------------------------------------------------------
1 | # Verify tests pass and builds succeed for pull requests.
2 |
3 | name: Verify Pull Request
4 |
5 | on:
6 | # Enable manual run
7 | workflow_dispatch:
8 | pull_request:
9 |
10 | concurrency:
11 | group: ci-verify-pr-${{ github.ref }}-1
12 | cancel-in-progress: true
13 |
14 | jobs:
15 | call-tests:
16 | uses: ./.github/workflows/tests.yml
17 |
18 | call-build-linux:
19 | needs: call-tests
20 | uses: ./.github/workflows/build-linux.yml
21 | with:
22 | pre-release: true
23 | secrets: inherit
24 | call-build-windows:
25 | needs: call-tests
26 | uses: ./.github/workflows/build-windows.yml
27 | with:
28 | pre-release: true
29 | secrets: inherit
30 | call-build-android:
31 | needs: call-tests
32 | uses: ./.github/workflows/build-android.yml
33 | with:
34 | pre-release: true
35 | secrets: inherit
36 |
37 | verify-pull-request:
38 | name: Verify Pull Request
39 | needs:
40 | [call-tests, call-build-linux, call-build-windows, call-build-android]
41 | runs-on: ubuntu-latest
42 | steps:
43 | - run: echo "Requirements passed, PR looks good!"
44 |
--------------------------------------------------------------------------------
/.github/workflows/release-android.yml:
--------------------------------------------------------------------------------
1 | name: Publish Android build to Google Play
2 |
3 | on:
4 | # Enable manual run
5 | workflow_dispatch:
6 | # Build & deploy for published releases
7 | release:
8 | types:
9 | - published
10 |
11 | env:
12 | appname-without-spaces: "AdventureList"
13 | packageName: "codes.merritt.adventurelist"
14 | repository: "merrit/adventure_list"
15 | repositoryUrl: https://github.com/Merrit/adventure_list
16 |
17 | jobs:
18 | release:
19 | runs-on: ubuntu-latest
20 |
21 | steps:
22 | - name: Download .aab artifact
23 | run: wget ${{env.repositoryUrl}}/releases/latest/download/${{env.appname-without-spaces}}-Android.aab
24 |
25 | # Works with the r0adkll/upload-google-play action.
26 | - name: Download changelog
27 | run: |
28 | mkdir whatsNewDirectory
29 | gh release view --json body --jq .body --repo ${{env.repository}} >> whatsNewDirectory/whatsnew-en-US
30 | env:
31 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
32 |
33 | - name: Access Google Play API key
34 | env:
35 | GOOGLE_PLAY_API_JSON: ${{ secrets.GOOGLE_PLAY_API_JSON }}
36 | run: echo "$GOOGLE_PLAY_API_JSON" | base64 --decode > google_play_api.json
37 |
38 | - name: Release Android build on Google Play
39 | uses: r0adkll/upload-google-play@v1
40 | with:
41 | serviceAccountJson: google_play_api.json
42 | packageName: ${{env.packageName}}
43 | releaseFiles: ${{env.appname-without-spaces}}-Android.aab
44 | track: production
45 |
--------------------------------------------------------------------------------
/.github/workflows/release-windows-store.yml:
--------------------------------------------------------------------------------
1 | name: Publish MSIX to Microsoft Store
2 |
3 | on:
4 | # Enable manual run
5 | workflow_dispatch:
6 | # Build & deploy for published releases
7 | release:
8 | types:
9 | - published
10 |
11 | concurrency:
12 | group: ci-release-${{ github.ref }}-1
13 | cancel-in-progress: true
14 |
15 | jobs:
16 | call-build-windows:
17 | uses: ./.github/workflows/build-windows.yml
18 | with:
19 | pre-release: false
20 | secrets: inherit
21 |
22 | docker:
23 | needs: call-build-windows
24 | runs-on: ubuntu-latest
25 | steps:
26 | - name: Download artifacts
27 | uses: actions/download-artifact@v4
28 | with:
29 | path: artifacts
30 |
31 | - name: Publish to Store
32 | uses: isaacrlevin/windows-store-action@main
33 | with:
34 | tenant-id: ${{ secrets.AZURE_AD_TENANT_ID }}
35 | client-id: ${{ secrets.AZURE_AD_APPLICATION_CLIENT_ID }}
36 | client-secret: ${{ secrets.AZURE_AD_APPLICATION_SECRET }}
37 | # "app-id" is the Store ID as listed in Partner Center
38 | # https://github.com/isaacrlevin/windows-store-action/issues/5#issuecomment-1086893615
39 | app-id: ${{ secrets.MICROSOFT_STORE_APP_ID }}
40 | package-path: "${{ github.workspace }}/artifacts/windows-store-artifact/"
41 | delete-pending: true
42 |
--------------------------------------------------------------------------------
/.github/workflows/release.yml:
--------------------------------------------------------------------------------
1 | # Create a new release
2 |
3 | name: Release
4 |
5 | on:
6 | # Build & deploy for tag events matching v*, i.e. v1.0.0, v20.15.10
7 | push:
8 | tags:
9 | - "v*"
10 |
11 | concurrency:
12 | group: ci-release-${{ github.ref }}-1
13 | cancel-in-progress: true
14 |
15 | jobs:
16 | call-tests:
17 | uses: ./.github/workflows/tests.yml
18 |
19 | call-build-linux:
20 | needs: call-tests
21 | uses: ./.github/workflows/build-linux.yml
22 | with:
23 | pre-release: false
24 | secrets: inherit
25 | call-build-windows:
26 | needs: call-tests
27 | uses: ./.github/workflows/build-windows.yml
28 | with:
29 | pre-release: false
30 | secrets: inherit
31 | call-build-android:
32 | needs: call-tests
33 | uses: ./.github/workflows/build-android.yml
34 | with:
35 | pre-release: false
36 | secrets: inherit
37 |
38 | release:
39 | name: "Release"
40 | needs: [call-build-linux, call-build-windows, call-build-android]
41 | runs-on: "ubuntu-latest"
42 |
43 | steps:
44 | - uses: actions/checkout@v4
45 |
46 | - name: Download artifacts
47 | uses: actions/download-artifact@v4
48 | with:
49 | path: artifacts
50 |
51 | - name: Create Draft Release & Upload artifacts
52 | uses: marvinpinto/action-automatic-releases@v1.2.1
53 | with:
54 | repo_token: "${{ secrets.GITHUB_TOKEN }}"
55 | draft: true
56 | prerelease: false
57 | files: |
58 | ${{ github.workspace }}/artifacts/linux-artifacts/*
59 | ${{ github.workspace }}/artifacts/windows-artifacts/*
60 | ${{ github.workspace }}/artifacts/android-artifacts/*
61 |
--------------------------------------------------------------------------------
/.github/workflows/tests.yml:
--------------------------------------------------------------------------------
1 | name: Run tests
2 |
3 | on:
4 | # Allow being called by other workflows
5 | workflow_call:
6 | # Allow being called manually
7 | workflow_dispatch:
8 |
9 | jobs:
10 | flutter_test:
11 | name: Run Tests
12 | runs-on: ubuntu-latest
13 | steps:
14 | - uses: actions/checkout@v4
15 |
16 | - name: Setup Flutter
17 | uses: subosito/flutter-action@v2
18 |
19 | - name: Setup
20 | run: |
21 | flutter pub get
22 |
23 | - name: Verify formatting
24 | run: dart format -o none --set-exit-if-changed --line-length=90 .
25 |
26 | - name: Run translations generation
27 | run: dart run easy_localization:generate --source-dir translations --output-dir lib/generated --output-file locale_keys.g.dart --format keys --skip-unnecessary-keys
28 |
29 | - name: Run code generation
30 | run: dart run build_runner build --delete-conflicting-outputs
31 |
32 | - name: Run tests
33 | run: flutter test
34 |
35 | - name: Print directory structure
36 | # Ensure this step runs even after a failure, but not when cancelled.
37 | if: success() || failure()
38 | run: tree -a
39 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # ---------------------------------------------------------------------------- #
2 | # Custom #
3 | # ---------------------------------------------------------------------------- #
4 |
5 | # Freezed
6 | *.freezed.dart
7 | *.g.dart
8 |
9 | # Generated code
10 | generated*
11 | Generated*
12 | *.mocks.dart
13 |
14 | # Packaging
15 | output/
16 | *.tar.gz
17 |
18 | # Test coverage
19 | lcov.info
20 |
21 |
22 | # ---------------------------------------------------------------------------- #
23 | # Default #
24 | # ---------------------------------------------------------------------------- #
25 |
26 | # Miscellaneous
27 | *.class
28 | *.log
29 | *.pyc
30 | *.swp
31 | .DS_Store
32 | .atom/
33 | .buildlog/
34 | .history
35 | .svn/
36 | migrate_working_dir/
37 |
38 | # IntelliJ related
39 | *.iml
40 | *.ipr
41 | *.iws
42 | .idea/
43 |
44 | # The .vscode folder contains launch configuration and tasks you configure in
45 | # VS Code which you may wish to be included in version control, so this line
46 | # is commented out by default.
47 | #.vscode/
48 |
49 | # Flutter/Dart/Pub related
50 | **/doc/api/
51 | **/ios/Flutter/.last_build_id
52 | .dart_tool/
53 | .flutter-plugins
54 | .flutter-plugins-dependencies
55 | .packages
56 | .pub-cache/
57 | .pub/
58 | /build/
59 |
60 |
61 | # Web related
62 | lib/generated_plugin_registrant.dart
63 |
64 | # Symbolication related
65 | app.*.symbols
66 |
67 | # Obfuscation related
68 | app.*.map.json
69 |
70 | # Android Studio will place build artifacts here
71 | /android/app/debug
72 | /android/app/profile
73 | /android/app/release
74 | .hugo_build.lock
75 |
--------------------------------------------------------------------------------
/.metadata:
--------------------------------------------------------------------------------
1 | # This file tracks properties of this Flutter project.
2 | # Used by Flutter tool to assess capabilities and perform upgrades etc.
3 | #
4 | # This file should be version controlled and should not be manually edited.
5 |
6 | version:
7 | revision: "35c388afb57ef061d06a39b537336c87e0e3d1b1"
8 | channel: "stable"
9 |
10 | project_type: app
11 |
12 | # Tracks metadata for the flutter migrate command
13 | migration:
14 | platforms:
15 | - platform: root
16 | create_revision: 35c388afb57ef061d06a39b537336c87e0e3d1b1
17 | base_revision: 35c388afb57ef061d06a39b537336c87e0e3d1b1
18 | - platform: android
19 | create_revision: 35c388afb57ef061d06a39b537336c87e0e3d1b1
20 | base_revision: 35c388afb57ef061d06a39b537336c87e0e3d1b1
21 |
22 | # User provided section
23 |
24 | # List of Local paths (relative to this file) that should be
25 | # ignored by the migrate tool.
26 | #
27 | # Files that are not part of the templates will be ignored by default.
28 | unmanaged_files:
29 | - 'lib/main.dart'
30 | - 'ios/Runner.xcodeproj/project.pbxproj'
31 |
--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | // Use IntelliSense to learn about possible attributes.
3 | // Hover to view descriptions of existing attributes.
4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5 | "version": "0.2.0",
6 | "configurations": [
7 | // Debug
8 | {
9 | "name": "Debug",
10 | "request": "launch",
11 | "type": "dart",
12 | "program": "lib/main.dart",
13 | "preLaunchTask": "${defaultBuildTask}",
14 | "flutterMode": "debug",
15 | },
16 | // Debug with verbose logging
17 | {
18 | "name": "Debug verbose",
19 | "request": "launch",
20 | "type": "dart",
21 | "flutterMode": "debug",
22 | "program": "lib/main.dart",
23 | "preLaunchTask": "${defaultBuildTask}",
24 | "toolArgs": [
25 | "--dart-define",
26 | "VERBOSE=true"
27 | ]
28 | },
29 | // Debug with verbose logging and verbose Flutter logging
30 | {
31 | "name": "Debug verbose: App + Flutter",
32 | "request": "launch",
33 | "type": "dart",
34 | "flutterMode": "debug",
35 | "program": "lib/main.dart",
36 | "preLaunchTask": "${defaultBuildTask}",
37 | "args": [
38 | "--dart-entrypoint-args",
39 | "--verbose",
40 | ],
41 | },
42 | // Debug with arguments
43 | {
44 | "name": "Debug with arguments",
45 | "request": "launch",
46 | "type": "dart",
47 | "flutterMode": "debug",
48 | "program": "lib/main.dart",
49 | "preLaunchTask": "${defaultBuildTask}",
50 | // "args": [
51 | // "--dart-entrypoint-args",
52 | // "--toggle,--verbose",
53 | // ],
54 | },
55 | // Profile
56 | {
57 | "name": "Profile",
58 | "request": "launch",
59 | "type": "dart",
60 | "program": "lib/main.dart",
61 | "preLaunchTask": "${defaultBuildTask}",
62 | "flutterMode": "profile",
63 | },
64 | // Release
65 | {
66 | "name": "Release",
67 | "request": "launch",
68 | "type": "dart",
69 | "program": "lib/main.dart",
70 | "preLaunchTask": "${defaultBuildTask}",
71 | "flutterMode": "release",
72 | },
73 | // Test current file
74 | {
75 | "name": "Test current file",
76 | "type": "dart",
77 | "request": "launch",
78 | "program": "${file}"
79 | }
80 | ]
81 | }
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "java.configuration.updateBuildConfiguration": "interactive",
3 | "git.detectSubmodules": false,
4 | "git.pullTags": false,
5 | "dart.flutterTestAdditionalArgs": [
6 | "--coverage"
7 | ],
8 | "dart.lineLength": 90,
9 | "[dart]": {
10 | "editor.rulers": [
11 | 90
12 | ],
13 | }
14 | }
--------------------------------------------------------------------------------
/.vscode/tasks.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "2.0.0",
3 | "tasks": [
4 | // Code generation (continuous)
5 | {
6 | "label": "build_runner watch",
7 | "detail": "Code generation (continuous)",
8 | "type": "flutter",
9 | "command": "flutter",
10 | "args": [
11 | "pub",
12 | "run",
13 | "build_runner",
14 | "watch",
15 | "--delete-conflicting-outputs"
16 | ],
17 | "problemMatcher": [
18 | "$dart-build_runner"
19 | ],
20 | "group": {
21 | "kind": "build",
22 | "isDefault": true
23 | },
24 | "presentation": {
25 | "panel": "dedicated",
26 | },
27 | "dependsOn": [
28 | "easy_localization:generate"
29 | ],
30 | },
31 | // Translations generation with easy_localization
32 | {
33 | "label": "easy_localization:generate",
34 | "detail": "Translations generation with easy_localization",
35 | "type": "flutter",
36 | "command": "flutter",
37 | "args": [
38 | "pub",
39 | "run",
40 | "easy_localization:generate",
41 | "--source-dir",
42 | "translations",
43 | "--output-dir",
44 | "lib/generated",
45 | "--output-file",
46 | "locale_keys.g.dart",
47 | "--format",
48 | "keys",
49 | "--skip-unnecessary-keys",
50 | ],
51 | "group": {
52 | "kind": "build",
53 | "isDefault": false
54 | },
55 | "presentation": {
56 | "reveal": "silent"
57 | },
58 | }
59 | ]
60 | }
--------------------------------------------------------------------------------
/BUILDING.md:
--------------------------------------------------------------------------------
1 | # Building from source
2 |
3 | ## Requirements
4 |
5 | 1. Requires a working instance of [Flutter](https://docs.flutter.dev/get-started/install).
6 |
7 | 2. Linux requires `libappindicator` and `keybinder`.
8 |
9 | Fedora:
10 |
11 | ```
12 | sudo dnf install libappindicator-gtk3 libappindicator-gtk3-devel keybinder keybinder3 keybinder3-devel
13 | ```
14 |
15 | Ubuntu:
16 |
17 | ```
18 | sudo apt-get install appindicator3-0.1 libappindicator3-dev keybinder-3.0
19 | ```
20 |
21 |
22 | ## Build
23 |
24 | Run these commands from the root directory of the repo:
25 |
26 | 1. `flutter clean`
27 | 2. `flutter pub get`
28 | 3. `dart run build_runner build --delete-conflicting-outputs`
29 | 4. `flutter pub run easy_localization:generate --source-dir translations --output-dir lib/generated --output-file locale_keys.g.dart --format keys --skip-unnecessary-keys`
30 | 5. Run the build command for the desired platform(s):
31 | - `flutter build linux`
32 | - `flutter build windows`
33 | - `flutter build apk --debug`
34 | - `flutter build appbundle --debug`
35 |
36 |
37 | Compiled app location:
38 |
39 | Linux: `build/linux/x64/release/bundle`
40 |
41 | Windows: `build\windows\runner\Release`
42 |
43 | Android APK: `build/app/outputs/flutter-apk/app-release.apk`
44 |
45 | Android App Bundle: `build/app/outputs/bundle/release/app-release.aab`
46 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | - [About](#about)
2 | - [Screenshots](#screenshots)
3 | - [Download](#download)
4 | - [Roadmap](#roadmap)
5 |
6 |
7 | ## About
8 |
9 | Are you ready for an adventure? Adventure List is a Todo list app that helps you organize your tasks and goals in a fun and easy way. Whether you want to plan a trip, learn a new skill, or just get things done, Adventure List is the app for you.
10 |
11 | Here are some of the features that make Adventure List great:
12 |
13 | - Due dates: Set due dates for your tasks and get reminders when they're due.
14 | - Recurring due dates: Set tasks to recur on a regular basis, so you never forget to do them.
15 | - Notifications: Get notifications when tasks are due, so you can stay on top of your to-do list.
16 | - Android widget: Add a widget to your Android home screen to quickly view your to-do list.
17 | - Desktop widget mode: Pin your to-do list to your computer desktop as a widget, so you can always see what you need to do.
18 | - Cross-platform: Available on Linux, Windows, and Android, so you can access your lists from anywhere.
19 | - Open source: Adventure List is open source, so you can contribute to its development or customize it to your liking.
20 |
21 | Adventure List is ready to help you get things done. Download it today and start your adventure!
22 |
23 |
24 | ## Screenshots
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 | ## Download
35 |
36 | [GitHub Releases](https://github.com/Merrit/adventure_list/releases)
37 |
38 | [Flathub](https://flathub.org/apps/codes.merritt.adventurelist)
39 |
40 | [Microsoft Store](https://apps.microsoft.com/store/detail/adventure-list/9NR8M88MSCC2)
41 |
42 | [Google Play](https://play.google.com/store/apps/details?id=codes.merritt.adventurelist)
43 |
44 |
45 | ## Roadmap
46 |
47 | **Planned**
48 |
49 | - ~~Due dates / reminders~~ ✅
50 | - ~~Recurring tasks~~ ✅
51 | - Offline mode
52 | - Improve offline capabilities so the app can reliably be used offline
53 | - Collaboration on lists with other users
54 | - ~~Desktop widget~~ ✅
55 | - ~~Desktop notifications~~ ✅
56 | - ~~Notification center / popup / tray icon badge / etc~~ ✅
57 |
58 | **Considering**
59 |
60 | - Improve Android widget (could use assistance)
61 | - Web version
62 | - iOS/iPadOS/macOS versions
63 |
--------------------------------------------------------------------------------
/analysis_options.yaml:
--------------------------------------------------------------------------------
1 | # This file configures the analyzer, which statically analyzes Dart code to
2 | # check for errors, warnings, and lints.
3 | #
4 | # The issues identified by the analyzer are surfaced in the UI of Dart-enabled
5 | # IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
6 | # invoked from the command line by running `flutter analyze`.
7 |
8 | # The following line activates a set of recommended lints for Flutter apps,
9 | # packages, and plugins designed to encourage good coding practices.
10 | include: package:flutter_lints/flutter.yaml
11 |
12 | linter:
13 | # The lint rules applied to this project can be customized in the
14 | # section below to disable rules from the `package:flutter_lints/flutter.yaml`
15 | # included above or to enable additional rules. A list of all available lints
16 | # and their documentation is published at
17 | # https://dart-lang.github.io/linter/lints/index.html.
18 | #
19 | # Instead of disabling a lint rule for the entire project in the
20 | # section below, it can also be suppressed for a single line of code
21 | # or a specific dart file by using the `// ignore: name_of_lint` and
22 | # `// ignore_for_file: name_of_lint` syntax on the line or in the file
23 | # producing the lint.
24 | rules:
25 | prefer_final_locals: true
26 | prefer_relative_imports: true
27 | sort_pub_dependencies: true
28 | # Additional information about this file can be found at
29 | # https://dart.dev/guides/language/analysis-options
30 |
31 | analyzer:
32 | errors:
33 | # Ignore lints for @JsonKey on Freezed classes
34 | invalid_annotation_target: ignore
35 | # Exclude generated files from analysis
36 | exclude:
37 | - "**/*.g.dart"
38 | - "**/*.freezed.dart"
39 |
--------------------------------------------------------------------------------
/android/.gitignore:
--------------------------------------------------------------------------------
1 | gradle-wrapper.jar
2 | /.gradle
3 | /captures/
4 | /gradlew
5 | /gradlew.bat
6 | /local.properties
7 | GeneratedPluginRegistrant.java
8 | .cxx/
9 |
10 | # Remember to never publicly share your keystore.
11 | # See https://flutter.dev/to/reference-keystore
12 | key.properties
13 | **/*.keystore
14 | **/*.jks
15 |
--------------------------------------------------------------------------------
/android/app/build.gradle.kts:
--------------------------------------------------------------------------------
1 | import java.util.Properties
2 | import java.io.FileInputStream
3 |
4 | plugins {
5 | id("com.android.application")
6 | id("kotlin-android")
7 | // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins.
8 | id("dev.flutter.flutter-gradle-plugin")
9 | }
10 |
11 | fun isRunningOnCI(): Boolean {
12 | return System.getenv("CI") != null ||
13 | System.getenv("GITHUB_ACTIONS") != null ||
14 | System.getenv("GITLAB_CI") != null
15 | }
16 |
17 | val keystoreProperties = Properties()
18 | val keystorePropertiesFile = rootProject.file("key.properties")
19 | if (keystorePropertiesFile.exists()) {
20 | keystoreProperties.load(FileInputStream(keystorePropertiesFile))
21 | } else if (isRunningOnCI()) {
22 | // If running on CI, the keystore properties must be set as environment variables.
23 | keystoreProperties["keyAlias"] = System.getenv("ALIAS")
24 | keystoreProperties["storePassword"] = System.getenv("KEY_STORE_PASSWORD")
25 | keystoreProperties["storeFile"] = System.getenv("KEY_PATH")
26 | keystoreProperties["keyPassword"] = System.getenv("KEY_PASSWORD")
27 | }
28 |
29 | android {
30 | namespace = "codes.merritt.adventurelist"
31 | compileSdk = flutter.compileSdkVersion
32 | // ndkVersion = flutter.ndkVersion
33 | // ndkVersion = "27.0.12077973"
34 | ndkVersion = "25.1.8937393"
35 |
36 | compileOptions {
37 | sourceCompatibility = JavaVersion.VERSION_17
38 | targetCompatibility = JavaVersion.VERSION_17
39 |
40 | isCoreLibraryDesugaringEnabled = true
41 | }
42 |
43 | kotlinOptions {
44 | jvmTarget = JavaVersion.VERSION_17.toString()
45 | }
46 |
47 | defaultConfig {
48 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
49 | applicationId = "codes.merritt.adventurelist"
50 | // You can update the following values to match your application needs.
51 | // For more information, see: https://flutter.dev/to/review-gradle-config.
52 | // minSdk = flutter.minSdkVersion
53 | minSdk = 23
54 | targetSdk = flutter.targetSdkVersion
55 | versionCode = flutter.versionCode
56 | versionName = flutter.versionName
57 | }
58 |
59 | signingConfigs {
60 | create("release") {
61 | if (keystorePropertiesFile.exists() || isRunningOnCI()) {
62 | storeFile = file(keystoreProperties["storeFile"])
63 | storePassword = keystoreProperties["storePassword"] as String
64 | keyAlias = keystoreProperties["keyAlias"] as String
65 | keyPassword = keystoreProperties["keyPassword"] as String
66 | } else {
67 | throw GradleException("key.properties not found")
68 | }
69 | }
70 | }
71 |
72 | buildTypes {
73 | release {
74 | // TODO: Add your own signing config for the release build.
75 | // Signing with the debug keys for now, so `flutter run --release` works.
76 | // signingConfig = signingConfigs.getByName("debug")
77 | signingConfig = signingConfigs.getByName("release")
78 | }
79 |
80 | debug {
81 | signingConfig = signingConfigs.getByName("debug")
82 | }
83 | }
84 | }
85 |
86 | dependencies {
87 | coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:1.2.2")
88 | }
89 |
90 | flutter {
91 | source = "../.."
92 | }
93 |
--------------------------------------------------------------------------------
/android/app/google-services.json:
--------------------------------------------------------------------------------
1 | {
2 | "project_info": {
3 | "project_number": "478765689275",
4 | "project_id": "adventure-list-354516",
5 | "storage_bucket": "adventure-list-354516.appspot.com"
6 | },
7 | "client": [
8 | {
9 | "client_info": {
10 | "mobilesdk_app_id": "1:478765689275:android:751873c2d07e57e0da3c9e",
11 | "android_client_info": {
12 | "package_name": "codes.merritt.adventurelist"
13 | }
14 | },
15 | "oauth_client": [
16 | {
17 | "client_id": "478765689275-2qneu0pfdhm2m4ej0lqdv69rm96shsg4.apps.googleusercontent.com",
18 | "client_type": 1,
19 | "android_info": {
20 | "package_name": "codes.merritt.adventurelist",
21 | "certificate_hash": "8124b413662fe1254ce85357f68cae94eea91de2"
22 | }
23 | },
24 | {
25 | "client_id": "478765689275-54bv4bf8lsbnjial5o39db2gaukjd9s9.apps.googleusercontent.com",
26 | "client_type": 1,
27 | "android_info": {
28 | "package_name": "codes.merritt.adventurelist",
29 | "certificate_hash": "a7ba2285590bdbb07f3b33dffd53ad2283266292"
30 | }
31 | },
32 | {
33 | "client_id": "478765689275-f5us0hu5mlu5s122dsrbc1kn1qb92sb1.apps.googleusercontent.com",
34 | "client_type": 1,
35 | "android_info": {
36 | "package_name": "codes.merritt.adventurelist",
37 | "certificate_hash": "e257f8738edcbbf1bc7ed4478ec1f83845380757"
38 | }
39 | }
40 | ],
41 | "api_key": [
42 | {
43 | "current_key": "AIzaSyDFYBvnQaRl6szsW6_unb2Xhi0H_IJOy8M"
44 | }
45 | ],
46 | "services": {
47 | "appinvite_service": {
48 | "other_platform_oauth_client": []
49 | }
50 | }
51 | }
52 | ],
53 | "configuration_version": "1"
54 | }
--------------------------------------------------------------------------------
/android/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # This file was added specifically for the flutter_local_notifications plugin.
2 |
3 |
4 | ## Gson rules
5 | # Gson uses generic type information stored in a class file when working with fields. Proguard
6 | # removes such information by default, so configure it to keep all of it.
7 | -keepattributes Signature
8 |
9 | # For using GSON @Expose annotation
10 | -keepattributes *Annotation*
11 |
12 | # Gson specific classes
13 | -dontwarn sun.misc.**
14 | #-keep class com.google.gson.stream.** { *; }
15 |
16 | # Prevent proguard from stripping interface information from TypeAdapter, TypeAdapterFactory,
17 | # JsonSerializer, JsonDeserializer instances (so they can be used in @JsonAdapter)
18 | -keep class * extends com.google.gson.TypeAdapter
19 | -keep class * implements com.google.gson.TypeAdapterFactory
20 | -keep class * implements com.google.gson.JsonSerializer
21 | -keep class * implements com.google.gson.JsonDeserializer
22 |
23 | # Prevent R8 from leaving Data object members always null
24 | -keepclassmembers,allowobfuscation class * {
25 | @com.google.gson.annotations.SerializedName ;
26 | }
27 |
28 | # Retain generic signatures of TypeToken and its subclasses with R8 version 3.0 and higher.
29 | -keep,allowobfuscation,allowshrinking class com.google.gson.reflect.TypeToken
30 | -keep,allowobfuscation,allowshrinking class * extends com.google.gson.reflect.TypeToken
31 |
32 | # file_picker plugin
33 | # https://github.com/miguelpruivo/flutter_file_picker/wiki/Setup
34 | -keep class androidx.lifecycle.DefaultLifecycleObserver
35 |
--------------------------------------------------------------------------------
/android/app/src/debug/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/android/app/src/main/kotlin/com/example/adventure_list/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package codes.merritt.adventurelist
2 |
3 | import io.flutter.embedding.android.FlutterActivity
4 |
5 | class MainActivity : FlutterActivity()
6 |
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-v21/app_widget_background.xml:
--------------------------------------------------------------------------------
1 |
5 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-v21/app_widget_inner_view_background.xml:
--------------------------------------------------------------------------------
1 |
5 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-v21/launch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable/app_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Merrit/adventure_list/c3da3d0963f6d209c5b2f79a335f2b4bd380c4e7/android/app/src/main/res/drawable/app_icon.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable/launch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable/widget_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/android/app/src/main/res/layout/example_layout.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
13 |
14 |
19 |
20 |
31 |
32 |
39 |
40 |
41 |
42 |
49 |
50 |
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Merrit/adventure_list/c3da3d0963f6d209c5b2f79a335f2b4bd380c4e7/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Merrit/adventure_list/c3da3d0963f6d209c5b2f79a335f2b4bd380c4e7/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Merrit/adventure_list/c3da3d0963f6d209c5b2f79a335f2b4bd380c4e7/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Merrit/adventure_list/c3da3d0963f6d209c5b2f79a335f2b4bd380c4e7/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Merrit/adventure_list/c3da3d0963f6d209c5b2f79a335f2b4bd380c4e7/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/raw/keep.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/android/app/src/main/res/values-night-v31/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
10 |
--------------------------------------------------------------------------------
/android/app/src/main/res/values-night/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
15 |
18 |
19 |
--------------------------------------------------------------------------------
/android/app/src/main/res/values-v21/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
14 |
--------------------------------------------------------------------------------
/android/app/src/main/res/values-v31/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
10 |
16 |
--------------------------------------------------------------------------------
/android/app/src/main/res/values-v31/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
11 |
--------------------------------------------------------------------------------
/android/app/src/main/res/values/attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/android/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 | #FFE1F5FE
3 | #FF81D4FA
4 | #FF039BE5
5 | #FF01579B
6 |
--------------------------------------------------------------------------------
/android/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
8 | 0dp
9 |
10 |
--------------------------------------------------------------------------------
/android/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | EXAMPLE
4 | Configure
5 | Add widget
6 | This is an app widget description
7 | Open App
8 | Select List
9 | Configure Widget
10 | Select List
11 | Task Name here
12 |
13 |
--------------------------------------------------------------------------------
/android/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
15 |
18 |
19 |
23 |
24 |
28 |
29 |
--------------------------------------------------------------------------------
/android/app/src/main/res/values/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
12 |
13 |
17 |
--------------------------------------------------------------------------------
/android/app/src/main/res/xml/home_widget_example.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
--------------------------------------------------------------------------------
/android/app/src/profile/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/android/build.gradle.kts:
--------------------------------------------------------------------------------
1 | allprojects {
2 | repositories {
3 | google()
4 | mavenCentral()
5 | }
6 | }
7 |
8 | val newBuildDir: Directory = rootProject.layout.buildDirectory.dir("../../build").get()
9 | rootProject.layout.buildDirectory.value(newBuildDir)
10 |
11 | subprojects {
12 | val newSubprojectBuildDir: Directory = newBuildDir.dir(project.name)
13 | project.layout.buildDirectory.value(newSubprojectBuildDir)
14 | }
15 | subprojects {
16 | project.evaluationDependsOn(":app")
17 | }
18 |
19 | tasks.register("clean") {
20 | delete(rootProject.layout.buildDirectory)
21 | }
22 |
--------------------------------------------------------------------------------
/android/gradle.properties:
--------------------------------------------------------------------------------
1 | org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError
2 | android.useAndroidX=true
3 | android.enableJetifier=true
4 |
--------------------------------------------------------------------------------
/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | zipStoreBase=GRADLE_USER_HOME
4 | zipStorePath=wrapper/dists
5 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-all.zip
6 |
--------------------------------------------------------------------------------
/android/settings.gradle.kts:
--------------------------------------------------------------------------------
1 | pluginManagement {
2 | val flutterSdkPath = run {
3 | val properties = java.util.Properties()
4 | file("local.properties").inputStream().use { properties.load(it) }
5 | val flutterSdkPath = properties.getProperty("flutter.sdk")
6 | require(flutterSdkPath != null) { "flutter.sdk not set in local.properties" }
7 | flutterSdkPath
8 | }
9 |
10 | includeBuild("$flutterSdkPath/packages/flutter_tools/gradle")
11 |
12 | repositories {
13 | google()
14 | mavenCentral()
15 | gradlePluginPortal()
16 | }
17 | }
18 |
19 | plugins {
20 | id("dev.flutter.flutter-plugin-loader") version "1.0.0"
21 | // id("com.android.application") version "8.7.0" apply false
22 | // id("org.jetbrains.kotlin.android") version "1.8.22" apply false
23 | id("com.android.application") version "8.3.2" apply false
24 | id("org.jetbrains.kotlin.android") version "2.0.20" apply false
25 | }
26 |
27 | include(":app")
28 |
--------------------------------------------------------------------------------
/assets/fonts/NotoSans-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Merrit/adventure_list/c3da3d0963f6d209c5b2f79a335f2b4bd380c4e7/assets/fonts/NotoSans-Regular.ttf
--------------------------------------------------------------------------------
/assets/icons/codes.merritt.adventurelist-symbolic-with-notification-badge.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Merrit/adventure_list/c3da3d0963f6d209c5b2f79a335f2b4bd380c4e7/assets/icons/codes.merritt.adventurelist-symbolic-with-notification-badge.ico
--------------------------------------------------------------------------------
/assets/icons/codes.merritt.adventurelist-symbolic-with-notification-badge.svg:
--------------------------------------------------------------------------------
1 |
2 |
55 |
--------------------------------------------------------------------------------
/assets/icons/codes.merritt.adventurelist-symbolic.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Merrit/adventure_list/c3da3d0963f6d209c5b2f79a335f2b4bd380c4e7/assets/icons/codes.merritt.adventurelist-symbolic.ico
--------------------------------------------------------------------------------
/assets/icons/codes.merritt.adventurelist-symbolic.svg:
--------------------------------------------------------------------------------
1 |
2 |
9 |
--------------------------------------------------------------------------------
/assets/icons/codes.merritt.adventurelist-with-notification-badge.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Merrit/adventure_list/c3da3d0963f6d209c5b2f79a335f2b4bd380c4e7/assets/icons/codes.merritt.adventurelist-with-notification-badge.ico
--------------------------------------------------------------------------------
/assets/icons/codes.merritt.adventurelist.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Merrit/adventure_list/c3da3d0963f6d209c5b2f79a335f2b4bd380c4e7/assets/icons/codes.merritt.adventurelist.ico
--------------------------------------------------------------------------------
/assets/icons/codes.merritt.adventurelist.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Merrit/adventure_list/c3da3d0963f6d209c5b2f79a335f2b4bd380c4e7/assets/icons/codes.merritt.adventurelist.png
--------------------------------------------------------------------------------
/build.yaml:
--------------------------------------------------------------------------------
1 | targets:
2 | $default:
3 | builders:
4 | json_serializable:
5 | options:
6 | # Options configure how source code is generated for every
7 | # `@JsonSerializable`-annotated class in the package.
8 | any_map: true
9 | explicit_to_json: true
10 |
--------------------------------------------------------------------------------
/devtools_options.yaml:
--------------------------------------------------------------------------------
1 | description: This file stores settings for Dart & Flutter DevTools.
2 | documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states
3 | extensions:
4 |
--------------------------------------------------------------------------------
/lib/firebase_options.dart:
--------------------------------------------------------------------------------
1 | // File generated by FlutterFire CLI.
2 | // ignore_for_file: lines_longer_than_80_chars, avoid_classes_with_only_static_members
3 | import 'package:firebase_core/firebase_core.dart' show FirebaseOptions;
4 | import 'package:flutter/foundation.dart'
5 | show defaultTargetPlatform, kIsWeb, TargetPlatform;
6 |
7 | /// Default [FirebaseOptions] for use with your Firebase apps.
8 | ///
9 | /// Example:
10 | /// ```dart
11 | /// import 'firebase_options.dart';
12 | /// // ...
13 | /// await Firebase.initializeApp(
14 | /// options: DefaultFirebaseOptions.currentPlatform,
15 | /// );
16 | /// ```
17 | class DefaultFirebaseOptions {
18 | static FirebaseOptions get currentPlatform {
19 | if (kIsWeb) {
20 | return web;
21 | }
22 | switch (defaultTargetPlatform) {
23 | case TargetPlatform.android:
24 | return android;
25 | case TargetPlatform.iOS:
26 | throw UnsupportedError(
27 | 'DefaultFirebaseOptions have not been configured for ios - '
28 | 'you can reconfigure this by running the FlutterFire CLI again.',
29 | );
30 | case TargetPlatform.macOS:
31 | throw UnsupportedError(
32 | 'DefaultFirebaseOptions have not been configured for macos - '
33 | 'you can reconfigure this by running the FlutterFire CLI again.',
34 | );
35 | case TargetPlatform.windows:
36 | throw UnsupportedError(
37 | 'DefaultFirebaseOptions have not been configured for windows - '
38 | 'you can reconfigure this by running the FlutterFire CLI again.',
39 | );
40 | case TargetPlatform.linux:
41 | throw UnsupportedError(
42 | 'DefaultFirebaseOptions have not been configured for linux - '
43 | 'you can reconfigure this by running the FlutterFire CLI again.',
44 | );
45 | default:
46 | throw UnsupportedError(
47 | 'DefaultFirebaseOptions are not supported for this platform.',
48 | );
49 | }
50 | }
51 |
52 | static const FirebaseOptions web = FirebaseOptions(
53 | apiKey: 'AIzaSyBlOvM_3kmgBpmbmWW1BIZ6hOxIFACy2xQ',
54 | appId: '1:478765689275:web:073d88ff3aad6880da3c9e',
55 | messagingSenderId: '478765689275',
56 | projectId: 'adventure-list-354516',
57 | authDomain: 'adventure-list-354516.firebaseapp.com',
58 | storageBucket: 'adventure-list-354516.appspot.com',
59 | measurementId: 'G-WK9C8EPC0N',
60 | );
61 |
62 | static const FirebaseOptions android = FirebaseOptions(
63 | apiKey: 'AIzaSyDFYBvnQaRl6szsW6_unb2Xhi0H_IJOy8M',
64 | appId: '1:478765689275:android:751873c2d07e57e0da3c9e',
65 | messagingSenderId: '478765689275',
66 | projectId: 'adventure-list-354516',
67 | storageBucket: 'adventure-list-354516.appspot.com',
68 | );
69 | }
70 |
--------------------------------------------------------------------------------
/lib/src/app/app.dart:
--------------------------------------------------------------------------------
1 | export 'cubit/cubit.dart';
2 |
--------------------------------------------------------------------------------
/lib/src/app/cubit/app_state.dart:
--------------------------------------------------------------------------------
1 | part of 'app_cubit.dart';
2 |
3 | @freezed
4 | class AppState with _$AppState {
5 | const factory AppState({
6 | /// True if this is the first run of the app.
7 | required bool firstRun,
8 | required String runningVersion,
9 | required String? updateVersion,
10 | required bool updateAvailable,
11 | required bool showUpdateButton,
12 |
13 | /// True if a condition has been met requiring the user to be
14 | /// prompted to purchase the pro upgrade.
15 | required bool promptForProUpgrade,
16 |
17 | /// Release notes for the current version.
18 | required ReleaseNotes? releaseNotes,
19 | }) = _AppState;
20 |
21 | factory AppState.initial() {
22 | return const AppState(
23 | firstRun: false,
24 | runningVersion: '',
25 | updateVersion: null,
26 | updateAvailable: false,
27 | showUpdateButton: false,
28 | promptForProUpgrade: false,
29 | releaseNotes: null,
30 | );
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/lib/src/app/cubit/cubit.dart:
--------------------------------------------------------------------------------
1 | export 'app_cubit.dart';
2 |
--------------------------------------------------------------------------------
/lib/src/authentication/authentication.dart:
--------------------------------------------------------------------------------
1 | export 'cubit/authentication_cubit.dart';
2 | export 'google_auth.dart';
3 |
--------------------------------------------------------------------------------
/lib/src/authentication/cubit/authentication_cubit.dart:
--------------------------------------------------------------------------------
1 | import 'dart:convert';
2 |
3 | import 'package:flutter_bloc/flutter_bloc.dart';
4 | import 'package:freezed_annotation/freezed_annotation.dart';
5 | import 'package:googleapis_auth/googleapis_auth.dart';
6 |
7 | import '../../logs/logging_manager.dart';
8 | import '../../storage/storage_repository.dart';
9 | import '../google_auth.dart';
10 |
11 | part 'authentication_state.dart';
12 | part 'authentication_cubit.freezed.dart';
13 |
14 | late final AuthenticationCubit authCubit;
15 |
16 | class AuthenticationCubit extends Cubit {
17 | final GoogleAuth _googleAuth;
18 | final StorageRepository _storageRepository;
19 |
20 | AuthenticationCubit._(
21 | this._googleAuth,
22 | this._storageRepository, {
23 | required AuthenticationState initialState,
24 | }) : super(initialState) {
25 | authCubit = this;
26 | }
27 |
28 | static Future initialize({
29 | required GoogleAuth googleAuth,
30 | required StorageRepository storageRepository,
31 | }) async {
32 | final String? savedCredentials = await storageRepository.get(
33 | 'accessCredentials',
34 | );
35 |
36 | AccessCredentials? credentials;
37 | if (savedCredentials != null) {
38 | credentials = AccessCredentials.fromJson(jsonDecode(savedCredentials));
39 | }
40 |
41 | return AuthenticationCubit._(
42 | googleAuth,
43 | storageRepository,
44 | initialState: AuthenticationState(
45 | accessCredentials: credentials,
46 | signedIn: (credentials != null),
47 | ),
48 | );
49 | }
50 |
51 | Future signIn() async {
52 | assert(!state.signedIn);
53 |
54 | log.i('Signing in...');
55 |
56 | final accessCredentials = await _googleAuth.signin();
57 | if (accessCredentials == null) {
58 | log.w('Unable to sign in');
59 | return;
60 | } else {
61 | log.i('Signed in successfully.');
62 | }
63 |
64 | emit(state.copyWith(
65 | accessCredentials: accessCredentials,
66 | signedIn: true,
67 | ));
68 |
69 | await _storageRepository.save(
70 | key: 'accessCredentials',
71 | value: jsonEncode(accessCredentials.toJson()),
72 | );
73 | }
74 |
75 | Future signOut() async {
76 | await _googleAuth.signOut();
77 | await _storageRepository.delete('accessCredentials');
78 |
79 | emit(state.copyWith(
80 | accessCredentials: null,
81 | signedIn: false,
82 | ));
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/lib/src/authentication/cubit/authentication_state.dart:
--------------------------------------------------------------------------------
1 | part of 'authentication_cubit.dart';
2 |
3 | @freezed
4 | class AuthenticationState with _$AuthenticationState {
5 | const factory AuthenticationState({
6 | required AccessCredentials? accessCredentials,
7 | required bool signedIn,
8 | }) = _AuthenticationState;
9 | }
10 |
--------------------------------------------------------------------------------
/lib/src/authentication/sign_in_page.dart:
--------------------------------------------------------------------------------
1 | import 'dart:async';
2 | import 'dart:io';
3 |
4 | import 'package:flutter/material.dart';
5 | import 'package:flutter_bloc/flutter_bloc.dart';
6 | import 'package:flutter_signin_button/button_list.dart';
7 | import 'package:flutter_signin_button/button_view.dart';
8 | import 'package:window_to_front/window_to_front.dart';
9 |
10 | import '../tasks/tasks.dart';
11 | import 'cubit/authentication_cubit.dart';
12 |
13 | class SignInPage extends StatelessWidget {
14 | static const routeName = '/signin_page';
15 |
16 | const SignInPage({super.key});
17 |
18 | @override
19 | Widget build(BuildContext context) {
20 | return Scaffold(
21 | body: BlocBuilder(
22 | builder: (context, state) {
23 | return Column(
24 | mainAxisSize: MainAxisSize.max,
25 | mainAxisAlignment: MainAxisAlignment.center,
26 | children: [
27 | // Signed in, inform user and proceed to load app.
28 | if (state.signedIn)
29 | Builder(builder: (context) {
30 | if (Platform.isLinux || Platform.isWindows) {
31 | // Focus app window after authentication.
32 | WindowToFront.activate();
33 | }
34 |
35 | Timer(const Duration(seconds: 2), () {
36 | Navigator.pushReplacementNamed(
37 | context,
38 | TasksPage.routeName,
39 | );
40 | });
41 |
42 | return const Center(
43 | child: Padding(
44 | padding: EdgeInsets.only(bottom: 30),
45 | child: Icon(
46 | Icons.check_circle_outline,
47 | size: 100,
48 | color: Colors.green,
49 | ),
50 | ),
51 | );
52 | }),
53 |
54 | // Not signed in, prompt for authentication.
55 | Center(
56 | child: SignInButton(
57 | Buttons.GoogleDark,
58 | onPressed: () async {
59 | await authCubit.signIn();
60 | },
61 | ),
62 | ),
63 | ],
64 | );
65 | },
66 | ),
67 | );
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/lib/src/autostart/autostart_service.dart:
--------------------------------------------------------------------------------
1 | import 'dart:io';
2 |
3 | import 'package:flutter/foundation.dart';
4 | import 'package:helpers/helpers.dart';
5 | import 'package:launch_at_startup/launch_at_startup.dart';
6 | import 'package:package_info_plus/package_info_plus.dart';
7 | import 'package:xdg_desktop_portal/xdg_desktop_portal.dart';
8 |
9 | import '../logs/logging_manager.dart';
10 |
11 | /// Service to enable/disable autostart on desktop platforms.
12 | class AutostartService {
13 | /// Disables autostart on login.
14 | Future disable() async {
15 | assert(defaultTargetPlatform.isDesktop);
16 |
17 | if (runningInFlatpak()) {
18 | await _setForFlatpak(false);
19 | } else {
20 | await _disableForDesktop();
21 | }
22 | }
23 |
24 | /// Enables autostart on login.
25 | Future enable() async {
26 | assert(defaultTargetPlatform.isDesktop);
27 |
28 | if (runningInFlatpak()) {
29 | await _setForFlatpak(true);
30 | } else {
31 | await _enableForDesktop();
32 | }
33 | }
34 |
35 | Future _disableForDesktop() async {
36 | await _setupLaunchAtStartup();
37 | await launchAtStartup.disable();
38 | }
39 |
40 | Future _enableForDesktop() async {
41 | await _setupLaunchAtStartup();
42 | await launchAtStartup.enable();
43 | }
44 |
45 | Future _setForFlatpak(bool enable) async {
46 | log.i('Setting up autostart for Flatpak app.');
47 | final client = XdgDesktopPortalClient();
48 |
49 | final result = await client.background.requestBackground(
50 | reason: 'Autostarting Adventure List',
51 | autostart: enable,
52 | commandLine: ['adventure_list'],
53 | ).first;
54 |
55 | log.i('Result: $result');
56 | await client.close();
57 | }
58 |
59 | Future _setupLaunchAtStartup() async {
60 | final packageInfo = await PackageInfo.fromPlatform();
61 |
62 | launchAtStartup.setup(
63 | appName: packageInfo.appName,
64 | appPath: Platform.resolvedExecutable,
65 | );
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/lib/src/background_tasks/background_tasks.dart:
--------------------------------------------------------------------------------
1 | export 'background_tasks_service.dart';
2 |
--------------------------------------------------------------------------------
/lib/src/core/constants.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/foundation.dart';
2 | import 'package:helpers/helpers.dart';
3 |
4 | const String kDonateUrl = 'https://merritt.codes/support';
5 | const String kPackageId = 'codes.merritt.adventurelist';
6 | const String kRepoUrl = 'https://github.com/Merrit/adventure_list';
7 | const String kWebsiteUrl = 'https://github.com/Merrit/adventure_list';
8 |
9 | /// The paths to the app's icons.
10 | abstract class AppIcons {
11 | /// Asset directory containing the app's icons.
12 | static const String path = 'assets/icons';
13 |
14 | /// Normal icon as an SVG.
15 | static const String linux = '$path/$kPackageId.svg';
16 |
17 | /// Normal icon as an ICO.
18 | static const String windows = '$path/$kPackageId.ico';
19 |
20 | /// Normal icon with a red dot indicating a notification, as an SVG.
21 | static const String linuxWithNotificationBadge =
22 | '$path/$kPackageId-with-notification-badge.svg';
23 |
24 | /// Normal icon with a red dot indicating a notification, as an ICO.
25 | static const String windowsWithNotificationBadge =
26 | '$path/$kPackageId-with-notification-badge.ico';
27 |
28 | /// Symbolic icon as an SVG.
29 | static const String linuxSymbolic = '$path/$kPackageId-symbolic.svg';
30 |
31 | /// Symbolic icon as an ICO.
32 | static const String windowsSymbolic = '$path/$kPackageId-symbolic.ico';
33 |
34 | /// Symbolic icon with a red dot indicating a notification, as an SVG.
35 | static const String linuxSymbolicWithNotificationBadge =
36 | '$path/$kPackageId-symbolic-with-notification-badge.svg';
37 |
38 | /// Symbolic icon with a red dot indicating a notification, as an ICO.
39 | static const String windowsSymbolicWithNotificationBadge =
40 | '$path/$kPackageId-symbolic-with-notification-badge.ico';
41 |
42 | /// Returns the appropriate icon path (or icon name) based on the current platform.
43 | static String platformSpecific({
44 | required bool symbolic,
45 | bool withNotificationBadge = false,
46 | }) {
47 | if (runningInFlatpak() || runningInSnap()) {
48 | // When running in a sandboxed environment the icon must be specified by
49 | // the icon's name, not the path.
50 | return kPackageId;
51 | }
52 |
53 | return defaultTargetPlatform.isWindows
54 | ? getWindowsIcon(symbolic, withNotificationBadge)
55 | : getLinuxIcon(symbolic, withNotificationBadge);
56 | }
57 |
58 | static String getWindowsIcon(bool symbolic, bool withNotificationBadge) {
59 | if (symbolic) {
60 | return withNotificationBadge
61 | ? windowsSymbolicWithNotificationBadge
62 | : windowsSymbolic;
63 | } else {
64 | return withNotificationBadge ? windowsWithNotificationBadge : windows;
65 | }
66 | }
67 |
68 | static String getLinuxIcon(bool symbolic, bool withNotificationBadge) {
69 | if (symbolic) {
70 | return withNotificationBadge ? linuxSymbolicWithNotificationBadge : linuxSymbolic;
71 | } else {
72 | return withNotificationBadge ? linuxWithNotificationBadge : linux;
73 | }
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/lib/src/core/core.dart:
--------------------------------------------------------------------------------
1 | export 'constants.dart';
2 | export 'package:helpers/helpers.dart';
3 | export 'widgets/widgets.dart';
4 |
--------------------------------------------------------------------------------
/lib/src/core/helpers/date_time.dart:
--------------------------------------------------------------------------------
1 | import 'package:intl/intl.dart';
2 |
3 | extension DateTimeHelper on DateTime {
4 | /// Returns true if this date is the same as [other] (ignoring time).
5 | bool isSameDay(DateTime other) {
6 | return year == other.year && month == other.month && day == other.day;
7 | }
8 |
9 | /// Returns a string representation of this date that is appropriate for
10 | /// displaying in the UI.
11 | ///
12 | /// If the task is due today, the label will be "Today,