├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── dependabot.yml ├── pull_request_template.md └── workflows │ ├── codacy.yml │ ├── docs.yml │ ├── publish.yml │ ├── publish_dry_run.yml │ └── test.yml ├── .gitignore ├── CHANGELOG.md ├── CODE-OF-CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── Makefile ├── README.md ├── SECURITY.md ├── analysis_options.yaml ├── build.yaml ├── example ├── alfred_workflow_auto_update_example.dart ├── alfred_workflow_caching_example.dart └── alfred_workflow_example.dart ├── lib ├── alfred_workflow.dart └── src │ ├── converters │ └── version_converter.dart │ ├── extensions │ ├── index.dart │ ├── string_helpers.dart │ └── user_defaults.dart │ ├── mixins │ └── delegating_items_list_mixin.dart │ ├── models │ ├── alfred_action.dart │ ├── alfred_action.g.dart │ ├── alfred_automatic_cache.dart │ ├── alfred_automatic_cache.g.dart │ ├── alfred_item.dart │ ├── alfred_item.g.dart │ ├── alfred_item_icon.dart │ ├── alfred_item_icon.g.dart │ ├── alfred_item_mod.dart │ ├── alfred_item_mod.g.dart │ ├── alfred_item_text.dart │ ├── alfred_item_text.g.dart │ ├── alfred_items.dart │ ├── alfred_items.g.dart │ ├── alfred_user_configuration.dart │ ├── alfred_user_configuration.g.dart │ ├── alfred_user_configuration_check_box.dart │ ├── alfred_user_configuration_check_box.g.dart │ ├── alfred_user_configuration_config.dart │ ├── alfred_user_configuration_config.g.dart │ ├── alfred_user_configuration_config_check_box.dart │ ├── alfred_user_configuration_config_check_box.g.dart │ ├── alfred_user_configuration_config_file_picker.dart │ ├── alfred_user_configuration_config_file_picker.g.dart │ ├── alfred_user_configuration_config_number_slider.dart │ ├── alfred_user_configuration_config_number_slider.g.dart │ ├── alfred_user_configuration_config_select.dart │ ├── alfred_user_configuration_config_select.g.dart │ ├── alfred_user_configuration_config_text_area.dart │ ├── alfred_user_configuration_config_text_area.g.dart │ ├── alfred_user_configuration_config_text_field.dart │ ├── alfred_user_configuration_config_text_field.g.dart │ ├── alfred_user_configuration_file_picker.dart │ ├── alfred_user_configuration_file_picker.g.dart │ ├── alfred_user_configuration_number_slider.dart │ ├── alfred_user_configuration_number_slider.g.dart │ ├── alfred_user_configuration_select.dart │ ├── alfred_user_configuration_select.g.dart │ ├── alfred_user_configuration_text_area.dart │ ├── alfred_user_configuration_text_area.g.dart │ ├── alfred_user_configuration_text_field.dart │ ├── alfred_user_configuration_text_field.g.dart │ ├── alfred_user_configuration_type.dart │ ├── github_asset.dart │ ├── github_asset.g.dart │ ├── github_release.dart │ ├── github_release.g.dart │ ├── github_user.dart │ ├── github_user.g.dart │ └── index.dart │ └── services │ ├── alfred_cache.dart │ ├── alfred_cache.g.dart │ ├── alfred_updater.dart │ ├── alfred_updater.g.dart │ └── index.dart ├── pubspec.yaml ├── scripts ├── compare_versions.dart ├── makefile_scripts.sh └── pubspec.yaml └── test ├── build └── ensure_build_test.dart ├── fixtures ├── alfred_workflow_fixture.dart ├── data │ ├── info.plist │ └── prefs.plist ├── extensions │ └── fixture_factory_extension.dart ├── models │ ├── alfred_action_fixture.dart │ ├── alfred_automatic_cache_fixture.dart │ ├── alfred_item_fixture.dart │ ├── alfred_item_icon_fixture.dart │ ├── alfred_item_mod_fixture.dart │ ├── alfred_item_text_fixture.dart │ ├── alfred_items_fixture.dart │ ├── github_asset_fixture.dart │ ├── github_release_fixture.dart │ └── github_user_fixture.dart └── services │ └── alfred_updater_fixture.dart ├── helpers ├── matchers.dart ├── mock_alfred_cache.dart └── mock_stdout.dart └── unit ├── alfred_workflow_test.dart ├── converters └── version_converter_test.dart ├── extensions ├── string_helpers_test.dart └── user_defaults_test.dart ├── mixin └── delegating_items_list_mixin_test.dart ├── models ├── alfred_automatic_cache_test.dart ├── alfred_item_test.dart └── alfred_items_test.dart └── services ├── alfred_cache_test.dart ├── alfred_updater_test.dart └── alfred_updater_test.mocks.dart /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: techouse 2 | custom: [ "https://paypal.me/ktusar" ] 3 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: The application is crashing or throws an exception, a widget is buggy, or something looks wrong. 4 | title: '' 5 | labels: bug 6 | assignees: techouse 7 | 8 | --- 9 | 10 | ## Steps to Reproduce 11 | 12 | 13 | 14 | 1. Execute `dart run` on the code sample 15 | 2. ... 16 | 3. ... 17 | 18 | **Expected results:** 19 | 20 | **Actual results:** 21 | 22 |
23 | Code sample 24 | 25 | 37 | 38 | ```dart 39 | ``` 40 | 41 |
42 | 43 |
44 | Logs 45 | 46 | 52 | 53 | ``` 54 | ``` 55 | 56 | 60 | 61 | ``` 62 | ``` 63 | 64 | 65 | 66 | ``` 67 | ``` 68 | 69 |
70 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: enhancement 6 | assignees: techouse 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "pub" 4 | directory: "/" 5 | schedule: 6 | interval: "weekly" 7 | - package-ecosystem: "github-actions" 8 | directory: "/" 9 | schedule: 10 | interval: "weekly" 11 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | ## Description 2 | 3 | Please include a summary of the changes and which issue is fixed. Please also include relevant motivation and context. 4 | 5 | Fixes #(issue) 6 | 7 | ## Type of change 8 | 9 | Please delete options that are not relevant. 10 | 11 | - [ ] Bug fix (non-breaking change which fixes an issue) 12 | - [ ] New feature (non-breaking change which adds functionality) 13 | - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) 14 | - [ ] This change requires a documentation update 15 | 16 | ## How Has This Been Tested? 17 | 18 | Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also 19 | list any relevant details for your test configuration 20 | 21 | - [ ] Test A 22 | - [ ] Test B 23 | 24 | ## Checklist: 25 | 26 | - [ ] My code follows the style guidelines of this project 27 | - [ ] I have performed a self-review of my own code 28 | - [ ] I have commented my code, particularly in hard-to-understand areas 29 | - [ ] I have made corresponding changes to the documentation 30 | - [ ] My changes generate no new warnings 31 | - [ ] I have added tests that prove my fix is effective or that my feature works 32 | - [ ] New and existing unit tests pass locally with my changes 33 | - [ ] Any dependent changes have been merged and published in downstream modules 34 | -------------------------------------------------------------------------------- /.github/workflows/codacy.yml: -------------------------------------------------------------------------------- 1 | name: Codacy Security Scan 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | pull_request: 8 | branches: 9 | - master 10 | schedule: 11 | - cron: '24 1 * * 0' 12 | 13 | permissions: 14 | contents: read 15 | 16 | jobs: 17 | codacy-security-scan: 18 | permissions: 19 | contents: read 20 | security-events: write 21 | actions: read 22 | name: Codacy Security Scan 23 | runs-on: ubuntu-latest 24 | steps: 25 | - name: Checkout code 26 | uses: actions/checkout@v4 27 | - name: Run Codacy Analysis CLI 28 | uses: codacy/codacy-analysis-cli-action@v4.4.5 29 | with: 30 | project-token: ${{ secrets.CODACY_PROJECT_TOKEN }} 31 | output: results.sarif 32 | format: sarif 33 | gh-code-scanning-compat: true 34 | # Force 0 exit code to allow SARIF file generation 35 | # This will handover control about PR rejection to the GitHub side 36 | max-allowed-issues: 2147483647 37 | - name: Upload SARIF results file 38 | uses: github/codeql-action/upload-sarif@v3 39 | with: 40 | sarif_file: results.sarif 41 | -------------------------------------------------------------------------------- /.github/workflows/docs.yml: -------------------------------------------------------------------------------- 1 | name: Docs 2 | 3 | on: 4 | workflow_call: 5 | 6 | permissions: 7 | contents: write 8 | 9 | jobs: 10 | docs: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - name: Setup Dart SDK 14 | uses: dart-lang/setup-dart@v1 15 | with: 16 | sdk: stable 17 | - id: checkout 18 | name: Checkout repository 19 | uses: actions/checkout@v4 20 | - id: install 21 | name: Install dependencies 22 | run: dart pub get 23 | - name: Build documentation 24 | run: dart doc . 25 | - name: Deploy to GitHub Pages 26 | uses: peaceiris/actions-gh-pages@v4 27 | with: 28 | publish_branch: gh-pages 29 | github_token: ${{ secrets.GITHUB_TOKEN }} 30 | publish_dir: doc/api/ 31 | force_orphan: true 32 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish package 2 | 3 | on: 4 | push: 5 | tags: 6 | - 'v[0-9]+.[0-9]+.[0-9]+*' # tag pattern on pub.dev: 'v' 7 | defaults: 8 | run: 9 | shell: bash 10 | env: 11 | PUB_ENVIRONMENT: bot.github 12 | permissions: read-all 13 | 14 | jobs: 15 | test: 16 | uses: ./.github/workflows/test.yml 17 | secrets: inherit 18 | publish: 19 | needs: test 20 | name: "Publish" 21 | permissions: 22 | id-token: write 23 | runs-on: ubuntu-latest 24 | environment: pub.dev 25 | steps: 26 | - uses: dart-lang/setup-dart@v1 27 | with: 28 | sdk: stable 29 | - id: checkout 30 | uses: actions/checkout@v4 31 | - name: Compare version with ref/tag 32 | id: compare_version_with_tag 33 | run: | 34 | set -e 35 | VERSION=$(awk '/^version: / {print $2}' pubspec.yaml) 36 | TAG=${GITHUB_REF_NAME#v} 37 | if [[ "$VERSION" != "$TAG" ]]; then 38 | echo "Version in pubspec.yaml ($VERSION) does not match tag ($TAG)" 39 | exit 1 40 | fi 41 | - name: Check CHANGELOG.md 42 | id: check_changelog 43 | run: | 44 | set -e 45 | if ! grep -q "## $VERSION" CHANGELOG.md; then 46 | echo "CHANGELOG.md does not contain a section for $VERSION" 47 | exit 1 48 | fi 49 | - name: Validate pub.dev topics 50 | id: validate_pub_dev_topics 51 | run: | 52 | set -e 53 | pattern="^[a-z][a-z0-9-]*[a-z0-9]$" 54 | for topic in $(yq -r '.topics[]' pubspec.yaml); do 55 | if [[ ! $topic =~ $pattern ]]; then 56 | echo "Invalid topic: $topic" 57 | exit 1 58 | fi 59 | done 60 | - name: Install dependencies 61 | run: dart pub get 62 | - name: Publish 63 | id: publish 64 | run: dart pub publish --force 65 | release: 66 | needs: [ test, publish ] 67 | name: "Release" 68 | runs-on: ubuntu-latest 69 | permissions: 70 | contents: write 71 | steps: 72 | - uses: actions/checkout@v4 73 | - name: Get version from pubspec.yaml 74 | id: get_version_and_name 75 | run: | 76 | set -e 77 | VERSION=$(awk '/^version: / {print $2}' pubspec.yaml) 78 | NAME=$(awk '/^name: / {print $2}' pubspec.yaml) 79 | echo "VERSION=$VERSION" >> $GITHUB_ENV 80 | echo "NAME=$NAME" >> $GITHUB_ENV 81 | - name: Create tag-specific CHANGELOG 82 | id: create_changelog 83 | run: | 84 | set -e 85 | CHANGELOG_PATH=$RUNNER_TEMP/CHANGELOG.md 86 | awk '/^##[[:space:]].*/ { if (count == 1) exit; count++; print } count == 1 && !/^##[[:space:]].*/ { print }' CHANGELOG.md | sed -e :a -e '/^\n*$/{$d;N;ba' -e '}' > $CHANGELOG_PATH 87 | echo -en "\n[https://pub.dev/packages/$NAME/versions/$VERSION](https://pub.dev/packages/$NAME/versions/$VERSION)" >> $CHANGELOG_PATH 88 | echo "CHANGELOG_PATH=$CHANGELOG_PATH" >> $GITHUB_ENV 89 | - name: Create release 90 | id: create_release 91 | uses: softprops/action-gh-release@v2 92 | with: 93 | name: ${{ env.VERSION }} 94 | tag_name: v${{ env.VERSION }} 95 | body_path: ${{ env.CHANGELOG_PATH }} 96 | - name: Clean up 97 | id: clean_up 98 | if: ${{ always() }} 99 | run: | 100 | rm -rf $CHANGELOG_PATH 101 | docs: 102 | uses: ./.github/workflows/docs.yml 103 | needs: [ test, publish ] 104 | permissions: 105 | contents: write 106 | secrets: inherit 107 | -------------------------------------------------------------------------------- /.github/workflows/publish_dry_run.yml: -------------------------------------------------------------------------------- 1 | name: Publish package (dry run) 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - master 7 | defaults: 8 | run: 9 | shell: bash 10 | env: 11 | PUB_ENVIRONMENT: bot.github 12 | permissions: read-all 13 | 14 | jobs: 15 | get_base_version: 16 | name: "Get base version" 17 | runs-on: ubuntu-latest 18 | outputs: 19 | BASE_VERSION: ${{ steps.load_base_version.outputs.BASE_VERSION }} 20 | steps: 21 | - uses: actions/cache@v4 22 | with: 23 | path: "~/.pub-cache/hosted" 24 | key: "os:ubuntu-latest;pub-cache-hosted;sdk:stable;packages:alfred_workflow;commands:get_base_version" 25 | restore-keys: | 26 | os:ubuntu-latest;pub-cache-hosted;sdk:stable;packages:alfred_workflow 27 | os:ubuntu-latest;pub-cache-hosted;sdk:stable 28 | os:ubuntu-latest;pub-cache-hosted 29 | os:ubuntu-latest 30 | - uses: dart-lang/setup-dart@v1 31 | with: 32 | sdk: stable 33 | - id: checkout 34 | uses: actions/checkout@v4 35 | with: 36 | ref: ${{ github.event.pull_request.base.ref }} 37 | - name: Load base version 38 | id: load_base_version 39 | run: | 40 | set -e 41 | echo "BASE_VERSION=$(awk '/^version: / {print $2}' pubspec.yaml)" >> $GITHUB_OUTPUT 42 | publish_dry_run: 43 | name: "Publish DRY RUN" 44 | needs: get_base_version 45 | runs-on: ubuntu-latest 46 | steps: 47 | - uses: actions/cache@v4 48 | with: 49 | path: "~/.pub-cache/hosted" 50 | key: "os:ubuntu-latest;pub-cache-hosted;sdk:stable;packages:alfred_workflow;commands:get_base_version" 51 | restore-keys: | 52 | os:ubuntu-latest;pub-cache-hosted;sdk:stable;packages:alfred_workflow 53 | os:ubuntu-latest;pub-cache-hosted;sdk:stable 54 | os:ubuntu-latest;pub-cache-hosted 55 | os:ubuntu-latest 56 | - uses: dart-lang/setup-dart@v1 57 | with: 58 | sdk: stable 59 | - id: checkout 60 | uses: actions/checkout@v4 61 | - name: Load this version 62 | id: load_this_version 63 | run: | 64 | set -e 65 | echo "THIS_VERSION=$(awk '/^version: / {print $2}' pubspec.yaml)" >> $GITHUB_ENV 66 | - name: Compare versions 67 | id: compare_versions 68 | env: 69 | BASE_VERSION: ${{ needs.get_base_version.outputs.BASE_VERSION }} 70 | run: | 71 | set -e 72 | pushd scripts || exit 73 | dart pub get 74 | echo "IS_VERSION_GREATER=$(dart run compare_versions.dart $THIS_VERSION $BASE_VERSION)" >> $GITHUB_ENV 75 | popd || exit 76 | - name: Validate pub.dev topics 77 | id: validate_pub_dev_topics 78 | run: | 79 | set -e 80 | pattern="^[a-z][a-z0-9-]*[a-z0-9]$" 81 | for topic in $(yq -r '.topics[]' pubspec.yaml); do 82 | if [[ ! $topic =~ $pattern ]]; then 83 | echo "Invalid topic: $topic" 84 | exit 1 85 | fi 86 | done 87 | - name: Publish (dry run) 88 | id: publish_dry_run 89 | if: ${{ env.IS_VERSION_GREATER == 1 }} 90 | run: dart pub publish --dry-run 91 | - name: Skip publish (dry run) 92 | id: skip_publish_dry_run 93 | if: ${{ env.IS_VERSION_GREATER == 0 }} 94 | run: echo "Skipping publish (dry run) because the version is not greater than the one on pub.dev" -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Test 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | pull_request: 8 | branches: 9 | - master 10 | workflow_call: 11 | defaults: 12 | run: 13 | shell: bash 14 | env: 15 | PUB_ENVIRONMENT: bot.github 16 | permissions: read-all 17 | 18 | jobs: 19 | test: 20 | name: "Test" 21 | runs-on: ubuntu-latest 22 | steps: 23 | - name: Cache Pub hosted dependencies 24 | uses: actions/cache@v4 25 | with: 26 | path: "~/.pub-cache/hosted" 27 | key: "os:ubuntu-latest;pub-cache-hosted;sdk:stable;packages:alfred_workflow;commands:codegen-test" 28 | restore-keys: | 29 | os:ubuntu-latest;pub-cache-hosted;sdk:stable;packages:alfred_workflow 30 | os:ubuntu-latest;pub-cache-hosted;sdk:stable 31 | os:ubuntu-latest;pub-cache-hosted 32 | os:ubuntu-latest 33 | - name: Setup Dart SDK 34 | uses: dart-lang/setup-dart@v1 35 | with: 36 | sdk: stable 37 | - id: checkout 38 | name: Checkout repository 39 | uses: actions/checkout@v4 40 | - id: install 41 | name: Install dependencies 42 | run: dart pub get 43 | - name: Run the build system for Dart code generation and modular compilation 44 | run: dart run build_runner build --delete-conflicting-outputs 45 | - name: Check the formatting of one or more Dart files 46 | run: | 47 | find lib test -name "*.dart" ! -name "*.mocks.dart" ! -name "*.g.dart" -print0 | xargs -0 dart format --output=none --set-exit-if-changed 48 | - name: Analyze the project's Dart code 49 | run: dart analyze lib test --fatal-infos 50 | - name: Install coverage dependencies 51 | run: | 52 | dart pub global activate coverage 53 | dart pub global activate remove_from_coverage 54 | - name: Collect and report coverage 55 | run: | 56 | dart pub global run coverage:test_with_coverage 57 | dart pub global run remove_from_coverage:remove_from_coverage -f coverage/lcov.info -r '\.g\.dart$' 58 | - name: Check Code Coverage 59 | uses: VeryGoodOpenSource/very_good_coverage@v3.0.0 60 | with: 61 | path: coverage/lcov.info 62 | min_coverage: 90 63 | - name: Upload coverage to Codecov 64 | uses: codecov/codecov-action@v5 65 | with: 66 | token: ${{ secrets.CODECOV_TOKEN }} 67 | slug: techouse/alfred_workflow 68 | files: ./coverage/lcov.info 69 | verbose: true 70 | - name: Upload coverage to Codacy 71 | uses: codacy/codacy-coverage-reporter-action@v1 72 | with: 73 | project-token: ${{ secrets.CODACY_PROJECT_TOKEN }} 74 | coverage-reports: coverage/lcov.info 75 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Files and directories created by pub. 2 | .dart_tool/ 3 | .packages 4 | 5 | # IDE specific 6 | .idea/ 7 | 8 | # Coverage 9 | coverage/ 10 | 11 | # Tooling 12 | scripts/pubspec.lock 13 | 14 | # Lock file 15 | pubspec.lock 16 | 17 | # Docs 18 | doc/ 19 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 1.1.5 2 | 3 | - Chore: update dependencies 4 | 5 | ## 1.1.4 6 | 7 | - Chore: migrate from autoequal to equatable_gen 8 | - Chore: update dependencies 9 | 10 | ## 1.1.3 11 | 12 | - Chore: improve caching mechanism 13 | - Chore: increase test coverage 14 | 15 | ## 1.1.2 16 | 17 | - Feat: add number slider configuration support in user settings 18 | 19 | ## 1.1.1 20 | 21 | - Fix: AlfredWorkflow.getItems is never nullable 22 | - Refactor: improve code readability and maintainability 23 | 24 | ## 1.1.0+1 25 | 26 | - Fix: expose Alfred automatic caching 27 | 28 | ## 1.1.0 29 | 30 | - Feat: add automatic caching support for Alfred items (Alfred 5.5 only) 31 | - Refactor: improve code readability and maintainability 32 | - Chore: update dependencies 33 | 34 | ## 1.0.2 35 | 36 | - Chore: update dependencies 37 | 38 | ## 1.0.1 39 | 40 | - Chore: update dependencies 41 | - Chore: add documentation 42 | 43 | ## 1.0.0 44 | 45 | - Chore: update dependencies 46 | 47 | ## 0.6.1 48 | 49 | - Chore: Update dependencies 50 | 51 | ## 0.6.0 52 | 53 | - **BREAKING:** User Defaults are now combined with the default prefs.plist 54 | file. This means that if you have a prefs.plist file in your workflow, it will 55 | be merged with the User Defaults when you call `AlfredWorkflow.run()`. 56 | This is to ensure that the workflow is always in a consistent state. 57 | 58 | ## 0.5.1 59 | 60 | - Chore: Update dependencies 61 | - Chore: Update Dart SDK to '>=3.2.0 <4.0.0' 62 | 63 | ## 0.5.0 64 | 65 | - Feat: Add ability to read User Defaults from prefs.plist 66 | - Chore: Update dependencies 67 | 68 | ## 0.4.2 69 | 70 | - Chore: Add pub topics to package metadata 71 | - Chore: Update dependencies 72 | 73 | ## 0.4.1 74 | 75 | - Chore: Add Dart 3 class modifiers 76 | - Chore: Add GitHub Release step to publishing GitHub Action 77 | 78 | ## 0.4.0 79 | 80 | - Chore: Update Dart SDK to '>=3.0.5 <4.0.0' 81 | - Chore: Update dependencies 82 | - Chore: Remove Dart Code Metrics because it's being deprecated https://dcm.dev/blog/2023/06/06/announcing-dcm-free-version-sunset/ 83 | 84 | ## 0.3.3 85 | 86 | - Chore: Update dependencies 87 | 88 | ## 0.3.2+1 89 | 90 | - Chore: Update dependencies 91 | - Chore: Automate publishing via GitHub Actions 92 | 93 | ## 0.3.2 94 | 95 | - Chore: Update Dart SDK to '>=2.17.0 <4.0.0' 96 | 97 | ## 0.3.1 98 | 99 | - Chore: Update copy_with_extension to 5.0.2 100 | - Chore: Replace all Object? with dynamic in models 101 | 102 | ## 0.3.0+1 103 | 104 | - Fix result ordering 105 | 106 | ## 0.3.0 107 | 108 | - **BREAKING:** Change AlfredItem.type from String to AlfredItemType enum 109 | - Add support for Universal Action 110 | - Add support result ordering 111 | 112 | ## 0.2.12 113 | 114 | - Add support for mods field in AlfredItem 115 | 116 | ## 0.2.11 117 | 118 | - Updated dependencies 119 | - Rebuilt generated files 120 | 121 | ## 0.2.10 122 | 123 | - Add support custom version tags 124 | 125 | ## 0.2.9 126 | 127 | - Updated examples 128 | - Updated dependencies 129 | 130 | ## 0.2.8 131 | 132 | - Updated dependencies 133 | - Rebuilt generated files 134 | 135 | ## 0.2.7 136 | 137 | - AlfredItems now has a const constructor 138 | - Added build_verify test to ensure all generated files get pushed correctly 139 | - Added EquatableMixin to AlfredCache and AlfredUpdater 140 | - Updated dependencies 141 | 142 | ## 0.2.6 143 | 144 | - Now using autoequal to auto-generate Equatable props 145 | 146 | ## 0.2.5 147 | 148 | - Updated development dependencies 149 | 150 | ## 0.2.4 151 | 152 | - Updated dependencies 153 | 154 | ## 0.2.3 155 | 156 | - Updated dependencies and rebuilt generated files 157 | 158 | ## 0.2.2 159 | 160 | - Stricter code linting 161 | 162 | ## 0.2.1 163 | 164 | - Upgraded stash to 4.3.0 165 | 166 | ## 0.2.0 167 | 168 | - Upgraded stash to 4.1.0 169 | - BREAKING: Changed minimum SDK version to 2.17.0 170 | 171 | ## 0.1.6 172 | 173 | - Pin stash to 4.0.x 174 | 175 | ## 0.1.5 176 | 177 | - Fix typo in changelog 178 | 179 | ## 0.1.4 180 | 181 | - Use a copy of AlfredItems when adding to beginning or end of JSON string 182 | - Update dependencies 183 | - Rebuild generated files 184 | - Add more tests 185 | 186 | ## 0.1.3 187 | 188 | - Add more documentation 189 | - Refactor exports 190 | 191 | ## 0.1.2 192 | 193 | - Limit library to macOS only as Alfred is a macOS only app. 194 | 195 | ## 0.1.1 196 | 197 | - Add more documentation 198 | 199 | ## 0.1.0 200 | 201 | - Add coverage 202 | 203 | ## 0.0.8 204 | 205 | - Bug fixes 206 | 207 | ## 0.0.7 208 | 209 | - Add more unit tests 210 | 211 | ## 0.0.6 212 | 213 | - Add unit tests 214 | - Fix some minor bugs 215 | 216 | ## 0.0.5 217 | 218 | - Add updater 219 | 220 | ## 0.0.4 221 | 222 | - Do not JSON serialize nullable null fields 223 | 224 | ## 0.0.3 225 | 226 | - Add basic file caching 227 | - BREAKING: AlfredItems now accepts only a single positional item 228 | 229 | ## 0.0.2 230 | 231 | - Use json_serializable to automate json serialization 232 | - BREAKING: Change Iterable for List 233 | 234 | ## 0.0.1 235 | 236 | - Initial version. 237 | -------------------------------------------------------------------------------- /CODE-OF-CONDUCT.md: -------------------------------------------------------------------------------- 1 | 2 | # Contributor Covenant Code of Conduct 3 | 4 | ## Our Pledge 5 | 6 | We as members, contributors, and leaders pledge to make participation in our 7 | community a harassment-free experience for everyone, regardless of age, body 8 | size, visible or invisible disability, ethnicity, sex characteristics, gender 9 | identity and expression, level of experience, education, socio-economic status, 10 | nationality, personal appearance, race, caste, color, religion, or sexual 11 | identity and orientation. 12 | 13 | We pledge to act and interact in ways that contribute to an open, welcoming, 14 | diverse, inclusive, and healthy community. 15 | 16 | ## Our Standards 17 | 18 | Examples of behavior that contributes to a positive environment for our 19 | community include: 20 | 21 | * Demonstrating empathy and kindness toward other people 22 | * Being respectful of differing opinions, viewpoints, and experiences 23 | * Giving and gracefully accepting constructive feedback 24 | * Accepting responsibility and apologizing to those affected by our mistakes, 25 | and learning from the experience 26 | * Focusing on what is best not just for us as individuals, but for the overall 27 | community 28 | 29 | Examples of unacceptable behavior include: 30 | 31 | * The use of sexualized language or imagery, and sexual attention or advances of 32 | any kind 33 | * Trolling, insulting or derogatory comments, and personal or political attacks 34 | * Public or private harassment 35 | * Publishing others' private information, such as a physical or email address, 36 | without their explicit permission 37 | * Other conduct which could reasonably be considered inappropriate in a 38 | professional setting 39 | 40 | ## Enforcement Responsibilities 41 | 42 | Community leaders are responsible for clarifying and enforcing our standards of 43 | acceptable behavior and will take appropriate and fair corrective action in 44 | response to any behavior that they deem inappropriate, threatening, offensive, 45 | or harmful. 46 | 47 | Community leaders have the right and responsibility to remove, edit, or reject 48 | comments, commits, code, wiki edits, issues, and other contributions that are 49 | not aligned to this Code of Conduct, and will communicate reasons for moderation 50 | decisions when appropriate. 51 | 52 | ## Scope 53 | 54 | This Code of Conduct applies within all community spaces, and also applies when 55 | an individual is officially representing the community in public spaces. 56 | Examples of representing our community include using an official email address, 57 | posting via an official social media account, or acting as an appointed 58 | representative at an online or offline event. 59 | 60 | ## Enforcement 61 | 62 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 63 | reported to the community leaders responsible for enforcement at 64 | [techouse@gmail.com](mailto:techouse@gmail.com). 65 | All complaints will be reviewed and investigated promptly and fairly. 66 | 67 | All community leaders are obligated to respect the privacy and security of the 68 | reporter of any incident. 69 | 70 | ## Enforcement Guidelines 71 | 72 | Community leaders will follow these Community Impact Guidelines in determining 73 | the consequences for any action they deem in violation of this Code of Conduct: 74 | 75 | ### 1. Correction 76 | 77 | **Community Impact**: Use of inappropriate language or other behavior deemed 78 | unprofessional or unwelcome in the community. 79 | 80 | **Consequence**: A private, written warning from community leaders, providing 81 | clarity around the nature of the violation and an explanation of why the 82 | behavior was inappropriate. A public apology may be requested. 83 | 84 | ### 2. Warning 85 | 86 | **Community Impact**: A violation through a single incident or series of 87 | actions. 88 | 89 | **Consequence**: A warning with consequences for continued behavior. No 90 | interaction with the people involved, including unsolicited interaction with 91 | those enforcing the Code of Conduct, for a specified period of time. This 92 | includes avoiding interactions in community spaces as well as external channels 93 | like social media. Violating these terms may lead to a temporary or permanent 94 | ban. 95 | 96 | ### 3. Temporary Ban 97 | 98 | **Community Impact**: A serious violation of community standards, including 99 | sustained inappropriate behavior. 100 | 101 | **Consequence**: A temporary ban from any sort of interaction or public 102 | communication with the community for a specified period of time. No public or 103 | private interaction with the people involved, including unsolicited interaction 104 | with those enforcing the Code of Conduct, is allowed during this period. 105 | Violating these terms may lead to a permanent ban. 106 | 107 | ### 4. Permanent Ban 108 | 109 | **Community Impact**: Demonstrating a pattern of violation of community 110 | standards, including sustained inappropriate behavior, harassment of an 111 | individual, or aggression toward or disparagement of classes of individuals. 112 | 113 | **Consequence**: A permanent ban from any sort of public interaction within the 114 | community. 115 | 116 | ## Attribution 117 | 118 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], 119 | version 2.1, available at 120 | [https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1]. 121 | 122 | Community Impact Guidelines were inspired by 123 | [Mozilla's code of conduct enforcement ladder][Mozilla CoC]. 124 | 125 | For answers to common questions about this code of conduct, see the FAQ at 126 | [https://www.contributor-covenant.org/faq][FAQ]. Translations are available at 127 | [https://www.contributor-covenant.org/translations][translations]. 128 | 129 | [homepage]: https://www.contributor-covenant.org 130 | [v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html 131 | [Mozilla CoC]: https://github.com/mozilla/diversity 132 | [FAQ]: https://www.contributor-covenant.org/faq 133 | [translations]: https://www.contributor-covenant.org/translations 134 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Thank you for your interest in contributing to this project. This project relies on the help of volunteer developers for 4 | its development and maintenance. 5 | 6 | Before making any changes to this repository, please first discuss the proposed changes with the repository owners 7 | through an issue, email, or any other appropriate method of communication. 8 | 9 | Please note that a [code of conduct](CODE-OF-CONDUCT.md) is in place and should be adhered to during all interactions 10 | related to the project. 11 | 12 | ## Dart version support 13 | 14 | Currently, the package supports Dart versions 3.2 and above. Once a new Dart version is released, we will aim to support 15 | it as soon as possible. If you encounter any issues with a new Dart version, please create an issue in the repository. 16 | 17 | ## Testing 18 | 19 | Given the critical nature of correctly encoded HTTP query strings and the potential for security vulnerabilities if 20 | encoding is not done correctly or consistently across platforms and versions of Dart and Flutter, thorough testing is 21 | of utmost importance. Please remember to write tests for any new code you create, using 22 | the [test](https://pub.dev/packages/test) package for all test cases. 23 | 24 | ### Running the test suite 25 | 26 | To run the test suite, follow these commands: 27 | 28 | ```bash 29 | git clone https://github.com/techouse/alfred_workflow 30 | cd alfred_workflow 31 | dart pub get 32 | dart test 33 | ``` 34 | 35 | ### Running the test suite with coverage 36 | 37 | ```bash 38 | dart pub global activate coverage 39 | dart pub global run coverage:test_with_coverage 40 | lcov --remove coverage/lcov.info '**.g.dart' '**.mock.dart' -o coverage/lcov_without_generated_code.info 41 | genhtml coverage/lcov_without_generated_code.info -o coverage/html 42 | source ./scripts/makefile_scripts.sh && open_link "coverage/html/index.html" 43 | ``` 44 | 45 | ## Submitting changes 46 | 47 | To contribute to this project, please submit a new pull request and provide a clear list of your changes. For guidance 48 | on creating pull requests, you can refer to this resource. When sending a pull request, we highly appreciate the 49 | inclusion of tests, as we strive to enhance our test coverage. 50 | Following our coding conventions is essential, and it would be ideal if you ensure that each commit focuses on a single 51 | feature. For commits, please write clear log messages. While concise one-line messages are suitable for small changes, 52 | more substantial modifications should follow a format similar to the example below: 53 | 54 | ```bash 55 | git commit -m "A brief summary of the commit 56 | > 57 | > A paragraph describing what changed and its impact." 58 | ``` 59 | 60 | ## Coding standards 61 | 62 | Prioritizing code readability and conciseness is essential. To achieve this, we recommend using `dart format` for code 63 | formatting. Once your work is deemed complete, it is advisable to run the following command: 64 | 65 | ```bash 66 | dart format lib test --output=none --set-exit-if-changed . 67 | dart analyze lib test --fatal-infos 68 | ``` 69 | 70 | This command runs the Dart analyzer to identify any potential issues or inconsistencies in your code. By following these 71 | guidelines, you can ensure a high-quality codebase. 72 | 73 | Thanks, Klemen Tusar 74 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 Klemen Tusar 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Makefile 2 | 3 | help: 4 | @printf "%-20s %s\n" "Target" "Description" 5 | @printf "%-20s %s\n" "------" "-----------" 6 | @make -pqR : 2>/dev/null \ 7 | | awk -v RS= -F: '/^# File/,/^# Finished Make data base/ {if ($$1 !~ "^[#.]") {print $$1}}' \ 8 | | sort \ 9 | | egrep -v -e '^[^[:alnum:]]' -e '^$@$$' \ 10 | | xargs -I _ sh -c 'printf "%-20s " _; make _ -nB | (grep -i "^# Help:" || echo "") | tail -1 | sed "s/^# Help: //g"' 11 | 12 | analyze: 13 | @# Help: Analyze the project's Dart code. 14 | dart analyze lib test --fatal-infos 15 | 16 | check_format: 17 | @# Help: Check the formatting of one or more Dart files. 18 | find lib test -name "*.dart" ! -name "*.mocks.dart" ! -name "*.g.dart" -print0 | xargs -0 dart format --output=none --set-exit-if-changed 19 | 20 | check_outdated: 21 | @# Help: Check which of the project's packages are outdated. 22 | dart pub outdated 23 | 24 | check_style: 25 | @# Help: Analyze the project's Dart code and check the formatting one or more Dart files. 26 | make analyze && make check_format 27 | 28 | code_gen: 29 | @# Help: Run the build system for Dart code generation and modular compilation. 30 | dart run build_runner build --delete-conflicting-outputs 31 | 32 | code_gen_watcher: 33 | @# Help: Run the build system for Dart code generation and modular compilation as a watcher. 34 | dart run build_runner watch --delete-conflicting-outputs 35 | 36 | format: 37 | @# Help: Format one or more Dart files. 38 | dart format . 39 | 40 | install: 41 | @# Help: Install all the project's packages 42 | dart pub get 43 | 44 | sure: 45 | @# Help: Analyze the project's Dart code, check the formatting one or more Dart files and run unit tests for the current project. 46 | make check_style && make tests 47 | 48 | show_test_coverage: 49 | @# Help: Run Dart unit tests for the current project and show the coverage. 50 | dart pub global activate coverage && dart pub global run coverage:test_with_coverage 51 | lcov --ignore-errors unused --remove coverage/lcov.info '**.g.dart' '**.mocks.dart' -o coverage/lcov_without_generated_code.info 52 | genhtml coverage/lcov_without_generated_code.info -o coverage/html 53 | source ./scripts/makefile_scripts.sh && open_link "coverage/html/index.html" 54 | 55 | tests: 56 | @# Help: Run VM tests 57 | dart test --platform vm 58 | 59 | upgrade: 60 | @# Help: Upgrade all the project's packages. 61 | dart pub upgrade 62 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Supported Versions 4 | 5 | | Version | Supported | 6 | |---------|--------------------| 7 | | 1.x.x | :white_check_mark: | 8 | | 0.x.x | :x: | 9 | 10 | ## Reporting a Vulnerability 11 | 12 | We take the security of our software seriously. If you believe you have found a security vulnerability, please report it 13 | to us as described below. 14 | 15 | **DO NOT CREATE A GITHUB ISSUE** reporting the vulnerability. 16 | 17 | Instead, send an email to [techouse@gmail.com](mailto:techouse@gmail.com). 18 | 19 | In the report, please include the following: 20 | 21 | - Your name and affiliation (if any). 22 | - A description of the technical details of the vulnerabilities. It is very important to let us know how we can 23 | reproduce your findings. 24 | - An explanation who can exploit this vulnerability, and what they gain when doing so -- write an attack scenario. This 25 | will help us evaluate your submission quickly, especially if it is a complex or creative vulnerability. 26 | - Whether this vulnerability is public or known to third parties. If it is, please provide details. 27 | 28 | If you don’t get an acknowledgment from us or have heard nothing from us in a week, please contact us again. 29 | 30 | We will send a response indicating the next steps in handling your report. We will keep you informed about the progress 31 | towards a fix and full announcement. 32 | 33 | We will not disclose your identity to the public without your permission. We strive to credit researchers in our 34 | advisories when we release a fix, but only after getting your permission. 35 | 36 | We appreciate your efforts to responsibly disclose your findings, and will make every effort to acknowledge your 37 | contributions. 38 | -------------------------------------------------------------------------------- /analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: package:lints/recommended.yaml 2 | 3 | analyzer: 4 | exclude: 5 | - "**.g.dart" 6 | - "**.mocks.dart" 7 | - "example/**" 8 | 9 | linter: 10 | rules: 11 | avoid_print: true 12 | prefer_single_quotes: true 13 | prefer_const_constructors: true 14 | -------------------------------------------------------------------------------- /build.yaml: -------------------------------------------------------------------------------- 1 | targets: 2 | $default: 3 | builders: 4 | equatable_gen: 5 | enabled: true 6 | options: 7 | auto_include: true 8 | json_serializable: 9 | options: 10 | field_rename: snake 11 | -------------------------------------------------------------------------------- /example/alfred_workflow_auto_update_example.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io' show exitCode; 2 | 3 | import 'package:alfred_workflow/alfred_workflow.dart'; 4 | import 'package:args/args.dart'; 5 | import 'package:cli_script/cli_script.dart'; 6 | 7 | void main(List arguments) { 8 | wrapMain(() async { 9 | /// Instantiate the updater 10 | final AlfredUpdater updater = AlfredUpdater( 11 | /// Declare your workflow's Github repository URL 12 | githubRepositoryUrl: Uri.parse('https://github.com/your/repo'), 13 | 14 | /// Declare your workflow's current working version 15 | currentVersion: '1.0.0', 16 | 17 | /// Optionally set an interval how frequently it should check for updates 18 | updateInterval: Duration(days: 7), 19 | ); 20 | 21 | /// Declare a control var 22 | bool update = false; 23 | 24 | final workflow = AlfredWorkflow(); 25 | 26 | try { 27 | exitCode = 0; 28 | 29 | final ArgParser parser = ArgParser() 30 | ..addOption('query', abbr: 'q', defaultsTo: '') 31 | 32 | /// Add another option to the arg parser 33 | ..addFlag('update', abbr: 'u', defaultsTo: false); 34 | 35 | final ArgResults args = parser.parse(arguments); 36 | 37 | /// Check if the workflow wants to trigger an update from the CLI 38 | update = args['update']; 39 | if (update) { 40 | /// Run the update 41 | return await updater.update(); 42 | } 43 | 44 | final String query = args['query'].replaceAll(RegExp(r'\s+'), ' ').trim(); 45 | 46 | if (query.isEmpty) { 47 | workflow.addItem( 48 | const AlfredItem( 49 | title: 'Search for some particular stuff ...', 50 | icon: AlfredItemIcon(path: 'icon.png'), 51 | ), 52 | ); 53 | } else { 54 | /// Define a cacheKey. In this case you can just use the query. 55 | workflow.cacheKey = query; 56 | 57 | /// Check if anything using that cacheKey is already in the cache. 58 | /// This will automatically add the cached items to the Alfred feedback. 59 | final AlfredItems? cachedItems = await workflow.getItems(); 60 | 61 | /// If noting was cached simply do as before 62 | if (cachedItems == null) { 63 | final Uri url = Uri.https('www.google.com', '/search', {'q': query}); 64 | 65 | /// This will now automatically add the AlfredItem to the cache. 66 | workflow.addItem( 67 | AlfredItem( 68 | title: 'Sorry I can\'t help you with that query.', 69 | subtitle: 'Shall I try and search Google?', 70 | arg: url.toString(), 71 | text: AlfredItemText( 72 | copy: url.toString(), 73 | ), 74 | quickLookUrl: url.toString(), 75 | icon: AlfredItemIcon(path: 'google.png'), 76 | valid: true, 77 | ), 78 | ); 79 | } 80 | } 81 | } catch (err) { 82 | exitCode = 1; 83 | workflow.addItem( 84 | AlfredItem(title: err.toString()), 85 | ); 86 | } finally { 87 | /// Check if the workflow is not in the middle of an update. 88 | if (!update) { 89 | /// Periodically check for updates (in this case once every 7 days). 90 | if (await updater.updateAvailable()) { 91 | /// If a new version is available let the user know about it in the Alfred feedback. 92 | workflow.run( 93 | addToBeginning: AlfredItem( 94 | title: 'Auto-Update available!', 95 | subtitle: 96 | 'Press to auto-update to a new version of this workflow.', 97 | arg: 'update:workflow', 98 | match: 99 | 'Auto-Update available! Press to auto-update to a new version of this workflow.', 100 | icon: AlfredItemIcon(path: 'alfredhatcog.png'), 101 | valid: true, 102 | ), 103 | ); 104 | } else { 105 | /// If there's no new version available just print out the results. 106 | workflow.run(); 107 | } 108 | } 109 | } 110 | }); 111 | } 112 | -------------------------------------------------------------------------------- /example/alfred_workflow_caching_example.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io' show exitCode; 2 | 3 | import 'package:alfred_workflow/alfred_workflow.dart'; 4 | import 'package:args/args.dart'; 5 | import 'package:cli_script/cli_script.dart'; 6 | 7 | void main(List arguments) { 8 | wrapMain(() async { 9 | final workflow = AlfredWorkflow(); 10 | 11 | try { 12 | exitCode = 0; 13 | 14 | final ArgParser parser = ArgParser() 15 | ..addOption('query', abbr: 'q', defaultsTo: ''); 16 | 17 | final ArgResults args = parser.parse(arguments); 18 | 19 | final String query = args['query'].replaceAll(RegExp(r'\s+'), ' ').trim(); 20 | 21 | if (query.isEmpty) { 22 | workflow.addItem( 23 | const AlfredItem( 24 | title: 'Search for some particular stuff ...', 25 | icon: AlfredItemIcon(path: 'icon.png'), 26 | ), 27 | ); 28 | } else { 29 | /// Define a cacheKey. In this case you can just use the query. 30 | workflow.cacheKey = query; 31 | 32 | /// Check if anything using that cacheKey is already in the cache. 33 | /// This will automatically add the cached items to the Alfred feedback. 34 | final AlfredItems? cachedItems = await workflow.getItems(); 35 | 36 | /// If noting was cached simply do as before 37 | if (cachedItems == null) { 38 | final Uri url = Uri.https('www.google.com', '/search', {'q': query}); 39 | 40 | /// This will now automatically add the AlfredItem to the cache. 41 | workflow.addItem( 42 | AlfredItem( 43 | title: 'Sorry I can\'t help you with that query.', 44 | subtitle: 'Shall I try and search Google?', 45 | arg: url.toString(), 46 | text: AlfredItemText( 47 | copy: url.toString(), 48 | ), 49 | quickLookUrl: url.toString(), 50 | icon: AlfredItemIcon(path: 'google.png'), 51 | valid: true, 52 | ), 53 | ); 54 | } 55 | } 56 | } catch (err) { 57 | exitCode = 1; 58 | workflow.addItem( 59 | AlfredItem(title: err.toString()), 60 | ); 61 | } finally { 62 | workflow.run(); 63 | } 64 | }); 65 | } 66 | -------------------------------------------------------------------------------- /example/alfred_workflow_example.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io' show exitCode; 2 | 3 | import 'package:alfred_workflow/alfred_workflow.dart'; 4 | import 'package:args/args.dart'; 5 | import 'package:cli_script/cli_script.dart'; 6 | 7 | void main(List arguments) { 8 | wrapMain(() async { 9 | /// Instantiate an AlfredWorkflow 10 | final workflow = AlfredWorkflow(); 11 | 12 | try { 13 | exitCode = 0; 14 | 15 | /// Define an ArgParser that uses -q/--query to listen to search queries 16 | final ArgParser parser = ArgParser() 17 | ..addOption('query', abbr: 'q', defaultsTo: ''); 18 | 19 | /// Parse the args 20 | final ArgResults args = parser.parse(arguments); 21 | 22 | /// Sanitize the query string obtained from the args 23 | final String query = args['query'].replaceAll(RegExp(r'\s+'), ' ').trim(); 24 | 25 | if (query.isEmpty) { 26 | /// In case of an empty query display a placeholder in the Alfred feedback 27 | workflow.addItem( 28 | const AlfredItem( 29 | title: 'Search for some particular stuff ...', 30 | icon: AlfredItemIcon(path: 'icon.png'), 31 | ), 32 | ); 33 | } else { 34 | /// When there is a query do something fancy 35 | 36 | /// In this case we'll search Google with our query. 37 | final Uri url = Uri.https('www.google.com', '/search', {'q': query}); 38 | 39 | /// Add an item to the Alfred feedback 40 | workflow.addItem( 41 | AlfredItem( 42 | title: 'Sorry I can\'t help you with that query.', 43 | subtitle: 'Shall I try and search Google?', 44 | arg: url.toString(), 45 | text: AlfredItemText( 46 | copy: url.toString(), 47 | ), 48 | quickLookUrl: url.toString(), 49 | icon: AlfredItemIcon(path: 'google.png'), 50 | valid: true, 51 | ), 52 | ); 53 | } 54 | } catch (err) { 55 | /// Set exit code to a non-zero number 56 | exitCode = 1; 57 | 58 | /// In case of errors you can simply output the message in the Alfred feedback 59 | workflow.addItem( 60 | AlfredItem(title: err.toString()), 61 | ); 62 | } finally { 63 | /// This will always print JSON to the stdout and send that to Alfred. 64 | workflow.run(); 65 | } 66 | }); 67 | } 68 | -------------------------------------------------------------------------------- /lib/src/converters/version_converter.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart' show JsonConverter; 2 | import 'package:pub_semver/pub_semver.dart' show Version; 3 | 4 | final class VersionConverter implements JsonConverter { 5 | const VersionConverter(); 6 | 7 | static const VersionConverter instance = VersionConverter(); 8 | 9 | static final RegExp _versionMatcher = RegExp(r'(\d+\.\d+\.\d+)'); 10 | 11 | @override 12 | Version fromJson(String string) => _versionMatcher.hasMatch(string) 13 | ? Version.parse(_versionMatcher.stringMatch(string).toString()) 14 | : Version.parse(string); 15 | 16 | @override 17 | String toJson(Version version) => version.toString(); 18 | } 19 | -------------------------------------------------------------------------------- /lib/src/extensions/index.dart: -------------------------------------------------------------------------------- 1 | export 'user_defaults.dart' show UserDefaults; 2 | -------------------------------------------------------------------------------- /lib/src/extensions/string_helpers.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert' show utf8; 2 | 3 | import 'package:crypto/crypto.dart' as crypto show md5; 4 | 5 | extension StringHelpers on String { 6 | String get md5hex => crypto.md5.convert(utf8.encode(this)).toString(); 7 | } 8 | -------------------------------------------------------------------------------- /lib/src/extensions/user_defaults.dart: -------------------------------------------------------------------------------- 1 | import 'package:alfred_workflow/alfred_workflow.dart'; 2 | import 'package:plist_parser/plist_parser.dart'; 3 | 4 | extension UserDefaults on AlfredWorkflow { 5 | static const String _userConfigurationConfigKey = 'userconfigurationconfig'; 6 | static const String _typeKey = 'type'; 7 | 8 | /// Returns a `Map` of user defaults from the workflow's `info.plist` file. 9 | Future?> getDefaults([ 10 | String path = 'info.plist', 11 | ]) async { 12 | try { 13 | return _mapDefaults(await PlistParser().parseFile(path)); 14 | } on NotFoundException { 15 | return null; 16 | } 17 | } 18 | 19 | /// Synchronously returns a `Map` of user defaults from the workflow's `info.plist` file. 20 | Map? getDefaultsSync([ 21 | String path = 'info.plist', 22 | ]) { 23 | try { 24 | return _mapDefaults(PlistParser().parseFileSync(path)); 25 | } on NotFoundException { 26 | return null; 27 | } 28 | } 29 | 30 | /// Returns a `Map` of user defaults from the workflow's `prefs.plist` file. 31 | Future?> getUserPreferences([ 32 | String path = 'prefs.plist', 33 | ]) async { 34 | try { 35 | return _mapUserDefaults(await PlistParser().parseFile(path)); 36 | } on NotFoundException { 37 | return null; 38 | } 39 | } 40 | 41 | /// Synchronously returns a `Map` of user defaults from the workflow's `prefs.plist` file. 42 | Map? getUserPreferencesSync([String path = 'prefs.plist']) { 43 | try { 44 | return _mapUserDefaults(PlistParser().parseFileSync(path)); 45 | } on NotFoundException { 46 | return null; 47 | } 48 | } 49 | 50 | /// Returns a `Map` of the user defaults from the workflow's `info.plist` merged with `prefs.plist` file. 51 | Future?> getUserDefaults({ 52 | String prefsPath = 'prefs.plist', 53 | String infoPath = 'info.plist', 54 | }) async { 55 | final Map userDefaults = 56 | await getUserPreferences(prefsPath) ?? {}; 57 | final Map defaults = 58 | await getDefaults(infoPath) ?? {}; 59 | 60 | return { 61 | for (final MapEntry defaultItem 62 | in defaults.entries) 63 | defaultItem.key: defaultItem.value.copyWithConfig( 64 | defaultItem.value.config.copyWithValue( 65 | userDefaults[defaultItem.key], 66 | ), 67 | ) 68 | }; 69 | } 70 | 71 | /// Synchronously returns a `Map` of user defaults from the workflow's `info.plist` merged with `prefs.plist` file. 72 | Map? getUserDefaultsSync({ 73 | String prefsPath = 'prefs.plist', 74 | String infoPath = 'info.plist', 75 | }) { 76 | final Map userDefaults = 77 | getUserPreferencesSync(prefsPath) ?? {}; 78 | final Map defaults = 79 | getDefaultsSync(infoPath) ?? {}; 80 | 81 | return { 82 | for (final MapEntry defaultItem 83 | in defaults.entries) 84 | defaultItem.key: defaultItem.value.copyWithConfig( 85 | defaultItem.value.config.copyWithValue( 86 | userDefaults[defaultItem.key], 87 | ), 88 | ) 89 | }; 90 | } 91 | 92 | static Map _mapDefaults(Map info) => 93 | { 94 | for (AlfredUserConfiguration item in [ 95 | for (final Map config in info[_userConfigurationConfigKey] as List) 96 | if (config[_typeKey] == 97 | AlfredUserConfigurationType.textField.toString()) 98 | AlfredUserConfigurationTextField.fromJson(config) 99 | else if (config[_typeKey] == 100 | AlfredUserConfigurationType.textArea.toString()) 101 | AlfredUserConfigurationTextArea.fromJson(config) 102 | else if (config[_typeKey] == 103 | AlfredUserConfigurationType.checkBox.toString()) 104 | AlfredUserConfigurationCheckBox.fromJson(config) 105 | else if (config[_typeKey] == 106 | AlfredUserConfigurationType.select.toString()) 107 | AlfredUserConfigurationSelect.fromJson(config) 108 | else if (config[_typeKey] == 109 | AlfredUserConfigurationType.filePicker.toString()) 110 | AlfredUserConfigurationFilePicker.fromJson(config) 111 | else if (config[_typeKey] == 112 | AlfredUserConfigurationType.slider.toString()) 113 | AlfredUserConfigurationNumberSlider.fromJson(config) 114 | ]) 115 | item.variable: item, 116 | }; 117 | 118 | static Map _mapUserDefaults(Map prefs) => { 119 | for (final MapEntry pref in prefs.entries) 120 | pref.key.toString(): pref.value, 121 | }; 122 | } 123 | -------------------------------------------------------------------------------- /lib/src/mixins/delegating_items_list_mixin.dart: -------------------------------------------------------------------------------- 1 | import 'dart:math' as math; 2 | 3 | /// A mixin that delegates common list operations to an underlying [List]. 4 | /// 5 | /// Classes that mix in [DelegatingItemsListMixin] must provide an implementation 6 | /// for the abstract [items] getter. The mixin exposes standard list operations 7 | /// (such as indexing, addition, removal, range operations, sorting, etc.) by delegating 8 | /// them to the underlying [items]. This enables code reuse for any class that manages a list. 9 | /// 10 | /// Example: 11 | /// ```dart 12 | /// class MyList with DelegatingItemsListMixin { 13 | /// @override 14 | /// final List items = []; 15 | /// } 16 | /// ``` 17 | mixin DelegatingItemsListMixin { 18 | abstract final List items; 19 | 20 | E operator [](int index) => items[index]; 21 | 22 | void operator []=(int index, E value) { 23 | items[index] = value; 24 | } 25 | 26 | List operator +(List other) => items + other; 27 | 28 | void add(E value) { 29 | items.add(value); 30 | } 31 | 32 | void addAll(Iterable iterable) { 33 | items.addAll(iterable); 34 | } 35 | 36 | Map asMap() => items.asMap(); 37 | 38 | List cast() => items.cast(); 39 | 40 | void clear() { 41 | items.clear(); 42 | } 43 | 44 | void fillRange(int start, int end, [E? fillValue]) { 45 | items.fillRange(start, end, fillValue); 46 | } 47 | 48 | set first(E value) { 49 | if (items.isEmpty) throw RangeError.index(0, this); 50 | this[0] = value; 51 | } 52 | 53 | Iterable getRange(int start, int end) => items.getRange(start, end); 54 | 55 | int indexOf(E element, [int start = 0]) => items.indexOf(element, start); 56 | 57 | int indexWhere(bool Function(E) test, [int start = 0]) => 58 | items.indexWhere(test, start); 59 | 60 | void insert(int index, E element) { 61 | items.insert(index, element); 62 | } 63 | 64 | void insertAll(int index, Iterable iterable) { 65 | items.insertAll(index, iterable); 66 | } 67 | 68 | set last(E value) { 69 | if (items.isEmpty) throw RangeError.index(0, this); 70 | this[items.length - 1] = value; 71 | } 72 | 73 | int lastIndexOf(E element, [int? start]) => items.lastIndexOf(element, start); 74 | 75 | int lastIndexWhere(bool Function(E) test, [int? start]) => 76 | items.lastIndexWhere(test, start); 77 | 78 | set length(int newLength) { 79 | items.length = newLength; 80 | } 81 | 82 | bool remove(Object? value) => items.remove(value); 83 | 84 | E removeAt(int index) => items.removeAt(index); 85 | 86 | E removeLast() => items.removeLast(); 87 | 88 | void removeRange(int start, int end) { 89 | items.removeRange(start, end); 90 | } 91 | 92 | void removeWhere(bool Function(E) test) { 93 | items.removeWhere(test); 94 | } 95 | 96 | void replaceRange(int start, int end, Iterable iterable) { 97 | items.replaceRange(start, end, iterable); 98 | } 99 | 100 | void retainWhere(bool Function(E) test) { 101 | items.retainWhere(test); 102 | } 103 | 104 | Iterable get reversed => items.reversed; 105 | 106 | void setAll(int index, Iterable iterable) { 107 | items.setAll(index, iterable); 108 | } 109 | 110 | void setRange(int start, int end, Iterable iterable, [int skipCount = 0]) { 111 | items.setRange(start, end, iterable, skipCount); 112 | } 113 | 114 | void shuffle([math.Random? random]) { 115 | items.shuffle(random); 116 | } 117 | 118 | void sort([int Function(E, E)? compare]) { 119 | items.sort(compare); 120 | } 121 | 122 | List sublist(int start, [int? end]) => items.sublist(start, end); 123 | 124 | bool any(bool Function(E) test) => items.any(test); 125 | 126 | bool contains(Object? element) => items.contains(element); 127 | 128 | E elementAt(int index) => items.elementAt(index); 129 | 130 | bool every(bool Function(E) test) => items.every(test); 131 | 132 | Iterable expand(Iterable Function(E) f) => items.expand(f); 133 | 134 | E get first => items.first; 135 | 136 | E firstWhere(bool Function(E) test, {E Function()? orElse}) => 137 | items.firstWhere(test, orElse: orElse); 138 | 139 | T fold(T initialValue, T Function(T previousValue, E element) combine) => 140 | items.fold(initialValue, combine); 141 | 142 | Iterable followedBy(Iterable other) => items.followedBy(other); 143 | 144 | void forEach(void Function(E) f) => items.forEach(f); 145 | 146 | bool get isEmpty => items.isEmpty; 147 | 148 | bool get isNotEmpty => items.isNotEmpty; 149 | 150 | Iterator get iterator => items.iterator; 151 | 152 | String join([String separator = '']) => items.join(separator); 153 | 154 | E get last => items.last; 155 | 156 | E lastWhere(bool Function(E) test, {E Function()? orElse}) => 157 | items.lastWhere(test, orElse: orElse); 158 | 159 | int get length => items.length; 160 | 161 | Iterable map(T Function(E) f) => items.map(f); 162 | 163 | E reduce(E Function(E value, E element) combine) => items.reduce(combine); 164 | 165 | E get single => items.single; 166 | 167 | E singleWhere(bool Function(E) test, {E Function()? orElse}) { 168 | return items.singleWhere(test, orElse: orElse); 169 | } 170 | 171 | Iterable skip(int n) => items.skip(n); 172 | 173 | Iterable skipWhile(bool Function(E) test) => items.skipWhile(test); 174 | 175 | Iterable take(int n) => items.take(n); 176 | 177 | Iterable takeWhile(bool Function(E) test) => items.takeWhile(test); 178 | 179 | List toList({bool growable = true}) => items.toList(growable: growable); 180 | 181 | Set toSet() => items.toSet(); 182 | 183 | Iterable where(bool Function(E) test) => items.where(test); 184 | 185 | Iterable whereType() => items.whereType(); 186 | } 187 | -------------------------------------------------------------------------------- /lib/src/models/alfred_action.dart: -------------------------------------------------------------------------------- 1 | import 'package:copy_with_extension/copy_with_extension.dart'; 2 | import 'package:equatable/equatable.dart'; 3 | import 'package:json_annotation/json_annotation.dart'; 4 | 5 | part 'alfred_action.g.dart'; 6 | 7 | /// https://www.alfredapp.com/help/features/universal-actions/ 8 | @CopyWith() 9 | @JsonSerializable() 10 | final class AlfredAction with EquatableMixin { 11 | const AlfredAction({ 12 | this.text, 13 | this.url, 14 | this.file, 15 | this.auto, 16 | }) : assert( 17 | !(text == null && url == null && file == null && auto == null), 18 | 'At least one of text, url, file or auto must be provided.', 19 | ), 20 | assert( 21 | text == null || (text is String || text is Iterable), 22 | 'Text must be a String or Iterable.', 23 | ); 24 | 25 | final dynamic text; 26 | final Uri? url; 27 | final String? file; 28 | final String? auto; 29 | 30 | factory AlfredAction.fromJson(Map json) => 31 | _$AlfredActionFromJson(json); 32 | 33 | Map toJson() => _$AlfredActionToJson(this); 34 | 35 | @override 36 | List get props => _$props; 37 | } 38 | -------------------------------------------------------------------------------- /lib/src/models/alfred_action.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'alfred_action.dart'; 4 | 5 | // ************************************************************************** 6 | // CopyWithGenerator 7 | // ************************************************************************** 8 | 9 | abstract class _$AlfredActionCWProxy { 10 | AlfredAction text(dynamic text); 11 | 12 | AlfredAction url(Uri? url); 13 | 14 | AlfredAction file(String? file); 15 | 16 | AlfredAction auto(String? auto); 17 | 18 | /// This function **does support** nullification of nullable fields. All `null` values passed to `non-nullable` fields will be ignored. You can also use `AlfredAction(...).copyWith.fieldName(...)` to override fields one at a time with nullification support. 19 | /// 20 | /// Usage 21 | /// ```dart 22 | /// AlfredAction(...).copyWith(id: 12, name: "My name") 23 | /// ```` 24 | AlfredAction call({ 25 | dynamic text, 26 | Uri? url, 27 | String? file, 28 | String? auto, 29 | }); 30 | } 31 | 32 | /// Proxy class for `copyWith` functionality. This is a callable class and can be used as follows: `instanceOfAlfredAction.copyWith(...)`. Additionally contains functions for specific fields e.g. `instanceOfAlfredAction.copyWith.fieldName(...)` 33 | class _$AlfredActionCWProxyImpl implements _$AlfredActionCWProxy { 34 | const _$AlfredActionCWProxyImpl(this._value); 35 | 36 | final AlfredAction _value; 37 | 38 | @override 39 | AlfredAction text(dynamic text) => this(text: text); 40 | 41 | @override 42 | AlfredAction url(Uri? url) => this(url: url); 43 | 44 | @override 45 | AlfredAction file(String? file) => this(file: file); 46 | 47 | @override 48 | AlfredAction auto(String? auto) => this(auto: auto); 49 | 50 | @override 51 | 52 | /// This function **does support** nullification of nullable fields. All `null` values passed to `non-nullable` fields will be ignored. You can also use `AlfredAction(...).copyWith.fieldName(...)` to override fields one at a time with nullification support. 53 | /// 54 | /// Usage 55 | /// ```dart 56 | /// AlfredAction(...).copyWith(id: 12, name: "My name") 57 | /// ```` 58 | AlfredAction call({ 59 | Object? text = const $CopyWithPlaceholder(), 60 | Object? url = const $CopyWithPlaceholder(), 61 | Object? file = const $CopyWithPlaceholder(), 62 | Object? auto = const $CopyWithPlaceholder(), 63 | }) { 64 | return AlfredAction( 65 | text: text == const $CopyWithPlaceholder() 66 | ? _value.text 67 | // ignore: cast_nullable_to_non_nullable 68 | : text as dynamic, 69 | url: url == const $CopyWithPlaceholder() 70 | ? _value.url 71 | // ignore: cast_nullable_to_non_nullable 72 | : url as Uri?, 73 | file: file == const $CopyWithPlaceholder() 74 | ? _value.file 75 | // ignore: cast_nullable_to_non_nullable 76 | : file as String?, 77 | auto: auto == const $CopyWithPlaceholder() 78 | ? _value.auto 79 | // ignore: cast_nullable_to_non_nullable 80 | : auto as String?, 81 | ); 82 | } 83 | } 84 | 85 | extension $AlfredActionCopyWith on AlfredAction { 86 | /// Returns a callable class that can be used as follows: `instanceOfAlfredAction.copyWith(...)` or like so:`instanceOfAlfredAction.copyWith.fieldName(...)`. 87 | // ignore: library_private_types_in_public_api 88 | _$AlfredActionCWProxy get copyWith => _$AlfredActionCWProxyImpl(this); 89 | } 90 | 91 | // ************************************************************************** 92 | // EquatableGenerator 93 | // ************************************************************************** 94 | 95 | extension _$AlfredActionEquatableAnnotations on AlfredAction { 96 | List get _$props => [text, url, file, auto]; 97 | } 98 | 99 | // ************************************************************************** 100 | // JsonSerializableGenerator 101 | // ************************************************************************** 102 | 103 | AlfredAction _$AlfredActionFromJson(Map json) => AlfredAction( 104 | text: json['text'], 105 | url: json['url'] == null ? null : Uri.parse(json['url'] as String), 106 | file: json['file'] as String?, 107 | auto: json['auto'] as String?, 108 | ); 109 | 110 | Map _$AlfredActionToJson(AlfredAction instance) => 111 | { 112 | 'text': instance.text, 113 | 'url': instance.url?.toString(), 114 | 'file': instance.file, 115 | 'auto': instance.auto, 116 | }; 117 | -------------------------------------------------------------------------------- /lib/src/models/alfred_automatic_cache.dart: -------------------------------------------------------------------------------- 1 | import 'package:copy_with_extension/copy_with_extension.dart'; 2 | import 'package:equatable/equatable.dart'; 3 | import 'package:json_annotation/json_annotation.dart'; 4 | 5 | part 'alfred_automatic_cache.g.dart'; 6 | 7 | /// https://www.alfredapp.com/help/workflows/inputs/script-filter/json/#cache 8 | @CopyWith() 9 | @JsonSerializable( 10 | createFactory: false, 11 | includeIfNull: false, 12 | ignoreUnannotated: true, 13 | ) 14 | class AlfredAutomaticCache with EquatableMixin { 15 | const AlfredAutomaticCache({ 16 | required this.seconds, 17 | this.looseReload, 18 | }) : assert( 19 | seconds >= minSeconds && seconds <= maxSeconds, 20 | 'Time to live for cached data must be between $minSeconds and $maxSeconds seconds (24 hours).', 21 | ); 22 | 23 | /// Time to live for cached data is defined as a number of seconds between 5 and 86400 (i.e. 24 hours). 24 | @JsonKey(name: 'seconds') 25 | final int seconds; 26 | 27 | /// The optional loosereload key asks the Script Filter to try to show any cached data first. 28 | /// If it's determined to be stale, the script runs in the background and replaces results 29 | /// with the new data when it becomes available. 30 | @JsonKey(name: 'loosereload') 31 | final bool? looseReload; 32 | 33 | /// The minimum value for the cache duration. 34 | static const int minSeconds = 5; 35 | 36 | /// The maximum value for the cache duration. 37 | static const int maxSeconds = 86400; 38 | 39 | Map toJson() => _$AlfredAutomaticCacheToJson(this); 40 | 41 | @override 42 | List get props => _$props; 43 | } 44 | -------------------------------------------------------------------------------- /lib/src/models/alfred_automatic_cache.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'alfred_automatic_cache.dart'; 4 | 5 | // ************************************************************************** 6 | // CopyWithGenerator 7 | // ************************************************************************** 8 | 9 | abstract class _$AlfredAutomaticCacheCWProxy { 10 | AlfredAutomaticCache seconds(int seconds); 11 | 12 | AlfredAutomaticCache looseReload(bool? looseReload); 13 | 14 | /// This function **does support** nullification of nullable fields. All `null` values passed to `non-nullable` fields will be ignored. You can also use `AlfredAutomaticCache(...).copyWith.fieldName(...)` to override fields one at a time with nullification support. 15 | /// 16 | /// Usage 17 | /// ```dart 18 | /// AlfredAutomaticCache(...).copyWith(id: 12, name: "My name") 19 | /// ```` 20 | AlfredAutomaticCache call({ 21 | int seconds, 22 | bool? looseReload, 23 | }); 24 | } 25 | 26 | /// Proxy class for `copyWith` functionality. This is a callable class and can be used as follows: `instanceOfAlfredAutomaticCache.copyWith(...)`. Additionally contains functions for specific fields e.g. `instanceOfAlfredAutomaticCache.copyWith.fieldName(...)` 27 | class _$AlfredAutomaticCacheCWProxyImpl 28 | implements _$AlfredAutomaticCacheCWProxy { 29 | const _$AlfredAutomaticCacheCWProxyImpl(this._value); 30 | 31 | final AlfredAutomaticCache _value; 32 | 33 | @override 34 | AlfredAutomaticCache seconds(int seconds) => this(seconds: seconds); 35 | 36 | @override 37 | AlfredAutomaticCache looseReload(bool? looseReload) => 38 | this(looseReload: looseReload); 39 | 40 | @override 41 | 42 | /// This function **does support** nullification of nullable fields. All `null` values passed to `non-nullable` fields will be ignored. You can also use `AlfredAutomaticCache(...).copyWith.fieldName(...)` to override fields one at a time with nullification support. 43 | /// 44 | /// Usage 45 | /// ```dart 46 | /// AlfredAutomaticCache(...).copyWith(id: 12, name: "My name") 47 | /// ```` 48 | AlfredAutomaticCache call({ 49 | Object? seconds = const $CopyWithPlaceholder(), 50 | Object? looseReload = const $CopyWithPlaceholder(), 51 | }) { 52 | return AlfredAutomaticCache( 53 | seconds: seconds == const $CopyWithPlaceholder() 54 | ? _value.seconds 55 | // ignore: cast_nullable_to_non_nullable 56 | : seconds as int, 57 | looseReload: looseReload == const $CopyWithPlaceholder() 58 | ? _value.looseReload 59 | // ignore: cast_nullable_to_non_nullable 60 | : looseReload as bool?, 61 | ); 62 | } 63 | } 64 | 65 | extension $AlfredAutomaticCacheCopyWith on AlfredAutomaticCache { 66 | /// Returns a callable class that can be used as follows: `instanceOfAlfredAutomaticCache.copyWith(...)` or like so:`instanceOfAlfredAutomaticCache.copyWith.fieldName(...)`. 67 | // ignore: library_private_types_in_public_api 68 | _$AlfredAutomaticCacheCWProxy get copyWith => 69 | _$AlfredAutomaticCacheCWProxyImpl(this); 70 | } 71 | 72 | // ************************************************************************** 73 | // EquatableGenerator 74 | // ************************************************************************** 75 | 76 | extension _$AlfredAutomaticCacheEquatableAnnotations on AlfredAutomaticCache { 77 | List get _$props => [seconds, looseReload]; 78 | } 79 | 80 | // ************************************************************************** 81 | // JsonSerializableGenerator 82 | // ************************************************************************** 83 | 84 | Map _$AlfredAutomaticCacheToJson( 85 | AlfredAutomaticCache instance) => 86 | { 87 | 'seconds': instance.seconds, 88 | if (instance.looseReload case final value?) 'loosereload': value, 89 | }; 90 | -------------------------------------------------------------------------------- /lib/src/models/alfred_item_icon.dart: -------------------------------------------------------------------------------- 1 | import 'package:copy_with_extension/copy_with_extension.dart'; 2 | import 'package:equatable/equatable.dart' show EquatableMixin; 3 | import 'package:json_annotation/json_annotation.dart'; 4 | 5 | part 'alfred_item_icon.g.dart'; 6 | 7 | enum AlfredItemIconType { 8 | @JsonValue('fileicon') 9 | fileicon, 10 | @JsonValue('filetype') 11 | filetype, 12 | } 13 | 14 | /// The icon displayed in the result row. 15 | /// 16 | /// Workflows are run from their workflow folder, so you can reference icons stored in your workflow relatively. 17 | @CopyWith() 18 | @JsonSerializable() 19 | final class AlfredItemIcon with EquatableMixin { 20 | const AlfredItemIcon({ 21 | required this.path, 22 | this.type, 23 | }); 24 | 25 | /// The local file path of the icon file. 26 | /// 27 | /// Alfred will not display an icon with a URL [path]. 28 | @JsonKey(required: true) 29 | final String path; 30 | 31 | /// By omitting the [type], Alfred will load the file path itself, for example a png. 32 | /// 33 | /// By using [type] = "fileicon", Alfred will get the icon for the specified path. 34 | /// Finally, by using [type] = "filetype", you can get the icon of a specific file, for example [path] = "public.png" 35 | @JsonKey(includeIfNull: false) 36 | final AlfredItemIconType? type; 37 | 38 | factory AlfredItemIcon.fromJson(Map json) => 39 | _$AlfredItemIconFromJson(json); 40 | 41 | Map toJson() => _$AlfredItemIconToJson(this); 42 | 43 | @override 44 | List get props => _$props; 45 | } 46 | -------------------------------------------------------------------------------- /lib/src/models/alfred_item_icon.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'alfred_item_icon.dart'; 4 | 5 | // ************************************************************************** 6 | // CopyWithGenerator 7 | // ************************************************************************** 8 | 9 | abstract class _$AlfredItemIconCWProxy { 10 | AlfredItemIcon path(String path); 11 | 12 | AlfredItemIcon type(AlfredItemIconType? type); 13 | 14 | /// This function **does support** nullification of nullable fields. All `null` values passed to `non-nullable` fields will be ignored. You can also use `AlfredItemIcon(...).copyWith.fieldName(...)` to override fields one at a time with nullification support. 15 | /// 16 | /// Usage 17 | /// ```dart 18 | /// AlfredItemIcon(...).copyWith(id: 12, name: "My name") 19 | /// ```` 20 | AlfredItemIcon call({ 21 | String path, 22 | AlfredItemIconType? type, 23 | }); 24 | } 25 | 26 | /// Proxy class for `copyWith` functionality. This is a callable class and can be used as follows: `instanceOfAlfredItemIcon.copyWith(...)`. Additionally contains functions for specific fields e.g. `instanceOfAlfredItemIcon.copyWith.fieldName(...)` 27 | class _$AlfredItemIconCWProxyImpl implements _$AlfredItemIconCWProxy { 28 | const _$AlfredItemIconCWProxyImpl(this._value); 29 | 30 | final AlfredItemIcon _value; 31 | 32 | @override 33 | AlfredItemIcon path(String path) => this(path: path); 34 | 35 | @override 36 | AlfredItemIcon type(AlfredItemIconType? type) => this(type: type); 37 | 38 | @override 39 | 40 | /// This function **does support** nullification of nullable fields. All `null` values passed to `non-nullable` fields will be ignored. You can also use `AlfredItemIcon(...).copyWith.fieldName(...)` to override fields one at a time with nullification support. 41 | /// 42 | /// Usage 43 | /// ```dart 44 | /// AlfredItemIcon(...).copyWith(id: 12, name: "My name") 45 | /// ```` 46 | AlfredItemIcon call({ 47 | Object? path = const $CopyWithPlaceholder(), 48 | Object? type = const $CopyWithPlaceholder(), 49 | }) { 50 | return AlfredItemIcon( 51 | path: path == const $CopyWithPlaceholder() 52 | ? _value.path 53 | // ignore: cast_nullable_to_non_nullable 54 | : path as String, 55 | type: type == const $CopyWithPlaceholder() 56 | ? _value.type 57 | // ignore: cast_nullable_to_non_nullable 58 | : type as AlfredItemIconType?, 59 | ); 60 | } 61 | } 62 | 63 | extension $AlfredItemIconCopyWith on AlfredItemIcon { 64 | /// Returns a callable class that can be used as follows: `instanceOfAlfredItemIcon.copyWith(...)` or like so:`instanceOfAlfredItemIcon.copyWith.fieldName(...)`. 65 | // ignore: library_private_types_in_public_api 66 | _$AlfredItemIconCWProxy get copyWith => _$AlfredItemIconCWProxyImpl(this); 67 | } 68 | 69 | // ************************************************************************** 70 | // EquatableGenerator 71 | // ************************************************************************** 72 | 73 | extension _$AlfredItemIconEquatableAnnotations on AlfredItemIcon { 74 | List get _$props => [path, type]; 75 | } 76 | 77 | // ************************************************************************** 78 | // JsonSerializableGenerator 79 | // ************************************************************************** 80 | 81 | AlfredItemIcon _$AlfredItemIconFromJson(Map json) { 82 | $checkKeys( 83 | json, 84 | requiredKeys: const ['path'], 85 | ); 86 | return AlfredItemIcon( 87 | path: json['path'] as String, 88 | type: $enumDecodeNullable(_$AlfredItemIconTypeEnumMap, json['type']), 89 | ); 90 | } 91 | 92 | Map _$AlfredItemIconToJson(AlfredItemIcon instance) => 93 | { 94 | 'path': instance.path, 95 | if (_$AlfredItemIconTypeEnumMap[instance.type] case final value?) 96 | 'type': value, 97 | }; 98 | 99 | const _$AlfredItemIconTypeEnumMap = { 100 | AlfredItemIconType.fileicon: 'fileicon', 101 | AlfredItemIconType.filetype: 'filetype', 102 | }; 103 | -------------------------------------------------------------------------------- /lib/src/models/alfred_item_mod.dart: -------------------------------------------------------------------------------- 1 | import 'package:alfred_workflow/src/models/alfred_item_icon.dart'; 2 | import 'package:copy_with_extension/copy_with_extension.dart'; 3 | import 'package:equatable/equatable.dart'; 4 | import 'package:json_annotation/json_annotation.dart'; 5 | 6 | part 'alfred_item_mod.g.dart'; 7 | 8 | enum AlfredItemModKey { 9 | @JsonValue('cmd') 10 | cmd, 11 | @JsonValue('ctrl') 12 | ctrl, 13 | @JsonValue('alt') 14 | alt, 15 | @JsonValue('shift') 16 | shift, 17 | @JsonValue('fn') 18 | fn, 19 | } 20 | 21 | /// The [AlfredItemMod] gives you control over how the modifier keys react. 22 | /// 23 | /// It can alter the looks of a result (e.g. [subtitle], [icon]) and output a different [arg]. 24 | @CopyWith() 25 | @JsonSerializable(explicitToJson: true) 26 | final class AlfredItemMod with EquatableMixin { 27 | const AlfredItemMod({ 28 | this.arg, 29 | this.subtitle, 30 | this.icon, 31 | this.valid = true, 32 | }); 33 | 34 | /// The argument which is passed through the workflow to the connected output action. 35 | @JsonKey(includeIfNull: false) 36 | final String? arg; 37 | 38 | /// The [subtitle] displayed in the result row. This element is optional. 39 | @JsonKey(includeIfNull: false) 40 | final String? subtitle; 41 | 42 | /// The [icon] displayed in the result row. 43 | @JsonKey(fromJson: _iconFromJson, includeIfNull: false) 44 | final AlfredItemIcon? icon; 45 | 46 | /// [valid] : true | false (optional, default = false) 47 | final bool valid; 48 | 49 | factory AlfredItemMod.fromJson(Map json) => 50 | _$AlfredItemModFromJson(json); 51 | 52 | Map toJson() => _$AlfredItemModToJson(this); 53 | 54 | static AlfredItemIcon? _iconFromJson(dynamic icon) => icon == null 55 | ? null 56 | : AlfredItemIcon.fromJson(Map.from(icon)); 57 | 58 | @override 59 | List get props => _$props; 60 | } 61 | -------------------------------------------------------------------------------- /lib/src/models/alfred_item_mod.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'alfred_item_mod.dart'; 4 | 5 | // ************************************************************************** 6 | // CopyWithGenerator 7 | // ************************************************************************** 8 | 9 | abstract class _$AlfredItemModCWProxy { 10 | AlfredItemMod arg(String? arg); 11 | 12 | AlfredItemMod subtitle(String? subtitle); 13 | 14 | AlfredItemMod icon(AlfredItemIcon? icon); 15 | 16 | AlfredItemMod valid(bool valid); 17 | 18 | /// This function **does support** nullification of nullable fields. All `null` values passed to `non-nullable` fields will be ignored. You can also use `AlfredItemMod(...).copyWith.fieldName(...)` to override fields one at a time with nullification support. 19 | /// 20 | /// Usage 21 | /// ```dart 22 | /// AlfredItemMod(...).copyWith(id: 12, name: "My name") 23 | /// ```` 24 | AlfredItemMod call({ 25 | String? arg, 26 | String? subtitle, 27 | AlfredItemIcon? icon, 28 | bool valid, 29 | }); 30 | } 31 | 32 | /// Proxy class for `copyWith` functionality. This is a callable class and can be used as follows: `instanceOfAlfredItemMod.copyWith(...)`. Additionally contains functions for specific fields e.g. `instanceOfAlfredItemMod.copyWith.fieldName(...)` 33 | class _$AlfredItemModCWProxyImpl implements _$AlfredItemModCWProxy { 34 | const _$AlfredItemModCWProxyImpl(this._value); 35 | 36 | final AlfredItemMod _value; 37 | 38 | @override 39 | AlfredItemMod arg(String? arg) => this(arg: arg); 40 | 41 | @override 42 | AlfredItemMod subtitle(String? subtitle) => this(subtitle: subtitle); 43 | 44 | @override 45 | AlfredItemMod icon(AlfredItemIcon? icon) => this(icon: icon); 46 | 47 | @override 48 | AlfredItemMod valid(bool valid) => this(valid: valid); 49 | 50 | @override 51 | 52 | /// This function **does support** nullification of nullable fields. All `null` values passed to `non-nullable` fields will be ignored. You can also use `AlfredItemMod(...).copyWith.fieldName(...)` to override fields one at a time with nullification support. 53 | /// 54 | /// Usage 55 | /// ```dart 56 | /// AlfredItemMod(...).copyWith(id: 12, name: "My name") 57 | /// ```` 58 | AlfredItemMod call({ 59 | Object? arg = const $CopyWithPlaceholder(), 60 | Object? subtitle = const $CopyWithPlaceholder(), 61 | Object? icon = const $CopyWithPlaceholder(), 62 | Object? valid = const $CopyWithPlaceholder(), 63 | }) { 64 | return AlfredItemMod( 65 | arg: arg == const $CopyWithPlaceholder() 66 | ? _value.arg 67 | // ignore: cast_nullable_to_non_nullable 68 | : arg as String?, 69 | subtitle: subtitle == const $CopyWithPlaceholder() 70 | ? _value.subtitle 71 | // ignore: cast_nullable_to_non_nullable 72 | : subtitle as String?, 73 | icon: icon == const $CopyWithPlaceholder() 74 | ? _value.icon 75 | // ignore: cast_nullable_to_non_nullable 76 | : icon as AlfredItemIcon?, 77 | valid: valid == const $CopyWithPlaceholder() 78 | ? _value.valid 79 | // ignore: cast_nullable_to_non_nullable 80 | : valid as bool, 81 | ); 82 | } 83 | } 84 | 85 | extension $AlfredItemModCopyWith on AlfredItemMod { 86 | /// Returns a callable class that can be used as follows: `instanceOfAlfredItemMod.copyWith(...)` or like so:`instanceOfAlfredItemMod.copyWith.fieldName(...)`. 87 | // ignore: library_private_types_in_public_api 88 | _$AlfredItemModCWProxy get copyWith => _$AlfredItemModCWProxyImpl(this); 89 | } 90 | 91 | // ************************************************************************** 92 | // EquatableGenerator 93 | // ************************************************************************** 94 | 95 | extension _$AlfredItemModEquatableAnnotations on AlfredItemMod { 96 | List get _$props => [arg, subtitle, icon, valid]; 97 | } 98 | 99 | // ************************************************************************** 100 | // JsonSerializableGenerator 101 | // ************************************************************************** 102 | 103 | AlfredItemMod _$AlfredItemModFromJson(Map json) => 104 | AlfredItemMod( 105 | arg: json['arg'] as String?, 106 | subtitle: json['subtitle'] as String?, 107 | icon: AlfredItemMod._iconFromJson(json['icon']), 108 | valid: json['valid'] as bool? ?? true, 109 | ); 110 | 111 | Map _$AlfredItemModToJson(AlfredItemMod instance) => 112 | { 113 | if (instance.arg case final value?) 'arg': value, 114 | if (instance.subtitle case final value?) 'subtitle': value, 115 | if (instance.icon?.toJson() case final value?) 'icon': value, 116 | 'valid': instance.valid, 117 | }; 118 | -------------------------------------------------------------------------------- /lib/src/models/alfred_item_text.dart: -------------------------------------------------------------------------------- 1 | import 'package:copy_with_extension/copy_with_extension.dart'; 2 | import 'package:equatable/equatable.dart' show EquatableMixin; 3 | import 'package:json_annotation/json_annotation.dart'; 4 | 5 | part 'alfred_item_text.g.dart'; 6 | 7 | /// The text element defines the text the user will get when copying the selected result row with ⌘C or displaying large type with ⌘L. 8 | /// 9 | /// If these are not defined, you will inherit Alfred's standard behaviour where the arg is copied to the Clipboard or used for Large Type. 10 | @CopyWith() 11 | @JsonSerializable() 12 | final class AlfredItemText with EquatableMixin { 13 | const AlfredItemText({ 14 | required this.copy, 15 | this.largeType, 16 | }); 17 | 18 | /// The text to copy 19 | @JsonKey(required: true) 20 | final String copy; 21 | 22 | /// The text for large type 23 | @JsonKey(name: 'largetype', includeIfNull: false) 24 | final String? largeType; 25 | 26 | factory AlfredItemText.fromJson(Map json) => 27 | _$AlfredItemTextFromJson(json); 28 | 29 | Map toJson() => _$AlfredItemTextToJson(this); 30 | 31 | @override 32 | List get props => _$props; 33 | } 34 | -------------------------------------------------------------------------------- /lib/src/models/alfred_item_text.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'alfred_item_text.dart'; 4 | 5 | // ************************************************************************** 6 | // CopyWithGenerator 7 | // ************************************************************************** 8 | 9 | abstract class _$AlfredItemTextCWProxy { 10 | AlfredItemText copy(String copy); 11 | 12 | AlfredItemText largeType(String? largeType); 13 | 14 | /// This function **does support** nullification of nullable fields. All `null` values passed to `non-nullable` fields will be ignored. You can also use `AlfredItemText(...).copyWith.fieldName(...)` to override fields one at a time with nullification support. 15 | /// 16 | /// Usage 17 | /// ```dart 18 | /// AlfredItemText(...).copyWith(id: 12, name: "My name") 19 | /// ```` 20 | AlfredItemText call({ 21 | String copy, 22 | String? largeType, 23 | }); 24 | } 25 | 26 | /// Proxy class for `copyWith` functionality. This is a callable class and can be used as follows: `instanceOfAlfredItemText.copyWith(...)`. Additionally contains functions for specific fields e.g. `instanceOfAlfredItemText.copyWith.fieldName(...)` 27 | class _$AlfredItemTextCWProxyImpl implements _$AlfredItemTextCWProxy { 28 | const _$AlfredItemTextCWProxyImpl(this._value); 29 | 30 | final AlfredItemText _value; 31 | 32 | @override 33 | AlfredItemText copy(String copy) => this(copy: copy); 34 | 35 | @override 36 | AlfredItemText largeType(String? largeType) => this(largeType: largeType); 37 | 38 | @override 39 | 40 | /// This function **does support** nullification of nullable fields. All `null` values passed to `non-nullable` fields will be ignored. You can also use `AlfredItemText(...).copyWith.fieldName(...)` to override fields one at a time with nullification support. 41 | /// 42 | /// Usage 43 | /// ```dart 44 | /// AlfredItemText(...).copyWith(id: 12, name: "My name") 45 | /// ```` 46 | AlfredItemText call({ 47 | Object? copy = const $CopyWithPlaceholder(), 48 | Object? largeType = const $CopyWithPlaceholder(), 49 | }) { 50 | return AlfredItemText( 51 | copy: copy == const $CopyWithPlaceholder() 52 | ? _value.copy 53 | // ignore: cast_nullable_to_non_nullable 54 | : copy as String, 55 | largeType: largeType == const $CopyWithPlaceholder() 56 | ? _value.largeType 57 | // ignore: cast_nullable_to_non_nullable 58 | : largeType as String?, 59 | ); 60 | } 61 | } 62 | 63 | extension $AlfredItemTextCopyWith on AlfredItemText { 64 | /// Returns a callable class that can be used as follows: `instanceOfAlfredItemText.copyWith(...)` or like so:`instanceOfAlfredItemText.copyWith.fieldName(...)`. 65 | // ignore: library_private_types_in_public_api 66 | _$AlfredItemTextCWProxy get copyWith => _$AlfredItemTextCWProxyImpl(this); 67 | } 68 | 69 | // ************************************************************************** 70 | // EquatableGenerator 71 | // ************************************************************************** 72 | 73 | extension _$AlfredItemTextEquatableAnnotations on AlfredItemText { 74 | List get _$props => [copy, largeType]; 75 | } 76 | 77 | // ************************************************************************** 78 | // JsonSerializableGenerator 79 | // ************************************************************************** 80 | 81 | AlfredItemText _$AlfredItemTextFromJson(Map json) { 82 | $checkKeys( 83 | json, 84 | requiredKeys: const ['copy'], 85 | ); 86 | return AlfredItemText( 87 | copy: json['copy'] as String, 88 | largeType: json['largetype'] as String?, 89 | ); 90 | } 91 | 92 | Map _$AlfredItemTextToJson(AlfredItemText instance) => 93 | { 94 | 'copy': instance.copy, 95 | if (instance.largeType case final value?) 'largetype': value, 96 | }; 97 | -------------------------------------------------------------------------------- /lib/src/models/alfred_items.dart: -------------------------------------------------------------------------------- 1 | import 'package:alfred_workflow/src/mixins/delegating_items_list_mixin.dart'; 2 | import 'package:alfred_workflow/src/models/alfred_automatic_cache.dart'; 3 | import 'package:equatable/equatable.dart' show EquatableMixin; 4 | 5 | import 'alfred_item.dart'; 6 | 7 | part 'alfred_items.g.dart'; 8 | 9 | final class AlfredItems 10 | with EquatableMixin, DelegatingItemsListMixin { 11 | const AlfredItems( 12 | this.items, { 13 | this.exactOrder, 14 | this.skipKnowledge, 15 | this.cache, 16 | }); 17 | 18 | /// A list of zero or more [AlfredItem]s. 19 | /// 20 | /// Each [AlfredItem] describes a result row displayed in Alfred. 21 | @override 22 | final List items; 23 | 24 | /// Alfred learns to prioritise item results like he learns any other, meaning 25 | /// the order in which your workflow results are presented will be based on Alfred's 26 | /// knowledge (using the item UID) and not the order your script returns the items. 27 | /// 28 | /// To have Alfred present the items in the exact sequence you define, exclude the UID attribute. 29 | final bool? exactOrder; 30 | 31 | /// This preserves the given item order while allowing Alfred to retain 32 | /// knowledge of your items, like your current selection during a re-run. 33 | /// 34 | /// Only available in Alfred 5 35 | final bool? skipKnowledge; 36 | 37 | /// Scripts which take a while to return can cache results so users see data sooner on subsequent runs. 38 | /// The Script Filter presents the results from the previous run when caching is active and hasn't expired. 39 | /// Because the script won't execute when loading cached data, we recommend this option only be used with 40 | /// "Alfred filters results". 41 | /// 42 | /// Only available in Alfred 5.5 43 | final AlfredAutomaticCache? cache; 44 | 45 | factory AlfredItems.fromJson(Map json) => AlfredItems( 46 | (json['items'] as List) 47 | .map((e) => AlfredItem.fromJson(Map.from(e))) 48 | .toList(), 49 | ); 50 | 51 | Map toJson() => { 52 | if (cache != null) 'cache': cache!.toJson(), 53 | if (skipKnowledge != null) 'skipknowledge': skipKnowledge, 54 | 'items': >[ 55 | for (final AlfredItem item in items) 56 | if (exactOrder ?? false) 57 | item.toJson()..remove('uid') 58 | else 59 | item.toJson(), 60 | ], 61 | }; 62 | 63 | @override 64 | List get props => _$props; 65 | 66 | /// Copy this [AlfredItems] with the given [items], [exactOrder], [skipKnowledge], of [cache]. 67 | AlfredItems copyWith({ 68 | List? items, 69 | bool? exactOrder, 70 | bool? skipKnowledge, 71 | AlfredAutomaticCache? cache, 72 | }) => 73 | AlfredItems( 74 | items ?? [...this.items], 75 | skipKnowledge: skipKnowledge ?? this.skipKnowledge, 76 | exactOrder: exactOrder ?? this.exactOrder, 77 | cache: cache ?? this.cache, 78 | ); 79 | } 80 | -------------------------------------------------------------------------------- /lib/src/models/alfred_items.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'alfred_items.dart'; 4 | 5 | // ************************************************************************** 6 | // EquatableGenerator 7 | // ************************************************************************** 8 | 9 | extension _$AlfredItemsEquatableAnnotations on AlfredItems { 10 | List get _$props => [items, exactOrder, skipKnowledge, cache]; 11 | } 12 | -------------------------------------------------------------------------------- /lib/src/models/alfred_user_configuration.dart: -------------------------------------------------------------------------------- 1 | import 'package:alfred_workflow/src/models/alfred_user_configuration_config.dart'; 2 | import 'package:alfred_workflow/src/models/alfred_user_configuration_type.dart'; 3 | import 'package:equatable/equatable.dart'; 4 | import 'package:meta/meta.dart'; 5 | 6 | part 'alfred_user_configuration.g.dart'; 7 | 8 | /// Alfred user configuration generic class 9 | abstract class AlfredUserConfiguration> with EquatableMixin { 11 | const AlfredUserConfiguration({ 12 | required this.type, 13 | required this.variable, 14 | this.description, 15 | this.label, 16 | }); 17 | 18 | /// Type of configuration 19 | final AlfredUserConfigurationType type; 20 | 21 | /// Variable name 22 | final String variable; 23 | 24 | /// Description 25 | final String? description; 26 | 27 | /// Label 28 | final String? label; 29 | 30 | /// [AlfredUserConfigurationConfig] configuration 31 | abstract final Q config; 32 | 33 | /// Default value 34 | T get defaultValue => config.defaultValue; 35 | 36 | /// User set value 37 | T get value => config.value; 38 | 39 | @internal 40 | AlfredUserConfiguration copyWithConfig(Q config); 41 | 42 | @override 43 | List get props => _$props; 44 | } 45 | -------------------------------------------------------------------------------- /lib/src/models/alfred_user_configuration.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'alfred_user_configuration.dart'; 4 | 5 | // ************************************************************************** 6 | // EquatableGenerator 7 | // ************************************************************************** 8 | 9 | extension _$AlfredUserConfigurationEquatableAnnotations 10 | on AlfredUserConfiguration { 11 | List get _$props => [type, variable, description, label, config]; 12 | } 13 | -------------------------------------------------------------------------------- /lib/src/models/alfred_user_configuration_check_box.dart: -------------------------------------------------------------------------------- 1 | import 'package:alfred_workflow/src/models/alfred_user_configuration.dart'; 2 | import 'package:alfred_workflow/src/models/alfred_user_configuration_config_check_box.dart'; 3 | import 'package:alfred_workflow/src/models/alfred_user_configuration_type.dart'; 4 | import 'package:copy_with_extension/copy_with_extension.dart'; 5 | import 'package:equatable/equatable.dart'; 6 | import 'package:json_annotation/json_annotation.dart'; 7 | import 'package:meta/meta.dart'; 8 | 9 | part 'alfred_user_configuration_check_box.g.dart'; 10 | 11 | /// Alfred check box user configuration 12 | @CopyWith() 13 | @JsonSerializable(explicitToJson: true, createToJson: false) 14 | final class AlfredUserConfigurationCheckBox 15 | extends AlfredUserConfiguration 16 | with EquatableMixin { 17 | const AlfredUserConfigurationCheckBox({ 18 | required super.type, 19 | required super.variable, 20 | required this.config, 21 | super.description, 22 | super.label, 23 | }); 24 | 25 | /// The configuration for the check box 26 | @override 27 | @JsonKey(fromJson: _configFromJson) 28 | final AlfredUserConfigurationConfigCheckBox config; 29 | 30 | @internal 31 | @override 32 | AlfredUserConfiguration 33 | copyWithConfig(AlfredUserConfigurationConfigCheckBox config) => 34 | copyWith(config: config); 35 | 36 | static AlfredUserConfigurationConfigCheckBox _configFromJson(Map json) => 37 | AlfredUserConfigurationConfigCheckBox.fromJson( 38 | json.map((k, v) => MapEntry(k.toString(), v)), 39 | ); 40 | 41 | factory AlfredUserConfigurationCheckBox.fromJson(Map json) => 42 | _$AlfredUserConfigurationCheckBoxFromJson( 43 | json.map((k, v) => MapEntry(k.toString(), v)), 44 | ); 45 | } 46 | -------------------------------------------------------------------------------- /lib/src/models/alfred_user_configuration_check_box.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'alfred_user_configuration_check_box.dart'; 4 | 5 | // ************************************************************************** 6 | // CopyWithGenerator 7 | // ************************************************************************** 8 | 9 | abstract class _$AlfredUserConfigurationCheckBoxCWProxy { 10 | AlfredUserConfigurationCheckBox type(AlfredUserConfigurationType type); 11 | 12 | AlfredUserConfigurationCheckBox variable(String variable); 13 | 14 | AlfredUserConfigurationCheckBox config( 15 | AlfredUserConfigurationConfigCheckBox config); 16 | 17 | AlfredUserConfigurationCheckBox description(String? description); 18 | 19 | AlfredUserConfigurationCheckBox label(String? label); 20 | 21 | /// This function **does support** nullification of nullable fields. All `null` values passed to `non-nullable` fields will be ignored. You can also use `AlfredUserConfigurationCheckBox(...).copyWith.fieldName(...)` to override fields one at a time with nullification support. 22 | /// 23 | /// Usage 24 | /// ```dart 25 | /// AlfredUserConfigurationCheckBox(...).copyWith(id: 12, name: "My name") 26 | /// ```` 27 | AlfredUserConfigurationCheckBox call({ 28 | AlfredUserConfigurationType type, 29 | String variable, 30 | AlfredUserConfigurationConfigCheckBox config, 31 | String? description, 32 | String? label, 33 | }); 34 | } 35 | 36 | /// Proxy class for `copyWith` functionality. This is a callable class and can be used as follows: `instanceOfAlfredUserConfigurationCheckBox.copyWith(...)`. Additionally contains functions for specific fields e.g. `instanceOfAlfredUserConfigurationCheckBox.copyWith.fieldName(...)` 37 | class _$AlfredUserConfigurationCheckBoxCWProxyImpl 38 | implements _$AlfredUserConfigurationCheckBoxCWProxy { 39 | const _$AlfredUserConfigurationCheckBoxCWProxyImpl(this._value); 40 | 41 | final AlfredUserConfigurationCheckBox _value; 42 | 43 | @override 44 | AlfredUserConfigurationCheckBox type(AlfredUserConfigurationType type) => 45 | this(type: type); 46 | 47 | @override 48 | AlfredUserConfigurationCheckBox variable(String variable) => 49 | this(variable: variable); 50 | 51 | @override 52 | AlfredUserConfigurationCheckBox config( 53 | AlfredUserConfigurationConfigCheckBox config) => 54 | this(config: config); 55 | 56 | @override 57 | AlfredUserConfigurationCheckBox description(String? description) => 58 | this(description: description); 59 | 60 | @override 61 | AlfredUserConfigurationCheckBox label(String? label) => this(label: label); 62 | 63 | @override 64 | 65 | /// This function **does support** nullification of nullable fields. All `null` values passed to `non-nullable` fields will be ignored. You can also use `AlfredUserConfigurationCheckBox(...).copyWith.fieldName(...)` to override fields one at a time with nullification support. 66 | /// 67 | /// Usage 68 | /// ```dart 69 | /// AlfredUserConfigurationCheckBox(...).copyWith(id: 12, name: "My name") 70 | /// ```` 71 | AlfredUserConfigurationCheckBox call({ 72 | Object? type = const $CopyWithPlaceholder(), 73 | Object? variable = const $CopyWithPlaceholder(), 74 | Object? config = const $CopyWithPlaceholder(), 75 | Object? description = const $CopyWithPlaceholder(), 76 | Object? label = const $CopyWithPlaceholder(), 77 | }) { 78 | return AlfredUserConfigurationCheckBox( 79 | type: type == const $CopyWithPlaceholder() 80 | ? _value.type 81 | // ignore: cast_nullable_to_non_nullable 82 | : type as AlfredUserConfigurationType, 83 | variable: variable == const $CopyWithPlaceholder() 84 | ? _value.variable 85 | // ignore: cast_nullable_to_non_nullable 86 | : variable as String, 87 | config: config == const $CopyWithPlaceholder() 88 | ? _value.config 89 | // ignore: cast_nullable_to_non_nullable 90 | : config as AlfredUserConfigurationConfigCheckBox, 91 | description: description == const $CopyWithPlaceholder() 92 | ? _value.description 93 | // ignore: cast_nullable_to_non_nullable 94 | : description as String?, 95 | label: label == const $CopyWithPlaceholder() 96 | ? _value.label 97 | // ignore: cast_nullable_to_non_nullable 98 | : label as String?, 99 | ); 100 | } 101 | } 102 | 103 | extension $AlfredUserConfigurationCheckBoxCopyWith 104 | on AlfredUserConfigurationCheckBox { 105 | /// Returns a callable class that can be used as follows: `instanceOfAlfredUserConfigurationCheckBox.copyWith(...)` or like so:`instanceOfAlfredUserConfigurationCheckBox.copyWith.fieldName(...)`. 106 | // ignore: library_private_types_in_public_api 107 | _$AlfredUserConfigurationCheckBoxCWProxy get copyWith => 108 | _$AlfredUserConfigurationCheckBoxCWProxyImpl(this); 109 | } 110 | 111 | // ************************************************************************** 112 | // JsonSerializableGenerator 113 | // ************************************************************************** 114 | 115 | AlfredUserConfigurationCheckBox _$AlfredUserConfigurationCheckBoxFromJson( 116 | Map json) => 117 | AlfredUserConfigurationCheckBox( 118 | type: $enumDecode(_$AlfredUserConfigurationTypeEnumMap, json['type']), 119 | variable: json['variable'] as String, 120 | config: AlfredUserConfigurationCheckBox._configFromJson( 121 | json['config'] as Map), 122 | description: json['description'] as String?, 123 | label: json['label'] as String?, 124 | ); 125 | 126 | const _$AlfredUserConfigurationTypeEnumMap = { 127 | AlfredUserConfigurationType.textField: 'textfield', 128 | AlfredUserConfigurationType.textArea: 'textarea', 129 | AlfredUserConfigurationType.checkBox: 'checkbox', 130 | AlfredUserConfigurationType.select: 'popupbutton', 131 | AlfredUserConfigurationType.filePicker: 'filepicker', 132 | AlfredUserConfigurationType.slider: 'slider', 133 | }; 134 | -------------------------------------------------------------------------------- /lib/src/models/alfred_user_configuration_config.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | import 'package:json_annotation/json_annotation.dart'; 3 | import 'package:meta/meta.dart'; 4 | 5 | part 'alfred_user_configuration_config.g.dart'; 6 | 7 | /// Alfred user configuration config generic class 8 | abstract class AlfredUserConfigurationConfig with EquatableMixin { 9 | const AlfredUserConfigurationConfig({ 10 | required this.defaultValue, 11 | T? value, 12 | }) : value = value ?? defaultValue; 13 | 14 | /// Default value 15 | @JsonKey(name: 'default', readValue: fromJsonDefaultValue) 16 | final T defaultValue; 17 | 18 | @internal 19 | static T fromJsonDefaultValue(Map json, String key) => 20 | json['defaultvalue'] as T? ?? json[key] as T; 21 | 22 | /// User set value 23 | @JsonKey(includeFromJson: false, includeToJson: false) 24 | final T value; 25 | 26 | @internal 27 | AlfredUserConfigurationConfig copyWithValue(T? value); 28 | 29 | @override 30 | List get props => _$props; 31 | } 32 | -------------------------------------------------------------------------------- /lib/src/models/alfred_user_configuration_config.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'alfred_user_configuration_config.dart'; 4 | 5 | // ************************************************************************** 6 | // EquatableGenerator 7 | // ************************************************************************** 8 | 9 | extension _$AlfredUserConfigurationConfigEquatableAnnotations 10 | on AlfredUserConfigurationConfig { 11 | List get _$props => [defaultValue, value]; 12 | } 13 | -------------------------------------------------------------------------------- /lib/src/models/alfred_user_configuration_config_check_box.dart: -------------------------------------------------------------------------------- 1 | import 'package:alfred_workflow/src/models/alfred_user_configuration_config.dart'; 2 | import 'package:copy_with_extension/copy_with_extension.dart'; 3 | import 'package:equatable/equatable.dart'; 4 | import 'package:json_annotation/json_annotation.dart'; 5 | import 'package:meta/meta.dart'; 6 | 7 | part 'alfred_user_configuration_config_check_box.g.dart'; 8 | 9 | /// Alfred check box user configuration config 10 | @CopyWith() 11 | @JsonSerializable(explicitToJson: true, createToJson: false) 12 | final class AlfredUserConfigurationConfigCheckBox 13 | extends AlfredUserConfigurationConfig with EquatableMixin { 14 | const AlfredUserConfigurationConfigCheckBox({ 15 | required super.defaultValue, 16 | required this.required, 17 | super.value, 18 | this.text, 19 | }); 20 | 21 | /// Whether the checkbox is required 22 | final bool required; 23 | 24 | /// The text to display next to the checkbox 25 | final String? text; 26 | 27 | @internal 28 | @override 29 | AlfredUserConfigurationConfig copyWithValue(bool? value) => 30 | copyWith(value: value); 31 | 32 | factory AlfredUserConfigurationConfigCheckBox.fromJson(Map json) => 33 | _$AlfredUserConfigurationConfigCheckBoxFromJson( 34 | json.map((k, v) => MapEntry(k.toString(), v)), 35 | ); 36 | } 37 | -------------------------------------------------------------------------------- /lib/src/models/alfred_user_configuration_config_check_box.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'alfred_user_configuration_config_check_box.dart'; 4 | 5 | // ************************************************************************** 6 | // CopyWithGenerator 7 | // ************************************************************************** 8 | 9 | abstract class _$AlfredUserConfigurationConfigCheckBoxCWProxy { 10 | AlfredUserConfigurationConfigCheckBox defaultValue(bool defaultValue); 11 | 12 | AlfredUserConfigurationConfigCheckBox required(bool required); 13 | 14 | AlfredUserConfigurationConfigCheckBox value(bool? value); 15 | 16 | AlfredUserConfigurationConfigCheckBox text(String? text); 17 | 18 | /// This function **does support** nullification of nullable fields. All `null` values passed to `non-nullable` fields will be ignored. You can also use `AlfredUserConfigurationConfigCheckBox(...).copyWith.fieldName(...)` to override fields one at a time with nullification support. 19 | /// 20 | /// Usage 21 | /// ```dart 22 | /// AlfredUserConfigurationConfigCheckBox(...).copyWith(id: 12, name: "My name") 23 | /// ```` 24 | AlfredUserConfigurationConfigCheckBox call({ 25 | bool defaultValue, 26 | bool required, 27 | bool? value, 28 | String? text, 29 | }); 30 | } 31 | 32 | /// Proxy class for `copyWith` functionality. This is a callable class and can be used as follows: `instanceOfAlfredUserConfigurationConfigCheckBox.copyWith(...)`. Additionally contains functions for specific fields e.g. `instanceOfAlfredUserConfigurationConfigCheckBox.copyWith.fieldName(...)` 33 | class _$AlfredUserConfigurationConfigCheckBoxCWProxyImpl 34 | implements _$AlfredUserConfigurationConfigCheckBoxCWProxy { 35 | const _$AlfredUserConfigurationConfigCheckBoxCWProxyImpl(this._value); 36 | 37 | final AlfredUserConfigurationConfigCheckBox _value; 38 | 39 | @override 40 | AlfredUserConfigurationConfigCheckBox defaultValue(bool defaultValue) => 41 | this(defaultValue: defaultValue); 42 | 43 | @override 44 | AlfredUserConfigurationConfigCheckBox required(bool required) => 45 | this(required: required); 46 | 47 | @override 48 | AlfredUserConfigurationConfigCheckBox value(bool? value) => 49 | this(value: value); 50 | 51 | @override 52 | AlfredUserConfigurationConfigCheckBox text(String? text) => this(text: text); 53 | 54 | @override 55 | 56 | /// This function **does support** nullification of nullable fields. All `null` values passed to `non-nullable` fields will be ignored. You can also use `AlfredUserConfigurationConfigCheckBox(...).copyWith.fieldName(...)` to override fields one at a time with nullification support. 57 | /// 58 | /// Usage 59 | /// ```dart 60 | /// AlfredUserConfigurationConfigCheckBox(...).copyWith(id: 12, name: "My name") 61 | /// ```` 62 | AlfredUserConfigurationConfigCheckBox call({ 63 | Object? defaultValue = const $CopyWithPlaceholder(), 64 | Object? required = const $CopyWithPlaceholder(), 65 | Object? value = const $CopyWithPlaceholder(), 66 | Object? text = const $CopyWithPlaceholder(), 67 | }) { 68 | return AlfredUserConfigurationConfigCheckBox( 69 | defaultValue: defaultValue == const $CopyWithPlaceholder() 70 | ? _value.defaultValue 71 | // ignore: cast_nullable_to_non_nullable 72 | : defaultValue as bool, 73 | required: required == const $CopyWithPlaceholder() 74 | ? _value.required 75 | // ignore: cast_nullable_to_non_nullable 76 | : required as bool, 77 | value: value == const $CopyWithPlaceholder() 78 | ? _value.value 79 | // ignore: cast_nullable_to_non_nullable 80 | : value as bool?, 81 | text: text == const $CopyWithPlaceholder() 82 | ? _value.text 83 | // ignore: cast_nullable_to_non_nullable 84 | : text as String?, 85 | ); 86 | } 87 | } 88 | 89 | extension $AlfredUserConfigurationConfigCheckBoxCopyWith 90 | on AlfredUserConfigurationConfigCheckBox { 91 | /// Returns a callable class that can be used as follows: `instanceOfAlfredUserConfigurationConfigCheckBox.copyWith(...)` or like so:`instanceOfAlfredUserConfigurationConfigCheckBox.copyWith.fieldName(...)`. 92 | // ignore: library_private_types_in_public_api 93 | _$AlfredUserConfigurationConfigCheckBoxCWProxy get copyWith => 94 | _$AlfredUserConfigurationConfigCheckBoxCWProxyImpl(this); 95 | } 96 | 97 | // ************************************************************************** 98 | // JsonSerializableGenerator 99 | // ************************************************************************** 100 | 101 | AlfredUserConfigurationConfigCheckBox 102 | _$AlfredUserConfigurationConfigCheckBoxFromJson( 103 | Map json) => 104 | AlfredUserConfigurationConfigCheckBox( 105 | defaultValue: AlfredUserConfigurationConfig.fromJsonDefaultValue( 106 | json, 'default') as bool, 107 | required: json['required'] as bool, 108 | text: json['text'] as String?, 109 | ); 110 | -------------------------------------------------------------------------------- /lib/src/models/alfred_user_configuration_config_file_picker.dart: -------------------------------------------------------------------------------- 1 | import 'package:alfred_workflow/src/models/alfred_user_configuration_config.dart'; 2 | import 'package:copy_with_extension/copy_with_extension.dart'; 3 | import 'package:equatable/equatable.dart'; 4 | import 'package:json_annotation/json_annotation.dart'; 5 | import 'package:meta/meta.dart'; 6 | 7 | part 'alfred_user_configuration_config_file_picker.g.dart'; 8 | 9 | /// Alfred file picker user configuration config 10 | 11 | @CopyWith() 12 | @JsonSerializable(explicitToJson: true, createToJson: false) 13 | final class AlfredUserConfigurationConfigFilePicker 14 | extends AlfredUserConfigurationConfig with EquatableMixin { 15 | const AlfredUserConfigurationConfigFilePicker({ 16 | required super.defaultValue, 17 | required this.required, 18 | required this.filterMode, 19 | super.value, 20 | this.placeholder, 21 | }); 22 | 23 | /// Whether the file picker is required 24 | final bool required; 25 | 26 | /// The placeholder text to display 27 | final String? placeholder; 28 | 29 | /// The filter mode 30 | @JsonKey(name: 'filtermode') 31 | final int filterMode; 32 | 33 | @internal 34 | @override 35 | AlfredUserConfigurationConfig copyWithValue(String? value) => 36 | copyWith(value: value); 37 | 38 | factory AlfredUserConfigurationConfigFilePicker.fromJson(Map json) => 39 | _$AlfredUserConfigurationConfigFilePickerFromJson( 40 | json.map((k, v) => MapEntry(k.toString(), v)), 41 | ); 42 | } 43 | -------------------------------------------------------------------------------- /lib/src/models/alfred_user_configuration_config_file_picker.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'alfred_user_configuration_config_file_picker.dart'; 4 | 5 | // ************************************************************************** 6 | // CopyWithGenerator 7 | // ************************************************************************** 8 | 9 | abstract class _$AlfredUserConfigurationConfigFilePickerCWProxy { 10 | AlfredUserConfigurationConfigFilePicker defaultValue(String defaultValue); 11 | 12 | AlfredUserConfigurationConfigFilePicker required(bool required); 13 | 14 | AlfredUserConfigurationConfigFilePicker filterMode(int filterMode); 15 | 16 | AlfredUserConfigurationConfigFilePicker value(String? value); 17 | 18 | AlfredUserConfigurationConfigFilePicker placeholder(String? placeholder); 19 | 20 | /// This function **does support** nullification of nullable fields. All `null` values passed to `non-nullable` fields will be ignored. You can also use `AlfredUserConfigurationConfigFilePicker(...).copyWith.fieldName(...)` to override fields one at a time with nullification support. 21 | /// 22 | /// Usage 23 | /// ```dart 24 | /// AlfredUserConfigurationConfigFilePicker(...).copyWith(id: 12, name: "My name") 25 | /// ```` 26 | AlfredUserConfigurationConfigFilePicker call({ 27 | String defaultValue, 28 | bool required, 29 | int filterMode, 30 | String? value, 31 | String? placeholder, 32 | }); 33 | } 34 | 35 | /// Proxy class for `copyWith` functionality. This is a callable class and can be used as follows: `instanceOfAlfredUserConfigurationConfigFilePicker.copyWith(...)`. Additionally contains functions for specific fields e.g. `instanceOfAlfredUserConfigurationConfigFilePicker.copyWith.fieldName(...)` 36 | class _$AlfredUserConfigurationConfigFilePickerCWProxyImpl 37 | implements _$AlfredUserConfigurationConfigFilePickerCWProxy { 38 | const _$AlfredUserConfigurationConfigFilePickerCWProxyImpl(this._value); 39 | 40 | final AlfredUserConfigurationConfigFilePicker _value; 41 | 42 | @override 43 | AlfredUserConfigurationConfigFilePicker defaultValue(String defaultValue) => 44 | this(defaultValue: defaultValue); 45 | 46 | @override 47 | AlfredUserConfigurationConfigFilePicker required(bool required) => 48 | this(required: required); 49 | 50 | @override 51 | AlfredUserConfigurationConfigFilePicker filterMode(int filterMode) => 52 | this(filterMode: filterMode); 53 | 54 | @override 55 | AlfredUserConfigurationConfigFilePicker value(String? value) => 56 | this(value: value); 57 | 58 | @override 59 | AlfredUserConfigurationConfigFilePicker placeholder(String? placeholder) => 60 | this(placeholder: placeholder); 61 | 62 | @override 63 | 64 | /// This function **does support** nullification of nullable fields. All `null` values passed to `non-nullable` fields will be ignored. You can also use `AlfredUserConfigurationConfigFilePicker(...).copyWith.fieldName(...)` to override fields one at a time with nullification support. 65 | /// 66 | /// Usage 67 | /// ```dart 68 | /// AlfredUserConfigurationConfigFilePicker(...).copyWith(id: 12, name: "My name") 69 | /// ```` 70 | AlfredUserConfigurationConfigFilePicker call({ 71 | Object? defaultValue = const $CopyWithPlaceholder(), 72 | Object? required = const $CopyWithPlaceholder(), 73 | Object? filterMode = const $CopyWithPlaceholder(), 74 | Object? value = const $CopyWithPlaceholder(), 75 | Object? placeholder = const $CopyWithPlaceholder(), 76 | }) { 77 | return AlfredUserConfigurationConfigFilePicker( 78 | defaultValue: defaultValue == const $CopyWithPlaceholder() 79 | ? _value.defaultValue 80 | // ignore: cast_nullable_to_non_nullable 81 | : defaultValue as String, 82 | required: required == const $CopyWithPlaceholder() 83 | ? _value.required 84 | // ignore: cast_nullable_to_non_nullable 85 | : required as bool, 86 | filterMode: filterMode == const $CopyWithPlaceholder() 87 | ? _value.filterMode 88 | // ignore: cast_nullable_to_non_nullable 89 | : filterMode as int, 90 | value: value == const $CopyWithPlaceholder() 91 | ? _value.value 92 | // ignore: cast_nullable_to_non_nullable 93 | : value as String?, 94 | placeholder: placeholder == const $CopyWithPlaceholder() 95 | ? _value.placeholder 96 | // ignore: cast_nullable_to_non_nullable 97 | : placeholder as String?, 98 | ); 99 | } 100 | } 101 | 102 | extension $AlfredUserConfigurationConfigFilePickerCopyWith 103 | on AlfredUserConfigurationConfigFilePicker { 104 | /// Returns a callable class that can be used as follows: `instanceOfAlfredUserConfigurationConfigFilePicker.copyWith(...)` or like so:`instanceOfAlfredUserConfigurationConfigFilePicker.copyWith.fieldName(...)`. 105 | // ignore: library_private_types_in_public_api 106 | _$AlfredUserConfigurationConfigFilePickerCWProxy get copyWith => 107 | _$AlfredUserConfigurationConfigFilePickerCWProxyImpl(this); 108 | } 109 | 110 | // ************************************************************************** 111 | // JsonSerializableGenerator 112 | // ************************************************************************** 113 | 114 | AlfredUserConfigurationConfigFilePicker 115 | _$AlfredUserConfigurationConfigFilePickerFromJson( 116 | Map json) => 117 | AlfredUserConfigurationConfigFilePicker( 118 | defaultValue: AlfredUserConfigurationConfig.fromJsonDefaultValue( 119 | json, 'default') as String, 120 | required: json['required'] as bool, 121 | filterMode: (json['filtermode'] as num).toInt(), 122 | placeholder: json['placeholder'] as String?, 123 | ); 124 | -------------------------------------------------------------------------------- /lib/src/models/alfred_user_configuration_config_number_slider.dart: -------------------------------------------------------------------------------- 1 | import 'package:alfred_workflow/src/models/alfred_user_configuration_config.dart'; 2 | import 'package:copy_with_extension/copy_with_extension.dart'; 3 | import 'package:equatable/equatable.dart'; 4 | import 'package:json_annotation/json_annotation.dart'; 5 | import 'package:meta/meta.dart'; 6 | 7 | part 'alfred_user_configuration_config_number_slider.g.dart'; 8 | 9 | /// Alfred integer slider user configuration config 10 | 11 | @CopyWith() 12 | @JsonSerializable(explicitToJson: true, createToJson: false) 13 | final class AlfredUserConfigurationConfigNumberSlider 14 | extends AlfredUserConfigurationConfig with EquatableMixin { 15 | const AlfredUserConfigurationConfigNumberSlider({ 16 | required super.defaultValue, 17 | super.value, 18 | required this.min, 19 | required this.max, 20 | this.onlyStopOnMarkers = false, 21 | this.showMarkers = false, 22 | this.markerCount, 23 | }) : assert(min < max, 'min must be less than max'), 24 | assert( 25 | defaultValue >= min && defaultValue <= max, 26 | 'defaultValue must be between min and max', 27 | ), 28 | assert( 29 | value == null || (value >= min && value <= max), 30 | 'value must be between min and max', 31 | ), 32 | assert( 33 | !(showMarkers || onlyStopOnMarkers) || markerCount != null, 34 | 'markerCount must be provided if showMarkers or onlyStopOnMarkers is true', 35 | ), 36 | assert( 37 | !(showMarkers || onlyStopOnMarkers) || markerCount != 0, 38 | 'markerCount must be greater than 0 if showMarkers or onlyStopOnMarkers is true', 39 | ), 40 | assert( 41 | markerCount == null || markerCount > 0, 42 | 'markerCount must be greater than 0 if provided', 43 | ); 44 | 45 | @JsonKey(name: 'minvalue') 46 | final int min; 47 | @JsonKey(name: 'maxvalue') 48 | final int max; 49 | @JsonKey(name: 'showmarkers') 50 | final bool showMarkers; 51 | @JsonKey(name: 'onlystoponmarkers') 52 | final bool onlyStopOnMarkers; 53 | @JsonKey(name: 'markercount') 54 | final int? markerCount; 55 | 56 | @internal 57 | @override 58 | AlfredUserConfigurationConfig copyWithValue(int? value) => 59 | copyWith(value: value); 60 | 61 | factory AlfredUserConfigurationConfigNumberSlider.fromJson(Map json) => 62 | _$AlfredUserConfigurationConfigNumberSliderFromJson( 63 | json.map((k, v) => MapEntry(k.toString(), v)), 64 | ); 65 | } 66 | -------------------------------------------------------------------------------- /lib/src/models/alfred_user_configuration_config_select.dart: -------------------------------------------------------------------------------- 1 | import 'package:alfred_workflow/src/models/alfred_user_configuration_config.dart'; 2 | import 'package:copy_with_extension/copy_with_extension.dart'; 3 | import 'package:equatable/equatable.dart'; 4 | import 'package:json_annotation/json_annotation.dart'; 5 | import 'package:meta/meta.dart'; 6 | 7 | part 'alfred_user_configuration_config_select.g.dart'; 8 | 9 | /// Alfred user configuration select pair record 10 | typedef AlfredUserConfigurationConfigSelectPair = ({ 11 | String label, 12 | String value 13 | }); 14 | 15 | /// Alfred user configuration select class 16 | 17 | @CopyWith() 18 | @JsonSerializable(explicitToJson: true, createToJson: false) 19 | final class AlfredUserConfigurationConfigSelect 20 | extends AlfredUserConfigurationConfig with EquatableMixin { 21 | const AlfredUserConfigurationConfigSelect({ 22 | required super.defaultValue, 23 | required this.pairs, 24 | super.value, 25 | }); 26 | 27 | /// The pairs of labels and values 28 | @JsonKey(fromJson: _pairsFromJson) 29 | final List pairs; 30 | 31 | @internal 32 | @override 33 | AlfredUserConfigurationConfig copyWithValue(String? value) => 34 | copyWith(value: value); 35 | 36 | static List _pairsFromJson( 37 | List json) { 38 | return [ 39 | for (final List pair in json) 40 | ( 41 | label: pair.first.toString(), 42 | value: pair.last.toString(), 43 | ), 44 | ]; 45 | } 46 | 47 | factory AlfredUserConfigurationConfigSelect.fromJson(Map json) => 48 | _$AlfredUserConfigurationConfigSelectFromJson( 49 | json.map((k, v) => MapEntry(k.toString(), v)), 50 | ); 51 | } 52 | -------------------------------------------------------------------------------- /lib/src/models/alfred_user_configuration_config_select.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'alfred_user_configuration_config_select.dart'; 4 | 5 | // ************************************************************************** 6 | // CopyWithGenerator 7 | // ************************************************************************** 8 | 9 | abstract class _$AlfredUserConfigurationConfigSelectCWProxy { 10 | AlfredUserConfigurationConfigSelect defaultValue(String defaultValue); 11 | 12 | AlfredUserConfigurationConfigSelect pairs( 13 | List<({String label, String value})> pairs); 14 | 15 | AlfredUserConfigurationConfigSelect value(String? value); 16 | 17 | /// This function **does support** nullification of nullable fields. All `null` values passed to `non-nullable` fields will be ignored. You can also use `AlfredUserConfigurationConfigSelect(...).copyWith.fieldName(...)` to override fields one at a time with nullification support. 18 | /// 19 | /// Usage 20 | /// ```dart 21 | /// AlfredUserConfigurationConfigSelect(...).copyWith(id: 12, name: "My name") 22 | /// ```` 23 | AlfredUserConfigurationConfigSelect call({ 24 | String defaultValue, 25 | List<({String label, String value})> pairs, 26 | String? value, 27 | }); 28 | } 29 | 30 | /// Proxy class for `copyWith` functionality. This is a callable class and can be used as follows: `instanceOfAlfredUserConfigurationConfigSelect.copyWith(...)`. Additionally contains functions for specific fields e.g. `instanceOfAlfredUserConfigurationConfigSelect.copyWith.fieldName(...)` 31 | class _$AlfredUserConfigurationConfigSelectCWProxyImpl 32 | implements _$AlfredUserConfigurationConfigSelectCWProxy { 33 | const _$AlfredUserConfigurationConfigSelectCWProxyImpl(this._value); 34 | 35 | final AlfredUserConfigurationConfigSelect _value; 36 | 37 | @override 38 | AlfredUserConfigurationConfigSelect defaultValue(String defaultValue) => 39 | this(defaultValue: defaultValue); 40 | 41 | @override 42 | AlfredUserConfigurationConfigSelect pairs( 43 | List<({String label, String value})> pairs) => 44 | this(pairs: pairs); 45 | 46 | @override 47 | AlfredUserConfigurationConfigSelect value(String? value) => 48 | this(value: value); 49 | 50 | @override 51 | 52 | /// This function **does support** nullification of nullable fields. All `null` values passed to `non-nullable` fields will be ignored. You can also use `AlfredUserConfigurationConfigSelect(...).copyWith.fieldName(...)` to override fields one at a time with nullification support. 53 | /// 54 | /// Usage 55 | /// ```dart 56 | /// AlfredUserConfigurationConfigSelect(...).copyWith(id: 12, name: "My name") 57 | /// ```` 58 | AlfredUserConfigurationConfigSelect call({ 59 | Object? defaultValue = const $CopyWithPlaceholder(), 60 | Object? pairs = const $CopyWithPlaceholder(), 61 | Object? value = const $CopyWithPlaceholder(), 62 | }) { 63 | return AlfredUserConfigurationConfigSelect( 64 | defaultValue: defaultValue == const $CopyWithPlaceholder() 65 | ? _value.defaultValue 66 | // ignore: cast_nullable_to_non_nullable 67 | : defaultValue as String, 68 | pairs: pairs == const $CopyWithPlaceholder() 69 | ? _value.pairs 70 | // ignore: cast_nullable_to_non_nullable 71 | : pairs as List<({String label, String value})>, 72 | value: value == const $CopyWithPlaceholder() 73 | ? _value.value 74 | // ignore: cast_nullable_to_non_nullable 75 | : value as String?, 76 | ); 77 | } 78 | } 79 | 80 | extension $AlfredUserConfigurationConfigSelectCopyWith 81 | on AlfredUserConfigurationConfigSelect { 82 | /// Returns a callable class that can be used as follows: `instanceOfAlfredUserConfigurationConfigSelect.copyWith(...)` or like so:`instanceOfAlfredUserConfigurationConfigSelect.copyWith.fieldName(...)`. 83 | // ignore: library_private_types_in_public_api 84 | _$AlfredUserConfigurationConfigSelectCWProxy get copyWith => 85 | _$AlfredUserConfigurationConfigSelectCWProxyImpl(this); 86 | } 87 | 88 | // ************************************************************************** 89 | // JsonSerializableGenerator 90 | // ************************************************************************** 91 | 92 | AlfredUserConfigurationConfigSelect 93 | _$AlfredUserConfigurationConfigSelectFromJson(Map json) => 94 | AlfredUserConfigurationConfigSelect( 95 | defaultValue: AlfredUserConfigurationConfig.fromJsonDefaultValue( 96 | json, 'default') as String, 97 | pairs: AlfredUserConfigurationConfigSelect._pairsFromJson( 98 | json['pairs'] as List), 99 | ); 100 | -------------------------------------------------------------------------------- /lib/src/models/alfred_user_configuration_config_text_area.dart: -------------------------------------------------------------------------------- 1 | import 'package:alfred_workflow/src/models/alfred_user_configuration_config.dart'; 2 | import 'package:copy_with_extension/copy_with_extension.dart'; 3 | import 'package:equatable/equatable.dart'; 4 | import 'package:json_annotation/json_annotation.dart'; 5 | import 'package:meta/meta.dart'; 6 | 7 | part 'alfred_user_configuration_config_text_area.g.dart'; 8 | 9 | /// A configuration for a text area 10 | 11 | @CopyWith() 12 | @JsonSerializable(explicitToJson: true, createToJson: false) 13 | final class AlfredUserConfigurationConfigTextArea 14 | extends AlfredUserConfigurationConfig with EquatableMixin { 15 | const AlfredUserConfigurationConfigTextArea({ 16 | required super.defaultValue, 17 | required this.required, 18 | required this.trim, 19 | required this.verticalSize, 20 | super.value, 21 | }); 22 | 23 | /// Whether the text area is required 24 | final bool required; 25 | 26 | /// Whether to trim the text 27 | final bool trim; 28 | 29 | /// The vertical size of the text area 30 | @JsonKey(name: 'verticalsize') 31 | final int verticalSize; 32 | 33 | @internal 34 | @override 35 | AlfredUserConfigurationConfig copyWithValue(String? value) => 36 | copyWith(value: value); 37 | 38 | factory AlfredUserConfigurationConfigTextArea.fromJson(Map json) => 39 | _$AlfredUserConfigurationConfigTextAreaFromJson( 40 | json.map((k, v) => MapEntry(k.toString(), v)), 41 | ); 42 | } 43 | -------------------------------------------------------------------------------- /lib/src/models/alfred_user_configuration_config_text_area.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'alfred_user_configuration_config_text_area.dart'; 4 | 5 | // ************************************************************************** 6 | // CopyWithGenerator 7 | // ************************************************************************** 8 | 9 | abstract class _$AlfredUserConfigurationConfigTextAreaCWProxy { 10 | AlfredUserConfigurationConfigTextArea defaultValue(String defaultValue); 11 | 12 | AlfredUserConfigurationConfigTextArea required(bool required); 13 | 14 | AlfredUserConfigurationConfigTextArea trim(bool trim); 15 | 16 | AlfredUserConfigurationConfigTextArea verticalSize(int verticalSize); 17 | 18 | AlfredUserConfigurationConfigTextArea value(String? value); 19 | 20 | /// This function **does support** nullification of nullable fields. All `null` values passed to `non-nullable` fields will be ignored. You can also use `AlfredUserConfigurationConfigTextArea(...).copyWith.fieldName(...)` to override fields one at a time with nullification support. 21 | /// 22 | /// Usage 23 | /// ```dart 24 | /// AlfredUserConfigurationConfigTextArea(...).copyWith(id: 12, name: "My name") 25 | /// ```` 26 | AlfredUserConfigurationConfigTextArea call({ 27 | String defaultValue, 28 | bool required, 29 | bool trim, 30 | int verticalSize, 31 | String? value, 32 | }); 33 | } 34 | 35 | /// Proxy class for `copyWith` functionality. This is a callable class and can be used as follows: `instanceOfAlfredUserConfigurationConfigTextArea.copyWith(...)`. Additionally contains functions for specific fields e.g. `instanceOfAlfredUserConfigurationConfigTextArea.copyWith.fieldName(...)` 36 | class _$AlfredUserConfigurationConfigTextAreaCWProxyImpl 37 | implements _$AlfredUserConfigurationConfigTextAreaCWProxy { 38 | const _$AlfredUserConfigurationConfigTextAreaCWProxyImpl(this._value); 39 | 40 | final AlfredUserConfigurationConfigTextArea _value; 41 | 42 | @override 43 | AlfredUserConfigurationConfigTextArea defaultValue(String defaultValue) => 44 | this(defaultValue: defaultValue); 45 | 46 | @override 47 | AlfredUserConfigurationConfigTextArea required(bool required) => 48 | this(required: required); 49 | 50 | @override 51 | AlfredUserConfigurationConfigTextArea trim(bool trim) => this(trim: trim); 52 | 53 | @override 54 | AlfredUserConfigurationConfigTextArea verticalSize(int verticalSize) => 55 | this(verticalSize: verticalSize); 56 | 57 | @override 58 | AlfredUserConfigurationConfigTextArea value(String? value) => 59 | this(value: value); 60 | 61 | @override 62 | 63 | /// This function **does support** nullification of nullable fields. All `null` values passed to `non-nullable` fields will be ignored. You can also use `AlfredUserConfigurationConfigTextArea(...).copyWith.fieldName(...)` to override fields one at a time with nullification support. 64 | /// 65 | /// Usage 66 | /// ```dart 67 | /// AlfredUserConfigurationConfigTextArea(...).copyWith(id: 12, name: "My name") 68 | /// ```` 69 | AlfredUserConfigurationConfigTextArea call({ 70 | Object? defaultValue = const $CopyWithPlaceholder(), 71 | Object? required = const $CopyWithPlaceholder(), 72 | Object? trim = const $CopyWithPlaceholder(), 73 | Object? verticalSize = const $CopyWithPlaceholder(), 74 | Object? value = const $CopyWithPlaceholder(), 75 | }) { 76 | return AlfredUserConfigurationConfigTextArea( 77 | defaultValue: defaultValue == const $CopyWithPlaceholder() 78 | ? _value.defaultValue 79 | // ignore: cast_nullable_to_non_nullable 80 | : defaultValue as String, 81 | required: required == const $CopyWithPlaceholder() 82 | ? _value.required 83 | // ignore: cast_nullable_to_non_nullable 84 | : required as bool, 85 | trim: trim == const $CopyWithPlaceholder() 86 | ? _value.trim 87 | // ignore: cast_nullable_to_non_nullable 88 | : trim as bool, 89 | verticalSize: verticalSize == const $CopyWithPlaceholder() 90 | ? _value.verticalSize 91 | // ignore: cast_nullable_to_non_nullable 92 | : verticalSize as int, 93 | value: value == const $CopyWithPlaceholder() 94 | ? _value.value 95 | // ignore: cast_nullable_to_non_nullable 96 | : value as String?, 97 | ); 98 | } 99 | } 100 | 101 | extension $AlfredUserConfigurationConfigTextAreaCopyWith 102 | on AlfredUserConfigurationConfigTextArea { 103 | /// Returns a callable class that can be used as follows: `instanceOfAlfredUserConfigurationConfigTextArea.copyWith(...)` or like so:`instanceOfAlfredUserConfigurationConfigTextArea.copyWith.fieldName(...)`. 104 | // ignore: library_private_types_in_public_api 105 | _$AlfredUserConfigurationConfigTextAreaCWProxy get copyWith => 106 | _$AlfredUserConfigurationConfigTextAreaCWProxyImpl(this); 107 | } 108 | 109 | // ************************************************************************** 110 | // JsonSerializableGenerator 111 | // ************************************************************************** 112 | 113 | AlfredUserConfigurationConfigTextArea 114 | _$AlfredUserConfigurationConfigTextAreaFromJson( 115 | Map json) => 116 | AlfredUserConfigurationConfigTextArea( 117 | defaultValue: AlfredUserConfigurationConfig.fromJsonDefaultValue( 118 | json, 'default') as String, 119 | required: json['required'] as bool, 120 | trim: json['trim'] as bool, 121 | verticalSize: (json['verticalsize'] as num).toInt(), 122 | ); 123 | -------------------------------------------------------------------------------- /lib/src/models/alfred_user_configuration_config_text_field.dart: -------------------------------------------------------------------------------- 1 | import 'package:alfred_workflow/src/models/alfred_user_configuration_config.dart'; 2 | import 'package:copy_with_extension/copy_with_extension.dart'; 3 | import 'package:equatable/equatable.dart'; 4 | import 'package:json_annotation/json_annotation.dart'; 5 | import 'package:meta/meta.dart'; 6 | 7 | part 'alfred_user_configuration_config_text_field.g.dart'; 8 | 9 | @CopyWith() 10 | @JsonSerializable(explicitToJson: true, createToJson: false) 11 | final class AlfredUserConfigurationConfigTextField 12 | extends AlfredUserConfigurationConfig with EquatableMixin { 13 | const AlfredUserConfigurationConfigTextField({ 14 | required super.defaultValue, 15 | required this.required, 16 | required this.trim, 17 | super.value, 18 | this.placeholder, 19 | }); 20 | 21 | /// Whether the text field is required 22 | final String? placeholder; 23 | 24 | /// Whether to trim the text 25 | final bool required; 26 | 27 | /// Whether to trim the text 28 | final bool trim; 29 | 30 | @internal 31 | @override 32 | AlfredUserConfigurationConfig copyWithValue(String? value) => 33 | copyWith(value: value); 34 | 35 | factory AlfredUserConfigurationConfigTextField.fromJson(Map json) => 36 | _$AlfredUserConfigurationConfigTextFieldFromJson( 37 | json.map((k, v) => MapEntry(k.toString(), v)), 38 | ); 39 | } 40 | -------------------------------------------------------------------------------- /lib/src/models/alfred_user_configuration_config_text_field.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'alfred_user_configuration_config_text_field.dart'; 4 | 5 | // ************************************************************************** 6 | // CopyWithGenerator 7 | // ************************************************************************** 8 | 9 | abstract class _$AlfredUserConfigurationConfigTextFieldCWProxy { 10 | AlfredUserConfigurationConfigTextField defaultValue(String defaultValue); 11 | 12 | AlfredUserConfigurationConfigTextField required(bool required); 13 | 14 | AlfredUserConfigurationConfigTextField trim(bool trim); 15 | 16 | AlfredUserConfigurationConfigTextField value(String? value); 17 | 18 | AlfredUserConfigurationConfigTextField placeholder(String? placeholder); 19 | 20 | /// This function **does support** nullification of nullable fields. All `null` values passed to `non-nullable` fields will be ignored. You can also use `AlfredUserConfigurationConfigTextField(...).copyWith.fieldName(...)` to override fields one at a time with nullification support. 21 | /// 22 | /// Usage 23 | /// ```dart 24 | /// AlfredUserConfigurationConfigTextField(...).copyWith(id: 12, name: "My name") 25 | /// ```` 26 | AlfredUserConfigurationConfigTextField call({ 27 | String defaultValue, 28 | bool required, 29 | bool trim, 30 | String? value, 31 | String? placeholder, 32 | }); 33 | } 34 | 35 | /// Proxy class for `copyWith` functionality. This is a callable class and can be used as follows: `instanceOfAlfredUserConfigurationConfigTextField.copyWith(...)`. Additionally contains functions for specific fields e.g. `instanceOfAlfredUserConfigurationConfigTextField.copyWith.fieldName(...)` 36 | class _$AlfredUserConfigurationConfigTextFieldCWProxyImpl 37 | implements _$AlfredUserConfigurationConfigTextFieldCWProxy { 38 | const _$AlfredUserConfigurationConfigTextFieldCWProxyImpl(this._value); 39 | 40 | final AlfredUserConfigurationConfigTextField _value; 41 | 42 | @override 43 | AlfredUserConfigurationConfigTextField defaultValue(String defaultValue) => 44 | this(defaultValue: defaultValue); 45 | 46 | @override 47 | AlfredUserConfigurationConfigTextField required(bool required) => 48 | this(required: required); 49 | 50 | @override 51 | AlfredUserConfigurationConfigTextField trim(bool trim) => this(trim: trim); 52 | 53 | @override 54 | AlfredUserConfigurationConfigTextField value(String? value) => 55 | this(value: value); 56 | 57 | @override 58 | AlfredUserConfigurationConfigTextField placeholder(String? placeholder) => 59 | this(placeholder: placeholder); 60 | 61 | @override 62 | 63 | /// This function **does support** nullification of nullable fields. All `null` values passed to `non-nullable` fields will be ignored. You can also use `AlfredUserConfigurationConfigTextField(...).copyWith.fieldName(...)` to override fields one at a time with nullification support. 64 | /// 65 | /// Usage 66 | /// ```dart 67 | /// AlfredUserConfigurationConfigTextField(...).copyWith(id: 12, name: "My name") 68 | /// ```` 69 | AlfredUserConfigurationConfigTextField call({ 70 | Object? defaultValue = const $CopyWithPlaceholder(), 71 | Object? required = const $CopyWithPlaceholder(), 72 | Object? trim = const $CopyWithPlaceholder(), 73 | Object? value = const $CopyWithPlaceholder(), 74 | Object? placeholder = const $CopyWithPlaceholder(), 75 | }) { 76 | return AlfredUserConfigurationConfigTextField( 77 | defaultValue: defaultValue == const $CopyWithPlaceholder() 78 | ? _value.defaultValue 79 | // ignore: cast_nullable_to_non_nullable 80 | : defaultValue as String, 81 | required: required == const $CopyWithPlaceholder() 82 | ? _value.required 83 | // ignore: cast_nullable_to_non_nullable 84 | : required as bool, 85 | trim: trim == const $CopyWithPlaceholder() 86 | ? _value.trim 87 | // ignore: cast_nullable_to_non_nullable 88 | : trim as bool, 89 | value: value == const $CopyWithPlaceholder() 90 | ? _value.value 91 | // ignore: cast_nullable_to_non_nullable 92 | : value as String?, 93 | placeholder: placeholder == const $CopyWithPlaceholder() 94 | ? _value.placeholder 95 | // ignore: cast_nullable_to_non_nullable 96 | : placeholder as String?, 97 | ); 98 | } 99 | } 100 | 101 | extension $AlfredUserConfigurationConfigTextFieldCopyWith 102 | on AlfredUserConfigurationConfigTextField { 103 | /// Returns a callable class that can be used as follows: `instanceOfAlfredUserConfigurationConfigTextField.copyWith(...)` or like so:`instanceOfAlfredUserConfigurationConfigTextField.copyWith.fieldName(...)`. 104 | // ignore: library_private_types_in_public_api 105 | _$AlfredUserConfigurationConfigTextFieldCWProxy get copyWith => 106 | _$AlfredUserConfigurationConfigTextFieldCWProxyImpl(this); 107 | } 108 | 109 | // ************************************************************************** 110 | // JsonSerializableGenerator 111 | // ************************************************************************** 112 | 113 | AlfredUserConfigurationConfigTextField 114 | _$AlfredUserConfigurationConfigTextFieldFromJson( 115 | Map json) => 116 | AlfredUserConfigurationConfigTextField( 117 | defaultValue: AlfredUserConfigurationConfig.fromJsonDefaultValue( 118 | json, 'default') as String, 119 | required: json['required'] as bool, 120 | trim: json['trim'] as bool, 121 | placeholder: json['placeholder'] as String?, 122 | ); 123 | -------------------------------------------------------------------------------- /lib/src/models/alfred_user_configuration_file_picker.dart: -------------------------------------------------------------------------------- 1 | import 'package:alfred_workflow/src/models/alfred_user_configuration.dart'; 2 | import 'package:alfred_workflow/src/models/alfred_user_configuration_config_file_picker.dart'; 3 | import 'package:alfred_workflow/src/models/alfred_user_configuration_type.dart'; 4 | import 'package:copy_with_extension/copy_with_extension.dart'; 5 | import 'package:equatable/equatable.dart'; 6 | import 'package:json_annotation/json_annotation.dart'; 7 | import 'package:meta/meta.dart'; 8 | 9 | part 'alfred_user_configuration_file_picker.g.dart'; 10 | 11 | /// A file picker configuration 12 | 13 | @CopyWith() 14 | @JsonSerializable(explicitToJson: true, createToJson: false) 15 | final class AlfredUserConfigurationFilePicker extends AlfredUserConfiguration< 16 | String, AlfredUserConfigurationConfigFilePicker> with EquatableMixin { 17 | const AlfredUserConfigurationFilePicker({ 18 | required super.type, 19 | required super.variable, 20 | required this.config, 21 | super.description, 22 | super.label, 23 | }); 24 | 25 | /// The configuration for the file picker 26 | @override 27 | @JsonKey(fromJson: _configFromJson) 28 | final AlfredUserConfigurationConfigFilePicker config; 29 | 30 | @internal 31 | @override 32 | AlfredUserConfiguration 33 | copyWithConfig(AlfredUserConfigurationConfigFilePicker config) => 34 | copyWith(config: config); 35 | 36 | static AlfredUserConfigurationConfigFilePicker _configFromJson(Map json) => 37 | AlfredUserConfigurationConfigFilePicker.fromJson( 38 | json.map((k, v) => MapEntry(k.toString(), v)), 39 | ); 40 | 41 | factory AlfredUserConfigurationFilePicker.fromJson(Map json) => 42 | _$AlfredUserConfigurationFilePickerFromJson( 43 | json.map((k, v) => MapEntry(k.toString(), v)), 44 | ); 45 | } 46 | -------------------------------------------------------------------------------- /lib/src/models/alfred_user_configuration_number_slider.dart: -------------------------------------------------------------------------------- 1 | import 'package:alfred_workflow/src/models/alfred_user_configuration.dart'; 2 | import 'package:alfred_workflow/src/models/alfred_user_configuration_config_number_slider.dart'; 3 | import 'package:alfred_workflow/src/models/alfred_user_configuration_type.dart'; 4 | import 'package:copy_with_extension/copy_with_extension.dart'; 5 | import 'package:equatable/equatable.dart'; 6 | import 'package:json_annotation/json_annotation.dart'; 7 | import 'package:meta/meta.dart'; 8 | 9 | part 'alfred_user_configuration_number_slider.g.dart'; 10 | 11 | /// Alfred number slider user configuration 12 | 13 | @CopyWith() 14 | @JsonSerializable(explicitToJson: true, createToJson: false) 15 | final class AlfredUserConfigurationNumberSlider extends AlfredUserConfiguration< 16 | int, AlfredUserConfigurationConfigNumberSlider> with EquatableMixin { 17 | const AlfredUserConfigurationNumberSlider({ 18 | required super.type, 19 | required super.variable, 20 | required this.config, 21 | super.description, 22 | super.label, 23 | }); 24 | 25 | /// The configuration for the number slider 26 | @override 27 | @JsonKey(fromJson: _configFromJson) 28 | final AlfredUserConfigurationConfigNumberSlider config; 29 | 30 | @internal 31 | @override 32 | AlfredUserConfiguration 33 | copyWithConfig(AlfredUserConfigurationConfigNumberSlider config) => 34 | copyWith(config: config); 35 | 36 | static AlfredUserConfigurationConfigNumberSlider _configFromJson(Map json) => 37 | AlfredUserConfigurationConfigNumberSlider.fromJson( 38 | json.map((k, v) => MapEntry(k.toString(), v)), 39 | ); 40 | 41 | factory AlfredUserConfigurationNumberSlider.fromJson(Map json) => 42 | _$AlfredUserConfigurationNumberSliderFromJson( 43 | json.map((k, v) => MapEntry(k.toString(), v)), 44 | ); 45 | } 46 | -------------------------------------------------------------------------------- /lib/src/models/alfred_user_configuration_select.dart: -------------------------------------------------------------------------------- 1 | import 'package:alfred_workflow/src/models/alfred_user_configuration.dart'; 2 | import 'package:alfred_workflow/src/models/alfred_user_configuration_config_select.dart'; 3 | import 'package:alfred_workflow/src/models/alfred_user_configuration_type.dart'; 4 | import 'package:copy_with_extension/copy_with_extension.dart'; 5 | import 'package:equatable/equatable.dart'; 6 | import 'package:json_annotation/json_annotation.dart'; 7 | import 'package:meta/meta.dart'; 8 | 9 | part 'alfred_user_configuration_select.g.dart'; 10 | 11 | /// Alfred select user configuration 12 | 13 | @CopyWith() 14 | @JsonSerializable(explicitToJson: true, createToJson: false) 15 | final class AlfredUserConfigurationSelect 16 | extends AlfredUserConfiguration 17 | with EquatableMixin { 18 | const AlfredUserConfigurationSelect({ 19 | required super.type, 20 | required super.variable, 21 | required this.config, 22 | super.description, 23 | super.label, 24 | }); 25 | 26 | /// The configuration for the select 27 | @override 28 | @JsonKey(fromJson: _configFromJson) 29 | final AlfredUserConfigurationConfigSelect config; 30 | 31 | @internal 32 | @override 33 | AlfredUserConfiguration 34 | copyWithConfig(AlfredUserConfigurationConfigSelect config) => 35 | copyWith(config: config); 36 | 37 | static AlfredUserConfigurationConfigSelect _configFromJson(Map json) => 38 | AlfredUserConfigurationConfigSelect.fromJson( 39 | json.map((k, v) => MapEntry(k.toString(), v)), 40 | ); 41 | 42 | factory AlfredUserConfigurationSelect.fromJson(Map json) => 43 | _$AlfredUserConfigurationSelectFromJson( 44 | json.map((k, v) => MapEntry(k.toString(), v)), 45 | ); 46 | } 47 | -------------------------------------------------------------------------------- /lib/src/models/alfred_user_configuration_select.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'alfred_user_configuration_select.dart'; 4 | 5 | // ************************************************************************** 6 | // CopyWithGenerator 7 | // ************************************************************************** 8 | 9 | abstract class _$AlfredUserConfigurationSelectCWProxy { 10 | AlfredUserConfigurationSelect type(AlfredUserConfigurationType type); 11 | 12 | AlfredUserConfigurationSelect variable(String variable); 13 | 14 | AlfredUserConfigurationSelect config( 15 | AlfredUserConfigurationConfigSelect config); 16 | 17 | AlfredUserConfigurationSelect description(String? description); 18 | 19 | AlfredUserConfigurationSelect label(String? label); 20 | 21 | /// This function **does support** nullification of nullable fields. All `null` values passed to `non-nullable` fields will be ignored. You can also use `AlfredUserConfigurationSelect(...).copyWith.fieldName(...)` to override fields one at a time with nullification support. 22 | /// 23 | /// Usage 24 | /// ```dart 25 | /// AlfredUserConfigurationSelect(...).copyWith(id: 12, name: "My name") 26 | /// ```` 27 | AlfredUserConfigurationSelect call({ 28 | AlfredUserConfigurationType type, 29 | String variable, 30 | AlfredUserConfigurationConfigSelect config, 31 | String? description, 32 | String? label, 33 | }); 34 | } 35 | 36 | /// Proxy class for `copyWith` functionality. This is a callable class and can be used as follows: `instanceOfAlfredUserConfigurationSelect.copyWith(...)`. Additionally contains functions for specific fields e.g. `instanceOfAlfredUserConfigurationSelect.copyWith.fieldName(...)` 37 | class _$AlfredUserConfigurationSelectCWProxyImpl 38 | implements _$AlfredUserConfigurationSelectCWProxy { 39 | const _$AlfredUserConfigurationSelectCWProxyImpl(this._value); 40 | 41 | final AlfredUserConfigurationSelect _value; 42 | 43 | @override 44 | AlfredUserConfigurationSelect type(AlfredUserConfigurationType type) => 45 | this(type: type); 46 | 47 | @override 48 | AlfredUserConfigurationSelect variable(String variable) => 49 | this(variable: variable); 50 | 51 | @override 52 | AlfredUserConfigurationSelect config( 53 | AlfredUserConfigurationConfigSelect config) => 54 | this(config: config); 55 | 56 | @override 57 | AlfredUserConfigurationSelect description(String? description) => 58 | this(description: description); 59 | 60 | @override 61 | AlfredUserConfigurationSelect label(String? label) => this(label: label); 62 | 63 | @override 64 | 65 | /// This function **does support** nullification of nullable fields. All `null` values passed to `non-nullable` fields will be ignored. You can also use `AlfredUserConfigurationSelect(...).copyWith.fieldName(...)` to override fields one at a time with nullification support. 66 | /// 67 | /// Usage 68 | /// ```dart 69 | /// AlfredUserConfigurationSelect(...).copyWith(id: 12, name: "My name") 70 | /// ```` 71 | AlfredUserConfigurationSelect call({ 72 | Object? type = const $CopyWithPlaceholder(), 73 | Object? variable = const $CopyWithPlaceholder(), 74 | Object? config = const $CopyWithPlaceholder(), 75 | Object? description = const $CopyWithPlaceholder(), 76 | Object? label = const $CopyWithPlaceholder(), 77 | }) { 78 | return AlfredUserConfigurationSelect( 79 | type: type == const $CopyWithPlaceholder() 80 | ? _value.type 81 | // ignore: cast_nullable_to_non_nullable 82 | : type as AlfredUserConfigurationType, 83 | variable: variable == const $CopyWithPlaceholder() 84 | ? _value.variable 85 | // ignore: cast_nullable_to_non_nullable 86 | : variable as String, 87 | config: config == const $CopyWithPlaceholder() 88 | ? _value.config 89 | // ignore: cast_nullable_to_non_nullable 90 | : config as AlfredUserConfigurationConfigSelect, 91 | description: description == const $CopyWithPlaceholder() 92 | ? _value.description 93 | // ignore: cast_nullable_to_non_nullable 94 | : description as String?, 95 | label: label == const $CopyWithPlaceholder() 96 | ? _value.label 97 | // ignore: cast_nullable_to_non_nullable 98 | : label as String?, 99 | ); 100 | } 101 | } 102 | 103 | extension $AlfredUserConfigurationSelectCopyWith 104 | on AlfredUserConfigurationSelect { 105 | /// Returns a callable class that can be used as follows: `instanceOfAlfredUserConfigurationSelect.copyWith(...)` or like so:`instanceOfAlfredUserConfigurationSelect.copyWith.fieldName(...)`. 106 | // ignore: library_private_types_in_public_api 107 | _$AlfredUserConfigurationSelectCWProxy get copyWith => 108 | _$AlfredUserConfigurationSelectCWProxyImpl(this); 109 | } 110 | 111 | // ************************************************************************** 112 | // JsonSerializableGenerator 113 | // ************************************************************************** 114 | 115 | AlfredUserConfigurationSelect _$AlfredUserConfigurationSelectFromJson( 116 | Map json) => 117 | AlfredUserConfigurationSelect( 118 | type: $enumDecode(_$AlfredUserConfigurationTypeEnumMap, json['type']), 119 | variable: json['variable'] as String, 120 | config: 121 | AlfredUserConfigurationSelect._configFromJson(json['config'] as Map), 122 | description: json['description'] as String?, 123 | label: json['label'] as String?, 124 | ); 125 | 126 | const _$AlfredUserConfigurationTypeEnumMap = { 127 | AlfredUserConfigurationType.textField: 'textfield', 128 | AlfredUserConfigurationType.textArea: 'textarea', 129 | AlfredUserConfigurationType.checkBox: 'checkbox', 130 | AlfredUserConfigurationType.select: 'popupbutton', 131 | AlfredUserConfigurationType.filePicker: 'filepicker', 132 | AlfredUserConfigurationType.slider: 'slider', 133 | }; 134 | -------------------------------------------------------------------------------- /lib/src/models/alfred_user_configuration_text_area.dart: -------------------------------------------------------------------------------- 1 | import 'package:alfred_workflow/src/models/alfred_user_configuration.dart'; 2 | import 'package:alfred_workflow/src/models/alfred_user_configuration_config_text_area.dart'; 3 | import 'package:alfred_workflow/src/models/alfred_user_configuration_type.dart'; 4 | import 'package:copy_with_extension/copy_with_extension.dart'; 5 | import 'package:equatable/equatable.dart'; 6 | import 'package:json_annotation/json_annotation.dart'; 7 | import 'package:meta/meta.dart'; 8 | 9 | part 'alfred_user_configuration_text_area.g.dart'; 10 | 11 | /// Alfred text area user configuration 12 | 13 | @CopyWith() 14 | @JsonSerializable(explicitToJson: true, createToJson: false) 15 | final class AlfredUserConfigurationTextArea extends AlfredUserConfiguration< 16 | String, AlfredUserConfigurationConfigTextArea> with EquatableMixin { 17 | const AlfredUserConfigurationTextArea({ 18 | required super.type, 19 | required super.variable, 20 | required this.config, 21 | super.description, 22 | super.label, 23 | }); 24 | 25 | /// The configuration for the text area 26 | @override 27 | @JsonKey(fromJson: _configFromJson) 28 | final AlfredUserConfigurationConfigTextArea config; 29 | 30 | @internal 31 | @override 32 | AlfredUserConfiguration 33 | copyWithConfig(AlfredUserConfigurationConfigTextArea config) => 34 | copyWith(config: config); 35 | 36 | static AlfredUserConfigurationConfigTextArea _configFromJson(Map json) => 37 | AlfredUserConfigurationConfigTextArea.fromJson( 38 | json.map((k, v) => MapEntry(k.toString(), v)), 39 | ); 40 | 41 | factory AlfredUserConfigurationTextArea.fromJson(Map json) => 42 | _$AlfredUserConfigurationTextAreaFromJson( 43 | json.map((k, v) => MapEntry(k.toString(), v)), 44 | ); 45 | } 46 | -------------------------------------------------------------------------------- /lib/src/models/alfred_user_configuration_text_field.dart: -------------------------------------------------------------------------------- 1 | import 'package:alfred_workflow/src/models/alfred_user_configuration.dart'; 2 | import 'package:alfred_workflow/src/models/alfred_user_configuration_config_text_field.dart'; 3 | import 'package:alfred_workflow/src/models/alfred_user_configuration_type.dart'; 4 | import 'package:copy_with_extension/copy_with_extension.dart'; 5 | import 'package:equatable/equatable.dart'; 6 | import 'package:json_annotation/json_annotation.dart'; 7 | import 'package:meta/meta.dart'; 8 | 9 | part 'alfred_user_configuration_text_field.g.dart'; 10 | 11 | /// Alfred text field user configuration 12 | 13 | @CopyWith() 14 | @JsonSerializable(explicitToJson: true, createToJson: false) 15 | final class AlfredUserConfigurationTextField extends AlfredUserConfiguration< 16 | String, AlfredUserConfigurationConfigTextField> with EquatableMixin { 17 | const AlfredUserConfigurationTextField({ 18 | required super.type, 19 | required super.variable, 20 | required this.config, 21 | super.description, 22 | super.label, 23 | }); 24 | 25 | /// The configuration for the text field 26 | @override 27 | @JsonKey(fromJson: _configFromJson) 28 | final AlfredUserConfigurationConfigTextField config; 29 | 30 | @internal 31 | @override 32 | AlfredUserConfiguration 33 | copyWithConfig(AlfredUserConfigurationConfigTextField config) => 34 | copyWith(config: config); 35 | 36 | static AlfredUserConfigurationConfigTextField _configFromJson(Map json) => 37 | AlfredUserConfigurationConfigTextField.fromJson( 38 | json.map((k, v) => MapEntry(k.toString(), v)), 39 | ); 40 | 41 | factory AlfredUserConfigurationTextField.fromJson(Map json) { 42 | return _$AlfredUserConfigurationTextFieldFromJson( 43 | json.map((k, v) => MapEntry(k.toString(), v)), 44 | ); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /lib/src/models/alfred_user_configuration_type.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart'; 2 | 3 | /// The type of user configuration 4 | enum AlfredUserConfigurationType { 5 | @JsonValue('textfield') 6 | textField('textfield'), 7 | @JsonValue('textarea') 8 | textArea('textarea'), 9 | @JsonValue('checkbox') 10 | checkBox('checkbox'), 11 | @JsonValue('popupbutton') 12 | select('popupbutton'), 13 | @JsonValue('filepicker') 14 | filePicker('filepicker'), 15 | @JsonValue('slider') 16 | slider('slider'); 17 | 18 | const AlfredUserConfigurationType(this.jsonValue); 19 | 20 | /// The JSON value of the type 21 | final String jsonValue; 22 | 23 | @override 24 | String toString() => jsonValue; 25 | } 26 | -------------------------------------------------------------------------------- /lib/src/models/github_asset.dart: -------------------------------------------------------------------------------- 1 | import 'package:copy_with_extension/copy_with_extension.dart'; 2 | import 'package:equatable/equatable.dart' show EquatableMixin; 3 | import 'package:json_annotation/json_annotation.dart'; 4 | 5 | import 'github_user.dart'; 6 | 7 | part 'github_asset.g.dart'; 8 | 9 | /// [GithubAsset] implements all the properties of the [Github Release Asset API](https://docs.github.com/en/rest/reference/releases#release-assets) 10 | 11 | @CopyWith() 12 | @JsonSerializable(explicitToJson: true) 13 | final class GithubAsset with EquatableMixin { 14 | const GithubAsset({ 15 | required this.url, 16 | required this.id, 17 | required this.nodeId, 18 | required this.name, 19 | this.label, 20 | required this.uploader, 21 | required this.contentType, 22 | required this.state, 23 | required this.size, 24 | required this.downloadCount, 25 | required this.createdAt, 26 | required this.updatedAt, 27 | required this.browserDownloadUrl, 28 | }); 29 | 30 | final Uri url; 31 | final int id; 32 | final String nodeId; 33 | final String name; 34 | final String? label; 35 | @JsonKey(fromJson: _githubUserFromJson) 36 | final GithubUser uploader; 37 | final String contentType; 38 | final String state; 39 | final int size; 40 | final int downloadCount; 41 | final DateTime createdAt; 42 | final DateTime updatedAt; 43 | final Uri browserDownloadUrl; 44 | 45 | static GithubUser _githubUserFromJson(dynamic json) => 46 | GithubUser.fromJson((Map.from(json))); 47 | 48 | factory GithubAsset.fromJson(Map json) => 49 | _$GithubAssetFromJson(json); 50 | 51 | Map toJson() => _$GithubAssetToJson(this); 52 | 53 | @override 54 | List get props => _$props; 55 | } 56 | -------------------------------------------------------------------------------- /lib/src/models/github_release.dart: -------------------------------------------------------------------------------- 1 | import 'package:copy_with_extension/copy_with_extension.dart'; 2 | import 'package:equatable/equatable.dart' show EquatableMixin; 3 | import 'package:json_annotation/json_annotation.dart'; 4 | import 'package:pub_semver/pub_semver.dart' show Version; 5 | 6 | import '../converters/version_converter.dart'; 7 | import 'github_asset.dart'; 8 | import 'github_user.dart'; 9 | 10 | part 'github_release.g.dart'; 11 | 12 | /// [GithubRelease] implements all the properties of the [Github Releases API](https://docs.github.com/en/rest/reference/releases) 13 | 14 | @CopyWith() 15 | @JsonSerializable(explicitToJson: true) 16 | @VersionConverter.instance 17 | final class GithubRelease with EquatableMixin { 18 | const GithubRelease({ 19 | required this.url, 20 | required this.assetsUrl, 21 | required this.uploadUrl, 22 | required this.htmlUrl, 23 | required this.id, 24 | required this.author, 25 | required this.nodeId, 26 | required this.tagName, 27 | required this.targetCommitish, 28 | required this.name, 29 | required this.draft, 30 | required this.prerelease, 31 | required this.createdAt, 32 | required this.publishedAt, 33 | required this.assets, 34 | required this.tarballUrl, 35 | required this.zipballUrl, 36 | required this.body, 37 | }); 38 | 39 | final Uri url; 40 | final Uri assetsUrl; 41 | final Uri uploadUrl; 42 | final Uri htmlUrl; 43 | final int id; 44 | @JsonKey(fromJson: _githubUserFromJson) 45 | final GithubUser author; 46 | final String nodeId; 47 | final Version tagName; 48 | final String targetCommitish; 49 | final String name; 50 | final bool draft; 51 | final bool prerelease; 52 | final DateTime createdAt; 53 | final DateTime publishedAt; 54 | @JsonKey(fromJson: _githubAssetsFromJson) 55 | final List assets; 56 | final Uri tarballUrl; 57 | final Uri zipballUrl; 58 | final String body; 59 | 60 | static GithubUser _githubUserFromJson(dynamic json) => 61 | GithubUser.fromJson((Map.from(json))); 62 | 63 | static List _githubAssetsFromJson(List items) => items 64 | .map((e) => GithubAsset.fromJson(Map.from(e))) 65 | .toList(); 66 | 67 | factory GithubRelease.fromJson(Map json) => 68 | _$GithubReleaseFromJson(json); 69 | 70 | Map toJson() => _$GithubReleaseToJson(this); 71 | 72 | @override 73 | List get props => _$props; 74 | } 75 | -------------------------------------------------------------------------------- /lib/src/models/github_user.dart: -------------------------------------------------------------------------------- 1 | import 'package:copy_with_extension/copy_with_extension.dart'; 2 | import 'package:equatable/equatable.dart' show EquatableMixin; 3 | import 'package:json_annotation/json_annotation.dart'; 4 | 5 | part 'github_user.g.dart'; 6 | 7 | /// [GithubUser] implements all the properties of the [Github Users API](https://docs.github.com/en/rest/reference/users) 8 | 9 | @CopyWith() 10 | @JsonSerializable() 11 | final class GithubUser with EquatableMixin { 12 | const GithubUser({ 13 | required this.login, 14 | required this.id, 15 | required this.nodeId, 16 | required this.avatarUrl, 17 | required this.gravatarId, 18 | required this.url, 19 | required this.htmlUrl, 20 | required this.reposUrl, 21 | required this.type, 22 | required this.siteAdmin, 23 | }); 24 | 25 | final String login; 26 | final int id; 27 | final String nodeId; 28 | final Uri avatarUrl; 29 | final String gravatarId; 30 | final Uri url; 31 | final Uri htmlUrl; 32 | final Uri reposUrl; 33 | final String type; 34 | final bool siteAdmin; 35 | 36 | factory GithubUser.fromJson(Map json) => 37 | _$GithubUserFromJson(json); 38 | 39 | Map toJson() => _$GithubUserToJson(this); 40 | 41 | @override 42 | List get props => _$props; 43 | } 44 | -------------------------------------------------------------------------------- /lib/src/models/index.dart: -------------------------------------------------------------------------------- 1 | export 'alfred_automatic_cache.dart' show AlfredAutomaticCache; 2 | export 'alfred_item.dart' show AlfredItem; 3 | export 'alfred_item_icon.dart' show AlfredItemIcon, AlfredItemIconType; 4 | export 'alfred_item_mod.dart' show AlfredItemMod, AlfredItemModKey; 5 | export 'alfred_item_text.dart' show AlfredItemText; 6 | export 'alfred_items.dart' show AlfredItems; 7 | export 'alfred_user_configuration.dart'; 8 | export 'alfred_user_configuration_check_box.dart'; 9 | export 'alfred_user_configuration_config.dart'; 10 | export 'alfred_user_configuration_config_check_box.dart'; 11 | export 'alfred_user_configuration_config_file_picker.dart'; 12 | export 'alfred_user_configuration_config_select.dart'; 13 | export 'alfred_user_configuration_config_text_area.dart'; 14 | export 'alfred_user_configuration_config_text_field.dart'; 15 | export 'alfred_user_configuration_file_picker.dart'; 16 | export 'alfred_user_configuration_number_slider.dart'; 17 | export 'alfred_user_configuration_select.dart'; 18 | export 'alfred_user_configuration_text_area.dart'; 19 | export 'alfred_user_configuration_text_field.dart'; 20 | export 'alfred_user_configuration_type.dart'; 21 | export 'github_asset.dart' show GithubAsset; 22 | export 'github_release.dart' show GithubRelease; 23 | export 'github_user.dart' show GithubUser; 24 | -------------------------------------------------------------------------------- /lib/src/services/alfred_cache.dart: -------------------------------------------------------------------------------- 1 | import 'dart:developer' show log; 2 | import 'dart:io' show Platform; 3 | 4 | import 'package:copy_with_extension/copy_with_extension.dart'; 5 | import 'package:equatable/equatable.dart'; 6 | import 'package:equatable_annotations/equatable_annotations.dart'; 7 | import 'package:path/path.dart' show dirname; 8 | import 'package:stash/stash_api.dart' 9 | show 10 | Cache, 11 | CacheEntryCreatedEvent, 12 | CacheEntryEvictedEvent, 13 | CacheEntryExpiredEvent, 14 | CacheEntryRemovedEvent, 15 | CacheEntryUpdatedEvent, 16 | CacheExtension, 17 | CreatedExpiryPolicy, 18 | EventListenerMode, 19 | EvictionPolicy, 20 | ExpiryPolicy, 21 | LruEvictionPolicy, 22 | Store; 23 | import 'package:stash_file/stash_file.dart' 24 | show FileCacheStore, newFileLocalCacheStore; 25 | 26 | part 'alfred_cache.g.dart'; 27 | 28 | @CopyWith() 29 | base class AlfredCache with EquatableMixin { 30 | /// Builds an [AlfredCache] providing a [Cache] backed by a [Store] 31 | /// 32 | /// * [fromEncodable] : A custom function the converts to the object from a `Map` representation 33 | /// * [path] : Optionally customize the base storage location for this store 34 | /// * [maxEntries] : The max number of entries this cache can hold if provided. Defaults to 10. 35 | /// * [name] : The name of the cache. Defaults to "query_cache". 36 | /// * [evictionPolicy] : Optionally customize the [EvictionPolicy]. Defaults to [LruEvictionPolicy] 37 | /// * [expiryPolicy] : Optionally customize the [ExpiryPolicy]. Defaults to [CreatedExpiryPolicy] with a [Duration] of 1 minute. 38 | /// * [verbose] : If set to true then listeners will print events to the developer log. Defaults to false. 39 | AlfredCache({ 40 | required this.fromEncodable, 41 | this.path, 42 | this.maxEntries = 10, 43 | this.name = 'query_cache', 44 | this.evictionPolicy = const LruEvictionPolicy(), 45 | this.expiryPolicy = const CreatedExpiryPolicy( 46 | Duration(minutes: 1), 47 | ), 48 | this.verbose = false, 49 | }) : assert(maxEntries > 0, 'maxEntries must be positive number'); 50 | 51 | /// A custom function the converts to the object from a `Map` representation 52 | final T Function(Map) fromEncodable; 53 | 54 | /// The base storage location for this store 55 | final String? path; 56 | 57 | /// The max number of entries this cache can hold if provided. To trigger the eviction policy this value should be provided 58 | final int maxEntries; 59 | 60 | /// The name of the cache 61 | final String name; 62 | 63 | /// Defines the eviction policy contract that every cache eviction algorithm should implement 64 | final EvictionPolicy evictionPolicy; 65 | 66 | /// Defines functions to determine when cache entries will expire based on 67 | /// creation, access and modification operations. 68 | /// 69 | /// Each of the functions return a new [Duration] that specifies the 70 | /// amount of time that must pass before a cache entry is considered expired. 71 | final ExpiryPolicy expiryPolicy; 72 | 73 | /// If [verbose] = true then listeners will print events to the developer log 74 | final bool verbose; 75 | 76 | /// The local [FileCacheStore] 77 | @ignore 78 | late final Future store = newFileLocalCacheStore( 79 | path: path ?? dirname(Platform.script.toFilePath()), 80 | ); 81 | 82 | /// The [Cache] backed by a [Store] 83 | @ignore 84 | late final Future> cache = store.then( 85 | (FileCacheStore cacheStore) async => await cacheStore.cache( 86 | name: name, 87 | fromEncodable: fromEncodable, 88 | maxEntries: maxEntries, 89 | eventListenerMode: EventListenerMode.synchronous, 90 | evictionPolicy: evictionPolicy, 91 | expiryPolicy: expiryPolicy, 92 | ) 93 | ..on>().listen( 94 | verbose ? (event) => log('Key "${event.entry.key}" added') : null, 95 | ) 96 | ..on>().listen( 97 | verbose ? (event) => log('Key "${event.newEntry.key}" updated') : null, 98 | ) 99 | ..on>().listen( 100 | verbose ? (event) => log('Key "${event.entry.key}" removed') : null, 101 | ) 102 | ..on>().listen( 103 | verbose ? (event) => log('Key "${event.entry.key}" expired') : null, 104 | ) 105 | ..on>().listen( 106 | verbose ? (event) => log('Key "${event.entry.key}" evicted') : null, 107 | ), 108 | ); 109 | 110 | @override 111 | List get props => _$props; 112 | } 113 | -------------------------------------------------------------------------------- /lib/src/services/alfred_cache.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'alfred_cache.dart'; 4 | 5 | // ************************************************************************** 6 | // CopyWithGenerator 7 | // ************************************************************************** 8 | 9 | abstract class _$AlfredCacheCWProxy { 10 | AlfredCache fromEncodable(T Function(Map) fromEncodable); 11 | 12 | AlfredCache path(String? path); 13 | 14 | AlfredCache maxEntries(int maxEntries); 15 | 16 | AlfredCache name(String name); 17 | 18 | AlfredCache evictionPolicy(EvictionPolicy evictionPolicy); 19 | 20 | AlfredCache expiryPolicy(ExpiryPolicy expiryPolicy); 21 | 22 | AlfredCache verbose(bool verbose); 23 | 24 | /// This function **does support** nullification of nullable fields. All `null` values passed to `non-nullable` fields will be ignored. You can also use `AlfredCache(...).copyWith.fieldName(...)` to override fields one at a time with nullification support. 25 | /// 26 | /// Usage 27 | /// ```dart 28 | /// AlfredCache(...).copyWith(id: 12, name: "My name") 29 | /// ```` 30 | AlfredCache call({ 31 | T Function(Map) fromEncodable, 32 | String? path, 33 | int maxEntries, 34 | String name, 35 | EvictionPolicy evictionPolicy, 36 | ExpiryPolicy expiryPolicy, 37 | bool verbose, 38 | }); 39 | } 40 | 41 | /// Proxy class for `copyWith` functionality. This is a callable class and can be used as follows: `instanceOfAlfredCache.copyWith(...)`. Additionally contains functions for specific fields e.g. `instanceOfAlfredCache.copyWith.fieldName(...)` 42 | class _$AlfredCacheCWProxyImpl implements _$AlfredCacheCWProxy { 43 | const _$AlfredCacheCWProxyImpl(this._value); 44 | 45 | final AlfredCache _value; 46 | 47 | @override 48 | AlfredCache fromEncodable( 49 | T Function(Map) fromEncodable) => 50 | this(fromEncodable: fromEncodable); 51 | 52 | @override 53 | AlfredCache path(String? path) => this(path: path); 54 | 55 | @override 56 | AlfredCache maxEntries(int maxEntries) => this(maxEntries: maxEntries); 57 | 58 | @override 59 | AlfredCache name(String name) => this(name: name); 60 | 61 | @override 62 | AlfredCache evictionPolicy(EvictionPolicy evictionPolicy) => 63 | this(evictionPolicy: evictionPolicy); 64 | 65 | @override 66 | AlfredCache expiryPolicy(ExpiryPolicy expiryPolicy) => 67 | this(expiryPolicy: expiryPolicy); 68 | 69 | @override 70 | AlfredCache verbose(bool verbose) => this(verbose: verbose); 71 | 72 | @override 73 | 74 | /// This function **does support** nullification of nullable fields. All `null` values passed to `non-nullable` fields will be ignored. You can also use `AlfredCache(...).copyWith.fieldName(...)` to override fields one at a time with nullification support. 75 | /// 76 | /// Usage 77 | /// ```dart 78 | /// AlfredCache(...).copyWith(id: 12, name: "My name") 79 | /// ```` 80 | AlfredCache call({ 81 | Object? fromEncodable = const $CopyWithPlaceholder(), 82 | Object? path = const $CopyWithPlaceholder(), 83 | Object? maxEntries = const $CopyWithPlaceholder(), 84 | Object? name = const $CopyWithPlaceholder(), 85 | Object? evictionPolicy = const $CopyWithPlaceholder(), 86 | Object? expiryPolicy = const $CopyWithPlaceholder(), 87 | Object? verbose = const $CopyWithPlaceholder(), 88 | }) { 89 | return AlfredCache( 90 | fromEncodable: fromEncodable == const $CopyWithPlaceholder() 91 | ? _value.fromEncodable 92 | // ignore: cast_nullable_to_non_nullable 93 | : fromEncodable as T Function(Map), 94 | path: path == const $CopyWithPlaceholder() 95 | ? _value.path 96 | // ignore: cast_nullable_to_non_nullable 97 | : path as String?, 98 | maxEntries: maxEntries == const $CopyWithPlaceholder() 99 | ? _value.maxEntries 100 | // ignore: cast_nullable_to_non_nullable 101 | : maxEntries as int, 102 | name: name == const $CopyWithPlaceholder() 103 | ? _value.name 104 | // ignore: cast_nullable_to_non_nullable 105 | : name as String, 106 | evictionPolicy: evictionPolicy == const $CopyWithPlaceholder() 107 | ? _value.evictionPolicy 108 | // ignore: cast_nullable_to_non_nullable 109 | : evictionPolicy as EvictionPolicy, 110 | expiryPolicy: expiryPolicy == const $CopyWithPlaceholder() 111 | ? _value.expiryPolicy 112 | // ignore: cast_nullable_to_non_nullable 113 | : expiryPolicy as ExpiryPolicy, 114 | verbose: verbose == const $CopyWithPlaceholder() 115 | ? _value.verbose 116 | // ignore: cast_nullable_to_non_nullable 117 | : verbose as bool, 118 | ); 119 | } 120 | } 121 | 122 | extension $AlfredCacheCopyWith on AlfredCache { 123 | /// Returns a callable class that can be used as follows: `instanceOfAlfredCache.copyWith(...)` or like so:`instanceOfAlfredCache.copyWith.fieldName(...)`. 124 | // ignore: library_private_types_in_public_api 125 | _$AlfredCacheCWProxy get copyWith => _$AlfredCacheCWProxyImpl(this); 126 | } 127 | 128 | // ************************************************************************** 129 | // EquatableGenerator 130 | // ************************************************************************** 131 | 132 | extension _$AlfredCacheEquatableAnnotations on AlfredCache { 133 | List get _$props => [ 134 | fromEncodable, 135 | path, 136 | maxEntries, 137 | name, 138 | evictionPolicy, 139 | expiryPolicy, 140 | verbose, 141 | ]; 142 | } 143 | -------------------------------------------------------------------------------- /lib/src/services/alfred_updater.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'alfred_updater.dart'; 4 | 5 | // ************************************************************************** 6 | // CopyWithGenerator 7 | // ************************************************************************** 8 | 9 | abstract class _$AlfredUpdaterCWProxy { 10 | AlfredUpdater githubRepositoryUrl(Uri githubRepositoryUrl); 11 | 12 | AlfredUpdater currentVersion(String currentVersion); 13 | 14 | AlfredUpdater updateInterval(Duration updateInterval); 15 | 16 | AlfredUpdater cache(AlfredCache? cache); 17 | 18 | AlfredUpdater client(Client? client); 19 | 20 | /// This function **does support** nullification of nullable fields. All `null` values passed to `non-nullable` fields will be ignored. You can also use `AlfredUpdater(...).copyWith.fieldName(...)` to override fields one at a time with nullification support. 21 | /// 22 | /// Usage 23 | /// ```dart 24 | /// AlfredUpdater(...).copyWith(id: 12, name: "My name") 25 | /// ```` 26 | AlfredUpdater call({ 27 | Uri githubRepositoryUrl, 28 | String currentVersion, 29 | Duration updateInterval, 30 | AlfredCache? cache, 31 | Client? client, 32 | }); 33 | } 34 | 35 | /// Proxy class for `copyWith` functionality. This is a callable class and can be used as follows: `instanceOfAlfredUpdater.copyWith(...)`. Additionally contains functions for specific fields e.g. `instanceOfAlfredUpdater.copyWith.fieldName(...)` 36 | class _$AlfredUpdaterCWProxyImpl implements _$AlfredUpdaterCWProxy { 37 | const _$AlfredUpdaterCWProxyImpl(this._value); 38 | 39 | final AlfredUpdater _value; 40 | 41 | @override 42 | AlfredUpdater githubRepositoryUrl(Uri githubRepositoryUrl) => 43 | this(githubRepositoryUrl: githubRepositoryUrl); 44 | 45 | @override 46 | AlfredUpdater currentVersion(String currentVersion) => 47 | this(currentVersion: currentVersion); 48 | 49 | @override 50 | AlfredUpdater updateInterval(Duration updateInterval) => 51 | this(updateInterval: updateInterval); 52 | 53 | @override 54 | AlfredUpdater cache(AlfredCache? cache) => this(cache: cache); 55 | 56 | @override 57 | AlfredUpdater client(Client? client) => this(client: client); 58 | 59 | @override 60 | 61 | /// This function **does support** nullification of nullable fields. All `null` values passed to `non-nullable` fields will be ignored. You can also use `AlfredUpdater(...).copyWith.fieldName(...)` to override fields one at a time with nullification support. 62 | /// 63 | /// Usage 64 | /// ```dart 65 | /// AlfredUpdater(...).copyWith(id: 12, name: "My name") 66 | /// ```` 67 | AlfredUpdater call({ 68 | Object? githubRepositoryUrl = const $CopyWithPlaceholder(), 69 | Object? currentVersion = const $CopyWithPlaceholder(), 70 | Object? updateInterval = const $CopyWithPlaceholder(), 71 | Object? cache = const $CopyWithPlaceholder(), 72 | Object? client = const $CopyWithPlaceholder(), 73 | }) { 74 | return AlfredUpdater( 75 | githubRepositoryUrl: githubRepositoryUrl == const $CopyWithPlaceholder() 76 | ? _value.githubRepositoryUrl 77 | // ignore: cast_nullable_to_non_nullable 78 | : githubRepositoryUrl as Uri, 79 | currentVersion: currentVersion == const $CopyWithPlaceholder() 80 | ? _value.currentVersion 81 | // ignore: cast_nullable_to_non_nullable 82 | : currentVersion as String, 83 | updateInterval: updateInterval == const $CopyWithPlaceholder() 84 | ? _value.updateInterval 85 | // ignore: cast_nullable_to_non_nullable 86 | : updateInterval as Duration, 87 | cache: cache == const $CopyWithPlaceholder() 88 | ? _value.cache 89 | // ignore: cast_nullable_to_non_nullable 90 | : cache as AlfredCache?, 91 | client: client == const $CopyWithPlaceholder() 92 | ? _value.client 93 | // ignore: cast_nullable_to_non_nullable 94 | : client as Client?, 95 | ); 96 | } 97 | } 98 | 99 | extension $AlfredUpdaterCopyWith on AlfredUpdater { 100 | /// Returns a callable class that can be used as follows: `instanceOfAlfredUpdater.copyWith(...)` or like so:`instanceOfAlfredUpdater.copyWith.fieldName(...)`. 101 | // ignore: library_private_types_in_public_api 102 | _$AlfredUpdaterCWProxy get copyWith => _$AlfredUpdaterCWProxyImpl(this); 103 | } 104 | 105 | // ************************************************************************** 106 | // EquatableGenerator 107 | // ************************************************************************** 108 | 109 | extension _$AlfredUpdaterEquatableAnnotations on AlfredUpdater { 110 | List get _$props => [ 111 | githubRepositoryUrl, 112 | updateInterval, 113 | cache, 114 | client, 115 | _currentVersion, 116 | ]; 117 | } 118 | -------------------------------------------------------------------------------- /lib/src/services/index.dart: -------------------------------------------------------------------------------- 1 | export 'alfred_cache.dart' show AlfredCache; 2 | export 'alfred_updater.dart' show AlfredUpdater; 3 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: alfred_workflow 2 | description: A helper library in Dart for authors of workflows for Alfred. 3 | version: 1.1.5 4 | repository: https://github.com/techouse/alfred_workflow 5 | homepage: https://techouse.github.io/alfred_workflow/ 6 | documentation: https://pub.dev/documentation/alfred_workflow/latest/ 7 | 8 | platforms: 9 | macos: 10 | 11 | environment: 12 | sdk: ^3.0.0 13 | 14 | dependencies: 15 | equatable_annotations: ^1.0.0 16 | collection: ^1.18.0 17 | copy_with_extension: ^6.0.1 18 | crypto: ^3.0.6 19 | equatable: ^2.0.7 20 | file: ^7.0.1 21 | http: ^1.3.0 22 | json_annotation: ^4.9.0 23 | meta: ^1.16.0 24 | path: ^1.9.1 25 | plist_parser: ^0.0.11 26 | pub_semver: ^2.2.0 27 | stash: ^5.2.0 28 | stash_file: ^5.2.0 29 | 30 | dev_dependencies: 31 | equatable_gen: ^1.0.2 32 | build_runner: ^2.4.15 33 | build_verify: ^3.1.0 34 | copy_with_extension_gen: ^6.0.1 35 | faker: ^2.2.0 36 | json_serializable: ^6.9.5 37 | lints: ">=5.1.1 <7.0.0" 38 | mockito: ^5.4.6 39 | test: ^1.25.15 40 | data_fixture_dart: ^3.0.0 41 | 42 | topics: 43 | - alfred 44 | - macos 45 | -------------------------------------------------------------------------------- /scripts/compare_versions.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io' show exitCode, stderr, stdout; 2 | import 'package:cli_script/cli_script.dart' show wrapMain; 3 | import 'package:pub_semver/pub_semver.dart' show Version; 4 | 5 | void main(List args) { 6 | wrapMain(() { 7 | exitCode = 0; 8 | 9 | if (args.length != 2) { 10 | stderr.write( 11 | 'Please provide two arguments!\n\nExample usage:\ndart run compare_versions.dart 2.0.0+1 1.9.0+5\n', 12 | ); 13 | exitCode = 1; 14 | return; 15 | } 16 | 17 | late final Version v1; 18 | late final Version v2; 19 | 20 | try { 21 | v1 = Version.parse(args[0]); 22 | } on FormatException catch (e) { 23 | stderr.write('Error parsing version 1: ${e.message}'); 24 | exitCode = 1; 25 | return; 26 | } 27 | 28 | try { 29 | v2 = Version.parse(args[1]); 30 | } on FormatException catch (e) { 31 | stderr.write('Error parsing version 2: ${e.message}'); 32 | exitCode = 1; 33 | return; 34 | } 35 | 36 | stdout.write(v1 > v2 ? 1 : 0); 37 | }); 38 | } 39 | -------------------------------------------------------------------------------- /scripts/makefile_scripts.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Opens a link with the default browser of OS (It works cross-platform) 4 | # 5 | ## You can call it like `open_link balad.ir` to open balad website on your default browser 6 | open_link() { 7 | case "$(uname -s)" in 8 | Darwin) 9 | # macOS 10 | open "$1" 11 | ;; 12 | 13 | Linux) 14 | # Linux: 15 | xdg-open "$1" 16 | ;; 17 | 18 | CYGWIN* | MINGW32* | MSYS* | MINGW*) 19 | # Windows 20 | start "$1" 21 | ;; 22 | 23 | *) 24 | echo 'Not supported OS' 25 | ;; 26 | esac 27 | } 28 | -------------------------------------------------------------------------------- /scripts/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: compare_versions 2 | 3 | publish_to: 'none' 4 | 5 | version: 1.0.0 6 | 7 | environment: 8 | sdk: ">=2.17.0 <4.0.0" 9 | 10 | dependencies: 11 | cli_script: ^0.3.1 12 | pub_semver: ^2.1.4 -------------------------------------------------------------------------------- /test/build/ensure_build_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:build_verify/build_verify.dart'; 2 | import 'package:test/test.dart'; 3 | 4 | void main() { 5 | test( 6 | 'ensure_build', 7 | () => expectBuildClean( 8 | gitDiffPathArguments: [ 9 | ':!pubspec.lock', 10 | ], 11 | ), 12 | ); 13 | } 14 | -------------------------------------------------------------------------------- /test/fixtures/alfred_workflow_fixture.dart: -------------------------------------------------------------------------------- 1 | import 'package:alfred_workflow/alfred_workflow.dart'; 2 | import 'package:data_fixture_dart/data_fixture_dart.dart'; 3 | import 'package:meta/meta.dart'; 4 | 5 | import '../helpers/mock_alfred_cache.dart'; 6 | import 'models/alfred_automatic_cache_fixture.dart'; 7 | 8 | extension AlfredWorkflowFixture on AlfredWorkflow { 9 | static AlfredWorkflowFactory get factory => AlfredWorkflowFactory(); 10 | } 11 | 12 | @internal 13 | final class AlfredWorkflowFactory extends FixtureFactory { 14 | @override 15 | FixtureDefinition definition() => 16 | define((Faker faker, [int index = 0]) => AlfredWorkflow()); 17 | 18 | FixtureRedefinitionBuilder withAutomaticCache([ 19 | AlfredAutomaticCache? automaticCache, 20 | ]) => 21 | (_, [int index = 0]) => AlfredWorkflow( 22 | automaticCache: automaticCache ?? 23 | AlfredAutomaticCacheFixture.factory.makeSingle(), 24 | ); 25 | 26 | FixtureRedefinitionBuilder withFileCache([ 27 | AlfredCache? fileCache, 28 | ]) => 29 | (_, [int index = 0]) => AlfredWorkflow( 30 | fileCache: fileCache ?? 31 | MockAlfredCache( 32 | fromEncodable: (Map json) => 33 | AlfredItems.fromJson(json), 34 | ), 35 | ); 36 | 37 | FixtureRedefinitionBuilder 38 | withoutAlfredSmartResultOrdering() => 39 | (AlfredWorkflow workflow, [int index = 0]) => 40 | workflow..disableAlfredSmartResultOrdering = true; 41 | } 42 | -------------------------------------------------------------------------------- /test/fixtures/data/info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | userconfigurationconfig 6 | 7 | 8 | config 9 | 10 | default 11 | baz value 12 | pairs 13 | 14 | 15 | foo label 16 | foo value 17 | 18 | 19 | bar label 20 | bar value 21 | 22 | 23 | baz label 24 | baz value 25 | 26 | 27 | qux label 28 | qux value 29 | 30 | 31 | 32 | description 33 | popupbutton description 34 | label 35 | popupbutton label 36 | type 37 | popupbutton 38 | variable 39 | popupbutton_variable 40 | 41 | 42 | config 43 | 44 | default 45 | textfield default 46 | placeholder 47 | textfield placeholder 48 | required 49 | 50 | trim 51 | 52 | 53 | description 54 | textfield description 55 | label 56 | textfield label 57 | type 58 | textfield 59 | variable 60 | textfield_variable 61 | 62 | 63 | config 64 | 65 | default 66 | textarea default 67 | required 68 | 69 | trim 70 | 71 | verticalsize 72 | 3 73 | 74 | description 75 | textarea description 76 | label 77 | textarea label 78 | type 79 | textarea 80 | variable 81 | textarea_variable 82 | 83 | 84 | config 85 | 86 | default 87 | 88 | required 89 | 90 | text 91 | checkbox text 92 | 93 | description 94 | checkbox description 95 | label 96 | checkbox label 97 | type 98 | checkbox 99 | variable 100 | checkbox_variable 101 | 102 | 103 | config 104 | 105 | default 106 | 107 | filtermode 108 | 0 109 | placeholder 110 | 111 | required 112 | 113 | 114 | description 115 | filepicker description 116 | label 117 | filepicker label 118 | type 119 | filepicker 120 | variable 121 | filepicker_variable 122 | 123 | 124 | config 125 | 126 | defaultvalue 127 | 50 128 | markercount 129 | 10 130 | maxvalue 131 | 100 132 | minvalue 133 | 0 134 | onlystoponmarkers 135 | 136 | showmarkers 137 | 138 | 139 | description 140 | number slider description 141 | label 142 | number slider label 143 | type 144 | slider 145 | variable 146 | number_slider_variable 147 | 148 | 149 | 150 | 151 | -------------------------------------------------------------------------------- /test/fixtures/data/prefs.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | popupbutton_variable 6 | foo value 7 | checkbox_variable 8 | 9 | filepicker_variable 10 | /home/user/Desktop/document.pdf 11 | textfield_variable 12 | lorem ipsum dolor 13 | New item 14 | 15 | textarea_variable 16 | lorem ipsum dolor sit amet 17 | number_slider_variable 18 | 69 19 | 20 | 21 | -------------------------------------------------------------------------------- /test/fixtures/extensions/fixture_factory_extension.dart: -------------------------------------------------------------------------------- 1 | import 'package:data_fixture_dart/data_fixture_dart.dart'; 2 | 3 | extension FixtureFactoryExtension on FixtureFactory { 4 | FixtureDefinition states( 5 | Iterable> definitions, 6 | ) => 7 | redefine( 8 | (Model model, [int index = 0]) => definitions.fold( 9 | model, 10 | (Model previousState, redefinitionBuilder) => 11 | redefinitionBuilder(previousState), 12 | ), 13 | ); 14 | } 15 | -------------------------------------------------------------------------------- /test/fixtures/models/alfred_action_fixture.dart: -------------------------------------------------------------------------------- 1 | import 'package:alfred_workflow/src/models/alfred_action.dart'; 2 | import 'package:data_fixture_dart/data_fixture_dart.dart'; 3 | import 'package:meta/meta.dart'; 4 | 5 | extension AlfredActionFixture on AlfredAction { 6 | static AlfredActionFactory get factory => AlfredActionFactory(); 7 | } 8 | 9 | @internal 10 | final class AlfredActionFactory extends FixtureFactory { 11 | @override 12 | FixtureDefinition definition() => define( 13 | (Faker faker, [int index = 0]) => AlfredAction( 14 | text: faker.lorem.words(3), 15 | url: Uri.parse(faker.internet.httpsUrl()), 16 | file: '/${faker.lorem.words(3).join('/')}.txt', 17 | auto: '/${faker.lorem.words(3).join('/')}.txt', 18 | ), 19 | ); 20 | 21 | FixtureRedefinitionBuilder text(Object? value) => 22 | (AlfredAction action, [int index = 0]) => action.copyWith(text: value); 23 | 24 | FixtureRedefinitionBuilder url(Uri? value) => 25 | (AlfredAction action, [int index = 0]) => action.copyWith(url: value); 26 | 27 | FixtureRedefinitionBuilder file(String? value) => 28 | (AlfredAction action, [int index = 0]) => action.copyWith(file: value); 29 | 30 | FixtureRedefinitionBuilder auto(String? value) => 31 | (AlfredAction action, [int index = 0]) => action.copyWith(auto: value); 32 | } 33 | -------------------------------------------------------------------------------- /test/fixtures/models/alfred_automatic_cache_fixture.dart: -------------------------------------------------------------------------------- 1 | import 'package:alfred_workflow/src/models/alfred_automatic_cache.dart'; 2 | import 'package:data_fixture_dart/data_fixture_dart.dart'; 3 | import 'package:meta/meta.dart'; 4 | 5 | extension AlfredAutomaticCacheFixture on AlfredAutomaticCache { 6 | static AlfredAutomaticCacheFactory get factory => 7 | AlfredAutomaticCacheFactory(); 8 | } 9 | 10 | @internal 11 | final class AlfredAutomaticCacheFactory 12 | extends FixtureFactory { 13 | @override 14 | FixtureDefinition definition() => define( 15 | (Faker faker, [int index = 0]) => AlfredAutomaticCache( 16 | seconds: faker.randomGenerator.integer(86400, min: 5), 17 | looseReload: faker.randomGenerator.boolean(), 18 | ), 19 | ); 20 | 21 | FixtureRedefinitionBuilder seconds(int value) => 22 | (AlfredAutomaticCache cache, [int index = 0]) => 23 | cache.copyWith(seconds: value); 24 | 25 | FixtureRedefinitionBuilder looseReload( 26 | bool? value, 27 | ) => 28 | (AlfredAutomaticCache cache, [int index = 0]) => 29 | cache.copyWith(looseReload: value); 30 | } 31 | -------------------------------------------------------------------------------- /test/fixtures/models/alfred_item_fixture.dart: -------------------------------------------------------------------------------- 1 | import 'package:alfred_workflow/alfred_workflow.dart'; 2 | import 'package:alfred_workflow/src/models/alfred_action.dart'; 3 | import 'package:alfred_workflow/src/models/alfred_item.dart'; 4 | import 'package:data_fixture_dart/data_fixture_dart.dart'; 5 | import 'package:meta/meta.dart'; 6 | 7 | import 'alfred_action_fixture.dart'; 8 | import 'alfred_item_icon_fixture.dart'; 9 | import 'alfred_item_mod_fixture.dart'; 10 | import 'alfred_item_text_fixture.dart'; 11 | 12 | extension AlfredItemFixture on AlfredItem { 13 | static AlfredItemFactory get factory => AlfredItemFactory(); 14 | } 15 | 16 | @internal 17 | final class AlfredItemFactory extends FixtureFactory { 18 | final bool useAction = faker.randomGenerator.boolean(); 19 | 20 | @override 21 | FixtureDefinition definition() => define( 22 | (Faker faker, [int index = 0]) => AlfredItem( 23 | title: faker.lorem.sentence(), 24 | type: AlfredItemType.Default, 25 | valid: faker.randomGenerator.boolean(), 26 | subtitle: 27 | faker.randomGenerator.boolean() ? faker.lorem.sentence() : null, 28 | arg: !useAction ? faker.lorem.sentence() : null, 29 | autocomplete: 30 | faker.randomGenerator.boolean() ? faker.lorem.sentence() : null, 31 | uid: faker.randomGenerator.boolean() ? faker.guid.guid() : null, 32 | icon: AlfredItemIconFixture.factory.makeSingle(), 33 | text: AlfredItemTextFixture.factory.makeSingle(), 34 | quickLookUrl: faker.randomGenerator.boolean() 35 | ? faker.internet.httpsUrl() 36 | : null, 37 | match: 38 | faker.randomGenerator.boolean() ? faker.lorem.sentence() : null, 39 | mods: { 40 | {AlfredItemModKey.cmd}: AlfredItemModFixture.factory.makeSingle(), 41 | {AlfredItemModKey.ctrl, AlfredItemModKey.alt}: 42 | AlfredItemModFixture.factory.makeSingle(), 43 | { 44 | AlfredItemModKey.cmd, 45 | AlfredItemModKey.shift, 46 | AlfredItemModKey.alt, 47 | }: AlfredItemModFixture.factory.makeSingle(), 48 | }, 49 | action: useAction ? _fakeAction() : null, 50 | ), 51 | ); 52 | 53 | Object _fakeAction() { 54 | final Type type = faker.randomGenerator.element([ 55 | String, 56 | List, 57 | AlfredAction, 58 | ]); 59 | 60 | switch (type) { 61 | case const (List): 62 | return List.from(faker.lorem.sentences(2)); 63 | case const (AlfredAction): 64 | return AlfredActionFixture.factory.makeSingle(); 65 | case const (String): 66 | default: 67 | return faker.lorem.sentence(); 68 | } 69 | } 70 | 71 | FixtureRedefinitionBuilder title(String value) => 72 | (AlfredItem item, [int index = 0]) => item.copyWith(title: value); 73 | 74 | FixtureRedefinitionBuilder type(AlfredItemType value) => 75 | (AlfredItem item, [int index = 0]) => item.copyWith(type: value); 76 | 77 | FixtureRedefinitionBuilder valid(bool value) => 78 | (AlfredItem item, [int index = 0]) => item.copyWith(valid: value); 79 | 80 | FixtureRedefinitionBuilder subtitle(String? value) => 81 | (AlfredItem item, [int index = 0]) => item.copyWith(subtitle: value); 82 | 83 | FixtureRedefinitionBuilder arg(String? value) => 84 | (AlfredItem item, [int index = 0]) => item.copyWith(arg: value); 85 | 86 | FixtureRedefinitionBuilder autocomplete(String? value) => 87 | (AlfredItem item, [int index = 0]) => item.copyWith(autocomplete: value); 88 | 89 | FixtureRedefinitionBuilder uid(String? value) => 90 | (AlfredItem item, [int index = 0]) => item.copyWith(uid: value); 91 | 92 | FixtureRedefinitionBuilder icon(AlfredItemIcon? value) => 93 | (AlfredItem item, [int index = 0]) => item.copyWith(icon: value); 94 | 95 | FixtureRedefinitionBuilder text(AlfredItemText? value) => 96 | (AlfredItem item, [int index = 0]) => item.copyWith(text: value); 97 | 98 | FixtureRedefinitionBuilder quickLookUrl(String? value) => 99 | (AlfredItem item, [int index = 0]) => item.copyWith(quickLookUrl: value); 100 | 101 | FixtureRedefinitionBuilder match(String? value) => 102 | (AlfredItem item, [int index = 0]) => item.copyWith(match: value); 103 | 104 | FixtureRedefinitionBuilder mods( 105 | Map, AlfredItemMod>? value, 106 | ) => 107 | (AlfredItem item, [int index = 0]) => item.copyWith(mods: value); 108 | 109 | FixtureRedefinitionBuilder action(Object? value) => 110 | (AlfredItem item, [int index = 0]) => 111 | value is String || value is Iterable || value is Map 112 | ? item.copyWith(action: value) 113 | : item; 114 | } 115 | -------------------------------------------------------------------------------- /test/fixtures/models/alfred_item_icon_fixture.dart: -------------------------------------------------------------------------------- 1 | import 'package:alfred_workflow/src/models/alfred_item_icon.dart'; 2 | import 'package:data_fixture_dart/data_fixture_dart.dart'; 3 | import 'package:meta/meta.dart'; 4 | 5 | extension AlfredItemIconFixture on AlfredItemIcon { 6 | static AlfredItemIconFactory get factory => AlfredItemIconFactory(); 7 | } 8 | 9 | @internal 10 | final class AlfredItemIconFactory extends FixtureFactory { 11 | @override 12 | FixtureDefinition definition() => define( 13 | (Faker faker, [int index = 0]) => AlfredItemIcon( 14 | path: [ 15 | '/${faker.randomGenerator.string(16)}', 16 | faker.randomGenerator.string(16), 17 | '${faker.randomGenerator.string(16)}.png', 18 | ].join('/'), 19 | type: faker.randomGenerator.boolean() 20 | ? faker.randomGenerator.element(AlfredItemIconType.values) 21 | : null, 22 | ), 23 | ); 24 | 25 | FixtureRedefinitionBuilder path(String value) => 26 | (AlfredItemIcon alfredItemIcon, [int index = 0]) => 27 | alfredItemIcon.copyWith(path: value); 28 | 29 | FixtureRedefinitionBuilder type(AlfredItemIconType? value) => 30 | (AlfredItemIcon alfredItemIcon, [int index = 0]) => 31 | alfredItemIcon.copyWith(type: value); 32 | } 33 | -------------------------------------------------------------------------------- /test/fixtures/models/alfred_item_mod_fixture.dart: -------------------------------------------------------------------------------- 1 | import 'package:alfred_workflow/src/models/alfred_item_icon.dart'; 2 | import 'package:alfred_workflow/src/models/alfred_item_mod.dart'; 3 | import 'package:data_fixture_dart/data_fixture_dart.dart'; 4 | import 'package:meta/meta.dart'; 5 | 6 | import 'alfred_item_icon_fixture.dart'; 7 | 8 | extension AlfredItemModFixture on AlfredItemMod { 9 | static AlfredItemModFactory get factory => AlfredItemModFactory(); 10 | } 11 | 12 | @internal 13 | final class AlfredItemModFactory extends FixtureFactory { 14 | @override 15 | FixtureDefinition definition() => define( 16 | (Faker faker, [int index = 0]) => AlfredItemMod( 17 | arg: faker.randomGenerator.boolean() ? faker.lorem.sentence() : null, 18 | subtitle: 19 | faker.randomGenerator.boolean() ? faker.lorem.sentence() : null, 20 | icon: faker.randomGenerator.boolean() 21 | ? AlfredItemIconFixture.factory.makeSingle() 22 | : null, 23 | valid: faker.randomGenerator.boolean(), 24 | ), 25 | ); 26 | 27 | FixtureRedefinitionBuilder arg(String value) => 28 | (AlfredItemMod item, [int index = 0]) => item.copyWith(arg: value); 29 | 30 | FixtureRedefinitionBuilder subtitle(String value) => 31 | (AlfredItemMod item, [int index = 0]) => item.copyWith(subtitle: value); 32 | 33 | FixtureRedefinitionBuilder icon(AlfredItemIcon value) => 34 | (AlfredItemMod item, [int index = 0]) => item.copyWith(icon: value); 35 | 36 | FixtureRedefinitionBuilder valid(bool value) => 37 | (AlfredItemMod item, [int index = 0]) => item.copyWith(valid: value); 38 | } 39 | -------------------------------------------------------------------------------- /test/fixtures/models/alfred_item_text_fixture.dart: -------------------------------------------------------------------------------- 1 | import 'package:alfred_workflow/src/models/alfred_item_text.dart'; 2 | import 'package:data_fixture_dart/data_fixture_dart.dart'; 3 | import 'package:meta/meta.dart'; 4 | 5 | extension AlfredItemTextFixture on AlfredItemText { 6 | static AlfredItemTextFactory get factory => AlfredItemTextFactory(); 7 | } 8 | 9 | @internal 10 | final class AlfredItemTextFactory extends FixtureFactory { 11 | @override 12 | FixtureDefinition definition() => define( 13 | (Faker faker, [int index = 0]) => AlfredItemText( 14 | copy: faker.lorem.sentence(), 15 | largeType: 16 | faker.randomGenerator.boolean() ? faker.lorem.sentence() : null, 17 | ), 18 | ); 19 | 20 | FixtureRedefinitionBuilder copy(String value) => 21 | (AlfredItemText alfredItemText, [int index = 0]) => 22 | alfredItemText.copyWith(copy: value); 23 | 24 | FixtureRedefinitionBuilder largeType(String value) => 25 | (AlfredItemText alfredItemText, [int index = 0]) => 26 | alfredItemText.copyWith(largeType: value); 27 | } 28 | -------------------------------------------------------------------------------- /test/fixtures/models/alfred_items_fixture.dart: -------------------------------------------------------------------------------- 1 | import 'package:alfred_workflow/src/models/alfred_automatic_cache.dart'; 2 | import 'package:alfred_workflow/src/models/alfred_item.dart'; 3 | import 'package:alfred_workflow/src/models/alfred_items.dart'; 4 | import 'package:data_fixture_dart/data_fixture_dart.dart'; 5 | import 'package:meta/meta.dart'; 6 | 7 | import 'alfred_item_fixture.dart'; 8 | 9 | extension AlfredItemsFixture on AlfredItems { 10 | static AlfredItemsFactory get factory => AlfredItemsFactory(); 11 | } 12 | 13 | @internal 14 | final class AlfredItemsFactory extends FixtureFactory { 15 | @override 16 | FixtureDefinition definition() => define( 17 | (Faker faker, [int index = 0]) => 18 | AlfredItems(AlfredItemFixture.factory.makeMany(20)), 19 | ); 20 | 21 | FixtureRedefinitionBuilder items(List value) => 22 | (AlfredItems items, [int index = 0]) => items.copyWith(items: value); 23 | 24 | FixtureRedefinitionBuilder withExactOrder(bool? value) => 25 | (AlfredItems items, [int index = 0]) => items.copyWith(exactOrder: value); 26 | 27 | FixtureRedefinitionBuilder withSkipKnowledge(bool? value) => 28 | (AlfredItems items, [int index = 0]) => 29 | items.copyWith(skipKnowledge: value); 30 | 31 | FixtureRedefinitionBuilder withCache( 32 | AlfredAutomaticCache? value) => 33 | (AlfredItems items, [int index = 0]) => items.copyWith(cache: value); 34 | } 35 | -------------------------------------------------------------------------------- /test/fixtures/models/github_asset_fixture.dart: -------------------------------------------------------------------------------- 1 | import 'package:alfred_workflow/src/models/github_asset.dart'; 2 | import 'package:data_fixture_dart/data_fixture_dart.dart'; 3 | import 'package:meta/meta.dart'; 4 | 5 | import '../extensions/fixture_factory_extension.dart'; 6 | import 'github_user_fixture.dart'; 7 | 8 | extension GithubAssetFixture on GithubAsset { 9 | static GithubAssetFactory get factory => GithubAssetFactory(); 10 | } 11 | 12 | @internal 13 | final class GithubAssetFactory extends FixtureFactory { 14 | final DateTime _now = DateTime.now(); 15 | 16 | @override 17 | FixtureDefinition definition() => define( 18 | (Faker faker, [int index = 0]) { 19 | final String repoName = faker.lorem.words(3).join('-').toLowerCase(); 20 | final String login = faker.lorem.word().toLowerCase(); 21 | final int userId = 22 | faker.randomGenerator.integer(9999999, min: 1000000); 23 | final int assetId = 24 | faker.randomGenerator.integer(9999999, min: 1000000); 25 | final String assetTag = 26 | 'v${faker.randomGenerator.integer(9)}.${faker.randomGenerator.integer(9)}.${faker.randomGenerator.integer(9, min: 1)}'; 27 | final String assetName = 28 | '${faker.lorem.words(3).join('-').toLowerCase()}-$assetTag.alfredworkflow'; 29 | final DateTime createdAt = faker.date 30 | .dateTime( 31 | maxYear: _now.year, 32 | minYear: _now.year - 2, 33 | ) 34 | .toUtc(); 35 | 36 | return GithubAsset( 37 | url: Uri.parse( 38 | 'https://api.github.com/repos/$login/$repoName/releases/assets/$assetId', 39 | ), 40 | id: assetId, 41 | nodeId: faker.randomGenerator.string(19), 42 | name: assetName, 43 | label: null, 44 | uploader: GithubUserFixture.factory.states([ 45 | GithubUserFixture.factory.id(userId), 46 | GithubUserFixture.factory.login(login), 47 | ]).makeSingle(), 48 | contentType: 'application/octet-stream', 49 | state: 'uploaded', 50 | size: faker.randomGenerator.integer(9999999, min: 1000000), 51 | downloadCount: faker.randomGenerator.integer(1000), 52 | createdAt: createdAt, 53 | updatedAt: createdAt, 54 | browserDownloadUrl: Uri.parse( 55 | 'https://github.com/$login/$repoName/releases/download/$assetTag/$assetName', 56 | ), 57 | ); 58 | }, 59 | ); 60 | 61 | FixtureRedefinitionBuilder withDetails({ 62 | required String repoName, 63 | required String login, 64 | required int userId, 65 | required String assetTag, 66 | required DateTime createdAt, 67 | }) { 68 | final int assetId = faker.randomGenerator.integer(9999999, min: 1000000); 69 | final String assetName = 70 | '${faker.lorem.words(3).join('-').toLowerCase()}-$assetTag.alfredworkflow'; 71 | 72 | return (GithubAsset asset, [int index = 0]) => asset.copyWith( 73 | url: Uri.parse( 74 | 'https://api.github.com/repos/$login/$repoName/releases/assets/$assetId', 75 | ), 76 | id: assetId, 77 | name: assetName, 78 | uploader: GithubUserFixture.factory.states([ 79 | GithubUserFixture.factory.id(userId), 80 | GithubUserFixture.factory.login(login), 81 | ]).makeSingle(), 82 | createdAt: createdAt, 83 | updatedAt: createdAt, 84 | browserDownloadUrl: Uri.parse( 85 | 'https://github.com/$login/$repoName/releases/download/$assetTag/$assetName', 86 | ), 87 | ); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /test/fixtures/models/github_user_fixture.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | import 'package:alfred_workflow/src/models/github_user.dart'; 4 | import 'package:data_fixture_dart/data_fixture_dart.dart'; 5 | import 'package:meta/meta.dart'; 6 | 7 | extension GithubUserFixture on GithubUser { 8 | static GithubUserFactory get factory => GithubUserFactory(); 9 | } 10 | 11 | @internal 12 | final class GithubUserFactory extends FixtureFactory { 13 | @override 14 | FixtureDefinition definition() => define( 15 | (Faker faker, [int index = 0]) { 16 | final String login = faker.lorem.word().toLowerCase(); 17 | final int id = faker.randomGenerator.integer(9999999, min: 1000000); 18 | 19 | return GithubUser( 20 | login: login, 21 | id: id, 22 | nodeId: base64.encode( 23 | utf8.encode( 24 | '${faker.randomGenerator.integer(10, min: 00)}:User$id', 25 | ), 26 | ), 27 | avatarUrl: 28 | Uri.parse('https://avatars.githubusercontent.com/u/$id?v=4'), 29 | gravatarId: '', 30 | url: Uri.parse('https://api.github.com/users/$login'), 31 | htmlUrl: Uri.parse('https://github.com/$login'), 32 | reposUrl: Uri.parse('https://api.github.com/users/$login/repos'), 33 | type: 'User', 34 | siteAdmin: false, 35 | ); 36 | }, 37 | ); 38 | 39 | FixtureRedefinitionBuilder id(int id) => 40 | (GithubUser githubUser, [int index = 0]) => githubUser.copyWith( 41 | id: id, 42 | nodeId: base64.encode( 43 | utf8.encode( 44 | '${faker.randomGenerator.integer(10, min: 00)}:User$id', 45 | ), 46 | ), 47 | avatarUrl: 48 | Uri.parse('https://avatars.githubusercontent.com/u/$id?v=4'), 49 | ); 50 | 51 | FixtureRedefinitionBuilder login(String login) => 52 | (GithubUser githubUser, [int index = 0]) => githubUser.copyWith( 53 | login: login, 54 | url: Uri.parse('https://api.github.com/users/$login'), 55 | htmlUrl: Uri.parse('https://github.com/$login'), 56 | reposUrl: Uri.parse('https://api.github.com/users/$login/repos'), 57 | ); 58 | } 59 | -------------------------------------------------------------------------------- /test/fixtures/services/alfred_updater_fixture.dart: -------------------------------------------------------------------------------- 1 | import 'package:alfred_workflow/src/models/github_release.dart'; 2 | import 'package:alfred_workflow/src/services/alfred_updater.dart'; 3 | import 'package:data_fixture_dart/data_fixture_dart.dart'; 4 | import 'package:http/http.dart' show Client; 5 | import 'package:meta/meta.dart'; 6 | import 'package:stash/stash_api.dart'; 7 | 8 | import '../../helpers/mock_alfred_cache.dart'; 9 | 10 | extension AlfredUpdaterFixture on AlfredUpdater { 11 | static AlfredUpdaterFactory get factory => AlfredUpdaterFactory(); 12 | } 13 | 14 | @internal 15 | final class AlfredUpdaterFactory extends FixtureFactory { 16 | @override 17 | FixtureDefinition definition() => define( 18 | (Faker faker, [int index = 0]) { 19 | final String repoName = faker.lorem.words(3).join('-').toLowerCase(); 20 | final String login = faker.lorem.word().toLowerCase(); 21 | final String currentVersion = 22 | '${faker.randomGenerator.integer(9)}.${faker.randomGenerator.integer(9)}.${faker.randomGenerator.integer(9, min: 1)}'; 23 | 24 | return AlfredUpdater( 25 | githubRepositoryUrl: Uri.https('github.com', '/$login/$repoName'), 26 | currentVersion: currentVersion, 27 | cache: MockAlfredCache( 28 | fromEncodable: (Map json) => 29 | GithubRelease.fromJson(json), 30 | maxEntries: 1, 31 | name: 'update_cache', 32 | ), 33 | ); 34 | }, 35 | ); 36 | 37 | FixtureRedefinitionBuilder githubRepositoryUrl( 38 | Uri githubRepositoryUrl, 39 | ) => 40 | (AlfredUpdater alfredUpdater, [int index = 0]) => alfredUpdater.copyWith( 41 | githubRepositoryUrl: githubRepositoryUrl, 42 | ); 43 | 44 | FixtureRedefinitionBuilder currentVersion( 45 | String currentVersion, 46 | ) => 47 | (AlfredUpdater alfredUpdater, [int index = 0]) => 48 | alfredUpdater.copyWith(currentVersion: currentVersion); 49 | 50 | FixtureRedefinitionBuilder updateInterval( 51 | Duration updateInterval, 52 | ) => 53 | (AlfredUpdater alfredUpdater, [int index = 0]) => alfredUpdater.copyWith( 54 | cache: MockAlfredCache( 55 | fromEncodable: (Map json) => 56 | GithubRelease.fromJson(json), 57 | maxEntries: 1, 58 | name: 'update_cache', 59 | evictionPolicy: const FifoEvictionPolicy(), 60 | expiryPolicy: CreatedExpiryPolicy(updateInterval), 61 | ), 62 | ); 63 | 64 | FixtureRedefinitionBuilder client(Client client) => 65 | (AlfredUpdater alfredUpdater, [int index = 0]) => 66 | alfredUpdater.copyWith(client: client); 67 | } 68 | -------------------------------------------------------------------------------- /test/helpers/matchers.dart: -------------------------------------------------------------------------------- 1 | import 'package:test/expect.dart'; 2 | 3 | Matcher containsSubstring( 4 | String substring, [ 5 | bool caseSensitive = true, 6 | ]) => 7 | predicate( 8 | (String expected) => expected.contains( 9 | RegExp( 10 | substring, 11 | caseSensitive: caseSensitive, 12 | ), 13 | ), 14 | ); 15 | -------------------------------------------------------------------------------- /test/helpers/mock_alfred_cache.dart: -------------------------------------------------------------------------------- 1 | import 'package:alfred_workflow/src/services/alfred_cache.dart'; 2 | import 'package:stash_file/stash_file.dart'; 3 | 4 | final class MockAlfredCache extends AlfredCache { 5 | MockAlfredCache({ 6 | required super.fromEncodable, 7 | super.path, 8 | super.maxEntries, 9 | super.name, 10 | super.evictionPolicy, 11 | super.expiryPolicy, 12 | super.verbose, 13 | }); 14 | 15 | @override 16 | Future get store => newFileMemoryCacheStore(); 17 | } 18 | -------------------------------------------------------------------------------- /test/helpers/mock_stdout.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert' show Encoding, utf8; 2 | import 'dart:io' show Stdout, IOSink; 3 | 4 | /// A mock implementation of stdout that captures output for testing. 5 | class MockStdout implements Stdout { 6 | final StringBuffer _buffer = StringBuffer(); 7 | String get output => _buffer.toString(); 8 | 9 | @override 10 | void write(Object? object) { 11 | _buffer.write(object); 12 | } 13 | 14 | @override 15 | void writeln([Object? object = '']) { 16 | _buffer.writeln(object); 17 | } 18 | 19 | @override 20 | void writeAll(Iterable objects, [String separator = '']) { 21 | _buffer.writeAll(objects, separator); 22 | } 23 | 24 | @override 25 | void writeCharCode(int charCode) { 26 | _buffer.writeCharCode(charCode); 27 | } 28 | 29 | @override 30 | void add(List bytes) { 31 | _buffer.write(utf8.decode(bytes)); 32 | } 33 | 34 | @override 35 | void addError(Object error, [StackTrace? stackTrace]) { 36 | throw UnimplementedError(); 37 | } 38 | 39 | @override 40 | Future addStream(Stream> stream) { 41 | throw UnimplementedError(); 42 | } 43 | 44 | @override 45 | Future close() { 46 | throw UnimplementedError(); 47 | } 48 | 49 | @override 50 | Future get done => throw UnimplementedError(); 51 | 52 | @override 53 | Encoding get encoding => utf8; 54 | 55 | @override 56 | set encoding(Encoding encoding) {} 57 | 58 | @override 59 | bool get hasTerminal => false; 60 | 61 | @override 62 | IOSink get nonBlocking => throw UnimplementedError(); 63 | 64 | @override 65 | bool get supportsAnsiEscapes => false; 66 | 67 | @override 68 | int get terminalColumns => 80; 69 | 70 | @override 71 | int get terminalLines => 24; 72 | 73 | @override 74 | Future flush() async {} 75 | 76 | @override 77 | String get lineTerminator => '\n'; 78 | 79 | @override 80 | set lineTerminator(String lineTerminator) {} 81 | 82 | void clear() { 83 | _buffer.clear(); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /test/unit/converters/version_converter_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:alfred_workflow/src/converters/version_converter.dart'; 2 | import 'package:faker/faker.dart'; 3 | import 'package:pub_semver/pub_semver.dart'; 4 | import 'package:test/test.dart'; 5 | 6 | void main() { 7 | final Faker faker = Faker(); 8 | late int major; 9 | late int minor; 10 | late int patch; 11 | late String name; 12 | 13 | setUp(() { 14 | major = faker.randomGenerator.integer(9999, min: 0); 15 | minor = faker.randomGenerator.integer(9999, min: 0); 16 | patch = faker.randomGenerator.integer(9999, min: 1); 17 | name = faker.internet.userName(); 18 | }); 19 | 20 | test('fromJson', () { 21 | expect( 22 | VersionConverter.instance.fromJson('$major.$minor.$patch'), 23 | Version(major, minor, patch), 24 | ); 25 | expect( 26 | VersionConverter.instance.fromJson('v$major.$minor.$patch'), 27 | Version(major, minor, patch), 28 | ); 29 | expect( 30 | VersionConverter.instance.fromJson('V$major.$minor.$patch'), 31 | Version(major, minor, patch), 32 | ); 33 | 34 | // custom versioning 35 | expect( 36 | VersionConverter.instance.fromJson('x$major.$minor.$patch'), 37 | Version(major, minor, patch), 38 | ); 39 | expect( 40 | VersionConverter.instance.fromJson('$name-$major.$minor.$patch'), 41 | Version(major, minor, patch), 42 | ); 43 | expect( 44 | VersionConverter.instance.fromJson('$name-v$major.$minor.$patch'), 45 | Version(major, minor, patch), 46 | ); 47 | expect( 48 | VersionConverter.instance.fromJson('$major.$minor.$patch-$name'), 49 | Version(major, minor, patch), 50 | ); 51 | expect( 52 | VersionConverter.instance.fromJson('v$major.$minor.$patch-$name'), 53 | Version(major, minor, patch), 54 | ); 55 | expect( 56 | VersionConverter.instance.fromJson('$name-$major.$minor.$patch-$name'), 57 | Version(major, minor, patch), 58 | ); 59 | 60 | // exceptions 61 | expect( 62 | () => VersionConverter.instance.fromJson('$major'), 63 | throwsA(const TypeMatcher()), 64 | ); 65 | expect( 66 | () => VersionConverter.instance.fromJson('$major.$minor'), 67 | throwsA(const TypeMatcher()), 68 | ); 69 | }); 70 | } 71 | -------------------------------------------------------------------------------- /test/unit/models/alfred_automatic_cache_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:alfred_workflow/alfred_workflow.dart'; 2 | import 'package:faker/faker.dart'; 3 | import 'package:test/test.dart'; 4 | 5 | void main() { 6 | final Faker faker = Faker(); 7 | 8 | group('AlfredAutomaticCache', () { 9 | test('props contains expected properties', () { 10 | final int seconds = faker.randomGenerator.integer( 11 | AlfredAutomaticCache.maxSeconds, 12 | min: AlfredAutomaticCache.minSeconds, 13 | ); 14 | final bool looseReload = faker.randomGenerator.boolean(); 15 | 16 | final AlfredAutomaticCache cache = AlfredAutomaticCache( 17 | seconds: seconds, 18 | looseReload: looseReload, 19 | ); 20 | 21 | // Test that props contains all the expected properties 22 | expect(cache.props, isNotEmpty); 23 | expect(cache.props, contains(cache.seconds)); 24 | expect(cache.props, contains(cache.looseReload)); 25 | }); 26 | 27 | test('instances with different properties are not equal', () { 28 | final int seconds = faker.randomGenerator.integer( 29 | AlfredAutomaticCache.maxSeconds, 30 | min: AlfredAutomaticCache.minSeconds, 31 | ); 32 | final bool looseReload = faker.randomGenerator.boolean(); 33 | 34 | final AlfredAutomaticCache cache1 = AlfredAutomaticCache( 35 | seconds: seconds, 36 | looseReload: looseReload, 37 | ); 38 | 39 | final cache2 = AlfredAutomaticCache( 40 | seconds: seconds, 41 | looseReload: !looseReload, // Different looseReload 42 | ); 43 | 44 | // They should not be equal because looseReload is different 45 | expect(cache1.looseReload, isNot(equals(cache2.looseReload))); 46 | expect(cache1.props, isNot(equals(cache2.props))); 47 | }); 48 | }); 49 | } 50 | -------------------------------------------------------------------------------- /test/unit/models/alfred_item_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:alfred_workflow/alfred_workflow.dart'; 2 | import 'package:test/test.dart'; 3 | 4 | void main() { 5 | group('AlfredItem', () { 6 | test('Constructor throws AssertionError for invalid action type', () { 7 | // Create an invalid action type (not String, Iterable, or AlfredAction) 8 | const int invalidAction = 123; // Integer is not a valid action type 9 | 10 | // Call the constructor with an invalid action type 11 | expect( 12 | () => AlfredItem( 13 | title: 'Test Item', 14 | action: invalidAction, 15 | valid: true, 16 | ), 17 | throwsA(isA()), 18 | ); 19 | }); 20 | 21 | test('_actionFromJson throws ArgumentError for invalid action type', () { 22 | // This test is a bit tricky since _actionFromJson is only called during JSON deserialization 23 | // We can't directly test it, but we can test that the factory method throws when given invalid data 24 | const Map invalidJson = { 25 | 'title': 'Test Item', 26 | 'valid': true, 27 | 'action': 123, // Integer is not a valid action type 28 | }; 29 | 30 | expect( 31 | () => AlfredItem.fromJson(invalidJson), 32 | throwsA(isA()), 33 | ); 34 | }); 35 | 36 | test('_actionToJson throws ArgumentError for invalid action type', () { 37 | // Create a valid AlfredItem 38 | const AlfredItem item = AlfredItem( 39 | title: 'Test Item', 40 | action: 'valid-action', // String is a valid action type 41 | valid: true, 42 | ); 43 | 44 | // Get its JSON representation 45 | final Map json = item.toJson(); 46 | 47 | // Modify the action to be an invalid type 48 | json['action'] = 123; // Integer is not a valid action type 49 | 50 | // Now try to create a new AlfredItem from this modified JSON 51 | // This should throw an ArgumentError when _actionFromJson tries to process the invalid action 52 | expect( 53 | () => AlfredItem.fromJson(json), 54 | throwsA(isA()), 55 | ); 56 | }); 57 | }); 58 | } 59 | -------------------------------------------------------------------------------- /test/unit/services/alfred_cache_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:alfred_workflow/alfred_workflow.dart'; 2 | import 'package:test/test.dart'; 3 | 4 | void main() { 5 | group('AlfredCache', () { 6 | test('props contains expected properties', () { 7 | final AlfredCache cache = AlfredCache( 8 | fromEncodable: (Map json) => json['value'] as String, 9 | maxEntries: 5, 10 | name: 'test_cache', 11 | verbose: true, 12 | ); 13 | 14 | // Test that props contains all the expected properties 15 | expect(cache.props, isNotEmpty); 16 | expect(cache.props, contains(cache.maxEntries)); 17 | expect(cache.props, contains(cache.name)); 18 | expect(cache.props, contains(cache.verbose)); 19 | }); 20 | 21 | test('instances with different properties are not equal', () { 22 | final AlfredCache cache1 = AlfredCache( 23 | fromEncodable: (Map json) => json['value'] as String, 24 | maxEntries: 5, 25 | name: 'test_cache', 26 | verbose: true, 27 | ); 28 | 29 | final AlfredCache cache2 = AlfredCache( 30 | fromEncodable: (Map json) => json['value'] as String, 31 | maxEntries: 10, // Different maxEntries 32 | name: 'test_cache', 33 | verbose: true, 34 | ); 35 | 36 | // They should not be equal because maxEntries is different 37 | expect(cache1.maxEntries, isNot(equals(cache2.maxEntries))); 38 | expect(cache1.props, isNot(equals(cache2.props))); 39 | }); 40 | }); 41 | } 42 | --------------------------------------------------------------------------------