├── .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