Compare commits

...

75 Commits

Author SHA1 Message Date
dependabot[bot]
337d861684 Bump denoland/deno in /supabase/functions/_cmd in the docker group
Bumps the docker group in /supabase/functions/_cmd with 1 update: denoland/deno.


Updates `denoland/deno` from 1.45.2 to 2.6.3

---
updated-dependencies:
- dependency-name: denoland/deno
  dependency-version: 2.6.3
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: docker
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-30 17:28:14 +00:00
ricoberger
906c2a1754 chore: linting, dependabot, release 2026-03-30 19:27:16 +02:00
ricoberger
bac50cb86e Update License 2026-01-15 12:59:13 +01:00
ricoberger
3e43029b96 Fix Readme 2026-01-15 12:57:35 +01:00
dependabot[bot]
b3e82b7a8e Bump the npm group in /supabase/email-templates with 6 updates (#283) 2025-10-31 15:16:22 +01:00
dependabot[bot]
2d3622487d Bump the npm group across 1 directory with 12 updates (#287) 2025-10-31 15:15:20 +01:00
dependabot[bot]
683f5b3369 Bump the github-actions group across 1 directory with 3 updates (#289) 2025-10-31 15:14:43 +01:00
Rico Berger
01250cfc35 Add Linting in CI and Fix Linting Errors (#281) 2025-07-27 15:58:48 +02:00
Rico Berger
e726b4b0ea Update Android Build Configuration (#280)
- Migrate Gradle build files from Groovy to Kotlin.
- Update target sdk version to `35`.
2025-07-27 15:50:13 +02:00
dependabot[bot]
648ed898d9 Bump the pub group across 1 directory with 25 updates (#279)
* Bump the pub group across 1 directory with 25 updates

Bumps the pub group with 23 updates in the /app directory:

| Package | From | To |
| --- | --- | --- |
| [carousel_slider](https://github.com/serenader2014/flutter_carousel_slider) | `5.0.0` | `5.1.1` |
| [file_picker](https://github.com/miguelpruivo/flutter_file_picker) | `10.1.2` | `10.2.0` |
| [flutter_launcher_icons](https://github.com/fluttercommunity/flutter_launcher_icons) | `0.14.3` | `0.14.4` |
| [flutter_lints](https://github.com/flutter/packages/tree/main/packages) | `5.0.0` | `6.0.0` |
| [flutter_markdown](https://github.com/flutter/packages/tree/main/packages) | `0.7.6` | `0.7.7+1` |
| [flutter_native_splash](https://github.com/jonbhanson/flutter_native_splash) | `2.4.5` | `2.4.6` |
| [html](https://github.com/dart-lang/tools/tree/main/pkgs) | `0.15.5` | `0.15.6` |
| [http](https://github.com/dart-lang/http/tree/master/pkgs) | `1.3.0` | `1.4.0` |
| [intl](https://github.com/dart-lang/i18n/tree/main/pkgs) | `0.19.0` | `0.20.2` |
| [just_audio](https://github.com/ryanheise/just_audio) | `0.9.46` | `0.10.4` |
| [just_audio_background](https://github.com/ryanheise/just_audio) | `0.0.1-beta.15` | `0.0.1-beta.17` |
| [just_audio_media_kit](https://github.com/Pato05/just_audio_media_kit) | `2.0.6` | `2.1.0` |
| [media_kit_libs_video](https://github.com/media-kit/media-kit) | `1.0.5` | `1.0.6` |
| [media_kit_video](https://github.com/media-kit/media-kit) | `1.2.5` | `1.3.0` |
| [msix](https://github.com/YehudaKremer/msix) | `3.16.8` | `3.16.9` |
| [provider](https://github.com/rrousselGit/provider) | `6.1.2` | `6.1.5` |
| [purchases_flutter](https://github.com/RevenueCat/purchases-flutter) | `8.6.1` | `9.1.0` |
| [shared_preferences](https://github.com/flutter/packages/tree/main/packages/shared_preferences) | `2.5.2` | `2.5.3` |
| [sign_in_with_apple](https://github.com/aboutyou/dart_packages) | `6.1.4` | `7.0.1` |
| [supabase_flutter](https://github.com/supabase/supabase-flutter/tree/main/packages) | `2.8.4` | `2.9.1` |
| [url_launcher](https://github.com/flutter/packages/tree/main/packages/url_launcher) | `6.3.1` | `6.3.2` |
| [window_manager](https://github.com/leanflutter/window_manager) | `0.4.3` | `0.5.1` |
| [youtube_explode_dart](https://github.com/Hexer10/youtube_explode_dart) | `2.3.10` | `2.5.1` |



Updates `carousel_slider` from 5.0.0 to 5.1.1
- [Release notes](https://github.com/serenader2014/flutter_carousel_slider/releases)
- [Changelog](https://github.com/serenader2014/flutter_carousel_slider/blob/master/CHANGELOG.md)
- [Commits](https://github.com/serenader2014/flutter_carousel_slider/commits)

Updates `file_picker` from 10.1.2 to 10.2.0
- [Release notes](https://github.com/miguelpruivo/flutter_file_picker/releases)
- [Changelog](https://github.com/miguelpruivo/flutter_file_picker/blob/master/CHANGELOG.md)
- [Commits](https://github.com/miguelpruivo/flutter_file_picker/commits)

Updates `flutter_launcher_icons` from 0.14.3 to 0.14.4
- [Release notes](https://github.com/fluttercommunity/flutter_launcher_icons/releases)
- [Changelog](https://github.com/fluttercommunity/flutter_launcher_icons/blob/master/CHANGELOG.md)
- [Commits](https://github.com/fluttercommunity/flutter_launcher_icons/commits/v0.14.4)

Updates `flutter_lints` from 5.0.0 to 6.0.0
- [Release notes](https://github.com/flutter/packages/releases)
- [Commits](https://github.com/flutter/packages/commits/flutter_lints-v6.0.0/packages)

Updates `flutter_markdown` from 0.7.6 to 0.7.7+1
- [Release notes](https://github.com/flutter/packages/releases)
- [Commits](https://github.com/flutter/packages/commits/flutter_markdown-v0.7.7/packages)

Updates `flutter_native_splash` from 2.4.5 to 2.4.6
- [Release notes](https://github.com/jonbhanson/flutter_native_splash/releases)
- [Changelog](https://github.com/jonbhanson/flutter_native_splash/blob/master/CHANGELOG.md)
- [Commits](https://github.com/jonbhanson/flutter_native_splash/compare/v2.4.5...v2.4.6)

Updates `html` from 0.15.5 to 0.15.6
- [Release notes](https://github.com/dart-lang/tools/releases)
- [Commits](https://github.com/dart-lang/tools/commits/html-v0.15.6/pkgs)

Updates `http` from 1.3.0 to 1.4.0
- [Release notes](https://github.com/dart-lang/http/releases)
- [Commits](https://github.com/dart-lang/http/commits/HEAD/pkgs)

Updates `intl` from 0.19.0 to 0.20.2
- [Release notes](https://github.com/dart-lang/i18n/releases)
- [Commits](https://github.com/dart-lang/i18n/commits/intl-v0.20.2/pkgs)

Updates `just_audio` from 0.9.46 to 0.10.4
- [Release notes](https://github.com/ryanheise/just_audio/releases)
- [Commits](https://github.com/ryanheise/just_audio/compare/just_audio-v0.9.46...just_audio-v0.10.4)

Updates `just_audio_background` from 0.0.1-beta.15 to 0.0.1-beta.17
- [Release notes](https://github.com/ryanheise/just_audio/releases)
- [Commits](https://github.com/ryanheise/just_audio/compare/just_audio_background-v0.0.1-beta.15...just_audio_background-v0.0.1-beta.17)

Updates `just_audio_media_kit` from 2.0.6 to 2.1.0
- [Changelog](https://github.com/Pato05/just_audio_media_kit/blob/main/CHANGELOG.md)
- [Commits](https://github.com/Pato05/just_audio_media_kit/compare/v2.0.6...v2.1.0)

Updates `media_kit` from 1.1.11 to 1.2.0
- [Release notes](https://github.com/media-kit/media-kit/releases)
- [Changelog](https://github.com/media-kit/media-kit/blob/main/CHANGELOG.md)
- [Commits](https://github.com/media-kit/media-kit/commits/media_kit_video-v1.2.0)

Updates `media_kit_libs_video` from 1.0.5 to 1.0.6
- [Release notes](https://github.com/media-kit/media-kit/releases)
- [Changelog](https://github.com/media-kit/media-kit/blob/main/CHANGELOG.md)
- [Commits](https://github.com/media-kit/media-kit/compare/media_kit_libs_ios_audio-v1.0.5...media_kit_libs_macos_audio-v1.0.6)

Updates `media_kit_video` from 1.2.5 to 1.3.0
- [Release notes](https://github.com/media-kit/media-kit/releases)
- [Changelog](https://github.com/media-kit/media-kit/blob/main/CHANGELOG.md)
- [Commits](https://github.com/media-kit/media-kit/commits/media_kit_libs_android_audio-v1.3.0)

Updates `msix` from 3.16.8 to 3.16.9
- [Release notes](https://github.com/YehudaKremer/msix/releases)
- [Changelog](https://github.com/YehudaKremer/msix/blob/main/CHANGELOG.md)
- [Commits](https://github.com/YehudaKremer/msix/compare/v3.16.8...v3.16.9)

Updates `provider` from 6.1.2 to 6.1.5
- [Commits](https://github.com/rrousselGit/provider/compare/provider-v6.1.2...provider-v6.1.5)

Updates `purchases_flutter` from 8.6.1 to 9.1.0
- [Release notes](https://github.com/RevenueCat/purchases-flutter/releases)
- [Changelog](https://github.com/RevenueCat/purchases-flutter/blob/main/CHANGELOG.md)
- [Commits](https://github.com/RevenueCat/purchases-flutter/compare/8.6.1...9.1.0)

Updates `shared_preferences` from 2.5.2 to 2.5.3
- [Release notes](https://github.com/flutter/packages/releases)
- [Commits](https://github.com/flutter/packages/commits/shared_preferences-v2.5.3/packages/shared_preferences)

Updates `sign_in_with_apple` from 6.1.4 to 7.0.1
- [Release notes](https://github.com/aboutyou/dart_packages/releases)
- [Commits](https://github.com/aboutyou/dart_packages/commits)

Updates `supabase_flutter` from 2.8.4 to 2.9.1
- [Changelog](https://github.com/supabase/supabase-flutter/blob/main/CHANGELOG.md)
- [Commits](https://github.com/supabase/supabase-flutter/commits/HEAD/packages)

Updates `timeago` from 3.7.0 to 3.7.1
- [Commits](https://github.com/andresaraujo/timeago.dart/commits)

Updates `url_launcher` from 6.3.1 to 6.3.2
- [Release notes](https://github.com/flutter/packages/releases)
- [Commits](https://github.com/flutter/packages/commits/url_launcher-v6.3.2/packages/url_launcher)

Updates `window_manager` from 0.4.3 to 0.5.1
- [Release notes](https://github.com/leanflutter/window_manager/releases)
- [Commits](https://github.com/leanflutter/window_manager/commits)

Updates `youtube_explode_dart` from 2.3.10 to 2.5.1
- [Release notes](https://github.com/Hexer10/youtube_explode_dart/releases)
- [Changelog](https://github.com/Hexer10/youtube_explode_dart/blob/master/CHANGELOG.md)
- [Commits](https://github.com/Hexer10/youtube_explode_dart/compare/v2.3.10...v2.5.1)

---
updated-dependencies:
- dependency-name: carousel_slider
  dependency-version: 5.1.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: pub
- dependency-name: file_picker
  dependency-version: 10.2.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: pub
- dependency-name: flutter_launcher_icons
  dependency-version: 0.14.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: pub
- dependency-name: flutter_lints
  dependency-version: 6.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: pub
- dependency-name: flutter_markdown
  dependency-version: 0.7.7+1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: pub
- dependency-name: flutter_native_splash
  dependency-version: 2.4.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: pub
- dependency-name: html
  dependency-version: 0.15.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: pub
- dependency-name: http
  dependency-version: 1.4.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: pub
- dependency-name: intl
  dependency-version: 0.20.2
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: pub
- dependency-name: just_audio
  dependency-version: 0.10.4
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: pub
- dependency-name: just_audio_background
  dependency-version: 0.0.1-beta.17
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: pub
- dependency-name: just_audio_media_kit
  dependency-version: 2.1.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: pub
- dependency-name: media_kit
  dependency-version: 1.2.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: pub
- dependency-name: media_kit_libs_video
  dependency-version: 1.0.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: pub
- dependency-name: media_kit_video
  dependency-version: 1.3.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: pub
- dependency-name: msix
  dependency-version: 3.16.9
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: pub
- dependency-name: provider
  dependency-version: 6.1.5
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: pub
- dependency-name: purchases_flutter
  dependency-version: 9.1.0
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: pub
- dependency-name: shared_preferences
  dependency-version: 2.5.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: pub
- dependency-name: sign_in_with_apple
  dependency-version: 7.0.1
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: pub
- dependency-name: supabase_flutter
  dependency-version: 2.9.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: pub
- dependency-name: timeago
  dependency-version: 3.7.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: pub
- dependency-name: url_launcher
  dependency-version: 6.3.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: pub
- dependency-name: window_manager
  dependency-version: 0.5.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: pub
- dependency-name: youtube_explode_dart
  dependency-version: 2.5.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: pub
...

Signed-off-by: dependabot[bot] <support@github.com>

* Update Flutter Version to 3.32.7

- Update Flutter version to 3.32.7
- Enable Swift Package Manager for iOS and macOS

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: ricoberger <mail@ricoberger.de>
2025-07-27 15:23:10 +02:00
Rico Berger
a563562edb Update GitHub Action Runner for Windows (#278) 2025-07-26 14:42:02 +02:00
dependabot[bot]
a16599ef96 Bump the npm group in /landing with 5 updates (#277)
Bumps the npm group in /landing with 5 updates:

| Package | From | To |
| --- | --- | --- |
| [@headlessui/react](https://github.com/tailwindlabs/headlessui/tree/HEAD/packages/@headlessui-react) | `2.2.4` | `2.2.6` |
| [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) | `24.0.8` | `24.1.0` |
| [eslint](https://github.com/eslint/eslint) | `9.30.0` | `9.32.0` |
| [eslint-config-next](https://github.com/vercel/next.js/tree/HEAD/packages/eslint-config-next) | `15.3.4` | `15.4.4` |
| [next](https://github.com/vercel/next.js) | `15.3.4` | `15.4.4` |


Updates `@headlessui/react` from 2.2.4 to 2.2.6
- [Release notes](https://github.com/tailwindlabs/headlessui/releases)
- [Changelog](https://github.com/tailwindlabs/headlessui/blob/main/packages/@headlessui-react/CHANGELOG.md)
- [Commits](https://github.com/tailwindlabs/headlessui/commits/@headlessui/react@v2.2.6/packages/@headlessui-react)

Updates `@types/node` from 24.0.8 to 24.1.0
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

Updates `eslint` from 9.30.0 to 9.32.0
- [Release notes](https://github.com/eslint/eslint/releases)
- [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md)
- [Commits](https://github.com/eslint/eslint/compare/v9.30.0...v9.32.0)

Updates `eslint-config-next` from 15.3.4 to 15.4.4
- [Release notes](https://github.com/vercel/next.js/releases)
- [Changelog](https://github.com/vercel/next.js/blob/canary/release.js)
- [Commits](https://github.com/vercel/next.js/commits/v15.4.4/packages/eslint-config-next)

Updates `next` from 15.3.4 to 15.4.4
- [Release notes](https://github.com/vercel/next.js/releases)
- [Changelog](https://github.com/vercel/next.js/blob/canary/release.js)
- [Commits](https://github.com/vercel/next.js/compare/v15.3.4...v15.4.4)

---
updated-dependencies:
- dependency-name: "@headlessui/react"
  dependency-version: 2.2.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: npm
- dependency-name: "@types/node"
  dependency-version: 24.1.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: npm
- dependency-name: eslint
  dependency-version: 9.32.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: npm
- dependency-name: eslint-config-next
  dependency-version: 15.4.4
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: npm
- dependency-name: next
  dependency-version: 15.4.4
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: npm
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-07-26 14:28:06 +02:00
dependabot[bot]
30a69f4174 Bump the npm group in /supabase/email-templates with 2 updates (#276)
Bumps the npm group in /supabase/email-templates with 2 updates: [@react-email/components](https://github.com/resend/react-email/tree/HEAD/packages/components) and [react-email](https://github.com/resend/react-email/tree/HEAD/packages/react-email).


Updates `@react-email/components` from 0.1.1 to 0.3.2
- [Release notes](https://github.com/resend/react-email/releases)
- [Changelog](https://github.com/resend/react-email/blob/@react-email/components@0.3.2/packages/components/CHANGELOG.md)
- [Commits](https://github.com/resend/react-email/commits/@react-email/components@0.3.2/packages/components)

Updates `react-email` from 4.0.17 to 4.2.4
- [Release notes](https://github.com/resend/react-email/releases)
- [Changelog](https://github.com/resend/react-email/blob/react-email@4.2.4/packages/react-email/CHANGELOG.md)
- [Commits](https://github.com/resend/react-email/commits/react-email@4.2.4/packages/react-email)

---
updated-dependencies:
- dependency-name: "@react-email/components"
  dependency-version: 0.3.2
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: npm
- dependency-name: react-email
  dependency-version: 4.2.4
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: npm
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-07-26 14:27:27 +02:00
ricoberger
008bf0bf6e Add CODEOWNERS File 2025-07-26 14:25:25 +02:00
dependabot[bot]
1dde1d2635 Bump brace-expansion from 2.0.1 to 2.0.2 in /supabase/email-templates (#270)
Bumps [brace-expansion](https://github.com/juliangruber/brace-expansion) from 2.0.1 to 2.0.2.
- [Release notes](https://github.com/juliangruber/brace-expansion/releases)
- [Commits](https://github.com/juliangruber/brace-expansion/compare/v2.0.1...v2.0.2)

---
updated-dependencies:
- dependency-name: brace-expansion
  dependency-version: 2.0.2
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-07-26 14:17:14 +02:00
dependabot[bot]
f9e1526d54 Bump @eslint/plugin-kit from 0.3.1 to 0.3.3 in /landing (#275)
Bumps [@eslint/plugin-kit](https://github.com/eslint/rewrite/tree/HEAD/packages/plugin-kit) from 0.3.1 to 0.3.3.
- [Release notes](https://github.com/eslint/rewrite/releases)
- [Changelog](https://github.com/eslint/rewrite/blob/main/packages/plugin-kit/CHANGELOG.md)
- [Commits](https://github.com/eslint/rewrite/commits/plugin-kit-v0.3.3/packages/plugin-kit)

---
updated-dependencies:
- dependency-name: "@eslint/plugin-kit"
  dependency-version: 0.3.3
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-07-26 14:16:41 +02:00
dependabot[bot]
1e2993305c Bump the npm group across 1 directory with 4 updates (#273)
Bumps the npm group with 4 updates in the /supabase/email-templates directory: [@react-email/components](https://github.com/resend/react-email/tree/HEAD/packages/components), [@types/react](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react), [@types/react-dom](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react-dom) and [react-email](https://github.com/resend/react-email/tree/HEAD/packages/react-email).


Updates `@react-email/components` from 0.0.41 to 0.1.1
- [Release notes](https://github.com/resend/react-email/releases)
- [Changelog](https://github.com/resend/react-email/blob/canary/packages/components/CHANGELOG.md)
- [Commits](https://github.com/resend/react-email/commits/@react-email/components@0.1.1/packages/components)

Updates `@types/react` from 19.1.4 to 19.1.8
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react)

Updates `@types/react-dom` from 19.1.5 to 19.1.6
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react-dom)

Updates `react-email` from 4.0.14 to 4.0.17
- [Release notes](https://github.com/resend/react-email/releases)
- [Changelog](https://github.com/resend/react-email/blob/canary/packages/react-email/CHANGELOG.md)
- [Commits](https://github.com/resend/react-email/commits/react-email@4.0.17/packages/react-email)

---
updated-dependencies:
- dependency-name: "@react-email/components"
  dependency-version: 0.1.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: npm
- dependency-name: "@types/react"
  dependency-version: 19.1.8
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: npm
- dependency-name: "@types/react-dom"
  dependency-version: 19.1.6
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: npm
- dependency-name: react-email
  dependency-version: 4.0.17
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: npm
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-07-26 14:13:15 +02:00
dependabot[bot]
cc36e2a89a Bump the npm group across 1 directory with 10 updates (#272)
Bumps the npm group with 9 updates in the /landing directory:

| Package | From | To |
| --- | --- | --- |
| [@headlessui/react](https://github.com/tailwindlabs/headlessui/tree/HEAD/packages/@headlessui-react) | `2.2.3` | `2.2.4` |
| [@tailwindcss/postcss](https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/@tailwindcss-postcss) | `4.1.7` | `4.1.11` |
| [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) | `22.15.18` | `24.0.8` |
| [@types/react](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react) | `19.1.4` | `19.1.8` |
| [@types/react-dom](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react-dom) | `19.1.5` | `19.1.6` |
| [eslint](https://github.com/eslint/eslint) | `9.27.0` | `9.30.0` |
| [eslint-config-next](https://github.com/vercel/next.js/tree/HEAD/packages/eslint-config-next) | `15.3.2` | `15.3.4` |
| [next](https://github.com/vercel/next.js) | `15.3.2` | `15.3.4` |
| [postcss](https://github.com/postcss/postcss) | `8.5.3` | `8.5.6` |



Updates `@headlessui/react` from 2.2.3 to 2.2.4
- [Release notes](https://github.com/tailwindlabs/headlessui/releases)
- [Changelog](https://github.com/tailwindlabs/headlessui/blob/main/packages/@headlessui-react/CHANGELOG.md)
- [Commits](https://github.com/tailwindlabs/headlessui/commits/@headlessui/react@v2.2.4/packages/@headlessui-react)

Updates `@tailwindcss/postcss` from 4.1.7 to 4.1.11
- [Release notes](https://github.com/tailwindlabs/tailwindcss/releases)
- [Changelog](https://github.com/tailwindlabs/tailwindcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/tailwindlabs/tailwindcss/commits/v4.1.11/packages/@tailwindcss-postcss)

Updates `@types/node` from 22.15.18 to 24.0.8
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

Updates `@types/react` from 19.1.4 to 19.1.8
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react)

Updates `@types/react-dom` from 19.1.5 to 19.1.6
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react-dom)

Updates `eslint` from 9.27.0 to 9.30.0
- [Release notes](https://github.com/eslint/eslint/releases)
- [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md)
- [Commits](https://github.com/eslint/eslint/compare/v9.27.0...v9.30.0)

Updates `eslint-config-next` from 15.3.2 to 15.3.4
- [Release notes](https://github.com/vercel/next.js/releases)
- [Changelog](https://github.com/vercel/next.js/blob/canary/release.js)
- [Commits](https://github.com/vercel/next.js/commits/v15.3.4/packages/eslint-config-next)

Updates `next` from 15.3.2 to 15.3.4
- [Release notes](https://github.com/vercel/next.js/releases)
- [Changelog](https://github.com/vercel/next.js/blob/canary/release.js)
- [Commits](https://github.com/vercel/next.js/compare/v15.3.2...v15.3.4)

Updates `postcss` from 8.5.3 to 8.5.6
- [Release notes](https://github.com/postcss/postcss/releases)
- [Changelog](https://github.com/postcss/postcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/postcss/postcss/compare/8.5.3...8.5.6)

Updates `tailwindcss` from 4.1.7 to 4.1.11
- [Release notes](https://github.com/tailwindlabs/tailwindcss/releases)
- [Changelog](https://github.com/tailwindlabs/tailwindcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/tailwindlabs/tailwindcss/commits/v4.1.11/packages/tailwindcss)

---
updated-dependencies:
- dependency-name: "@headlessui/react"
  dependency-version: 2.2.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: npm
- dependency-name: "@tailwindcss/postcss"
  dependency-version: 4.1.11
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: npm
- dependency-name: "@types/node"
  dependency-version: 24.0.8
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: npm
- dependency-name: "@types/react"
  dependency-version: 19.1.8
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: npm
- dependency-name: "@types/react-dom"
  dependency-version: 19.1.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: npm
- dependency-name: eslint
  dependency-version: 9.30.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: npm
- dependency-name: eslint-config-next
  dependency-version: 15.3.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: npm
- dependency-name: next
  dependency-version: 15.3.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: npm
- dependency-name: postcss
  dependency-version: 8.5.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: npm
- dependency-name: tailwindcss
  dependency-version: 4.1.11
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: npm
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-07-26 14:12:52 +02:00
dependabot[bot]
e8c0048229 Bump the npm group in /landing with 9 updates (#265)
Bumps the npm group in /landing with 9 updates:

| Package | From | To |
| --- | --- | --- |
| [@headlessui/react](https://github.com/tailwindlabs/headlessui/tree/HEAD/packages/@headlessui-react) | `2.2.2` | `2.2.3` |
| [@tailwindcss/postcss](https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/@tailwindcss-postcss) | `4.1.5` | `4.1.7` |
| [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) | `22.15.3` | `22.15.18` |
| [@types/react](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react) | `19.1.2` | `19.1.4` |
| [@types/react-dom](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react-dom) | `19.1.3` | `19.1.5` |
| [eslint](https://github.com/eslint/eslint) | `9.25.1` | `9.27.0` |
| [eslint-config-next](https://github.com/vercel/next.js/tree/HEAD/packages/eslint-config-next) | `15.3.1` | `15.3.2` |
| [next](https://github.com/vercel/next.js) | `15.3.1` | `15.3.2` |
| [tailwindcss](https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/tailwindcss) | `4.1.5` | `4.1.7` |


Updates `@headlessui/react` from 2.2.2 to 2.2.3
- [Release notes](https://github.com/tailwindlabs/headlessui/releases)
- [Changelog](https://github.com/tailwindlabs/headlessui/blob/main/packages/@headlessui-react/CHANGELOG.md)
- [Commits](https://github.com/tailwindlabs/headlessui/commits/@headlessui/react@v2.2.3/packages/@headlessui-react)

Updates `@tailwindcss/postcss` from 4.1.5 to 4.1.7
- [Release notes](https://github.com/tailwindlabs/tailwindcss/releases)
- [Changelog](https://github.com/tailwindlabs/tailwindcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/tailwindlabs/tailwindcss/commits/v4.1.7/packages/@tailwindcss-postcss)

Updates `@types/node` from 22.15.3 to 22.15.18
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

Updates `@types/react` from 19.1.2 to 19.1.4
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react)

Updates `@types/react-dom` from 19.1.3 to 19.1.5
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react-dom)

Updates `eslint` from 9.25.1 to 9.27.0
- [Release notes](https://github.com/eslint/eslint/releases)
- [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md)
- [Commits](https://github.com/eslint/eslint/compare/v9.25.1...v9.27.0)

Updates `eslint-config-next` from 15.3.1 to 15.3.2
- [Release notes](https://github.com/vercel/next.js/releases)
- [Changelog](https://github.com/vercel/next.js/blob/canary/release.js)
- [Commits](https://github.com/vercel/next.js/commits/v15.3.2/packages/eslint-config-next)

Updates `next` from 15.3.1 to 15.3.2
- [Release notes](https://github.com/vercel/next.js/releases)
- [Changelog](https://github.com/vercel/next.js/blob/canary/release.js)
- [Commits](https://github.com/vercel/next.js/compare/v15.3.1...v15.3.2)

Updates `tailwindcss` from 4.1.5 to 4.1.7
- [Release notes](https://github.com/tailwindlabs/tailwindcss/releases)
- [Changelog](https://github.com/tailwindlabs/tailwindcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/tailwindlabs/tailwindcss/commits/v4.1.7/packages/tailwindcss)

---
updated-dependencies:
- dependency-name: "@headlessui/react"
  dependency-version: 2.2.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: npm
- dependency-name: "@tailwindcss/postcss"
  dependency-version: 4.1.7
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: npm
- dependency-name: "@types/node"
  dependency-version: 22.15.18
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: npm
- dependency-name: "@types/react"
  dependency-version: 19.1.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: npm
- dependency-name: "@types/react-dom"
  dependency-version: 19.1.5
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: npm
- dependency-name: eslint
  dependency-version: 9.27.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: npm
- dependency-name: eslint-config-next
  dependency-version: 15.3.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: npm
- dependency-name: next
  dependency-version: 15.3.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: npm
- dependency-name: tailwindcss
  dependency-version: 4.1.7
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: npm
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-17 16:48:33 +02:00
Rico Berger
6a1a21eec3 Update React Email (#264)
Update React Email to the latest version and add Dependabot
configuration to keep it up-to-date.
2025-05-17 16:42:10 +02:00
Rico Berger
2d838240fd Improve openUrl Function (#262)
Instead of using an external browser on Android, we are now using the
In-App-Browser to open all urls. For all other platforms we keep the
current behaviour and just set the launch mode explicitly, for the case
the the default is changed in the used package.
2025-05-11 11:11:00 +02:00
ricoberger
3a8308b66c Adjust Triggers for GitHub Actions 2025-05-03 15:50:20 +02:00
dependabot[bot]
a5ed230f90 Bump the npm group in /landing with 10 updates (#254)
Bumps the npm group in /landing with 10 updates:

| Package | From | To |
| --- | --- | --- |
| [@headlessui/react](https://github.com/tailwindlabs/headlessui/tree/HEAD/packages/@headlessui-react) | `2.2.0` | `2.2.2` |
| [@tailwindcss/postcss](https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/@tailwindcss-postcss) | `4.0.17` | `4.1.5` |
| [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) | `22.13.16` | `22.15.3` |
| [@types/react](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react) | `19.0.12` | `19.1.2` |
| [@types/react-dom](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react-dom) | `19.0.4` | `19.1.3` |
| [eslint](https://github.com/eslint/eslint) | `9.23.0` | `9.25.1` |
| [eslint-config-next](https://github.com/vercel/next.js/tree/HEAD/packages/eslint-config-next) | `15.2.4` | `15.3.1` |
| [next](https://github.com/vercel/next.js) | `15.2.4` | `15.3.1` |
| [tailwindcss](https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/tailwindcss) | `4.0.17` | `4.1.5` |
| [typescript](https://github.com/microsoft/TypeScript) | `5.8.2` | `5.8.3` |


Updates `@headlessui/react` from 2.2.0 to 2.2.2
- [Release notes](https://github.com/tailwindlabs/headlessui/releases)
- [Changelog](https://github.com/tailwindlabs/headlessui/blob/main/packages/@headlessui-react/CHANGELOG.md)
- [Commits](https://github.com/tailwindlabs/headlessui/commits/@headlessui/react@v2.2.2/packages/@headlessui-react)

Updates `@tailwindcss/postcss` from 4.0.17 to 4.1.5
- [Release notes](https://github.com/tailwindlabs/tailwindcss/releases)
- [Changelog](https://github.com/tailwindlabs/tailwindcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/tailwindlabs/tailwindcss/commits/v4.1.5/packages/@tailwindcss-postcss)

Updates `@types/node` from 22.13.16 to 22.15.3
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

Updates `@types/react` from 19.0.12 to 19.1.2
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react)

Updates `@types/react-dom` from 19.0.4 to 19.1.3
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react-dom)

Updates `eslint` from 9.23.0 to 9.25.1
- [Release notes](https://github.com/eslint/eslint/releases)
- [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md)
- [Commits](https://github.com/eslint/eslint/compare/v9.23.0...v9.25.1)

Updates `eslint-config-next` from 15.2.4 to 15.3.1
- [Release notes](https://github.com/vercel/next.js/releases)
- [Changelog](https://github.com/vercel/next.js/blob/canary/release.js)
- [Commits](https://github.com/vercel/next.js/commits/v15.3.1/packages/eslint-config-next)

Updates `next` from 15.2.4 to 15.3.1
- [Release notes](https://github.com/vercel/next.js/releases)
- [Changelog](https://github.com/vercel/next.js/blob/canary/release.js)
- [Commits](https://github.com/vercel/next.js/compare/v15.2.4...v15.3.1)

Updates `tailwindcss` from 4.0.17 to 4.1.5
- [Release notes](https://github.com/tailwindlabs/tailwindcss/releases)
- [Changelog](https://github.com/tailwindlabs/tailwindcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/tailwindlabs/tailwindcss/commits/v4.1.5/packages/tailwindcss)

Updates `typescript` from 5.8.2 to 5.8.3
- [Release notes](https://github.com/microsoft/TypeScript/releases)
- [Changelog](https://github.com/microsoft/TypeScript/blob/main/azure-pipelines.release-publish.yml)
- [Commits](https://github.com/microsoft/TypeScript/compare/v5.8.2...v5.8.3)

---
updated-dependencies:
- dependency-name: "@headlessui/react"
  dependency-version: 2.2.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: npm
- dependency-name: "@tailwindcss/postcss"
  dependency-version: 4.1.5
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: npm
- dependency-name: "@types/node"
  dependency-version: 22.15.3
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: npm
- dependency-name: "@types/react"
  dependency-version: 19.1.2
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: npm
- dependency-name: "@types/react-dom"
  dependency-version: 19.1.3
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: npm
- dependency-name: eslint
  dependency-version: 9.25.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: npm
- dependency-name: eslint-config-next
  dependency-version: 15.3.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: npm
- dependency-name: next
  dependency-version: 15.3.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: npm
- dependency-name: tailwindcss
  dependency-version: 4.1.5
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: npm
- dependency-name: typescript
  dependency-version: 5.8.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: npm
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-02 23:43:21 +02:00
Rico Berger
7b37aa749c Remove Drag Handles from Sources (#260)
Remove the drag handle icon from the sources. The icon was used together
with the `ReorderableDragStartListener` widget to sort the sources. This
can now be done without the icon, because we wrap the source card widget
within the `ReorderableDragStartListener` widget.
2025-05-02 23:41:05 +02:00
Rico Berger
74b11075cd Adjust Database Functions (#259)
- Set `search_path` for all database functions, as this is recommended
  by the Supabase security advisor
- Fix `items_delete` functions: The function was never working, which
  caused that we saved to many items for a source, which slowed down our
  performance
- Revoke execution rights for users for the `sources_delete_files` and
  `items_delete` functions
- Add E2E test, to check if users can call the database functions
2025-05-02 21:31:09 +02:00
Rico Berger
7d85dff1f7 Add E2E Test (#258) 2025-05-02 18:26:06 +02:00
Rico Berger
9ef3ce60ca Change Row Level Security (#257)
Change all defined row level security policies, to apply the new
performance recommendations by Supabase.

See https://supabase.com/docs/guides/database/database-advisors?queryGroups=lint&lint=0003_auth_rls_initplan
2025-05-02 17:25:34 +02:00
ricoberger
eb331f1540 Add Test Data to Landing Page for E2E Tests
This commit adds a RSS feed and test image to the landing page, which
can be used in the E2E tests.
2025-05-02 14:35:09 +02:00
ricoberger
4b9683d5b6 Format YAML Files 2025-05-01 08:14:39 +02:00
Rico Berger
8fc68951b0 Simplify Self Hosting of Edge Functions (#253)
Until now we had a `find` command to delete existing edge functions
before copying them for the self hosting set up. This command is now
removed, because we also moved the `main` function to the existing
functions directory and just not push it as function to Supabase.
2025-04-26 15:38:59 +02:00
Mr. T.
2270943066 Update README.md (#250)
git and find parameters changed

Signed-off-by: Mr. T. <28456716+DXorSX@users.noreply.github.com>
2025-04-26 15:05:25 +02:00
Rico Berger
c551d1635a Allow Importing / Exporting of Decks (#251)
It is now possible import and export decks. Decks can be imported from
OPML files. For each import a new deck is created. If the OPML file
contains nested `outline` tags, we will create one column for each
parent `outline` tag. Otherwise we will create a column named `Unknown`
and all sources to this column. When a deck is exported we will create
one `outline` tag for each column with it's sources as siblings.
2025-04-26 14:57:08 +02:00
Rico Berger
f100925eff [youtube] Fix Video Playback (#249)
Until now we only checkeed if we could fetch a video which contains the
video and audio of a YouTube video. Since this is not always the case we
are now also returning the videos which do not contains the audio and
fetching the corresponding audio file seperatly.
2025-04-24 22:30:02 +02:00
Rico Berger
48f504ede9 Add Self-Hosting Setup (#248)
* Add Self-Hosting Setup

* Add Self-Hosting Setup

Add Docker Compose set up to self-host FeedDeck.
2025-04-24 09:03:08 +02:00
Rico Berger
b8fdbf17a2 Rework Edge Functions (#247)
Instead of using an `import_map.json` file to define the versions for
dependencies, they are now defined directly within the import. Since the
`import_map.json` file should not be used anymore and instead a
`deno.json` file per function should be used, we decided to define them
directly with the code. The overhead compared to a `deno.json` file per
function shouldn't be that large and it makes using functions in a
self-hosted setup easier.
2025-04-23 17:00:21 +02:00
Rico Berger
6a3b481219 Allow Swiping Gestures to Switch Column (#246)
It is now possible to switch the column in a deck by swiping to the left
/ right.
2025-04-19 15:31:57 +02:00
Rico Berger
bf95846e6c Allow Re-Ordering of Sources in a Column (#245)
It is now possible to re-order sources in a column by dragging them into
a new position. To achieve this a new `position` field was added to the
`sources` column, which contains the index of the source in the column.
We also added a new `updateSourcePositions` function, which is used to
sort the sources locally and update `position` field in the database
afterwards. The dragging is handled via a `ReorderableListView` widget.
Last but not least the selection of sources from the database was
changed, so order them by the `position` column and if the column is
`null` by the `createdAt` data as it was before.
2025-04-19 15:08:55 +02:00
Rico Berger
2c712f6a07 Fix Flutter Deprecations (#244)
- Change `surfaceVariant` to `surfaceContainerHighest`
- Remove `library` statement
- Migrate from `dart:html` to `package:web/web.dart`
2025-04-19 11:34:40 +02:00
Rico Berger
61a30eaa06 Prefer content over description for Item Description (#243)
Until now, we always checked the `description` field of an item first to
get our description value. If the `description` field is present we
directly used it and never checked the `content` field.

Now we are checking the `content` field first and afterwards the
`description` field. This way by default the `content` field is used as
our description. This should be more common to get the full article text
when both fields are present in an RSS feed.

When both fields are present and the `description` field is longer then
the `content` field, we will still prefer the `description` field.
2025-04-19 10:53:05 +02:00
Rico Berger
a9b4bef96f Update Deno Version to 1.45.2 (#242)
* Update Deno Version to 1.45.2

Update Deno Version in the Docker image to version 1.45.2 and update the
`@supabase/supabase-js` dependency specified in the `import_map.json`
file.

**NOTES:**

- The current recommended approach for managing dependencies is using a
  `deno.json` file, which is currently not working locally and returns
  the following error:

```
serving the request with supabase/functions/add-or-update-source-v1
worker boot error: failed to create the graph: Relative import path "@supabase/supabase-js" not prefixed with / or ./ or ../
    at file:///Users/ricoberger/Documents/GitHub/feeddeck/feeddeck/supabase/functions/add-or-update-source-v1/index.ts:1:30
worker boot error: failed to create the graph: Relative import path "@supabase/supabase-js" not prefixed with / or ./ or ../
    at file:///Users/ricoberger/Documents/GitHub/feeddeck/feeddeck/supabase/functions/add-or-update-source-v1/index.ts:1:30
InvalidWorkerCreation: worker boot error: failed to create the graph: Relative import path "@supabase/supabase-js" not prefixed with / or ./ or ../
    at file:///Users/ricoberger/Documents/GitHub/feeddeck/feeddeck/supabase/functions/add-or-update-source-v1/index.ts:1:30
    at async UserWorker.create (ext:sb_user_workers/user_workers.js:139:15)
    at async Object.handler (file:///root/index.ts:157:22)
    at async respond (ext:sb_core_main_js/js/http.js:197:14) {
  name: "InvalidWorkerCreation"
}
```

- When using Deno v2 the dependencies via the `deno.json` file are
  working. To enable Deno v2 the following must be set in the
  `config.toml` file:

```
[edge_runtime]
deno_version = 2
```

- Deno v2 is currently only supported locally, see
  https://supabase.com/blog/supabase-edge-functions-deploy-dashboard-deno-2-1#deno-21-preview

- Once Deno v2 is supported in the hosted platform, we should switch
  from the `import_map.json` to `deno.json` to manage dependencies and
  update the existing dependencies.

* Fix Errors

- Replace `err.toString()` with just `err` when logging errors.
- Add new `blobToFile` function, to upload files to the Supabase
  storage, otherwise we receive the following error (https://github.com/feeddeck/feeddeck/actions/runs/14546547197/job/40812707871):

```
error: TS2345 [ERROR]: Argument of type 'Blob' is not assignable to parameter of type 'FileBody'.
  Type 'Blob' is missing the following properties from type 'File': lastModified, name, webkitRelativePath
        file,
        ~~~~
    at file:///home/runner/work/feeddeck/feeddeck/supabase/functions/_shared/feed/utils/uploadFile.ts:66:9
```
2025-04-19 09:10:43 +02:00
Rico Berger
4e0296e226 Update Flutter Version to 3.29.3 (#241) 2025-04-18 15:45:44 +02:00
dependabot[bot]
f4c755e131 Bump @types/node from 22.13.14 to 22.13.16 in /landing in the npm group (#237)
Bumps the npm group in /landing with 1 update: [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node).


Updates `@types/node` from 22.13.14 to 22.13.16
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

---
updated-dependencies:
- dependency-name: "@types/node"
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: npm
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-18 15:23:40 +02:00
Rico Berger
ad0d214528 Update Flutter Version to 3.29.2 (#236) 2025-03-30 09:54:16 +02:00
dependabot[bot]
965c647b07 Bump the pub group in /app with 2 updates (#233)
* Bump the pub group in /app with 2 updates

Bumps the pub group in /app with 2 updates: [piped_client](https://github.com/KRTirtho/piped_client) and [purchases_flutter](https://github.com/RevenueCat/purchases-flutter).


Updates `piped_client` from 0.1.1 to 0.1.2
- [Changelog](https://github.com/KRTirtho/piped_client/blob/main/CHANGELOG.md)
- [Commits](https://github.com/KRTirtho/piped_client/commits)

Updates `purchases_flutter` from 8.6.0 to 8.6.1
- [Release notes](https://github.com/RevenueCat/purchases-flutter/releases)
- [Changelog](https://github.com/RevenueCat/purchases-flutter/blob/main/CHANGELOG.md)
- [Commits](https://github.com/RevenueCat/purchases-flutter/compare/8.6.0...8.6.1)

---
updated-dependencies:
- dependency-name: piped_client
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: pub
- dependency-name: purchases_flutter
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: pub
...

Signed-off-by: dependabot[bot] <support@github.com>

* Update Podfile.lock

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: ricoberger <mail@ricoberger.de>
2025-03-30 09:38:35 +02:00
dependabot[bot]
2094b36384 Bump the npm group across 1 directory with 10 updates (#235)
Bumps the npm group with 9 updates in the /landing directory:

| Package | From | To |
| --- | --- | --- |
| [@tailwindcss/postcss](https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/@tailwindcss-postcss) | `4.0.9` | `4.0.17` |
| [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) | `22.13.8` | `22.13.14` |
| [autoprefixer](https://github.com/postcss/autoprefixer) | `10.4.20` | `10.4.21` |
| [eslint](https://github.com/eslint/eslint) | `9.21.0` | `9.23.0` |
| [eslint-config-next](https://github.com/vercel/next.js/tree/HEAD/packages/eslint-config-next) | `15.2.0` | `15.2.4` |
| [next](https://github.com/vercel/next.js) | `15.2.3` | `15.2.4` |
| [react](https://github.com/facebook/react/tree/HEAD/packages/react) | `19.0.0` | `19.1.0` |
| [@types/react](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react) | `19.0.10` | `19.0.12` |
| [react-dom](https://github.com/facebook/react/tree/HEAD/packages/react-dom) | `19.0.0` | `19.1.0` |



Updates `@tailwindcss/postcss` from 4.0.9 to 4.0.17
- [Release notes](https://github.com/tailwindlabs/tailwindcss/releases)
- [Changelog](https://github.com/tailwindlabs/tailwindcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/tailwindlabs/tailwindcss/commits/v4.0.17/packages/@tailwindcss-postcss)

Updates `@types/node` from 22.13.8 to 22.13.14
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

Updates `autoprefixer` from 10.4.20 to 10.4.21
- [Release notes](https://github.com/postcss/autoprefixer/releases)
- [Changelog](https://github.com/postcss/autoprefixer/blob/main/CHANGELOG.md)
- [Commits](https://github.com/postcss/autoprefixer/compare/10.4.20...10.4.21)

Updates `eslint` from 9.21.0 to 9.23.0
- [Release notes](https://github.com/eslint/eslint/releases)
- [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md)
- [Commits](https://github.com/eslint/eslint/compare/v9.21.0...v9.23.0)

Updates `eslint-config-next` from 15.2.0 to 15.2.4
- [Release notes](https://github.com/vercel/next.js/releases)
- [Changelog](https://github.com/vercel/next.js/blob/canary/release.js)
- [Commits](https://github.com/vercel/next.js/commits/v15.2.4/packages/eslint-config-next)

Updates `next` from 15.2.3 to 15.2.4
- [Release notes](https://github.com/vercel/next.js/releases)
- [Changelog](https://github.com/vercel/next.js/blob/canary/release.js)
- [Commits](https://github.com/vercel/next.js/compare/v15.2.3...v15.2.4)

Updates `react` from 19.0.0 to 19.1.0
- [Release notes](https://github.com/facebook/react/releases)
- [Changelog](https://github.com/facebook/react/blob/main/CHANGELOG.md)
- [Commits](https://github.com/facebook/react/commits/v19.1.0/packages/react)

Updates `@types/react` from 19.0.10 to 19.0.12
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react)

Updates `react-dom` from 19.0.0 to 19.1.0
- [Release notes](https://github.com/facebook/react/releases)
- [Changelog](https://github.com/facebook/react/blob/main/CHANGELOG.md)
- [Commits](https://github.com/facebook/react/commits/v19.1.0/packages/react-dom)

Updates `tailwindcss` from 4.0.9 to 4.0.17
- [Release notes](https://github.com/tailwindlabs/tailwindcss/releases)
- [Changelog](https://github.com/tailwindlabs/tailwindcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/tailwindlabs/tailwindcss/commits/v4.0.17/packages/tailwindcss)

---
updated-dependencies:
- dependency-name: "@tailwindcss/postcss"
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: npm
- dependency-name: "@types/node"
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: npm
- dependency-name: autoprefixer
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: npm
- dependency-name: eslint
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: npm
- dependency-name: eslint-config-next
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: npm
- dependency-name: next
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: npm
- dependency-name: react
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: npm
- dependency-name: "@types/react"
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: npm
- dependency-name: react-dom
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: npm
- dependency-name: tailwindcss
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: npm
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-30 09:26:13 +02:00
dependabot[bot]
394e64d26b Bump next from 15.2.0 to 15.2.3 in /landing (#234)
Bumps [next](https://github.com/vercel/next.js) from 15.2.0 to 15.2.3.
- [Release notes](https://github.com/vercel/next.js/releases)
- [Changelog](https://github.com/vercel/next.js/blob/canary/release.js)
- [Commits](https://github.com/vercel/next.js/compare/v15.2.0...v15.2.3)

---
updated-dependencies:
- dependency-name: next
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-30 09:19:00 +02:00
dependabot[bot]
a7c134e53c Bump the npm group in /supabase/email-templates (#230)
* Bump @babel/helpers from 7.25.0 to 7.26.10 in /supabase/email-templates

Bumps [@babel/helpers](https://github.com/babel/babel/tree/HEAD/packages/babel-helpers) from 7.25.0 to 7.26.10.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.26.10/packages/babel-helpers)

---
updated-dependencies:
- dependency-name: "@babel/helpers"
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

* Update Dependencies

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: ricoberger <mail@ricoberger.de>
2025-03-16 15:04:53 +01:00
ricoberger
6cc79ef8c6 Fix Typo in GitHub Action 2025-03-16 14:50:17 +01:00
Rico Berger
842c78bf1d Maintenance: GitHub Actions (#231)
- Use `docker/metadata-action` GitHub Action to determine the tag for
  Docker images
- Add `changelog: changed` label to Dependabot PRs
- Adjust `version-resolver` for Release Drafter to use `patch` versions
  for PRs with `changelog: changed` label
2025-03-16 14:48:14 +01:00
dependabot[bot]
0218342f46 Bump the pub group in /app with 9 updates (#225)
* Bump the pub group in /app with 9 updates

Bumps the pub group in /app with 9 updates:

| Package | From | To |
| --- | --- | --- |
| [app_links](https://github.com/llfbandit/app_links) | `6.3.3` | `6.4.0` |
| [flutter_native_splash](https://github.com/jonbhanson/flutter_native_splash) | `2.4.4` | `2.4.5` |
| [just_audio](https://github.com/ryanheise/just_audio) | `0.9.44` | `0.9.46` |
| [just_audio_background](https://github.com/ryanheise/just_audio) | `0.0.1-beta.14` | `0.0.1-beta.15` |
| [package_info_plus](https://github.com/fluttercommunity/plus_plugins/tree/main/packages/package_info_plus) | `8.1.4` | `8.3.0` |
| [purchases_flutter](https://github.com/RevenueCat/purchases-flutter) | `8.4.4` | `8.6.0` |
| [shared_preferences](https://github.com/flutter/packages/tree/main/packages/shared_preferences) | `2.5.1` | `2.5.2` |
| [supabase_flutter](https://github.com/supabase/supabase-flutter/tree/main/packages) | `2.8.3` | `2.8.4` |
| [youtube_explode_dart](https://github.com/Hexer10/youtube_explode_dart) | `2.3.6` | `2.3.10` |


Updates `app_links` from 6.3.3 to 6.4.0
- [Release notes](https://github.com/llfbandit/app_links/releases)
- [Commits](https://github.com/llfbandit/app_links/commits)

Updates `flutter_native_splash` from 2.4.4 to 2.4.5
- [Release notes](https://github.com/jonbhanson/flutter_native_splash/releases)
- [Changelog](https://github.com/jonbhanson/flutter_native_splash/blob/master/CHANGELOG.md)
- [Commits](https://github.com/jonbhanson/flutter_native_splash/compare/v2.4.4...v2.4.5)

Updates `just_audio` from 0.9.44 to 0.9.46
- [Release notes](https://github.com/ryanheise/just_audio/releases)
- [Commits](https://github.com/ryanheise/just_audio/compare/just_audio-v0.9.44...just_audio-v0.9.46)

Updates `just_audio_background` from 0.0.1-beta.14 to 0.0.1-beta.15
- [Release notes](https://github.com/ryanheise/just_audio/releases)
- [Commits](https://github.com/ryanheise/just_audio/compare/just_audio_background-v0.0.1-beta.14...just_audio_background-v0.0.1-beta.15)

Updates `package_info_plus` from 8.1.4 to 8.3.0
- [Release notes](https://github.com/fluttercommunity/plus_plugins/releases)
- [Commits](https://github.com/fluttercommunity/plus_plugins/commits/package_info_plus-v8.3.0/packages/package_info_plus)

Updates `purchases_flutter` from 8.4.4 to 8.6.0
- [Release notes](https://github.com/RevenueCat/purchases-flutter/releases)
- [Changelog](https://github.com/RevenueCat/purchases-flutter/blob/main/CHANGELOG.md)
- [Commits](https://github.com/RevenueCat/purchases-flutter/compare/8.4.4...8.6.0)

Updates `shared_preferences` from 2.5.1 to 2.5.2
- [Release notes](https://github.com/flutter/packages/releases)
- [Commits](https://github.com/flutter/packages/commits/shared_preferences-v2.5.2/packages/shared_preferences)

Updates `supabase_flutter` from 2.8.3 to 2.8.4
- [Changelog](https://github.com/supabase/supabase-flutter/blob/main/CHANGELOG.md)
- [Commits](https://github.com/supabase/supabase-flutter/commits/supabase_flutter-v2.8.4/packages)

Updates `youtube_explode_dart` from 2.3.6 to 2.3.10
- [Release notes](https://github.com/Hexer10/youtube_explode_dart/releases)
- [Changelog](https://github.com/Hexer10/youtube_explode_dart/blob/v2.3.10/CHANGELOG.md)
- [Commits](https://github.com/Hexer10/youtube_explode_dart/compare/v2.3.6...v2.3.10)

---
updated-dependencies:
- dependency-name: app_links
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: pub
- dependency-name: flutter_native_splash
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: pub
- dependency-name: just_audio
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: pub
- dependency-name: just_audio_background
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: pub
- dependency-name: package_info_plus
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: pub
- dependency-name: purchases_flutter
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: pub
- dependency-name: shared_preferences
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: pub
- dependency-name: supabase_flutter
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: pub
- dependency-name: youtube_explode_dart
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: pub
...

Signed-off-by: dependabot[bot] <support@github.com>

* Update Podfile.lock

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: ricoberger <mail@ricoberger.de>
2025-03-16 14:26:32 +01:00
dependabot[bot]
432118ae47 Bump the npm group in /landing with 10 updates (#224)
Bumps the npm group in /landing with 10 updates:

| Package | From | To |
| --- | --- | --- |
| [@tailwindcss/postcss](https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/@tailwindcss-postcss) | `4.0.3` | `4.0.9` |
| [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) | `22.13.0` | `22.13.8` |
| [@types/react](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react) | `19.0.8` | `19.0.10` |
| [@types/react-dom](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react-dom) | `19.0.3` | `19.0.4` |
| [eslint](https://github.com/eslint/eslint) | `9.19.0` | `9.21.0` |
| [eslint-config-next](https://github.com/vercel/next.js/tree/HEAD/packages/eslint-config-next) | `15.1.6` | `15.2.0` |
| [next](https://github.com/vercel/next.js) | `15.1.6` | `15.2.0` |
| [postcss](https://github.com/postcss/postcss) | `8.5.1` | `8.5.3` |
| [tailwindcss](https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/tailwindcss) | `4.0.3` | `4.0.9` |
| [typescript](https://github.com/microsoft/TypeScript) | `5.7.3` | `5.8.2` |


Updates `@tailwindcss/postcss` from 4.0.3 to 4.0.9
- [Release notes](https://github.com/tailwindlabs/tailwindcss/releases)
- [Changelog](https://github.com/tailwindlabs/tailwindcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/tailwindlabs/tailwindcss/commits/v4.0.9/packages/@tailwindcss-postcss)

Updates `@types/node` from 22.13.0 to 22.13.8
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

Updates `@types/react` from 19.0.8 to 19.0.10
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react)

Updates `@types/react-dom` from 19.0.3 to 19.0.4
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react-dom)

Updates `eslint` from 9.19.0 to 9.21.0
- [Release notes](https://github.com/eslint/eslint/releases)
- [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md)
- [Commits](https://github.com/eslint/eslint/compare/v9.19.0...v9.21.0)

Updates `eslint-config-next` from 15.1.6 to 15.2.0
- [Release notes](https://github.com/vercel/next.js/releases)
- [Changelog](https://github.com/vercel/next.js/blob/canary/release.js)
- [Commits](https://github.com/vercel/next.js/commits/v15.2.0/packages/eslint-config-next)

Updates `next` from 15.1.6 to 15.2.0
- [Release notes](https://github.com/vercel/next.js/releases)
- [Changelog](https://github.com/vercel/next.js/blob/canary/release.js)
- [Commits](https://github.com/vercel/next.js/compare/v15.1.6...v15.2.0)

Updates `postcss` from 8.5.1 to 8.5.3
- [Release notes](https://github.com/postcss/postcss/releases)
- [Changelog](https://github.com/postcss/postcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/postcss/postcss/compare/8.5.1...8.5.3)

Updates `tailwindcss` from 4.0.3 to 4.0.9
- [Release notes](https://github.com/tailwindlabs/tailwindcss/releases)
- [Changelog](https://github.com/tailwindlabs/tailwindcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/tailwindlabs/tailwindcss/commits/v4.0.9/packages/tailwindcss)

Updates `typescript` from 5.7.3 to 5.8.2
- [Release notes](https://github.com/microsoft/TypeScript/releases)
- [Changelog](https://github.com/microsoft/TypeScript/blob/main/azure-pipelines.release.yml)
- [Commits](https://github.com/microsoft/TypeScript/compare/v5.7.3...v5.8.2)

---
updated-dependencies:
- dependency-name: "@tailwindcss/postcss"
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: npm
- dependency-name: "@types/node"
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: npm
- dependency-name: "@types/react"
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: npm
- dependency-name: "@types/react-dom"
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: npm
- dependency-name: eslint
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: npm
- dependency-name: eslint-config-next
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: npm
- dependency-name: next
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: npm
- dependency-name: postcss
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: npm
- dependency-name: tailwindcss
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: npm
- dependency-name: typescript
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: npm
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-16 14:08:05 +01:00
Rico Berger
f481f2ceb9 Update Flutter Version to 3.29.0 (#223) 2025-02-26 21:42:07 +01:00
dependabot[bot]
d768b0ffdf Bump the pub group in /app with 8 updates (#222)
* Bump the pub group in /app with 8 updates

Bumps the pub group in /app with 8 updates:

| Package | From | To |
| --- | --- | --- |
| [flutter_launcher_icons](https://github.com/fluttercommunity/flutter_launcher_icons) | `0.14.2` | `0.14.3` |
| [flutter_markdown](https://github.com/flutter/packages/tree/main/packages) | `0.7.4+1` | `0.7.6` |
| [http](https://github.com/dart-lang/http/tree/master/pkgs) | `1.2.2` | `1.3.0` |
| [just_audio](https://github.com/ryanheise/just_audio) | `0.9.42` | `0.9.44` |
| [package_info_plus](https://github.com/fluttercommunity/plus_plugins/tree/main/packages/package_info_plus) | `8.1.2` | `8.1.4` |
| [purchases_flutter](https://github.com/RevenueCat/purchases-flutter) | `8.4.0` | `8.4.4` |
| [shared_preferences](https://github.com/flutter/packages/tree/main/packages/shared_preferences) | `2.3.4` | `2.5.1` |
| [supabase_flutter](https://github.com/supabase/supabase-flutter/tree/main/packages) | `2.8.2` | `2.8.3` |


Updates `flutter_launcher_icons` from 0.14.2 to 0.14.3
- [Release notes](https://github.com/fluttercommunity/flutter_launcher_icons/releases)
- [Changelog](https://github.com/fluttercommunity/flutter_launcher_icons/blob/master/CHANGELOG.md)
- [Commits](https://github.com/fluttercommunity/flutter_launcher_icons/commits)

Updates `flutter_markdown` from 0.7.4+1 to 0.7.6
- [Release notes](https://github.com/flutter/packages/releases)
- [Commits](https://github.com/flutter/packages/commits/flutter_markdown-v0.7.6/packages)

Updates `http` from 1.2.2 to 1.3.0
- [Release notes](https://github.com/dart-lang/http/releases)
- [Commits](https://github.com/dart-lang/http/commits/http-v1.3.0/pkgs)

Updates `just_audio` from 0.9.42 to 0.9.44
- [Release notes](https://github.com/ryanheise/just_audio/releases)
- [Commits](https://github.com/ryanheise/just_audio/compare/just_audio-v0.9.42...just_audio-v0.9.44)

Updates `package_info_plus` from 8.1.2 to 8.1.4
- [Release notes](https://github.com/fluttercommunity/plus_plugins/releases)
- [Commits](https://github.com/fluttercommunity/plus_plugins/commits/package_info_plus-v8.1.4/packages/package_info_plus)

Updates `purchases_flutter` from 8.4.0 to 8.4.4
- [Release notes](https://github.com/RevenueCat/purchases-flutter/releases)
- [Changelog](https://github.com/RevenueCat/purchases-flutter/blob/main/CHANGELOG.md)
- [Commits](https://github.com/RevenueCat/purchases-flutter/compare/8.4.0...8.4.4)

Updates `shared_preferences` from 2.3.4 to 2.5.1
- [Release notes](https://github.com/flutter/packages/releases)
- [Commits](https://github.com/flutter/packages/commits/shared_preferences-v2.5.1/packages/shared_preferences)

Updates `supabase_flutter` from 2.8.2 to 2.8.3
- [Changelog](https://github.com/supabase/supabase-flutter/blob/main/CHANGELOG.md)
- [Commits](https://github.com/supabase/supabase-flutter/commits/gotrue-v2.8.3/packages)

---
updated-dependencies:
- dependency-name: flutter_launcher_icons
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: pub
- dependency-name: flutter_markdown
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: pub
- dependency-name: http
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: pub
- dependency-name: just_audio
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: pub
- dependency-name: package_info_plus
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: pub
- dependency-name: purchases_flutter
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: pub
- dependency-name: shared_preferences
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: pub
- dependency-name: supabase_flutter
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: pub
...

Signed-off-by: dependabot[bot] <support@github.com>

* Update Podfile.lock

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: ricoberger <mail@ricoberger.de>
2025-02-26 21:31:23 +01:00
dependabot[bot]
a0229d8ece Bump the npm group in /landing with 3 updates (#221)
Bumps the npm group in /landing with 3 updates: [@tailwindcss/postcss](https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/@tailwindcss-postcss), [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) and [tailwindcss](https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/tailwindcss).


Updates `@tailwindcss/postcss` from 4.0.0 to 4.0.3
- [Release notes](https://github.com/tailwindlabs/tailwindcss/releases)
- [Changelog](https://github.com/tailwindlabs/tailwindcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/tailwindlabs/tailwindcss/commits/v4.0.3/packages/@tailwindcss-postcss)

Updates `@types/node` from 22.10.10 to 22.13.0
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

Updates `tailwindcss` from 4.0.0 to 4.0.3
- [Release notes](https://github.com/tailwindlabs/tailwindcss/releases)
- [Changelog](https://github.com/tailwindlabs/tailwindcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/tailwindlabs/tailwindcss/commits/v4.0.3/packages/tailwindcss)

---
updated-dependencies:
- dependency-name: "@tailwindcss/postcss"
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: npm
- dependency-name: "@types/node"
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: npm
- dependency-name: tailwindcss
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: npm
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-26 20:59:25 +01:00
ricoberger
50ad24a7bc Update License 2025-01-26 15:56:15 +01:00
Rico Berger
76854e72df Update Landing Page (#220) 2025-01-26 15:35:26 +01:00
dependabot[bot]
88bbb9f56f Bump the npm group across 1 directory with 11 updates (#219)
Bumps the npm group with 11 updates in the /landing directory:

| Package | From | To |
| --- | --- | --- |
| [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) | `22.9.0` | `22.10.10` |
| [eslint](https://github.com/eslint/eslint) | `9.14.0` | `9.19.0` |
| [eslint-config-next](https://github.com/vercel/next.js/tree/HEAD/packages/eslint-config-next) | `15.0.3` | `15.1.6` |
| [next](https://github.com/vercel/next.js) | `15.1.2` | `15.1.6` |
| [postcss](https://github.com/postcss/postcss) | `8.4.47` | `8.5.1` |
| [react](https://github.com/facebook/react/tree/HEAD/packages/react) | `18.3.1` | `19.0.0` |
| [@types/react](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react) | `18.3.12` | `19.0.8` |
| [react-dom](https://github.com/facebook/react/tree/HEAD/packages/react-dom) | `18.3.1` | `19.0.0` |
| [@types/react-dom](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react-dom) | `18.3.1` | `19.0.3` |
| [tailwindcss](https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/tailwindcss) | `3.4.14` | `4.0.0` |
| [typescript](https://github.com/microsoft/TypeScript) | `5.6.3` | `5.7.3` |



Updates `@types/node` from 22.9.0 to 22.10.10
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

Updates `eslint` from 9.14.0 to 9.19.0
- [Release notes](https://github.com/eslint/eslint/releases)
- [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md)
- [Commits](https://github.com/eslint/eslint/compare/v9.14.0...v9.19.0)

Updates `eslint-config-next` from 15.0.3 to 15.1.6
- [Release notes](https://github.com/vercel/next.js/releases)
- [Changelog](https://github.com/vercel/next.js/blob/canary/release.js)
- [Commits](https://github.com/vercel/next.js/commits/v15.1.6/packages/eslint-config-next)

Updates `next` from 15.1.2 to 15.1.6
- [Release notes](https://github.com/vercel/next.js/releases)
- [Changelog](https://github.com/vercel/next.js/blob/canary/release.js)
- [Commits](https://github.com/vercel/next.js/compare/v15.1.2...v15.1.6)

Updates `postcss` from 8.4.47 to 8.5.1
- [Release notes](https://github.com/postcss/postcss/releases)
- [Changelog](https://github.com/postcss/postcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/postcss/postcss/compare/8.4.47...8.5.1)

Updates `react` from 18.3.1 to 19.0.0
- [Release notes](https://github.com/facebook/react/releases)
- [Changelog](https://github.com/facebook/react/blob/main/CHANGELOG.md)
- [Commits](https://github.com/facebook/react/commits/v19.0.0/packages/react)

Updates `@types/react` from 18.3.12 to 19.0.8
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react)

Updates `react-dom` from 18.3.1 to 19.0.0
- [Release notes](https://github.com/facebook/react/releases)
- [Changelog](https://github.com/facebook/react/blob/main/CHANGELOG.md)
- [Commits](https://github.com/facebook/react/commits/v19.0.0/packages/react-dom)

Updates `@types/react-dom` from 18.3.1 to 19.0.3
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react-dom)

Updates `tailwindcss` from 3.4.14 to 4.0.0
- [Release notes](https://github.com/tailwindlabs/tailwindcss/releases)
- [Changelog](https://github.com/tailwindlabs/tailwindcss/blob/next/CHANGELOG.md)
- [Commits](https://github.com/tailwindlabs/tailwindcss/commits/v4.0.0/packages/tailwindcss)

Updates `typescript` from 5.6.3 to 5.7.3
- [Release notes](https://github.com/microsoft/TypeScript/releases)
- [Changelog](https://github.com/microsoft/TypeScript/blob/main/azure-pipelines.release.yml)
- [Commits](https://github.com/microsoft/TypeScript/compare/v5.6.3...v5.7.3)

---
updated-dependencies:
- dependency-name: "@types/node"
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: npm
- dependency-name: eslint
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: npm
- dependency-name: eslint-config-next
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: npm
- dependency-name: next
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: npm
- dependency-name: postcss
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: npm
- dependency-name: react
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: npm
- dependency-name: "@types/react"
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: npm
- dependency-name: react-dom
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: npm
- dependency-name: "@types/react-dom"
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: npm
- dependency-name: tailwindcss
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: npm
- dependency-name: typescript
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: npm
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-26 15:04:22 +01:00
dependabot[bot]
fb97f818b3 Bump cross-spawn from 7.0.3 to 7.0.6 in /landing (#208)
Bumps [cross-spawn](https://github.com/moxystudio/node-cross-spawn) from 7.0.3 to 7.0.6.
- [Changelog](https://github.com/moxystudio/node-cross-spawn/blob/master/CHANGELOG.md)
- [Commits](https://github.com/moxystudio/node-cross-spawn/compare/v7.0.3...v7.0.6)

---
updated-dependencies:
- dependency-name: cross-spawn
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-26 15:00:23 +01:00
dependabot[bot]
2e3110e298 Bump nanoid from 3.3.7 to 3.3.8 in /landing (#211)
Bumps [nanoid](https://github.com/ai/nanoid) from 3.3.7 to 3.3.8.
- [Release notes](https://github.com/ai/nanoid/releases)
- [Changelog](https://github.com/ai/nanoid/blob/main/CHANGELOG.md)
- [Commits](https://github.com/ai/nanoid/compare/3.3.7...3.3.8)

---
updated-dependencies:
- dependency-name: nanoid
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-26 14:59:54 +01:00
dependabot[bot]
a167d94165 Bump next and react-email in /supabase/email-templates (#218)
* Bump next and react-email in /supabase/email-templates

Removes [next](https://github.com/vercel/next.js). It's no longer used after updating ancestor dependency [react-email](https://github.com/resend/react-email/tree/HEAD/packages/react-email). These dependencies need to be updated together.


Removes `next`

Updates `react-email` from 3.0.4 to 3.0.6
- [Release notes](https://github.com/resend/react-email/releases)
- [Changelog](https://github.com/resend/react-email/blob/canary/packages/react-email/CHANGELOG.md)
- [Commits](https://github.com/resend/react-email/commits/react-email@3.0.6/packages/react-email)

---
updated-dependencies:
- dependency-name: next
  dependency-type: indirect
- dependency-name: react-email
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>

* Update Dependencies

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: ricoberger <mail@ricoberger.de>
2025-01-26 14:59:07 +01:00
dependabot[bot]
614a1b9ab9 Bump @eslint/plugin-kit from 0.2.2 to 0.2.3 in /landing (#206)
Bumps [@eslint/plugin-kit](https://github.com/eslint/rewrite) from 0.2.2 to 0.2.3.
- [Release notes](https://github.com/eslint/rewrite/releases)
- [Changelog](https://github.com/eslint/rewrite/blob/main/release-please-config.json)
- [Commits](https://github.com/eslint/rewrite/compare/plugin-kit-v0.2.2...plugin-kit-v0.2.3)

---
updated-dependencies:
- dependency-name: "@eslint/plugin-kit"
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-26 14:57:28 +01:00
dependabot[bot]
8f2008a179 Bump the pub group across 1 directory with 11 updates (#215)
* Bump the pub group across 1 directory with 11 updates

Bumps the pub group with 10 updates in the /app directory:

| Package | From | To |
| --- | --- | --- |
| [app_links](https://github.com/llfbandit/app_links) | `6.3.2` | `6.3.3` |
| [flutter_launcher_icons](https://github.com/fluttercommunity/flutter_launcher_icons) | `0.14.1` | `0.14.2` |
| [flutter_native_splash](https://github.com/jonbhanson/flutter_native_splash) | `2.4.2` | `2.4.4` |
| [just_audio_background](https://github.com/ryanheise/just_audio) | `0.0.1-beta.13` | `0.0.1-beta.14` |
| [package_info_plus](https://github.com/fluttercommunity/plus_plugins/tree/main/packages/package_info_plus) | `8.1.1` | `8.1.2` |
| [purchases_flutter](https://github.com/RevenueCat/purchases-flutter) | `8.2.1` | `8.4.0` |
| [shared_preferences](https://github.com/flutter/packages/tree/main/packages/shared_preferences) | `2.3.3` | `2.3.4` |
| [sign_in_with_apple](https://github.com/aboutyou/dart_packages) | `6.1.3` | `6.1.4` |
| [supabase_flutter](https://github.com/supabase/supabase-flutter/tree/main/packages) | `2.8.0` | `2.8.2` |
| [youtube_explode_dart](https://github.com/Hexer10/youtube_explode_dart) | `2.3.5` | `2.3.6` |



Updates `app_links` from 6.3.2 to 6.3.3
- [Release notes](https://github.com/llfbandit/app_links/releases)
- [Commits](https://github.com/llfbandit/app_links/compare/6.3.2...6.3.3)

Updates `collection` from 1.18.0 to 1.19.0
- [Release notes](https://github.com/dart-lang/core/releases)
- [Commits](https://github.com/dart-lang/core/commits/collection-v1.19.0/pkgs)

Updates `flutter_launcher_icons` from 0.14.1 to 0.14.2
- [Release notes](https://github.com/fluttercommunity/flutter_launcher_icons/releases)
- [Changelog](https://github.com/fluttercommunity/flutter_launcher_icons/blob/master/CHANGELOG.md)
- [Commits](https://github.com/fluttercommunity/flutter_launcher_icons/compare/v0.14.1...v0.14.2)

Updates `flutter_native_splash` from 2.4.2 to 2.4.4
- [Release notes](https://github.com/jonbhanson/flutter_native_splash/releases)
- [Changelog](https://github.com/jonbhanson/flutter_native_splash/blob/master/CHANGELOG.md)
- [Commits](https://github.com/jonbhanson/flutter_native_splash/compare/v2.4.2...v2.4.4)

Updates `just_audio_background` from 0.0.1-beta.13 to 0.0.1-beta.14
- [Release notes](https://github.com/ryanheise/just_audio/releases)
- [Commits](https://github.com/ryanheise/just_audio/compare/just_audio_background-v0.0.1-beta.13...just_audio_background-v0.0.1-beta.14)

Updates `package_info_plus` from 8.1.1 to 8.1.2
- [Release notes](https://github.com/fluttercommunity/plus_plugins/releases)
- [Commits](https://github.com/fluttercommunity/plus_plugins/commits/package_info_plus-v8.1.2/packages/package_info_plus)

Updates `purchases_flutter` from 8.2.1 to 8.4.0
- [Release notes](https://github.com/RevenueCat/purchases-flutter/releases)
- [Changelog](https://github.com/RevenueCat/purchases-flutter/blob/main/CHANGELOG.md)
- [Commits](https://github.com/RevenueCat/purchases-flutter/compare/8.2.1...8.4.0)

Updates `shared_preferences` from 2.3.3 to 2.3.4
- [Release notes](https://github.com/flutter/packages/releases)
- [Commits](https://github.com/flutter/packages/commits/shared_preferences-v2.3.4/packages/shared_preferences)

Updates `sign_in_with_apple` from 6.1.3 to 6.1.4
- [Release notes](https://github.com/aboutyou/dart_packages/releases)
- [Commits](https://github.com/aboutyou/dart_packages/commits)

Updates `supabase_flutter` from 2.8.0 to 2.8.2
- [Changelog](https://github.com/supabase/supabase-flutter/blob/main/CHANGELOG.md)
- [Commits](https://github.com/supabase/supabase-flutter/commits/gotrue-v2.8.2/packages)

Updates `youtube_explode_dart` from 2.3.5 to 2.3.6
- [Release notes](https://github.com/Hexer10/youtube_explode_dart/releases)
- [Changelog](https://github.com/Hexer10/youtube_explode_dart/blob/master/CHANGELOG.md)
- [Commits](https://github.com/Hexer10/youtube_explode_dart/compare/v2.3.5...v2.3.6)

---
updated-dependencies:
- dependency-name: app_links
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: pub
- dependency-name: collection
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: pub
- dependency-name: flutter_launcher_icons
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: pub
- dependency-name: flutter_native_splash
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: pub
- dependency-name: just_audio_background
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: pub
- dependency-name: package_info_plus
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: pub
- dependency-name: purchases_flutter
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: pub
- dependency-name: shared_preferences
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: pub
- dependency-name: sign_in_with_apple
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: pub
- dependency-name: supabase_flutter
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: pub
- dependency-name: youtube_explode_dart
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: pub
...

Signed-off-by: dependabot[bot] <support@github.com>

* Update Flutter Version to 3.27.3

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: ricoberger <mail@ricoberger.de>
2025-01-26 14:55:22 +01:00
dependabot[bot]
0cc98b85b1 Bump next from 15.0.3 to 15.1.2 in /landing (#216)
Bumps [next](https://github.com/vercel/next.js) from 15.0.3 to 15.1.2.
- [Release notes](https://github.com/vercel/next.js/releases)
- [Changelog](https://github.com/vercel/next.js/blob/canary/release.js)
- [Commits](https://github.com/vercel/next.js/compare/v15.0.3...v15.1.2)

---
updated-dependencies:
- dependency-name: next
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-26 14:54:39 +01:00
dependabot[bot]
b34497a6bc Bump next and react-email in /supabase/email-templates (#213)
* Bump next and react-email in /supabase/email-templates

Removes [next](https://github.com/vercel/next.js). It's no longer used after updating ancestor dependency [react-email](https://github.com/resend/react-email/tree/HEAD/packages/react-email). These dependencies need to be updated together.


Removes `next`

Updates `react-email` from 3.0.2 to 3.0.4
- [Release notes](https://github.com/resend/react-email/releases)
- [Changelog](https://github.com/resend/react-email/blob/canary/packages/react-email/CHANGELOG.md)
- [Commits](https://github.com/resend/react-email/commits/react-email@3.0.4/packages/react-email)

---
updated-dependencies:
- dependency-name: next
  dependency-type: indirect
- dependency-name: react-email
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>

* Update Dependencies

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: ricoberger <mail@ricoberger.de>
2025-01-26 14:52:02 +01:00
dependabot[bot]
504b88510c Bump the pub group in /app with 3 updates (#205)
* Bump the pub group in /app with 3 updates

Bumps the pub group in /app with 3 updates: [package_info_plus](https://github.com/fluttercommunity/plus_plugins/tree/main/packages/package_info_plus), [purchases_flutter](https://github.com/RevenueCat/purchases-flutter) and [shared_preferences](https://github.com/flutter/packages/tree/main/packages/shared_preferences).


Updates `package_info_plus` from 8.1.0 to 8.1.1
- [Release notes](https://github.com/fluttercommunity/plus_plugins/releases)
- [Commits](https://github.com/fluttercommunity/plus_plugins/commits/HEAD/packages/package_info_plus)

Updates `purchases_flutter` from 8.1.6 to 8.2.1
- [Release notes](https://github.com/RevenueCat/purchases-flutter/releases)
- [Changelog](https://github.com/RevenueCat/purchases-flutter/blob/main/CHANGELOG.md)
- [Commits](https://github.com/RevenueCat/purchases-flutter/compare/8.1.6...8.2.1)

Updates `shared_preferences` from 2.3.2 to 2.3.3
- [Release notes](https://github.com/flutter/packages/releases)
- [Commits](https://github.com/flutter/packages/commits/shared_preferences-v2.3.3/packages/shared_preferences)

---
updated-dependencies:
- dependency-name: package_info_plus
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: pub
- dependency-name: purchases_flutter
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: pub
- dependency-name: shared_preferences
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: pub
...

Signed-off-by: dependabot[bot] <support@github.com>

* Update Flutter Version to 3.24.4

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: ricoberger <mail@ricoberger.de>
2024-11-10 15:46:34 +01:00
dependabot[bot]
481b5c6490 Bump the npm group in /landing with 4 updates (#204)
Bumps the npm group in /landing with 4 updates: [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node), [eslint](https://github.com/eslint/eslint), [eslint-config-next](https://github.com/vercel/next.js/tree/HEAD/packages/eslint-config-next) and [next](https://github.com/vercel/next.js).


Updates `@types/node` from 22.8.6 to 22.9.0
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

Updates `eslint` from 9.13.0 to 9.14.0
- [Release notes](https://github.com/eslint/eslint/releases)
- [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md)
- [Commits](https://github.com/eslint/eslint/compare/v9.13.0...v9.14.0)

Updates `eslint-config-next` from 15.0.2 to 15.0.3
- [Release notes](https://github.com/vercel/next.js/releases)
- [Changelog](https://github.com/vercel/next.js/blob/canary/release.js)
- [Commits](https://github.com/vercel/next.js/commits/v15.0.3/packages/eslint-config-next)

Updates `next` from 15.0.2 to 15.0.3
- [Release notes](https://github.com/vercel/next.js/releases)
- [Changelog](https://github.com/vercel/next.js/blob/canary/release.js)
- [Commits](https://github.com/vercel/next.js/compare/v15.0.2...v15.0.3)

---
updated-dependencies:
- dependency-name: "@types/node"
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: npm
- dependency-name: eslint
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: npm
- dependency-name: eslint-config-next
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: npm
- dependency-name: next
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: npm
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-10 15:31:38 +01:00
ricoberger
10278aefbb Update Dependabot Configuration 2024-11-10 15:20:53 +01:00
dependabot[bot]
9117344e82 Bump cookie and react-email in /supabase/email-templates (#203)
* Bump cookie and react-email in /supabase/email-templates

Bumps [cookie](https://github.com/jshttp/cookie) to 0.7.2 and updates ancestor dependency [react-email](https://github.com/resend/react-email/tree/HEAD/packages/react-email). These dependencies need to be updated together.


Updates `cookie` from 0.4.2 to 0.7.2
- [Release notes](https://github.com/jshttp/cookie/releases)
- [Commits](https://github.com/jshttp/cookie/compare/v0.4.2...v0.7.2)

Updates `react-email` from 2.1.6 to 3.0.2
- [Release notes](https://github.com/resend/react-email/releases)
- [Changelog](https://github.com/resend/react-email/blob/canary/packages/react-email/CHANGELOG.md)
- [Commits](https://github.com/resend/react-email/commits/react-email@3.0.2/packages/react-email)

---
updated-dependencies:
- dependency-name: cookie
  dependency-type: indirect
- dependency-name: react-email
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>

* Update react-email

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: ricoberger <mail@ricoberger.de>
2024-11-10 15:19:07 +01:00
dependabot[bot]
bb4a380a7c Bump the pub group across 1 directory with 24 updates (#199)
* Bump the pub group across 1 directory with 24 updates

Bumps the pub group with 20 updates in the /app directory:

| Package | From | To |
| --- | --- | --- |
| [app_links](https://github.com/llfbandit/app_links) | `6.1.4` | `6.3.2` |
| [cached_network_image](https://github.com/Baseflow/flutter_cached_network_image) | `3.4.0` | `3.4.1` |
| [crypto](https://github.com/dart-lang/core/tree/main/pkgs) | `3.0.3` | `3.0.6` |
| [flutter_launcher_icons](https://github.com/fluttercommunity/flutter_launcher_icons) | `0.13.1` | `0.14.1` |
| [flutter_lints](https://github.com/flutter/packages/tree/main/packages) | `4.0.0` | `5.0.0` |
| [flutter_markdown](https://github.com/flutter/packages/tree/main/packages) | `0.7.3+1` | `0.7.4+1` |
| [flutter_native_splash](https://github.com/jonbhanson/flutter_native_splash) | `2.4.1` | `2.4.2` |
| [html](https://github.com/dart-lang/tools/tree/main/pkgs) | `0.15.4` | `0.15.5` |
| [just_audio](https://github.com/ryanheise/just_audio) | `0.9.39` | `0.9.42` |
| [just_audio_media_kit](https://github.com/Pato05/just_audio_media_kit) | `2.0.5` | `2.0.6` |
| [media_kit_libs_video](https://github.com/media-kit/media-kit) | `1.0.4` | `1.0.5` |
| [media_kit_video](https://github.com/media-kit/media-kit) | `1.2.4` | `1.2.5` |
| [msix](https://github.com/YehudaKremer/msix) | `3.16.7` | `3.16.8` |
| [purchases_flutter](https://github.com/RevenueCat/purchases-flutter) | `6.30.2` | `8.1.6` |
| [rxdart](https://github.com/ReactiveX/rxdart) | `0.27.7` | `0.28.0` |
| [shared_preferences](https://github.com/flutter/packages/tree/main/packages/shared_preferences) | `2.3.1` | `2.3.2` |
| [sign_in_with_apple](https://github.com/aboutyou/dart_packages) | `6.1.1` | `6.1.3` |
| [url_launcher](https://github.com/flutter/packages/tree/main/packages/url_launcher) | `6.3.0` | `6.3.1` |
| [window_manager](https://github.com/leanflutter/window_manager) | `0.3.9` | `0.4.3` |
| [youtube_explode_dart](https://github.com/Hexer10/youtube_explode_dart) | `2.2.1` | `2.3.5` |



Updates `app_links` from 6.1.4 to 6.3.2
- [Release notes](https://github.com/llfbandit/app_links/releases)
- [Commits](https://github.com/llfbandit/app_links/compare/6.1.4...6.3.2)

Updates `cached_network_image` from 3.4.0 to 3.4.1
- [Release notes](https://github.com/Baseflow/flutter_cached_network_image/releases)
- [Commits](https://github.com/Baseflow/flutter_cached_network_image/compare/v3.4.0...v3.4.1)

Updates `crypto` from 3.0.3 to 3.0.6
- [Release notes](https://github.com/dart-lang/core/releases)
- [Commits](https://github.com/dart-lang/core/commits/crypto-v3.0.6/pkgs)

Updates `flutter_cache_manager` from 3.4.0 to 3.4.1
- [Release notes](https://github.com/Baseflow/flutter_cache_manager/releases)
- [Commits](https://github.com/Baseflow/flutter_cache_manager/compare/v3.4.0...v3.4.1)

Updates `flutter_launcher_icons` from 0.13.1 to 0.14.1
- [Release notes](https://github.com/fluttercommunity/flutter_launcher_icons/releases)
- [Changelog](https://github.com/fluttercommunity/flutter_launcher_icons/blob/master/CHANGELOG.md)
- [Commits](https://github.com/fluttercommunity/flutter_launcher_icons/compare/v0.13.1...v0.14.1)

Updates `flutter_lints` from 4.0.0 to 5.0.0
- [Release notes](https://github.com/flutter/packages/releases)
- [Commits](https://github.com/flutter/packages/commits/flutter_lints-v5.0.0/packages)

Updates `flutter_markdown` from 0.7.3+1 to 0.7.4+1
- [Release notes](https://github.com/flutter/packages/releases)
- [Commits](https://github.com/flutter/packages/commits/flutter_markdown-v0.7.4/packages)

Updates `flutter_native_splash` from 2.4.1 to 2.4.2
- [Release notes](https://github.com/jonbhanson/flutter_native_splash/releases)
- [Changelog](https://github.com/jonbhanson/flutter_native_splash/blob/master/CHANGELOG.md)
- [Commits](https://github.com/jonbhanson/flutter_native_splash/commits/v2.4.2)

Updates `html` from 0.15.4 to 0.15.5
- [Release notes](https://github.com/dart-lang/tools/releases)
- [Commits](https://github.com/dart-lang/tools/commits/html-v0.15.5/pkgs)

Updates `just_audio` from 0.9.39 to 0.9.42
- [Release notes](https://github.com/ryanheise/just_audio/releases)
- [Commits](https://github.com/ryanheise/just_audio/commits)

Updates `just_audio_media_kit` from 2.0.5 to 2.0.6
- [Changelog](https://github.com/Pato05/just_audio_media_kit/blob/main/CHANGELOG.md)
- [Commits](https://github.com/Pato05/just_audio_media_kit/compare/v2.0.5...v2.0.6)

Updates `media_kit` from 1.1.10+1 to 1.1.11
- [Release notes](https://github.com/media-kit/media-kit/releases)
- [Commits](https://github.com/media-kit/media-kit/commits)

Updates `media_kit_libs_video` from 1.0.4 to 1.0.5
- [Release notes](https://github.com/media-kit/media-kit/releases)
- [Commits](https://github.com/media-kit/media-kit/compare/media_kit_libs_ios_audio-v1.0.4...media_kit_libs_ios_audio-v1.0.5)

Updates `media_kit_video` from 1.2.4 to 1.2.5
- [Release notes](https://github.com/media-kit/media-kit/releases)
- [Commits](https://github.com/media-kit/media-kit/commits)

Updates `msix` from 3.16.7 to 3.16.8
- [Release notes](https://github.com/YehudaKremer/msix/releases)
- [Changelog](https://github.com/YehudaKremer/msix/blob/main/CHANGELOG.md)
- [Commits](https://github.com/YehudaKremer/msix/compare/v3.16.7...v3.16.8)

Updates `package_info_plus` from 8.0.1 to 8.1.0
- [Release notes](https://github.com/fluttercommunity/plus_plugins/releases)
- [Commits](https://github.com/fluttercommunity/plus_plugins/commits/package_info_plus-v8.1.0/packages/package_info_plus)

Updates `purchases_flutter` from 6.30.2 to 8.1.6
- [Release notes](https://github.com/RevenueCat/purchases-flutter/releases)
- [Changelog](https://github.com/RevenueCat/purchases-flutter/blob/main/CHANGELOG.md)
- [Commits](https://github.com/RevenueCat/purchases-flutter/compare/6.30.2...8.1.6)

Updates `rxdart` from 0.27.7 to 0.28.0
- [Release notes](https://github.com/ReactiveX/rxdart/releases)
- [Commits](https://github.com/ReactiveX/rxdart/compare/0.27.7...0.28.0)

Updates `shared_preferences` from 2.3.1 to 2.3.2
- [Release notes](https://github.com/flutter/packages/releases)
- [Commits](https://github.com/flutter/packages/commits/shared_preferences-v2.3.2/packages/shared_preferences)

Updates `sign_in_with_apple` from 6.1.1 to 6.1.3
- [Release notes](https://github.com/aboutyou/dart_packages/releases)
- [Commits](https://github.com/aboutyou/dart_packages/commits)

Updates `supabase_flutter` from 2.5.11 to 2.8.0
- [Changelog](https://github.com/supabase/supabase-flutter/blob/main/CHANGELOG.md)
- [Commits](https://github.com/supabase/supabase-flutter/commits/supabase_flutter-v2.8.0/packages)

Updates `url_launcher` from 6.3.0 to 6.3.1
- [Release notes](https://github.com/flutter/packages/releases)
- [Commits](https://github.com/flutter/packages/commits/url_launcher-v6.3.1/packages/url_launcher)

Updates `window_manager` from 0.3.9 to 0.4.3
- [Release notes](https://github.com/leanflutter/window_manager/releases)
- [Commits](https://github.com/leanflutter/window_manager/commits)

Updates `youtube_explode_dart` from 2.2.1 to 2.3.5
- [Release notes](https://github.com/Hexer10/youtube_explode_dart/releases)
- [Changelog](https://github.com/Hexer10/youtube_explode_dart/blob/master/CHANGELOG.md)
- [Commits](https://github.com/Hexer10/youtube_explode_dart/compare/v2.2.1...v2.3.5)

---
updated-dependencies:
- dependency-name: app_links
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: pub
- dependency-name: cached_network_image
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: pub
- dependency-name: crypto
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: pub
- dependency-name: flutter_cache_manager
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: pub
- dependency-name: flutter_launcher_icons
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: pub
- dependency-name: flutter_lints
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: pub
- dependency-name: flutter_markdown
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: pub
- dependency-name: flutter_native_splash
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: pub
- dependency-name: html
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: pub
- dependency-name: just_audio
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: pub
- dependency-name: just_audio_media_kit
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: pub
- dependency-name: media_kit
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: pub
- dependency-name: media_kit_libs_video
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: pub
- dependency-name: media_kit_video
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: pub
- dependency-name: msix
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: pub
- dependency-name: package_info_plus
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: pub
- dependency-name: purchases_flutter
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: pub
- dependency-name: rxdart
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: pub
- dependency-name: shared_preferences
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: pub
- dependency-name: sign_in_with_apple
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: pub
- dependency-name: supabase_flutter
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: pub
- dependency-name: url_launcher
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: pub
- dependency-name: window_manager
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: pub
- dependency-name: youtube_explode_dart
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: pub
...

Signed-off-by: dependabot[bot] <support@github.com>

* Update Podfile.lock

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: ricoberger <mail@ricoberger.de>
2024-11-10 15:11:12 +01:00
dependabot[bot]
62ac6d1ade Bump micromatch from 4.0.5 to 4.0.8 in /landing (#192)
Bumps [micromatch](https://github.com/micromatch/micromatch) from 4.0.5 to 4.0.8.
- [Release notes](https://github.com/micromatch/micromatch/releases)
- [Changelog](https://github.com/micromatch/micromatch/blob/master/CHANGELOG.md)
- [Commits](https://github.com/micromatch/micromatch/compare/4.0.5...4.0.8)

---
updated-dependencies:
- dependency-name: micromatch
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-10 15:04:58 +01:00
dependabot[bot]
22ebd600b9 Bump the npm group across 1 directory with 11 updates (#200)
* Bump the npm group across 1 directory with 11 updates

Bumps the npm group with 11 updates in the /landing directory:

| Package | From | To |
| --- | --- | --- |
| [@headlessui/react](https://github.com/tailwindlabs/headlessui/tree/HEAD/packages/@headlessui-react) | `2.1.2` | `2.2.0` |
| [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) | `22.0.2` | `22.8.6` |
| [@types/react](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react) | `18.3.3` | `18.3.12` |
| [@types/react-dom](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react-dom) | `18.3.0` | `18.3.1` |
| [autoprefixer](https://github.com/postcss/autoprefixer) | `10.4.19` | `10.4.20` |
| [eslint](https://github.com/eslint/eslint) | `8.57.0` | `9.13.0` |
| [eslint-config-next](https://github.com/vercel/next.js/tree/HEAD/packages/eslint-config-next) | `14.2.5` | `15.0.2` |
| [next](https://github.com/vercel/next.js) | `14.2.5` | `15.0.2` |
| [postcss](https://github.com/postcss/postcss) | `8.4.40` | `8.4.47` |
| [tailwindcss](https://github.com/tailwindlabs/tailwindcss) | `3.4.7` | `3.4.14` |
| [typescript](https://github.com/microsoft/TypeScript) | `5.5.4` | `5.6.3` |



Updates `@headlessui/react` from 2.1.2 to 2.2.0
- [Release notes](https://github.com/tailwindlabs/headlessui/releases)
- [Changelog](https://github.com/tailwindlabs/headlessui/blob/main/packages/@headlessui-react/CHANGELOG.md)
- [Commits](https://github.com/tailwindlabs/headlessui/commits/@headlessui/react@v2.2.0/packages/@headlessui-react)

Updates `@types/node` from 22.0.2 to 22.8.6
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

Updates `@types/react` from 18.3.3 to 18.3.12
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react)

Updates `@types/react-dom` from 18.3.0 to 18.3.1
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react-dom)

Updates `autoprefixer` from 10.4.19 to 10.4.20
- [Release notes](https://github.com/postcss/autoprefixer/releases)
- [Changelog](https://github.com/postcss/autoprefixer/blob/main/CHANGELOG.md)
- [Commits](https://github.com/postcss/autoprefixer/compare/10.4.19...10.4.20)

Updates `eslint` from 8.57.0 to 9.13.0
- [Release notes](https://github.com/eslint/eslint/releases)
- [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md)
- [Commits](https://github.com/eslint/eslint/compare/v8.57.0...v9.13.0)

Updates `eslint-config-next` from 14.2.5 to 15.0.2
- [Release notes](https://github.com/vercel/next.js/releases)
- [Changelog](https://github.com/vercel/next.js/blob/canary/release.js)
- [Commits](https://github.com/vercel/next.js/commits/v15.0.2/packages/eslint-config-next)

Updates `next` from 14.2.5 to 15.0.2
- [Release notes](https://github.com/vercel/next.js/releases)
- [Changelog](https://github.com/vercel/next.js/blob/canary/release.js)
- [Commits](https://github.com/vercel/next.js/compare/v14.2.5...v15.0.2)

Updates `postcss` from 8.4.40 to 8.4.47
- [Release notes](https://github.com/postcss/postcss/releases)
- [Changelog](https://github.com/postcss/postcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/postcss/postcss/compare/8.4.40...8.4.47)

Updates `tailwindcss` from 3.4.7 to 3.4.14
- [Release notes](https://github.com/tailwindlabs/tailwindcss/releases)
- [Changelog](https://github.com/tailwindlabs/tailwindcss/blob/v3.4.14/CHANGELOG.md)
- [Commits](https://github.com/tailwindlabs/tailwindcss/compare/v3.4.7...v3.4.14)

Updates `typescript` from 5.5.4 to 5.6.3
- [Release notes](https://github.com/microsoft/TypeScript/releases)
- [Changelog](https://github.com/microsoft/TypeScript/blob/main/azure-pipelines.release.yml)
- [Commits](https://github.com/microsoft/TypeScript/compare/v5.5.4...v5.6.3)

---
updated-dependencies:
- dependency-name: "@headlessui/react"
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: npm
- dependency-name: "@types/node"
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: npm
- dependency-name: "@types/react"
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: npm
- dependency-name: "@types/react-dom"
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: npm
- dependency-name: autoprefixer
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: npm
- dependency-name: eslint
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: npm
- dependency-name: eslint-config-next
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: npm
- dependency-name: next
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: npm
- dependency-name: postcss
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: npm
- dependency-name: tailwindcss
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: npm
- dependency-name: typescript
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: npm
...

Signed-off-by: dependabot[bot] <support@github.com>

* Fix Import of Download Component

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: ricoberger <mail@ricoberger.de>
2024-11-10 12:14:46 +01:00
dependabot[bot]
452177f993 Bump denoland/setup-deno from 1 to 2 in the github-actions group (#201)
Bumps the github-actions group with 1 update: [denoland/setup-deno](https://github.com/denoland/setup-deno).


Updates `denoland/setup-deno` from 1 to 2
- [Release notes](https://github.com/denoland/setup-deno/releases)
- [Commits](https://github.com/denoland/setup-deno/compare/v1...v2)

---
updated-dependencies:
- dependency-name: denoland/setup-deno
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: github-actions
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-10 11:41:48 +01:00
Rico Berger
a6a54ac02e Update Flutter Version to 3.24.1 (#191) 2024-08-31 17:10:00 +02:00
Rico Berger
96eccb5503 [core] Update Flutter to Version 3.24.0 (#189)
Update Flutter to Version 3.24.0 and replace the deprecated `background`
and `onBackground` colors with `surface` and `onSurface`. Within this
migration we also adjusted the `onSecondary` color, so that the apps
look as before the update.
2024-08-09 14:06:53 +02:00
Rico Berger
43a8ebe513 [core] Fix App Listing Quality (#188)
Fix the quality of the app listing on Flathub, by adjusting the app
summary and changing the app icon. This should fix the following
warnings in the "App Listing Quality" report:

- App Icon: Doesn't fill too much or too little of the canvas
- Summary: No weird formatting or punctuation
2024-08-09 11:35:47 +02:00
212 changed files with 12553 additions and 17525 deletions

1
.github/CODEOWNERS vendored Normal file
View File

@@ -0,0 +1 @@
* @ricoberger

1
.github/FUNDING.yml vendored
View File

@@ -1,2 +1,3 @@
---
github: [ricoberger]
custom: ["https://www.paypal.me/ricoberger"]

BIN
.github/assets/badge-app-store.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

BIN
.github/assets/badge-flathub.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

BIN
.github/assets/badge-google-play.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

BIN
.github/assets/badge-mac-app-store.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

BIN
.github/assets/badge-web.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

BIN
.github/assets/badge-windows-store.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

View File

@@ -1,3 +1,4 @@
---
version: 2
updates:
- package-ecosystem: "github-actions"
@@ -6,6 +7,9 @@ updates:
interval: "monthly"
assignees:
- "ricoberger"
commit-message:
prefix: "chore"
include: "scope"
groups:
github-actions:
patterns:
@@ -17,6 +21,9 @@ updates:
interval: "monthly"
assignees:
- "ricoberger"
commit-message:
prefix: "chore"
include: "scope"
groups:
pub:
patterns:
@@ -28,6 +35,9 @@ updates:
interval: "monthly"
assignees:
- "ricoberger"
commit-message:
prefix: "chore"
include: "scope"
groups:
docker:
patterns:
@@ -39,6 +49,23 @@ updates:
interval: "monthly"
assignees:
- "ricoberger"
commit-message:
prefix: "chore"
include: "scope"
groups:
npm:
patterns:
- "*"
- package-ecosystem: "npm"
directory: "/supabase/email-templates"
schedule:
interval: "monthly"
assignees:
- "ricoberger"
commit-message:
prefix: "chore"
include: "scope"
groups:
npm:
patterns:

29
.github/release.yaml vendored
View File

@@ -1,29 +0,0 @@
name-template: "$RESOLVED_VERSION"
tag-template: "$RESOLVED_VERSION"
version-template: "v$MAJOR.$MINOR.$PATCH"
categories:
- title: "Added"
labels:
- "changelog: added"
- title: "Fixed"
labels:
- "changelog: fixed"
- title: "Changed"
labels:
- "changelog: changed"
version-resolver:
minor:
labels:
- "changelog: added"
- "changelog: changed"
patch:
labels:
- "changelog: fixed"
default: patch
category-template: "### $TITLE"
change-template: '- #$NUMBER: $TITLE @$AUTHOR'
template: |
$CHANGES
replacers:
- search: ':warning:'
replace: ':warning: _Breaking change:_ :warning:'

View File

@@ -1,3 +1,4 @@
---
name: Continuous Delivery
on:
@@ -5,35 +6,41 @@ on:
branches:
- main
pull_request:
branches:
- main
release:
types:
- published
jobs:
# The "Docker" job builds the Docker image and pushes it to the GitHub Container Registry. The job only runs when a
# commit is pushed to the main branch or a new tag is created.
# The "Docker" job builds the Docker image and pushes it to the GitHub
# Container Registry. The job only runs when a commit is pushed to the main
# branch or a new tag is created.
docker:
name: Docker
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main' || (github.event_name == 'release' && github.event.action == 'published')
if:
github.ref == 'refs/heads/main' || (github.event_name == 'release' &&
github.event.action == 'published')
permissions:
contents: read
packages: write
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v5
with:
fetch-depth: 0
- name: Set Docker Tag
id: tag
run: |
if [[ $GITHUB_REF == refs/tags/* ]]; then
echo TAG=${GITHUB_REF:10} >> $GITHUB_ENV
else
echo TAG=main >> $GITHUB_ENV
fi
- name: Docker Metadata
id: metadata
uses: docker/metadata-action@v5
with:
images: |
ghcr.io/${{ github.repository }}
tags: |
type=ref,event=branch
type=semver,pattern={{raw}}
- name: Setup QEMU
uses: docker/setup-qemu-action@v3
@@ -41,7 +48,7 @@ jobs:
- name: Setup Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to DockerHub
- name: Login to GitHub Container Registry
uses: docker/login-action@v3
with:
username: ${{ github.repository_owner }}
@@ -56,20 +63,24 @@ jobs:
context: ./supabase/functions
file: ./supabase/functions/_cmd/Dockerfile
platforms: linux/amd64,linux/arm64/v8
tags: ghcr.io/${{ github.repository_owner }}/feeddeck:${{ env.TAG }}
tags: ${{ steps.metadata.outputs.tags }}
labels: ${{ steps.metadata.outputs.labels }}
# The "Supabase" job runs the database migrations and deploys all Supabase functions. The job only runs when a commit
# is pushed to the main branch or a new tag is created.
# The "Supabase" job runs the database migrations and deploys all Supabase
# functions. The job only runs when a commit is pushed to the main branch or
# a new tag is created.
supabase:
name: Supabase
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main' || (github.event_name == 'release' && github.event.action == 'published')
if:
github.ref == 'refs/heads/main' || (github.event_name == 'release' &&
github.event.action == 'published')
permissions:
contents: read
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v5
with:
fetch-depth: 0
@@ -87,20 +98,22 @@ jobs:
supabase db push
supabase functions deploy add-or-update-source-v1 --project-ref $PROJECT_ID --import-map supabase/functions/import_map.json
# supabase functions deploy add-source-v1 --project-ref $PROJECT_ID --import-map supabase/functions/import_map.json
supabase functions deploy delete-user-v1 --project-ref $PROJECT_ID --import-map supabase/functions/import_map.json
supabase functions deploy generate-magic-link-v1 --project-ref $PROJECT_ID --import-map supabase/functions/import_map.json
supabase functions deploy image-proxy-v1 --no-verify-jwt --project-ref $PROJECT_ID --import-map supabase/functions/import_map.json
# supabase functions deploy profile-v1 --project-ref $PROJECT_ID --import-map supabase/functions/import_map.json
supabase functions deploy profile-v2 --project-ref $PROJECT_ID --import-map supabase/functions/import_map.json
supabase functions deploy revenuecat-webhooks-v1 --no-verify-jwt --project-ref $PROJECT_ID --import-map supabase/functions/import_map.json
supabase functions deploy stripe-create-billing-portal-link-v1 --project-ref $PROJECT_ID --import-map supabase/functions/import_map.json
supabase functions deploy stripe-create-checkout-session-v1 --project-ref $PROJECT_ID --import-map supabase/functions/import_map.json
supabase functions deploy stripe-webhooks-v1 --no-verify-jwt --project-ref $PROJECT_ID --import-map supabase/functions/import_map.json
supabase functions deploy add-or-update-source-v1 --project-ref $PROJECT_ID
# supabase functions deploy add-source-v1 --project-ref $PROJECT_ID
supabase functions deploy delete-user-v1 --project-ref $PROJECT_ID
supabase functions deploy generate-magic-link-v1 --project-ref $PROJECT_ID
supabase functions deploy image-proxy-v1 --no-verify-jwt --project-ref $PROJECT_ID
# supabase functions deploy profile-v1 --project-ref $PROJECT_ID
supabase functions deploy profile-v2 --project-ref $PROJECT_ID
supabase functions deploy revenuecat-webhooks-v1 --no-verify-jwt --project-ref $PROJECT_ID
supabase functions deploy stripe-create-billing-portal-link-v1 --project-ref $PROJECT_ID
supabase functions deploy stripe-create-checkout-session-v1 --project-ref $PROJECT_ID
supabase functions deploy stripe-webhooks-v1 --no-verify-jwt --project-ref $PROJECT_ID
- name: Push Database Migration and Deploy Functions
if: ${{ github.event_name == 'release' && github.event.action == 'published' }}
if:
${{ github.event_name == 'release' && github.event.action ==
'published' }}
env:
SUPABASE_ACCESS_TOKEN: ${{ secrets.SUPABASE_ACCESS_TOKEN }}
SUPABASE_DB_PASSWORD: ${{ secrets.SUPABASE_PROD_DB_PASSWORD }}
@@ -110,26 +123,30 @@ jobs:
supabase db push
supabase functions deploy add-or-update-source-v1 --project-ref $PROJECT_ID --import-map supabase/functions/import_map.json
supabase functions deploy add-source-v1 --project-ref $PROJECT_ID --import-map supabase/functions/import_map.json
supabase functions deploy delete-user-v1 --project-ref $PROJECT_ID --import-map supabase/functions/import_map.json
supabase functions deploy generate-magic-link-v1 --project-ref $PROJECT_ID --import-map supabase/functions/import_map.json
supabase functions deploy image-proxy-v1 --no-verify-jwt --project-ref $PROJECT_ID --import-map supabase/functions/import_map.json
supabase functions deploy profile-v1 --project-ref $PROJECT_ID --import-map supabase/functions/import_map.json
supabase functions deploy profile-v2 --project-ref $PROJECT_ID --import-map supabase/functions/import_map.json
supabase functions deploy revenuecat-webhooks-v1 --no-verify-jwt --project-ref $PROJECT_ID --import-map supabase/functions/import_map.json
supabase functions deploy stripe-create-billing-portal-link-v1 --project-ref $PROJECT_ID --import-map supabase/functions/import_map.json
supabase functions deploy stripe-create-checkout-session-v1 --project-ref $PROJECT_ID --import-map supabase/functions/import_map.json
supabase functions deploy stripe-webhooks-v1 --no-verify-jwt --project-ref $PROJECT_ID --import-map supabase/functions/import_map.json
supabase functions deploy add-or-update-source-v1 --project-ref $PROJECT_ID
supabase functions deploy add-source-v1 --project-ref $PROJECT_ID
supabase functions deploy delete-user-v1 --project-ref $PROJECT_ID
supabase functions deploy generate-magic-link-v1 --project-ref $PROJECT_ID
supabase functions deploy image-proxy-v1 --no-verify-jwt --project-ref $PROJECT_ID
supabase functions deploy profile-v1 --project-ref $PROJECT_ID
supabase functions deploy profile-v2 --project-ref $PROJECT_ID
supabase functions deploy revenuecat-webhooks-v1 --no-verify-jwt --project-ref $PROJECT_ID
supabase functions deploy stripe-create-billing-portal-link-v1 --project-ref $PROJECT_ID
supabase functions deploy stripe-create-checkout-session-v1 --project-ref $PROJECT_ID
supabase functions deploy stripe-webhooks-v1 --no-verify-jwt --project-ref $PROJECT_ID
# The "Web" job builds the Flutter web app and publishes it to Cloudflare Pages. The job only runs on pull requests or
# when a commit is pushed to the main branch or a new tag is created.
# The "Web" job builds the Flutter web app and publishes it to Cloudflare
# Pages. The job only runs on pull requests or when a commit is pushed to the
# main branch or a new tag is created.
#
# When the job runs on a pull request it only builds the app but doesn't upload the build to Cloudflare.
# When the job runs on a pull request it only builds the app but doesn't
# upload the build to Cloudflare.
web:
name: Web
runs-on: ubuntu-latest
if: github.event_name == 'pull_request' || github.ref == 'refs/heads/main' || (github.event_name == 'release' && github.event.action == 'published')
if:
github.event_name == 'pull_request' || github.ref == 'refs/heads/main' ||
(github.event_name == 'release' && github.event.action == 'published')
permissions:
contents: read
defaults:
@@ -138,7 +155,7 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v5
with:
fetch-depth: 0
@@ -170,11 +187,12 @@ jobs:
- name: Setup Flutter
uses: subosito/flutter-action@v2
with:
flutter-version: '3.22.2'
channel: 'stable'
flutter-version: "3.32.7"
channel: "stable"
cache: true
cache-key: 'flutter-:os:-:channel:-:version:-:arch:-:hash:'
cache-path: '${{ runner.tool_cache }}/flutter/:channel:-:version:-:arch:'
cache-key: "flutter-:os:-:channel:-:version:-:arch:-:hash:"
cache-path:
"${{ runner.tool_cache }}/flutter/:channel:-:version:-:arch:"
- name: Install Dependencies
run: |
@@ -187,7 +205,9 @@ jobs:
- name: Publish to Cloudflare Pages
uses: cloudflare/pages-action@v1
if: github.ref == 'refs/heads/main' || (github.event_name == 'release' && github.event.action == 'published')
if:
github.ref == 'refs/heads/main' || (github.event_name == 'release' &&
github.event.action == 'published')
with:
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
@@ -195,12 +215,15 @@ jobs:
directory: ./app/build/web
branch: main
# The "macOS" job builds the Flutter macOS app and uploads it to the GitHub release or the pull request. The job only
# runs for pull requests and when a new release is published.
# The "macOS" job builds the Flutter macOS app and uploads it to the GitHub
# release or the pull request. The job only runs for pull requests and when a
# new release is published.
macos:
name: macOS
runs-on: macos-14
if: github.event_name == 'pull_request' || (github.event_name == 'release' && github.event.action == 'published')
if:
github.event_name == 'pull_request' || (github.event_name == 'release' &&
github.event.action == 'published')
permissions:
contents: write
defaults:
@@ -209,16 +232,17 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: Setup Flutter
uses: subosito/flutter-action@v2
with:
flutter-version: '3.22.2'
channel: 'stable'
flutter-version: "3.32.7"
channel: "stable"
cache: true
cache-key: 'flutter-:os:-:channel:-:version:-:arch:-:hash:'
cache-path: '${{ runner.tool_cache }}/flutter/:channel:-:version:-:arch:'
cache-key: "flutter-:os:-:channel:-:version:-:arch:-:hash:"
cache-path:
"${{ runner.tool_cache }}/flutter/:channel:-:version:-:arch:"
- name: Install Dependencies
run: |
@@ -227,6 +251,7 @@ jobs:
- name: Build
run: |
flutter config --enable-macos-desktop
flutter config --enable-swift-package-manager
FLUTTER_XCODE_CODE_SIGN_IDENTITY="" FLUTTER_XCODE_CODE_SIGNING_REQUIRED=NO flutter build macos --release --dart-define SUPABASE_URL=${{ secrets.SUPABASE_PROD_URL }} --dart-define SUPABASE_ANON_KEY=${{ secrets.SUPABASE_PROD_ANON_KEY }} --dart-define SUPABASE_SITE_URL=${{ secrets.SUPABASE_PROD_SITE_URL }} --dart-define GOOGLE_CLIENT_ID=${{ secrets.SUPABASE_PROD_GOOGLE_CLIENT_ID }}
- name: Package
@@ -243,17 +268,22 @@ jobs:
- name: Upload Artifacts (Release)
uses: shogo82148/actions-upload-release-asset@v1
if: ${{ github.event_name == 'release' && github.event.action == 'published' }}
if:
${{ github.event_name == 'release' && github.event.action ==
'published' }}
with:
upload_url: ${{ github.event.release.upload_url }}
asset_path: app/build/macos/Build/Products/Release/feeddeck-macos-universal.zip
# The "Linux (x86_64)" job builds the Flutter Linux app and uploads it to the GitHub release or the pull request. The
# job only runs for pull requests and when a new release is published.
# The "Linux (x86_64)" job builds the Flutter Linux app and uploads it to the
# GitHub release or the pull request. The job only runs for pull requests and
# when a new release is published.
linux-x86_64:
name: Linux (x86_64)
runs-on: ubuntu-latest
if: github.event_name == 'pull_request' || (github.event_name == 'release' && github.event.action == 'published')
if:
github.event_name == 'pull_request' || (github.event_name == 'release' &&
github.event.action == 'published')
permissions:
contents: write
defaults:
@@ -262,25 +292,27 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: Install Packages
run: |
# Required for Flutter
sudo apt-get update -y
sudo apt-get install -y ninja-build libgtk-3-dev
# Required for Package "media_kit" which is used via "just_audio_media_kit" for Linux and Windows:
# Required for Package "media_kit" which is used via
# "just_audio_media_kit" for Linux and Windows:
# See: https://pub.dev/packages/media_kit and https://pub.dev/packages/just_audio_media_kit
sudo apt-get install -y libmpv-dev mpv
- name: Setup Flutter
uses: subosito/flutter-action@v2
with:
flutter-version: '3.22.2'
channel: 'stable'
flutter-version: "3.32.7"
channel: "stable"
cache: true
cache-key: 'flutter-:os:-:channel:-:version:-:arch:-:hash:'
cache-path: '${{ runner.tool_cache }}/flutter/:channel:-:version:-:arch:'
cache-key: "flutter-:os:-:channel:-:version:-:arch:-:hash:"
cache-path:
"${{ runner.tool_cache }}/flutter/:channel:-:version:-:arch:"
- name: Install Dependencies
run: |
@@ -310,16 +342,21 @@ jobs:
- name: Upload Artifacts (Release)
uses: shogo82148/actions-upload-release-asset@v1
if: ${{ github.event_name == 'release' && github.event.action == 'published' }}
if:
${{ github.event_name == 'release' && github.event.action ==
'published' }}
with:
upload_url: ${{ github.event.release.upload_url }}
asset_path: app/build/feeddeck-linux-x86_64.tar.gz
# The "Linux (arm64)" job builds the Flutter Linux app and uploads it to the GitHub release or the pull request. The
# job only runs for pull requests and when a new release is published.
# The "Linux (arm64)" job builds the Flutter Linux app and uploads it to the
# GitHub release or the pull request. The job only runs for pull requests and
# when a new release is published.
#
# NOTE: Normally this job should run for every pull request and when a new release is published, but since we have to
# pay for the "ubicloud-standard-2-arm" runner, we only run the job when a new release is published.
# NOTE: Normally this job should run for every pull request and when a new
# release is published, but since we have to pay for the
# "ubicloud-standard-2-arm" runner, we only run the job when a new release is
# published.
linux-arm64:
name: Linux (arm64)
runs-on: ubicloud-standard-2-arm
@@ -333,25 +370,27 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: Install Packages
run: |
# Required for Flutter
sudo apt-get update -y
sudo apt-get install -y ninja-build libgtk-3-dev
# Required for Package "media_kit" which is used via "just_audio_media_kit" for Linux and Windows:
# Required for Package "media_kit" which is used via
# "just_audio_media_kit" for Linux and Windows:
# See: https://pub.dev/packages/media_kit and https://pub.dev/packages/just_audio_media_kit
sudo apt-get install -y libmpv-dev mpv
- name: Setup Flutter
uses: subosito/flutter-action@v2
with:
flutter-version: '3.22.2'
channel: 'master'
flutter-version: "3.32.7"
channel: "master"
cache: true
cache-key: 'flutter-:os:-:channel:-:version:-:arch:-:hash:'
cache-path: '${{ runner.tool_cache }}/flutter/:channel:-:version:-:arch:'
cache-key: "flutter-:os:-:channel:-:version:-:arch:-:hash:"
cache-path:
"${{ runner.tool_cache }}/flutter/:channel:-:version:-:arch:"
- name: Install Dependencies
run: |
@@ -381,17 +420,22 @@ jobs:
- name: Upload Artifacts (Release)
uses: shogo82148/actions-upload-release-asset@v1
if: ${{ github.event_name == 'release' && github.event.action == 'published' }}
if:
${{ github.event_name == 'release' && github.event.action ==
'published' }}
with:
upload_url: ${{ github.event.release.upload_url }}
asset_path: app/build/feeddeck-linux-arm64.tar.gz
# The "Windows" job builds the Flutter Windows app and uploads it to the GitHub release or the pull request. The job
# only runs for pull requests and when a new release is published.
# The "Windows" job builds the Flutter Windows app and uploads it to the
# GitHub release or the pull request. The job only runs for pull requests and
# when a new release is published.
windows:
name: Windows
runs-on: windows-2019
if: github.event_name == 'pull_request' || (github.event_name == 'release' && github.event.action == 'published')
runs-on: windows-latest
if:
github.event_name == 'pull_request' || (github.event_name == 'release' &&
github.event.action == 'published')
permissions:
contents: write
defaults:
@@ -400,16 +444,17 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: Setup Flutter
uses: subosito/flutter-action@v2
with:
flutter-version: '3.22.2'
channel: 'stable'
flutter-version: "3.32.7"
channel: "stable"
cache: true
cache-key: 'flutter-:os:-:channel:-:version:-:arch:-:hash:'
cache-path: '${{ runner.tool_cache }}/flutter/:channel:-:version:-:arch:'
cache-key: "flutter-:os:-:channel:-:version:-:arch:-:hash:"
cache-path:
"${{ runner.tool_cache }}/flutter/:channel:-:version:-:arch:"
- name: Install Dependencies
run: |
@@ -439,7 +484,9 @@ jobs:
- name: Upload Artifacts (Release)
uses: shogo82148/actions-upload-release-asset@v1
if: ${{ github.event_name == 'release' && github.event.action == 'published' }}
if:
${{ github.event_name == 'release' && github.event.action ==
'published' }}
with:
upload_url: ${{ github.event.release.upload_url }}
asset_path: app/feeddeck-windows-x86_64.zip
@@ -454,33 +501,39 @@ jobs:
- name: Upload Artifacts (Release)
uses: shogo82148/actions-upload-release-asset@v1
if: ${{ github.event_name == 'release' && github.event.action == 'published' }}
if:
${{ github.event_name == 'release' && github.event.action ==
'published' }}
with:
upload_url: ${{ github.event.release.upload_url }}
asset_path: app/build/feeddeck-windows-x86_64-msix.zip
# The "iOS" job builds the Flutter iOS app on every pull request. This is only used to test that the build of the iOS
# app works. The artifact of the build isn't uploaded / used.
# The "iOS" job builds the Flutter iOS app on every pull request. This is only
# used to test that the build of the iOS app works. The artifact of the build
# isn't uploaded / used.
ios:
name: iOS
runs-on: macos-14
if: github.event_name == 'pull_request' || (github.event_name == 'release' && github.event.action == 'published')
if:
github.event_name == 'pull_request' || (github.event_name == 'release' &&
github.event.action == 'published')
defaults:
run:
working-directory: "app"
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: Setup Flutter
uses: subosito/flutter-action@v2
with:
flutter-version: '3.22.2'
channel: 'stable'
flutter-version: "3.32.7"
channel: "stable"
cache: true
cache-key: 'flutter-:os:-:channel:-:version:-:arch:-:hash:'
cache-path: '${{ runner.tool_cache }}/flutter/:channel:-:version:-:arch:'
cache-key: "flutter-:os:-:channel:-:version:-:arch:-:hash:"
cache-path:
"${{ runner.tool_cache }}/flutter/:channel:-:version:-:arch:"
- name: Install Dependencies
run: |
@@ -489,21 +542,25 @@ jobs:
- name: Build
run: |
flutter config --enable-ios
flutter config --enable-swift-package-manager
flutter build ipa --no-codesign --release --dart-define SUPABASE_URL=${{ secrets.SUPABASE_PROD_URL }} --dart-define SUPABASE_ANON_KEY=${{ secrets.SUPABASE_PROD_ANON_KEY }} --dart-define SUPABASE_SITE_URL=${{ secrets.SUPABASE_PROD_SITE_URL }} --dart-define GOOGLE_CLIENT_ID=${{ secrets.SUPABASE_PROD_GOOGLE_CLIENT_ID }}
# The "Android" job builds the Flutter Android app on every pull request. This is only used to test that the build of
# the Android app works. The artifact of the build isn't uploaded / used.
# The "Android" job builds the Flutter Android app on every pull request. This
# is only used to test that the build of the Android app works. The artifact
# of the build isn't uploaded / used.
android:
name: Android
runs-on: ubuntu-latest
if: github.event_name == 'pull_request' || (github.event_name == 'release' && github.event.action == 'published')
if:
github.event_name == 'pull_request' || (github.event_name == 'release' &&
github.event.action == 'published')
defaults:
run:
working-directory: "app"
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: Setup Java
run: echo "JAVA_HOME=$JAVA_HOME_17_X64" >> $GITHUB_ENV
@@ -511,11 +568,12 @@ jobs:
- name: Setup Flutter
uses: subosito/flutter-action@v2
with:
flutter-version: '3.22.2'
channel: 'stable'
flutter-version: "3.32.7"
channel: "stable"
cache: true
cache-key: 'flutter-:os:-:channel:-:version:-:arch:-:hash:'
cache-path: '${{ runner.tool_cache }}/flutter/:channel:-:version:-:arch:'
cache-key: "flutter-:os:-:channel:-:version:-:arch:-:hash:"
cache-path:
"${{ runner.tool_cache }}/flutter/:channel:-:version:-:arch:"
- name: Install Dependencies
run: |

View File

@@ -1,3 +1,4 @@
---
name: Continuous Integration
on:
@@ -5,6 +6,8 @@ on:
branches:
- main
pull_request:
branches:
- main
jobs:
flutter:
@@ -16,21 +19,26 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: Setup Flutter
uses: subosito/flutter-action@v2
with:
flutter-version: '3.22.2'
channel: 'stable'
flutter-version: "3.32.7"
channel: "stable"
cache: true
cache-key: 'flutter-:os:-:channel:-:version:-:arch:-:hash:'
cache-path: '${{ runner.tool_cache }}/flutter/:channel:-:version:-:arch:'
cache-key: "flutter-:os:-:channel:-:version:-:arch:-:hash:"
cache-path:
"${{ runner.tool_cache }}/flutter/:channel:-:version:-:arch:"
- name: Install Dependencies
run: |
flutter pub get
- name: Lint
run: |
dart analyze --fatal-infos
- name: Test
run: |
flutter test
@@ -38,16 +46,44 @@ jobs:
deno:
name: Deno
runs-on: ubuntu-latest
env:
FEEDDECK_SUPABASE_URL: http://localhost:54321
FEEDDECK_SUPABASE_ANON_KEY: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6ImFub24iLCJleHAiOjE5ODM4MTI5OTZ9.CRXP1A7WOeoJeXxjNni43kdQwgnWNReilDMblYTn_I0
FEEDDECK_LOG_LEVEL: debug
FEEDDECK_SUPABASE_SERVICE_ROLE_KEY: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6InNlcnZpY2Vfcm9sZSIsImV4cCI6MTk4MzgxMjk5Nn0.EGIM96RAZx35lJzdJsyH-qQwv8Hdp7fsn3W0YpN81IU
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: Setup Supabase
uses: supabase/setup-cli@v1
- name: Setup Deno
uses: denoland/setup-deno@v1
uses: denoland/setup-deno@v2
with:
deno-version: v1.x
deno-version: v1.45.2
- name: Start Supabase
run: |
echo "FEEDDECK_LOG_LEVEL=${FEEDDECK_LOG_LEVEL}" >> ./supabase/.env.test
echo "FEEDDECK_SUPABASE_URL=${FEEDDECK_SUPABASE_URL}" >> ./supabase/.env.test
echo "FEEDDECK_SUPABASE_ANON_KEY=${FEEDDECK_SUPABASE_ANON_KEY}" >> ./supabase/.env.test
echo "FEEDDECK_SUPABASE_SERVICE_ROLE_KEY=${FEEDDECK_SUPABASE_SERVICE_ROLE_KEY}" >> ./supabase/.env.test
supabase start
supabase db reset
supabase functions serve --no-verify-jwt --env-file supabase/.env.test &
psql postgresql://postgres:postgres@127.0.0.1:54322/postgres -c "UPDATE settings SET value='http://kong:8000' WHERE name='supabase_api_url'"
psql postgresql://postgres:postgres@127.0.0.1:54322/postgres -c "UPDATE settings SET value='${FEEDDECK_SUPABASE_SERVICE_ROLE_KEY}' WHERE name='supabase_service_role_key'"
- name: Lint
working-directory: "supabase/functions"
run: |
deno task lint
- name: Test
working-directory: "supabase/functions"
run: |
deno test --allow-env --import-map=supabase/functions/import_map.json supabase/functions
deno task test

65
.github/workflows/landingpage.yaml vendored Normal file
View File

@@ -0,0 +1,65 @@
---
name: Landing Page
on:
push:
branches:
- main
jobs:
# The "Build Landing Page" job builds our landing page.
build-landing-page:
name: Build Landing Page
runs-on: ubuntu-latest
permissions:
contents: read
pages: write
id-token: write
defaults:
run:
working-directory: "landing"
steps:
- name: Checkout
uses: actions/checkout@v5
- name: Setup Node
uses: actions/setup-node@v5
with:
node-version: "20"
cache: npm
cache-dependency-path: landing/package-lock.json
- name: Setup Pages
uses: actions/configure-pages@v5
- name: Install Dependencies
run: |
npm install
- name: Build
run: |
npm run build
- name: Upload Artifact
uses: actions/upload-pages-artifact@v4
with:
path: ./landing/out
# The "Deploy Landing Page" job deploys our landing page to GitHub Pages.
deploy-landing-page:
name: Deploy Landing Page
runs-on: ubuntu-latest
needs: build-landing-page
permissions:
contents: read
pages: write
id-token: write
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4

View File

@@ -1,81 +1,21 @@
---
name: Release
on:
push:
branches:
- main
tags:
- v*
jobs:
# The "Changelog" job creates a new release draft on GitHub.
changelog:
name: Changelog
release:
name: Release
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
steps:
- name: Update Changelog
uses: release-drafter/release-drafter@v6
- name: Release
uses: softprops/action-gh-release@v2
if: github.ref_type == 'tag'
with:
config-name: release.yaml
disable-autolabeler: true
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# The "Build Landing Page" job builds our landing page.
build-landing-page:
name: Build Landing Page
runs-on: ubuntu-latest
permissions:
contents: read
pages: write
id-token: write
defaults:
run:
working-directory: "landing"
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: "20"
cache: npm
cache-dependency-path: landing/package-lock.json
- name: Setup Pages
uses: actions/configure-pages@v5
- name: Install Dependencies
run: |
npm install
- name: Build
run: |
npm run build
- name: Upload Artifact
uses: actions/upload-pages-artifact@v3
with:
path: ./landing/out
# The "Deploy Landing Page" job deploys our landing page to GitHub Pages.
deploy-landing-page:
name: Deploy Landing Page
runs-on: ubuntu-latest
needs: build-landing-page
permissions:
contents: read
pages: write
id-token: write
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
generate_release_notes: true
make_latest: true

View File

@@ -57,10 +57,10 @@ check your installed version:
```sh
$ flutter --version
Flutter 3.22.2 • channel stable • https://github.com/flutter/flutter.git
Framework • revision 761747bfc5 (3 days ago) • 2024-06-05 22:15:13 +0200
Engine • revision edd8546116
Tools • Dart 3.4.3 • DevTools 2.34.3
Flutter 3.29.2 • channel stable • https://github.com/flutter/flutter.git
Framework • revision c236373904 (2 weeks ago) • 2025-03-13 16:17:06 -0400
Engine • revision 18b71d647a
Tools • Dart 3.7.2 • DevTools 2.42.3
$ deno --version
@@ -233,26 +233,26 @@ docker-compose up --build
To build the Docker image, the following commands can be run:
```sh
docker build -f supabase/functions/_cmd/Dockerfile -t ghcr.io/feeddeck/feeddeck:dev supabase/functions
docker build -f supabase/functions/_cmd/Dockerfile -t ghcr.io/feeddeck/feeddeck:latest supabase/functions
# To build the Docker image for another platform use the following:
docker buildx build --platform linux/amd64 -f supabase/functions/_cmd/Dockerfile -t ghcr.io/feeddeck/feeddeck:dev supabase/functions
docker buildx build --platform linux/amd64 -f supabase/functions/_cmd/Dockerfile -t ghcr.io/feeddeck/feeddeck:latest supabase/functions
# The Docker image can then be used to run the scheduler, worker or tools, e.g.
docker run ghcr.io/feeddeck/feeddeck:dev tools get-feed '{"type": "reddit", "options": {"reddit": "/r/kubernetes"}}'
docker run ghcr.io/feeddeck/feeddeck:latest tools get-feed '{"type": "reddit", "options": {"reddit": "/r/kubernetes"}}'
```
To run the tests for our code, the following command can be used:
```sh
deno test --allow-env --import-map=supabase/functions/import_map.json supabase/functions
deno test --allow-env supabase/functions
```
To check the test coverage the `--coverage` flag can be added to the command and
an HTML report can be generated:
```sh
deno test --allow-env --import-map=supabase/functions/import_map.json supabase/functions --coverage=coverage_deno
deno test --allow-env supabase/functions --coverage=coverage_deno
# To generate the HTML report lcov is required, which can be installed via Homebrew:
brew install lcov
@@ -283,17 +283,17 @@ supabase secrets set --env-file supabase/.env
supabase secrets list
# Deploy all functions
supabase functions deploy add-or-update-source-v1 --project-ref <PROJECT-ID> --import-map supabase/functions/import_map.json
supabase functions deploy add-source-v1 --project-ref <PROJECT-ID> --import-map supabase/functions/import_map.json
supabase functions deploy delete-user-v1 --project-ref <PROJECT-ID> --import-map supabase/functions/import_map.json
supabase functions deploy generate-magic-link-v1 --project-ref <PROJECT-ID> --import-map supabase/functions/import_map.json
supabase functions deploy image-proxy-v1 --no-verify-jwt --project-ref <PROJECT-ID> --import-map supabase/functions/import_map.json
supabase functions deploy profile-v1 --project-ref <PROJECT-ID> --import-map supabase/functions/import_map.json
supabase functions deploy profile-v2 --project-ref <PROJECT-ID> --import-map supabase/functions/import_map.json
supabase functions deploy revenuecat-webhooks-v1 --no-verify-jwt --project-ref <PROJECT-ID> --import-map supabase/functions/import_map.json
supabase functions deploy stripe-create-billing-portal-link-v1 --project-ref <PROJECT-ID> --import-map supabase/functions/import_map.json
supabase functions deploy stripe-create-checkout-session-v1 --project-ref <PROJECT-ID> --import-map supabase/functions/import_map.json
supabase functions deploy stripe-webhooks-v1 --no-verify-jwt --project-ref <PROJECT-ID> --import-map supabase/functions/import_map.json
supabase functions deploy add-or-update-source-v1 --project-ref <PROJECT-ID>
supabase functions deploy add-source-v1 --project-ref <PROJECT-ID>
supabase functions deploy delete-user-v1 --project-ref <PROJECT-ID>
supabase functions deploy generate-magic-link-v1 --project-ref <PROJECT-ID>
supabase functions deploy image-proxy-v1 --no-verify-jwt --project-ref <PROJECT-ID>
supabase functions deploy profile-v1 --project-ref <PROJECT-ID>
supabase functions deploy profile-v2 --project-ref <PROJECT-ID>
supabase functions deploy revenuecat-webhooks-v1 --no-verify-jwt --project-ref <PROJECT-ID>
supabase functions deploy stripe-create-billing-portal-link-v1 --project-ref <PROJECT-ID>
supabase functions deploy stripe-create-checkout-session-v1 --project-ref <PROJECT-ID>
supabase functions deploy stripe-webhooks-v1 --no-verify-jwt --project-ref <PROJECT-ID>
```
Now we have to do some manual steps to finish the setup of our Supabase project:

View File

@@ -1,6 +1,6 @@
MIT License
Copyright (c) 2024 Rico Berger
Copyright (c) 2026 Rico Berger
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in

View File

@@ -1,22 +1,25 @@
<div align="center">
<img src=".github/assets/icon.png" width="200" />
<br><br>
<img src=".github/assets/icon.png" width="200" />
<br><br>
**FeedDeck** is an open source RSS and social media feed reader, inspired by
TweetDeck. FeedDeck allows you to follow your favorite feeds in one place on all
platforms.
<p>
<a href="https://apps.apple.com/us/app/feeddeck/id6451055362" target="_blank"><img src=".github/assets/badge-app-store.svg" height="50"></a>
<a href="https://play.google.com/store/apps/details?id=app.feeddeck.feeddeck" target="_blank"><img src=".github/assets/badge-google-play.svg" height="50"></a>
<a href="https://app.feeddeck.app" target="_blank"><img src=".github/assets/badge-web.svg" height="50"></a>
<a href="https://apps.apple.com/us/app/feeddeck/id6451055362" target="_blank"><img src=".github/assets/badge-mac-app-store.svg" height="50"></a>
<a href="https://www.microsoft.com/store/apps/9NPHPGRRCT5H" target="_blank"><img src=".github/assets/badge-windows-store.svg" height="50"></a>
<a href="https://flathub.org/en/apps/app.feeddeck.feeddeck" target="_blank"><img src=".github/assets/badge-flathub.svg" height="50"></a>
</div>
<p align="center">
<a href="https://apps.apple.com/us/app/feeddeck/id6451055362" target="_blank"><img src=".github/assets/badge-app-store.png" height="50"></a>
<a href="https://play.google.com/store/apps/details?id=app.feeddeck.feeddeck" target="_blank"><img src=".github/assets/badge-google-play.png" height="50"></a>
<a href="https://app.feeddeck.app" target="_blank"><img src=".github/assets/badge-web.png" height="50"></a>
<a href="https://apps.apple.com/us/app/feeddeck/id6451055362" target="_blank"><img src=".github/assets/badge-mac-app-store.png" height="50"></a>
<a href="https://www.microsoft.com/store/apps/9NPHPGRRCT5H" target="_blank"><img src=".github/assets/badge-windows-store.png" height="50"></a>
<a href="https://flathub.org/en/apps/app.feeddeck.feeddeck" target="_blank"><img src=".github/assets/badge-flathub.png" height="50"></a>
</p>
<img src=".github/assets/screenshot.png" width="100%" />
<br><br>
<div align="center">
<img src=".github/assets/screenshot.png" width="100%" />
<br><br>
</div>
**FeedDeck** is an open source RSS and social media feed reader, inspired by

8
app/.dockerignore Normal file
View File

@@ -0,0 +1,8 @@
.dart_tool/
.flutter-plugins
.flutter-plugins-dependencies
.packages
.pub-cache/
.pub/
/build/
/coverage

2
app/.gitignore vendored
View File

@@ -5,9 +5,11 @@
*.swp
.DS_Store
.atom/
.build/
.buildlog/
.history
.svn/
.swiftpm/
migrate_working_dir/
# IntelliJ related

14
app/Dockerfile Normal file
View File

@@ -0,0 +1,14 @@
FROM ghcr.io/cirruslabs/flutter:3.29.3 AS build
ARG SUPABASE_URL
ARG SUPABASE_ANON_KEY
ARG SUPABASE_SITE_URL
ARG GOOGLE_CLIENT_ID
RUN mkdir /app/
COPY . /app/
WORKDIR /app/
RUN flutter build web --release --dart-define SUPABASE_URL=${SUPABASE_URL} --dart-define SUPABASE_ANON_KEY=${SUPABASE_ANON_KEY} --dart-define SUPABASE_SITE_URL=${SUPABASE_SITE_URL} --dart-define GOOGLE_CLIENT_ID=${GOOGLE_CLIENT_ID}
FROM nginx:1.26.3
COPY --from=build /app/build/web /usr/share/nginx/html

View File

@@ -5,6 +5,7 @@ gradle-wrapper.jar
/gradlew.bat
/local.properties
GeneratedPluginRegistrant.java
.cxx/
# Remember to never publicly share your keystore.
# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app

View File

@@ -1,88 +0,0 @@
plugins {
id "com.android.application"
id "kotlin-android"
id "dev.flutter.flutter-gradle-plugin"
}
def localProperties = new Properties()
def localPropertiesFile = rootProject.file('local.properties')
if (localPropertiesFile.exists()) {
localPropertiesFile.withReader('UTF-8') { reader ->
localProperties.load(reader)
}
}
def keystoreProperties = new Properties()
def keystorePropertiesFile = rootProject.file('key.properties')
if (keystorePropertiesFile.exists()) {
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
}
def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
if (flutterVersionCode == null) {
flutterVersionCode = '1'
}
def flutterVersionName = localProperties.getProperty('flutter.versionName')
if (flutterVersionName == null) {
flutterVersionName = '1.0'
}
android {
namespace "app.feeddeck.feeddeck"
compileSdkVersion flutter.compileSdkVersion
ndkVersion flutter.ndkVersion
compileOptions {
sourceCompatibility JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_17
}
kotlinOptions {
jvmTarget = '17'
}
sourceSets {
main.java.srcDirs += 'src/main/kotlin'
}
defaultConfig {
applicationId "app.feeddeck.feeddeck"
// You can update the following values to match your application needs.
// For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
// minSdkVersion flutter.minSdkVersion
// targetSdkVersion flutter.targetSdkVersion
minSdkVersion 21
targetSdkVersion 34
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
}
signingConfigs {
release {
keyAlias keystoreProperties['keyAlias']
keyPassword keystoreProperties['keyPassword']
storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null
storePassword keystoreProperties['storePassword']
}
}
buildTypes {
release {
if (keystorePropertiesFile.exists()) {
signingConfig signingConfigs.release
} else {
// For testing purposes we sign with dummy credentials if no key properties are given.
signingConfig signingConfigs.debug
}
}
}
}
flutter {
source '../..'
}
dependencies {
implementation 'com.google.android.gms:play-services-auth:20.6.0'
}

View File

@@ -0,0 +1,73 @@
import java.util.Properties
import java.io.FileInputStream
plugins {
id("com.android.application")
id("kotlin-android")
// The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins.
id("dev.flutter.flutter-gradle-plugin")
}
val keystoreProperties = Properties()
val keystorePropertiesFile = rootProject.file("key.properties")
if (keystorePropertiesFile.exists()) {
keystoreProperties.load(FileInputStream(keystorePropertiesFile))
}
android {
namespace = "app.feeddeck.feeddeck"
compileSdk = flutter.compileSdkVersion
// Use 27.0.12077973 as NDK version instead of the default which is defined in ~/flutter/packages/flutter_tools/gradle/src/main/kotlin/FlutterExtension.kt
// ndkVersion = flutter.ndkVersion
ndkVersion = "27.0.12077973"
compileOptions {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
kotlinOptions {
jvmTarget = JavaVersion.VERSION_17.toString()
}
defaultConfig {
// Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId = "app.feeddeck.feeddeck"
// You can update the following values to match your application needs.
// For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
minSdk = 21
targetSdk = 35
versionCode = flutter.versionCode
versionName = flutter.versionName
}
signingConfigs {
create("release") {
if (keystorePropertiesFile.exists()) {
keyAlias = keystoreProperties["keyAlias"] as String
keyPassword = keystoreProperties["keyPassword"] as String
storeFile = keystoreProperties["storeFile"]?.let { file(it) }
storePassword = keystoreProperties["storePassword"] as String
}
}
}
buildTypes {
release {
if (keystorePropertiesFile.exists()) {
signingConfig = signingConfigs.getByName("release")
}
}
}
}
flutter {
source = "../.."
}
dependencies {
implementation("com.google.android.gms:play-services-auth:20.6.0")
// This is required for the "file_picker" Flutter package, because without the app crash when exporting a file with the following error:
// "java.lang.NoClassDefFoundError: Failed resolution of: Ljavax/xml/stream/XMLResolver;"
implementation("javax.xml.stream:stax-api:1.0-2")
}

View File

@@ -1,18 +0,0 @@
allprojects {
repositories {
google()
mavenCentral()
}
}
rootProject.buildDir = '../build'
subprojects {
project.buildDir = "${rootProject.buildDir}/${project.name}"
}
subprojects {
project.evaluationDependsOn(':app')
}
tasks.register("clean", Delete) {
delete rootProject.buildDir
}

View File

@@ -0,0 +1,21 @@
allprojects {
repositories {
google()
mavenCentral()
}
}
val newBuildDir: Directory = rootProject.layout.buildDirectory.dir("../../build").get()
rootProject.layout.buildDirectory.value(newBuildDir)
subprojects {
val newSubprojectBuildDir: Directory = newBuildDir.dir(project.name)
project.layout.buildDirectory.value(newSubprojectBuildDir)
}
subprojects {
project.evaluationDependsOn(":app")
}
tasks.register<Delete>("clean") {
delete(rootProject.layout.buildDirectory)
}

View File

@@ -1,3 +1,3 @@
org.gradle.jvmargs=-Xmx1536M
org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError
android.useAndroidX=true
android.enableJetifier=true

View File

@@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-all.zip

View File

@@ -1,26 +0,0 @@
pluginManagement {
def flutterSdkPath = {
def properties = new Properties()
file("local.properties").withInputStream { properties.load(it) }
def flutterSdkPath = properties.getProperty("flutter.sdk")
assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
return flutterSdkPath
}
settings.ext.flutterSdkPath = flutterSdkPath()
includeBuild("${settings.ext.flutterSdkPath}/packages/flutter_tools/gradle")
repositories {
google()
mavenCentral()
gradlePluginPortal()
}
}
plugins {
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
id "com.android.application" version "8.1.2" apply false
id "org.jetbrains.kotlin.android" version "1.9.10" apply false
}
include ":app"

View File

@@ -0,0 +1,25 @@
pluginManagement {
val flutterSdkPath = run {
val properties = java.util.Properties()
file("local.properties").inputStream().use { properties.load(it) }
val flutterSdkPath = properties.getProperty("flutter.sdk")
require(flutterSdkPath != null) { "flutter.sdk not set in local.properties" }
flutterSdkPath
}
includeBuild("$flutterSdkPath/packages/flutter_tools/gradle")
repositories {
google()
mavenCentral()
gradlePluginPortal()
}
}
plugins {
id("dev.flutter.flutter-plugin-loader") version "1.0.0"
id("com.android.application") version "8.7.3" apply false
id("org.jetbrains.kotlin.android") version "2.1.0" apply false
}
include(":app")

View File

@@ -1,5 +1,5 @@
# Uncomment this line to define a global platform for your project
platform :ios, '12.0'
platform :ios, '13.0'
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
@@ -27,6 +27,9 @@ require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelpe
flutter_ios_podfile_setup
Pod::PICKER_MEDIA = false
Pod::PICKER_AUDIO = false
target 'Runner' do
use_frameworks!
use_modular_headers!

View File

@@ -1,68 +1,30 @@
PODS:
- app_links (0.0.1):
- Flutter
- audio_service (0.0.1):
- Flutter
- audio_session (0.0.1):
- Flutter
- Flutter (1.0.0)
- flutter_native_splash (0.0.1):
- Flutter
- just_audio (0.0.1):
- Flutter
- media_kit_libs_ios_video (1.0.4):
- Flutter
- media_kit_native_event_loop (1.0.0):
- Flutter
- media_kit_video (0.0.1):
- Flutter
- package_info_plus (0.4.5):
- purchases_flutter (9.1.0):
- Flutter
- path_provider_foundation (0.0.1):
- Flutter
- FlutterMacOS
- purchases_flutter (6.30.2):
- Flutter
- PurchasesHybridCommon (= 11.1.0)
- PurchasesHybridCommon (11.1.0):
- RevenueCat (= 4.43.2)
- RevenueCat (4.43.2)
- screen_brightness_ios (0.1.0):
- Flutter
- shared_preferences_foundation (0.0.1):
- Flutter
- FlutterMacOS
- PurchasesHybridCommon (= 16.0.2)
- PurchasesHybridCommon (16.0.2):
- RevenueCat (= 5.33.1)
- RevenueCat (5.33.1)
- sign_in_with_apple (0.0.1):
- Flutter
- sqflite (0.0.3):
- Flutter
- FlutterMacOS
- url_launcher_ios (0.0.1):
- Flutter
- volume_controller (0.0.1):
- Flutter
- wakelock_plus (0.0.1):
- Flutter
DEPENDENCIES:
- app_links (from `.symlinks/plugins/app_links/ios`)
- audio_service (from `.symlinks/plugins/audio_service/ios`)
- audio_session (from `.symlinks/plugins/audio_session/ios`)
- Flutter (from `Flutter`)
- flutter_native_splash (from `.symlinks/plugins/flutter_native_splash/ios`)
- just_audio (from `.symlinks/plugins/just_audio/ios`)
- media_kit_libs_ios_video (from `.symlinks/plugins/media_kit_libs_ios_video/ios`)
- media_kit_native_event_loop (from `.symlinks/plugins/media_kit_native_event_loop/ios`)
- media_kit_video (from `.symlinks/plugins/media_kit_video/ios`)
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
- purchases_flutter (from `.symlinks/plugins/purchases_flutter/ios`)
- screen_brightness_ios (from `.symlinks/plugins/screen_brightness_ios/ios`)
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
- sign_in_with_apple (from `.symlinks/plugins/sign_in_with_apple/ios`)
- sqflite (from `.symlinks/plugins/sqflite/darwin`)
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
- volume_controller (from `.symlinks/plugins/volume_controller/ios`)
- wakelock_plus (from `.symlinks/plugins/wakelock_plus/ios`)
SPEC REPOS:
@@ -71,68 +33,32 @@ SPEC REPOS:
- RevenueCat
EXTERNAL SOURCES:
app_links:
:path: ".symlinks/plugins/app_links/ios"
audio_service:
:path: ".symlinks/plugins/audio_service/ios"
audio_session:
:path: ".symlinks/plugins/audio_session/ios"
Flutter:
:path: Flutter
flutter_native_splash:
:path: ".symlinks/plugins/flutter_native_splash/ios"
just_audio:
:path: ".symlinks/plugins/just_audio/ios"
media_kit_libs_ios_video:
:path: ".symlinks/plugins/media_kit_libs_ios_video/ios"
media_kit_native_event_loop:
:path: ".symlinks/plugins/media_kit_native_event_loop/ios"
media_kit_video:
:path: ".symlinks/plugins/media_kit_video/ios"
package_info_plus:
:path: ".symlinks/plugins/package_info_plus/ios"
path_provider_foundation:
:path: ".symlinks/plugins/path_provider_foundation/darwin"
purchases_flutter:
:path: ".symlinks/plugins/purchases_flutter/ios"
screen_brightness_ios:
:path: ".symlinks/plugins/screen_brightness_ios/ios"
shared_preferences_foundation:
:path: ".symlinks/plugins/shared_preferences_foundation/darwin"
sign_in_with_apple:
:path: ".symlinks/plugins/sign_in_with_apple/ios"
sqflite:
:path: ".symlinks/plugins/sqflite/darwin"
url_launcher_ios:
:path: ".symlinks/plugins/url_launcher_ios/ios"
volume_controller:
:path: ".symlinks/plugins/volume_controller/ios"
wakelock_plus:
:path: ".symlinks/plugins/wakelock_plus/ios"
SPEC CHECKSUMS:
app_links: e70ca16b4b0f88253b3b3660200d4a10b4ea9795
audio_service: f509d65da41b9521a61f1c404dd58651f265a567
audio_session: 088d2483ebd1dc43f51d253d4a1c517d9a2e7207
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
flutter_native_splash: edf599c81f74d093a4daf8e17bd7a018854bc778
just_audio: baa7252489dbcf47a4c7cc9ca663e9661c99aafa
media_kit_libs_ios_video: a5fe24bc7875ccd6378a0978c13185e1344651c1
media_kit_native_event_loop: e6b2ab20cf0746eb1c33be961fcf79667304fa2a
media_kit_video: 5da63f157170e5bf303bf85453b7ef6971218a2e
package_info_plus: 58f0028419748fad15bf008b270aaa8e54380b1c
path_provider_foundation: 3784922295ac71e43754bd15e0653ccfd36a147c
purchases_flutter: 42d5544e7730ea89a88cc2f008b7c700fd147052
PurchasesHybridCommon: 4022d5944cb30ec44ba5159e42aa161fe0e30175
RevenueCat: 3d934653b7e8b09af88fd47e9e84cfaf5d0a89ba
screen_brightness_ios: 715ca807df953bf676d339f11464e438143ee625
shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78
sign_in_with_apple: f3bf75217ea4c2c8b91823f225d70230119b8440
sqflite: 673a0e54cc04b7d6dba8d24fb8095b31c3a99eec
url_launcher_ios: bbd758c6e7f9fd7b5b1d4cde34d2b95fcce5e812
volume_controller: 531ddf792994285c9b17f9d8a7e4dcdd29b3eae9
wakelock_plus: 78ec7c5b202cab7761af8e2b2b3d0671be6c4ae1
media_kit_libs_ios_video: 5a18affdb97d1f5d466dc79988b13eff6c5e2854
media_kit_video: 1746e198cb697d1ffb734b1d05ec429d1fcd1474
purchases_flutter: 818eabac676b9037ac7692d4bc48a52a10b276be
PurchasesHybridCommon: ae7a0a6e105ecdde3e8816a004e57f0a2a7b9261
RevenueCat: b0ed01125b05a45b8264a2951ad68acb61942038
sign_in_with_apple: c5dcc141574c8c54d5ac99dd2163c0c72ad22418
sqflite: c35dad70033b8862124f8337cc994a809fcd9fa3
wakelock_plus: fd58c82b1388f4afe3fe8aa2c856503a262a5b03
PODFILE CHECKSUM: 016564c560c4c9dbcb210e12c7aa6039072645f1
PODFILE CHECKSUM: a35dde46ea09af570b675187a949f5fa3bc82280
COCOAPODS: 1.15.2
COCOAPODS: 1.16.2

View File

@@ -15,6 +15,7 @@
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */ = {isa = PBXBuildFile; productRef = 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */; };
/* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */
@@ -57,6 +58,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */,
11A5CB70E48EE53811F041B1 /* Pods_Runner.framework in Frameworks */,
55F35B592ABF74D1007331B3 /* StoreKit.framework in Frameworks */,
);
@@ -134,6 +136,9 @@
/* Begin PBXNativeTarget section */
97C146ED1CF9000F007C117D /* Runner */ = {
packageProductDependencies = (
78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */,
);
isa = PBXNativeTarget;
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
buildPhases = (
@@ -159,6 +164,9 @@
/* Begin PBXProject section */
97C146E61CF9000F007C117D /* Project object */ = {
packageReferences = (
781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage" */,
);
isa = PBXProject;
attributes = {
LastUpgradeCheck = 1510;
@@ -561,6 +569,18 @@
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
/* Begin XCLocalSwiftPackageReference section */
781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage" */ = {
isa = XCLocalSwiftPackageReference;
relativePath = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage;
};
/* End XCLocalSwiftPackageReference section */
/* Begin XCSwiftPackageProductDependency section */
78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */ = {
isa = XCSwiftPackageProductDependency;
productName = FlutterGeneratedPluginSwiftPackage;
};
/* End XCSwiftPackageProductDependency section */
};
rootObject = 97C146E61CF9000F007C117D /* Project object */;
}

View File

@@ -0,0 +1,60 @@
{
"originHash" : "34b4b4fd64d12b3f877c43c5c1afbd609747cf0fa590d3e8fb35fc7cd91a1fa3",
"pins" : [
{
"identity" : "dkcamera",
"kind" : "remoteSourceControl",
"location" : "https://github.com/zhangao0086/DKCamera",
"state" : {
"branch" : "master",
"revision" : "5c691d11014b910aff69f960475d70e65d9dcc96"
}
},
{
"identity" : "dkimagepickercontroller",
"kind" : "remoteSourceControl",
"location" : "https://github.com/zhangao0086/DKImagePickerController",
"state" : {
"branch" : "4.3.9",
"revision" : "0bdfeacefa308545adde07bef86e349186335915"
}
},
{
"identity" : "dkphotogallery",
"kind" : "remoteSourceControl",
"location" : "https://github.com/zhangao0086/DKPhotoGallery",
"state" : {
"branch" : "master",
"revision" : "311c1bc7a94f1538f82773a79c84374b12a2ef3d"
}
},
{
"identity" : "sdwebimage",
"kind" : "remoteSourceControl",
"location" : "https://github.com/SDWebImage/SDWebImage",
"state" : {
"revision" : "b62cb63bf4ed1f04c961a56c9c6c9d5ab8524ec6",
"version" : "5.21.1"
}
},
{
"identity" : "swiftygif",
"kind" : "remoteSourceControl",
"location" : "https://github.com/kirualex/SwiftyGif.git",
"state" : {
"revision" : "4430cbc148baa3907651d40562d96325426f409a",
"version" : "5.4.5"
}
},
{
"identity" : "tocropviewcontroller",
"kind" : "remoteSourceControl",
"location" : "https://github.com/TimOliver/TOCropViewController",
"state" : {
"revision" : "a634cb7cdfd580006e79a6e74e64417fe9e9783b",
"version" : "2.7.4"
}
}
],
"version" : 3
}

View File

@@ -5,6 +5,24 @@
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<PreActions>
<ExecutionAction
ActionType = "Xcode.IDEStandardExecutionActionsCore.ExecutionActionType.ShellScriptAction">
<ActionContent
title = "Run Prepare Flutter Framework Script"
scriptText = "/bin/sh &quot;$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh&quot; prepare&#10;">
<EnvironmentBuildable>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</EnvironmentBuildable>
</ActionContent>
</ExecutionAction>
</PreActions>
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
@@ -26,6 +44,7 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
customLLDBInitFile = "$(SRCROOT)/Flutter/ephemeral/flutter_lldbinit"
shouldUseLaunchSchemeArgsEnv = "YES">
<MacroExpansion>
<BuildableReference
@@ -43,11 +62,13 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
customLLDBInitFile = "$(SRCROOT)/Flutter/ephemeral/flutter_lldbinit"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
enableGPUValidationMode = "1"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">

View File

@@ -0,0 +1,60 @@
{
"originHash" : "34b4b4fd64d12b3f877c43c5c1afbd609747cf0fa590d3e8fb35fc7cd91a1fa3",
"pins" : [
{
"identity" : "dkcamera",
"kind" : "remoteSourceControl",
"location" : "https://github.com/zhangao0086/DKCamera",
"state" : {
"branch" : "master",
"revision" : "5c691d11014b910aff69f960475d70e65d9dcc96"
}
},
{
"identity" : "dkimagepickercontroller",
"kind" : "remoteSourceControl",
"location" : "https://github.com/zhangao0086/DKImagePickerController",
"state" : {
"branch" : "4.3.9",
"revision" : "0bdfeacefa308545adde07bef86e349186335915"
}
},
{
"identity" : "dkphotogallery",
"kind" : "remoteSourceControl",
"location" : "https://github.com/zhangao0086/DKPhotoGallery",
"state" : {
"branch" : "master",
"revision" : "311c1bc7a94f1538f82773a79c84374b12a2ef3d"
}
},
{
"identity" : "sdwebimage",
"kind" : "remoteSourceControl",
"location" : "https://github.com/SDWebImage/SDWebImage",
"state" : {
"revision" : "b62cb63bf4ed1f04c961a56c9c6c9d5ab8524ec6",
"version" : "5.21.1"
}
},
{
"identity" : "swiftygif",
"kind" : "remoteSourceControl",
"location" : "https://github.com/kirualex/SwiftyGif.git",
"state" : {
"revision" : "4430cbc148baa3907651d40562d96325426f409a",
"version" : "5.4.5"
}
},
{
"identity" : "tocropviewcontroller",
"kind" : "remoteSourceControl",
"location" : "https://github.com/TimOliver/TOCropViewController",
"state" : {
"revision" : "a634cb7cdfd580006e79a6e74e64417fe9e9783b",
"version" : "2.7.4"
}
}
],
"version" : 3
}

View File

@@ -1,7 +1,7 @@
import UIKit
import Flutter
@UIApplicationMain
@main
@objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,

View File

@@ -68,6 +68,8 @@
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
<false/>
<key>UISupportsDocumentBrowser</key>
<true/>
</dict>
</plist>

View File

@@ -18,8 +18,8 @@ import 'package:feeddeck/repositories/settings_repository.dart';
import 'package:feeddeck/utils/constants.dart';
import 'package:feeddeck/widgets/confirmation/confirmation.dart';
import 'package:feeddeck/widgets/home/home.dart';
import 'package:feeddeck/widgets/reset_password/reset_password.dart';
import 'package:feeddeck/widgets/item/details/utils/item_audio_palyer/item_audio_player_init/item_audio_player_init.dart';
import 'package:feeddeck/widgets/reset_password/reset_password.dart';
/// Before we are calling [runApp] we have to ensure that the widget bindings
/// are initialized, so that we can preserve the splash screen until we are done
@@ -91,12 +91,12 @@ void main() async {
class FeedDeckScrollBehavior extends MaterialScrollBehavior {
@override
Set<PointerDeviceKind> get dragDevices => {
PointerDeviceKind.touch,
PointerDeviceKind.mouse,
PointerDeviceKind.trackpad,
PointerDeviceKind.stylus,
PointerDeviceKind.unknown,
};
PointerDeviceKind.touch,
PointerDeviceKind.mouse,
PointerDeviceKind.trackpad,
PointerDeviceKind.stylus,
PointerDeviceKind.unknown,
};
}
/// [onGenerateRoute] is used in `onGenerateRoute` and `onGenerateInitialRoutes`
@@ -119,15 +119,11 @@ Route onGenerateRoute(RouteSettings settings) {
),
);
case '/reset-password':
return MaterialPageRoute(
builder: (_) => const ResetPassword(),
);
return MaterialPageRoute(builder: (_) => const ResetPassword());
}
}
return MaterialPageRoute(
builder: (_) => const Home(),
);
return MaterialPageRoute(builder: (_) => const Home());
}
/// The [FeedDeckApp] is the root widget of the app. The widget is used to
@@ -159,8 +155,6 @@ class FeedDeckApp extends StatelessWidget {
onSecondary: Constants.onSecondary,
error: Constants.error,
onError: Constants.onError,
background: Constants.background,
onBackground: Constants.onBackground,
surface: Constants.surface,
onSurface: Constants.onSurface,
),
@@ -172,32 +166,26 @@ class FeedDeckApp extends StatelessWidget {
elevation: Constants.appBarElevation,
),
snackBarTheme: const SnackBarThemeData(
backgroundColor: Constants.surface,
contentTextStyle: TextStyle(
color: Constants.onSurface,
),
backgroundColor: Constants.secondary,
contentTextStyle: TextStyle(color: Constants.onSurface),
),
dialogTheme: const DialogTheme(
backgroundColor: Constants.background,
surfaceTintColor: Constants.background,
contentTextStyle: TextStyle(
color: Constants.onBackground,
),
dialogTheme: const DialogThemeData(
backgroundColor: Constants.surface,
surfaceTintColor: Constants.surface,
contentTextStyle: TextStyle(color: Constants.onSurface),
),
popupMenuTheme: const PopupMenuThemeData(
color: Constants.background,
surfaceTintColor: Constants.background,
textStyle: TextStyle(
color: Constants.onBackground,
),
color: Constants.surface,
surfaceTintColor: Constants.surface,
textStyle: TextStyle(color: Constants.onSurface),
),
drawerTheme: const DrawerThemeData(
backgroundColor: Constants.background,
surfaceTintColor: Constants.background,
backgroundColor: Constants.surface,
surfaceTintColor: Constants.surface,
),
bottomSheetTheme: const BottomSheetThemeData(
backgroundColor: Constants.background,
surfaceTintColor: Constants.background,
backgroundColor: Constants.surface,
surfaceTintColor: Constants.surface,
),
pageTransitionsTheme: const PageTransitionsTheme(
builders: {
@@ -210,8 +198,9 @@ class FeedDeckApp extends StatelessWidget {
),
),
scrollBehavior: FeedDeckScrollBehavior(),
onGenerateInitialRoutes: (initialRoute) =>
[onGenerateRoute(RouteSettings(name: initialRoute))],
onGenerateInitialRoutes: (initialRoute) => [
onGenerateRoute(RouteSettings(name: initialRoute)),
],
onGenerateRoute: (RouteSettings settings) =>
onGenerateRoute(settings),
),

View File

@@ -1,3 +1,5 @@
import 'package:xml/xml.dart';
import 'package:feeddeck/models/source.dart';
/// [FDColumn] is the model for a column in our app. The following fields are
@@ -26,11 +28,12 @@ class FDColumn {
id: data['id'],
name: data['name'],
position: data['position'],
sources: data.containsKey('sources') && data['sources'] != null
? List<FDSource>.from(
data['sources'].map((source) => FDSource.fromJson(source)),
)
: [],
sources:
data.containsKey('sources') && data['sources'] != null
? List<FDSource>.from(
data['sources'].map((source) => FDSource.fromJson(source)),
)
: [],
);
}
@@ -40,4 +43,34 @@ class FDColumn {
String identifier() {
return 'id: $id, sources: ${sources.map((source) => source.id).join(' ')}';
}
factory FDColumn.fromXml(XmlElement element) {
final sources = <FDSource>[];
element.findElements('outline').forEach((outline) {
final source = FDSource.fromXml(outline);
if (source.type != FDSourceType.none) {
sources.add(source);
}
});
return FDColumn(
id: '',
name: element.getAttribute('text') ?? 'Unknown',
position: 0,
sources: sources,
);
}
void toXml(XmlBuilder builder) {
builder.element(
'outline',
nest: () {
builder.attribute('text', name);
for (var i = 0; i < sources.length; i++) {
sources[i].toXml(builder);
}
},
);
}
}

View File

@@ -1,5 +1,7 @@
import 'package:flutter/material.dart';
import 'package:xml/xml.dart';
import 'package:feeddeck/models/sources/github.dart';
import 'package:feeddeck/models/sources/googlenews.dart';
import 'package:feeddeck/models/sources/stackoverflow.dart';
@@ -236,20 +238,25 @@ class FDSource {
required this.icon,
});
String get prettyTitle => title.replaceAll(RegExp(r'(?! )\s+| \s+'), ' ');
factory FDSource.fromJson(Map<String, dynamic> data) {
return FDSource(
id: data['id'],
type: getSourceTypeFromString(data['type']),
title: data['title'],
options: data.containsKey('options') && data['options'] != null
? FDSourceOptions.fromJson(data['options'])
: null,
link: data.containsKey('link') && data['link'] != null
? data['link']
: null,
icon: data.containsKey('icon') && data['icon'] != null
? data['icon']
: null,
options:
data.containsKey('options') && data['options'] != null
? FDSourceOptions.fromJson(data['options'])
: null,
link:
data.containsKey('link') && data['link'] != null
? data['link']
: null,
icon:
data.containsKey('icon') && data['icon'] != null
? data['icon']
: null,
);
}
@@ -263,6 +270,46 @@ class FDSource {
'icon': icon,
};
}
factory FDSource.fromXml(XmlElement element) {
final type = getSourceTypeFromString(element.getAttribute('type') ?? '');
final text = element.getAttribute('text');
if (type == FDSourceType.none || text == null) {
return FDSource(
id: '',
type: FDSourceType.none,
title: '',
options: null,
link: null,
icon: null,
);
}
return FDSource(
id: '',
type: type,
title: text,
options: FDSourceOptions.fromXml(element),
link: null,
icon: null,
);
}
void toXml(XmlBuilder builder) {
builder.element(
'outline',
nest: () {
builder.attribute('type', type.toShortString());
builder.attribute('text', prettyTitle);
builder.attribute('htmlUrl', link);
if (options != null) {
options!.toXml(builder);
}
},
);
}
}
/// [FDSourceOptions] defines all options for the different source types which
@@ -302,25 +349,29 @@ class FDSourceOptions {
factory FDSourceOptions.fromJson(Map<String, dynamic> responseData) {
return FDSourceOptions(
fourchan: responseData.containsKey('fourchan') &&
responseData['fourchan'] != null
? responseData['fourchan']
: null,
fourchan:
responseData.containsKey('fourchan') &&
responseData['fourchan'] != null
? responseData['fourchan']
: null,
github:
responseData.containsKey('github') && responseData['github'] != null
? FDGitHubOptions.fromJson(responseData['github'])
: null,
googlenews: responseData.containsKey('googlenews') &&
responseData['googlenews'] != null
? FDGoogleNewsOptions.fromJson(responseData['googlenews'])
: null,
lemmy: responseData.containsKey('lemmy') && responseData['lemmy'] != null
? responseData['lemmy']
: null,
mastodon: responseData.containsKey('mastodon') &&
responseData['mastodon'] != null
? responseData['mastodon']
: null,
googlenews:
responseData.containsKey('googlenews') &&
responseData['googlenews'] != null
? FDGoogleNewsOptions.fromJson(responseData['googlenews'])
: null,
lemmy:
responseData.containsKey('lemmy') && responseData['lemmy'] != null
? responseData['lemmy']
: null,
mastodon:
responseData.containsKey('mastodon') &&
responseData['mastodon'] != null
? responseData['mastodon']
: null,
medium:
responseData.containsKey('medium') && responseData['medium'] != null
? responseData['medium']
@@ -329,10 +380,11 @@ class FDSourceOptions {
responseData.containsKey('nitter') && responseData['nitter'] != null
? responseData['nitter']
: null,
pinterest: responseData.containsKey('pinterest') &&
responseData['pinterest'] != null
? responseData['pinterest']
: null,
pinterest:
responseData.containsKey('pinterest') &&
responseData['pinterest'] != null
? responseData['pinterest']
: null,
podcast:
responseData.containsKey('podcast') && responseData['podcast'] != null
? responseData['podcast']
@@ -341,13 +393,15 @@ class FDSourceOptions {
responseData.containsKey('reddit') && responseData['reddit'] != null
? responseData['reddit']
: null,
rss: responseData.containsKey('rss') && responseData['rss'] != null
? responseData['rss']
: null,
stackoverflow: responseData.containsKey('stackoverflow') &&
responseData['stackoverflow'] != null
? FDStackOverflowOptions.fromJson(responseData['stackoverflow'])
: null,
rss:
responseData.containsKey('rss') && responseData['rss'] != null
? responseData['rss']
: null,
stackoverflow:
responseData.containsKey('stackoverflow') &&
responseData['stackoverflow'] != null
? FDStackOverflowOptions.fromJson(responseData['stackoverflow'])
: null,
tumblr:
responseData.containsKey('tumblr') && responseData['tumblr'] != null
? responseData['tumblr']
@@ -377,4 +431,55 @@ class FDSourceOptions {
'youtube': youtube,
};
}
factory FDSourceOptions.fromXml(XmlElement element) {
return FDSourceOptions(
fourchan: element.getAttribute('fourchan'),
github: FDGitHubOptions.fromXml(element),
googlenews: FDGoogleNewsOptions.fromXml(element),
lemmy: element.getAttribute('lemmy'),
mastodon: element.getAttribute('mastodon'),
medium: element.getAttribute('medium'),
nitter: element.getAttribute('nitter'),
pinterest: element.getAttribute('pinterest'),
podcast: element.getAttribute('podcast'),
reddit: element.getAttribute('reddit'),
rss: element.getAttribute('xmlUrl'),
stackoverflow: FDStackOverflowOptions.fromXml(element),
tumblr: element.getAttribute('tumblr'),
youtube: element.getAttribute('youtube'),
);
}
void toXml(XmlBuilder builder) {
if (fourchan != null) {
builder.attribute('fourchan', fourchan);
} else if (github != null) {
github!.toXml(builder);
} else if (googlenews != null) {
googlenews!.toXml(builder);
} else if (lemmy != null) {
builder.attribute('lemmy', lemmy);
} else if (mastodon != null) {
builder.attribute('mastodon', mastodon);
} else if (medium != null) {
builder.attribute('medium', medium);
} else if (nitter != null) {
builder.attribute('nitter', nitter);
} else if (pinterest != null) {
builder.attribute('pinterest', pinterest);
} else if (podcast != null) {
builder.attribute('podcast', podcast);
} else if (reddit != null) {
builder.attribute('reddit', reddit);
} else if (rss != null) {
builder.attribute('xmlUrl', rss);
} else if (stackoverflow != null) {
stackoverflow!.toXml(builder);
} else if (tumblr != null) {
builder.attribute('tumblr', tumblr);
} else if (youtube != null) {
builder.attribute('youtube', youtube);
}
}
}

View File

@@ -1,3 +1,5 @@
import 'package:xml/xml.dart';
/// [FDGitHubType] is an enum value which defines the type for the GitHub
/// source.
enum FDGitHubType {
@@ -88,31 +90,38 @@ class FDGitHubOptions {
factory FDGitHubOptions.fromJson(Map<String, dynamic> responseData) {
return FDGitHubOptions(
type: responseData.containsKey('type') && responseData['type'] != null
? getGitHubTypeFromString(responseData['type'])
: null,
participating: responseData.containsKey('participating') &&
responseData['participating'] != null
? responseData['participating']
: null,
repository: responseData.containsKey('repository') &&
responseData['repository'] != null
? responseData['repository']
: null,
user: responseData.containsKey('user') && responseData['user'] != null
? responseData['user']
: null,
organization: responseData.containsKey('organization') &&
responseData['organization'] != null
? responseData['organization']
: null,
queryName: responseData.containsKey('queryName') &&
responseData['queryName'] != null
? responseData['queryName']
: null,
query: responseData.containsKey('query') && responseData['query'] != null
? responseData['query']
: null,
type:
responseData.containsKey('type') && responseData['type'] != null
? getGitHubTypeFromString(responseData['type'])
: null,
participating:
responseData.containsKey('participating') &&
responseData['participating'] != null
? responseData['participating']
: null,
repository:
responseData.containsKey('repository') &&
responseData['repository'] != null
? responseData['repository']
: null,
user:
responseData.containsKey('user') && responseData['user'] != null
? responseData['user']
: null,
organization:
responseData.containsKey('organization') &&
responseData['organization'] != null
? responseData['organization']
: null,
queryName:
responseData.containsKey('queryName') &&
responseData['queryName'] != null
? responseData['queryName']
: null,
query:
responseData.containsKey('query') && responseData['query'] != null
? responseData['query']
: null,
);
}
@@ -127,4 +136,40 @@ class FDGitHubOptions {
'query': query,
};
}
factory FDGitHubOptions.fromXml(XmlElement element) {
return FDGitHubOptions(
type: getGitHubTypeFromString(element.getAttribute('githubType') ?? ''),
participating: element.getAttribute('githubParticipating') == 'true',
repository: element.getAttribute('githubRepository'),
user: element.getAttribute('githubUser'),
organization: element.getAttribute('githubOrganization'),
queryName: element.getAttribute('githubQueryName'),
query: element.getAttribute('githubQuery'),
);
}
void toXml(XmlBuilder builder) {
if (type != null) {
builder.attribute('githubType', type!.toShortString());
}
if (participating != null) {
builder.attribute('githubParticipating', participating);
}
if (repository != null) {
builder.attribute('githubRepository', repository);
}
if (user != null) {
builder.attribute('githubUser', user);
}
if (organization != null) {
builder.attribute('githubOrganization', organization);
}
if (queryName != null) {
builder.attribute('githubQueryName', queryName);
}
if (query != null) {
builder.attribute('githubQuery', query);
}
}
}

View File

@@ -1,9 +1,8 @@
import 'package:xml/xml.dart';
/// [FDGoogleNewsType] is an enum value which defines the type for the Google
/// News source.
enum FDGoogleNewsType {
url,
search,
}
enum FDGoogleNewsType { url, search }
/// [FDGoogleNewsTypeExtension] defines all extensions which are available for
/// the [FDGoogleNewsType] enum type.
@@ -61,25 +60,30 @@ class FDGoogleNewsOptions {
factory FDGoogleNewsOptions.fromJson(Map<String, dynamic> responseData) {
return FDGoogleNewsOptions(
type: responseData.containsKey('type') && responseData['type'] != null
? getGoogleNewsTypeFromString(responseData['type'])
: null,
url: responseData.containsKey('url') && responseData['url'] != null
? responseData['url']
: null,
type:
responseData.containsKey('type') && responseData['type'] != null
? getGoogleNewsTypeFromString(responseData['type'])
: null,
url:
responseData.containsKey('url') && responseData['url'] != null
? responseData['url']
: null,
search:
responseData.containsKey('search') && responseData['search'] != null
? responseData['search']
: null,
ceid: responseData.containsKey('ceid') && responseData['ceid'] != null
? responseData['ceid']
: null,
gl: responseData.containsKey('gl') && responseData['gl'] != null
? responseData['gl']
: null,
hl: responseData.containsKey('hl') && responseData['hl'] != null
? responseData['hl']
: null,
ceid:
responseData.containsKey('ceid') && responseData['ceid'] != null
? responseData['ceid']
: null,
gl:
responseData.containsKey('gl') && responseData['gl'] != null
? responseData['gl']
: null,
hl:
responseData.containsKey('hl') && responseData['hl'] != null
? responseData['hl']
: null,
);
}
@@ -93,4 +97,38 @@ class FDGoogleNewsOptions {
'hl': hl,
};
}
factory FDGoogleNewsOptions.fromXml(XmlElement element) {
return FDGoogleNewsOptions(
type: getGoogleNewsTypeFromString(
element.getAttribute('googlenewsType') ?? '',
),
url: element.getAttribute('googlenewsUrl'),
search: element.getAttribute('googlenewsSearch'),
ceid: element.getAttribute('googlenewsCeid'),
gl: element.getAttribute('googlenewsGl'),
hl: element.getAttribute('googlenewsHl'),
);
}
void toXml(XmlBuilder builder) {
if (type != null) {
builder.attribute('googlenewsType', type!.toShortString());
}
if (url != null) {
builder.attribute('googlenewsUrl', url);
}
if (search != null) {
builder.attribute('googlenewsSearch', search);
}
if (ceid != null) {
builder.attribute('googlenewsCeid', ceid);
}
if (gl != null) {
builder.attribute('googlenewsGl', gl);
}
if (hl != null) {
builder.attribute('googlenewsHl', hl);
}
}
}

View File

@@ -1,9 +1,8 @@
import 'package:xml/xml.dart';
/// [FDStackOverflowType] is an enum value which defines the type for the
/// StackOverflow source.
enum FDStackOverflowType {
url,
tag,
}
enum FDStackOverflowType { url, tag }
/// [FDStackOverflowTypeExtension] defines all extensions which are available for
/// the [FDStackOverflowType] enum type.
@@ -42,12 +41,7 @@ FDStackOverflowType getStackOverflowTypeFromString(String state) {
/// [FDStackOverflowSort] is an enum value which defines the available sort
/// properties for the [FDStackOverflowOptions]
enum FDStackOverflowSort {
newest,
active,
featured,
votes,
}
enum FDStackOverflowSort { newest, active, featured, votes }
/// [FDStackOverflowSortExtension] defines all extensions which are available
/// for the [FDStackOverflowSort] enum type.
@@ -100,27 +94,26 @@ class FDStackOverflowOptions {
String? tag;
FDStackOverflowSort? sort;
FDStackOverflowOptions({
this.type,
this.url,
this.tag,
this.sort,
});
FDStackOverflowOptions({this.type, this.url, this.tag, this.sort});
factory FDStackOverflowOptions.fromJson(Map<String, dynamic> responseData) {
return FDStackOverflowOptions(
type: responseData.containsKey('type') && responseData['type'] != null
? getStackOverflowTypeFromString(responseData['type'])
: null,
url: responseData.containsKey('url') && responseData['url'] != null
? responseData['url']
: null,
tag: responseData.containsKey('tag') && responseData['tag'] != null
? responseData['tag']
: null,
sort: responseData.containsKey('sort') && responseData['sort'] != null
? getStackOverflowSortFromString(responseData['sort'])
: null,
type:
responseData.containsKey('type') && responseData['type'] != null
? getStackOverflowTypeFromString(responseData['type'])
: null,
url:
responseData.containsKey('url') && responseData['url'] != null
? responseData['url']
: null,
tag:
responseData.containsKey('tag') && responseData['tag'] != null
? responseData['tag']
: null,
sort:
responseData.containsKey('sort') && responseData['sort'] != null
? getStackOverflowSortFromString(responseData['sort'])
: null,
);
}
@@ -132,4 +125,32 @@ class FDStackOverflowOptions {
'sort': sort?.toShortString(),
};
}
factory FDStackOverflowOptions.fromXml(XmlElement element) {
return FDStackOverflowOptions(
type: getStackOverflowTypeFromString(
element.getAttribute('stackoverflowType') ?? '',
),
url: element.getAttribute('stackoverflowUrl'),
tag: element.getAttribute('stackoverflowTag'),
sort: getStackOverflowSortFromString(
element.getAttribute('stackoverflowSort') ?? '',
),
);
}
void toXml(XmlBuilder builder) {
if (type != null) {
builder.attribute('stackoverflowType', type!.toShortString());
}
if (url != null) {
builder.attribute('stackoverflowUrl', url);
}
if (tag != null) {
builder.attribute('stackoverflowTag', tag);
}
if (sort != null) {
builder.attribute('stackoverflowSort', sort);
}
}
}

View File

@@ -10,11 +10,7 @@ import 'package:feeddeck/models/deck.dart';
import 'package:feeddeck/models/source.dart';
import 'package:feeddeck/utils/api_exception.dart';
enum FDAppStatus {
uninitialized,
authenticated,
unauthenticated,
}
enum FDAppStatus { uninitialized, authenticated, unauthenticated }
/// [AppRepository] is the repository for our app. The repository is responsible
/// for managing the state of our app, this includes the authentication status
@@ -82,10 +78,7 @@ class AppRepository with ChangeNotifier {
///
/// If the user was signed in successfully, we run the same logic as in the
/// [init] function, to set the active deck for the user.
Future<void> signInWithPassword(
String email,
String password,
) async {
Future<void> signInWithPassword(String email, String password) async {
await Supabase.instance.client.auth.signInWithPassword(
email: email,
password: password,
@@ -115,9 +108,7 @@ class AppRepository with ChangeNotifier {
///
/// If the user was signed in successfully, we run the same logic as in the
/// [init] function, to set the active deck for the user.
Future<void> signInWithCallback(
Uri uri,
) async {
Future<void> signInWithCallback(Uri uri) async {
await Supabase.instance.client.auth.getSessionFromUrl(
uri,
storeSession: true,
@@ -145,17 +136,16 @@ class AppRepository with ChangeNotifier {
/// create a new deck for the user with the given name. After the deck was
/// created, the deck is set as the users active deck and the deck is added to
/// the list of decks.
Future<void> createDeck(
String name,
) async {
final data = await Supabase.instance.client
.from('decks')
.insert({
'name': name,
'userId': Supabase.instance.client.auth.currentUser!.id,
})
.select()
.single();
Future<void> createDeck(String name) async {
final data =
await Supabase.instance.client
.from('decks')
.insert({
'name': name,
'userId': Supabase.instance.client.auth.currentUser!.id,
})
.select()
.single();
final newDeck = FDDeck.fromJson(data);
@@ -178,17 +168,28 @@ class AppRepository with ChangeNotifier {
return List<FDDeck>.from(data.map((deck) => FDDeck.fromJson(deck)));
}
/// [getDecksWithNotifiy] uses the [getDecks] function to get a list of all
/// decks for the user, but instead of returning the decks it updates the
/// [_decks] property and calls all the registered listeners.
///
/// This function can be used to trigger an update of the decks when they are
/// created outside of the AppRepository, like it is done in the import
/// process.
Future<void> getDecksWithNotifiy() async {
final decks = await getDecks();
_decks = decks;
notifyListeners();
}
/// [updateDeck] is called to update a deck for the user. The function takes
/// a [deckId] and a [name] as parameters. The function calls the Supabase
/// client to update the name of the deck. After the deck was updated, the
/// deck is also updated in the list of decks.
Future<void> updateDeck(
String deckId,
String name,
) async {
Future<void> updateDeck(String deckId, String name) async {
await Supabase.instance.client
.from('decks')
.update({'name': name}).eq('id', deckId);
.update({'name': name})
.eq('id', deckId);
for (var i = 0; i < _decks.length; i++) {
if (_decks[i].id == deckId) {
@@ -205,9 +206,7 @@ class AppRepository with ChangeNotifier {
/// the deck. After the deck was deleted, the deck is also removed from the
/// list of decks. If the deleted deck was the active deck, the active deck is
/// set to `null`.
Future<void> deleteDeck(
String deckId,
) async {
Future<void> deleteDeck(String deckId) async {
await Supabase.instance.client.from('decks').delete().eq('id', deckId);
_decks.removeWhere((deck) => deck.id == deckId);
@@ -223,9 +222,7 @@ class AppRepository with ChangeNotifier {
/// to get the columns for the deck and all sources for each column. After the
/// columns and sources are fetched, the active deck is set to the provided
/// deckId and the columns and sources are stored in the repository.
Future<void> selectDeck(
String deckId,
) async {
Future<void> selectDeck(String deckId) async {
final columns = await getColumns(deckId);
for (final column in columns) {
column.sources = await getSources(column.id);
@@ -243,18 +240,18 @@ class AppRepository with ChangeNotifier {
/// function takes a [name] as parameter. The function calls the Supabase
/// client to create a new column for the active deck with the given name.
/// Finally the newly created column is added to the list of columns.
Future<void> createColumn(
String name,
) async {
final data = await Supabase.instance.client.from('columns').insert({
'deckId': _activeDeckId,
'userId': Supabase.instance.client.auth.currentUser!.id,
'name': name,
'position': _columns.length,
}).select();
Future<void> createColumn(String name) async {
final data =
await Supabase.instance.client.from('columns').insert({
'deckId': _activeDeckId,
'userId': Supabase.instance.client.auth.currentUser!.id,
'name': name,
'position': _columns.length,
}).select();
final newColumn =
List<FDColumn>.from(data.map((column) => FDColumn.fromJson(column)));
final newColumn = List<FDColumn>.from(
data.map((column) => FDColumn.fromJson(column)),
);
_columns.addAll(newColumn);
notifyListeners();
}
@@ -262,9 +259,7 @@ class AppRepository with ChangeNotifier {
/// [getColumns] is called to get all columns for the deck with the provided
/// [deckId]. The function calls the Supabase client to get all columns for
/// the deck. The function returns a list of [FDColumn]s.
Future<List<FDColumn>> getColumns(
String deckId,
) async {
Future<List<FDColumn>> getColumns(String deckId) async {
final data = await Supabase.instance.client
.from('columns')
.select('id, name, position')
@@ -276,9 +271,7 @@ class AppRepository with ChangeNotifier {
/// [deleteColumn] is called to delete a column with the provided [columnId].
/// The function calls the Supabase client to delete the column. After the
/// column was deleted, the column is also removed from the list of columns.
Future<void> deleteColumn(
String columnId,
) async {
Future<void> deleteColumn(String columnId) async {
await Supabase.instance.client.from('columns').delete().eq('id', columnId);
_columns.removeWhere((column) => column.id == columnId);
@@ -289,13 +282,11 @@ class AppRepository with ChangeNotifier {
/// The function takes a [name] as parameter. The function calls the Supabase
/// client to update the name of the column. After the column was updated, the
/// column is also updated in the list of columns.
Future<void> updateColumn(
String columnId,
String name,
) async {
Future<void> updateColumn(String columnId, String name) async {
await Supabase.instance.client
.from('columns')
.update({'name': name}).eq('id', columnId);
.update({'name': name})
.eq('id', columnId);
for (var i = 0; i < _columns.length; i++) {
if (_columns[i].id == columnId) {
@@ -311,22 +302,15 @@ class AppRepository with ChangeNotifier {
/// with the provided [index1] and [index2]. The function calls the Supabase
/// client to update the positions of the columns. After the columns were
/// updated, the columns are also updated in the list of columns.
Future<void> updateColumnPositions(
int index1,
int index2,
) async {
Future<void> updateColumnPositions(int index1, int index2) async {
await Supabase.instance.client
.from('columns')
.update({'position': _columns[index2].position}).eq(
'id',
_columns[index1].id,
);
.update({'position': _columns[index2].position})
.eq('id', _columns[index1].id);
await Supabase.instance.client
.from('columns')
.update({'position': _columns[index1].position}).eq(
'id',
_columns[index2].id,
);
.update({'position': _columns[index1].position})
.eq('id', _columns[index2].id);
final tmp = _columns[index1];
_columns[index1] = _columns[index2];
@@ -340,13 +324,19 @@ class AppRepository with ChangeNotifier {
/// [getSources] is called to get all sources for the column with the provided
/// [columnId]. The function calls the Supabase client to get all sources for
/// the column. The function returns a list of [FDSource]s.
Future<List<FDSource>> getSources(
String columnId,
) async {
///
/// The returned list of sources is ordered by the `position` field. Since the
/// position field was added later there might be columns where the field is
/// `null`, which will come after all columns with a `position`. The source
/// where the position is `null` will be ordered by the `createdAt` date. This
/// should retain the order as before the `position` field was added and
/// should also work for new sources, which are added without a position.
Future<List<FDSource>> getSources(String columnId) async {
final data = await Supabase.instance.client
.from('sources')
.select('id, type, title, options, link, icon')
.eq('columnId', columnId)
.order('position', ascending: true, nullsFirst: false)
.order('createdAt', ascending: true);
return List<FDSource>.from(data.map((source) => FDSource.fromJson(source)));
}
@@ -355,10 +345,7 @@ class AppRepository with ChangeNotifier {
/// The function calls the Supabase client to delete the source. After the
/// source was deleted, the source is also removed from the list of sources of
/// the column with the provided [columnId].
Future<void> deleteSource(
String columnId,
String sourceId,
) async {
Future<void> deleteSource(String columnId, String sourceId) async {
await Supabase.instance.client.from('sources').delete().eq('id', sourceId);
/// It could take some time before we can retrieve the items after a source
@@ -423,4 +410,51 @@ class AppRepository with ChangeNotifier {
notifyListeners();
}
/// [updateSourcePositions] can be used to reorder the list of sources for a
/// column. To achieve this order the list of sources for the provided
/// [columnId] locally and update the `position` field of each source
/// afterwards in the database.
///
/// We have to check if the user drags a source from top to bottom ([start]
/// is lower then [current]) or from the bottom to the top ([start] is greater
/// then [current]), to apply a different logic for the reordering.
Future<void> updateSourcePositions(
String columnId,
int start,
int current,
) async {
final columnIndex = _columns.indexWhere((column) => column.id == columnId);
if (columnIndex == -1) {
return;
}
if (start < current) {
int end = current - 1;
FDSource startItem = _columns[columnIndex].sources[start];
int i = 0;
int local = start;
do {
_columns[columnIndex].sources[local] =
_columns[columnIndex].sources[++local];
i++;
} while (i < end - start);
_columns[columnIndex].sources[end] = startItem;
} else if (start > current) {
FDSource startItem = _columns[columnIndex].sources[start];
for (int i = start; i > current; i--) {
_columns[columnIndex].sources[i] = _columns[columnIndex].sources[i - 1];
}
_columns[columnIndex].sources[current] = startItem;
}
for (var i = 0; i < _columns[columnIndex].sources.length; i++) {
await Supabase.instance.client
.from('sources')
.update({'position': i})
.eq('id', _columns[columnIndex].sources[i].id);
}
notifyListeners();
}
}

View File

@@ -31,12 +31,7 @@ class ItemsFilters {
/// [ItemStateFilter] is a enum value which defines the state filter for items.
/// The filter can be [read], [unread] or [bookmarked]. The [none] filter is
/// used to return all items regardless if they are read, unread or bookmarked.
enum ItemStateFilter {
none,
read,
unread,
bookmarked,
}
enum ItemStateFilter { none, read, unread, bookmarked }
/// The [ToString] extension defines a [toShortString] function, which returns a
/// `String` which can be safely passed within a database query for the specifed
@@ -53,11 +48,7 @@ extension ToString on ItemStateFilter {
/// - [loading] during the time when the items are retrieved from our database
/// - [loadedLast] when there are no more items which can be loaded from the
/// database.
enum ItemsStatus {
loaded,
loading,
loadedLast,
}
enum ItemsStatus { loaded, loading, loadedLast }
/// [now] returns the current Unix timestamp in seconds.
int now() {
@@ -69,9 +60,7 @@ int now() {
/// initialized we have to call the [_init] function to load the items for the
/// provided column.
class ItemsRepository with ChangeNotifier {
ItemsRepository({
required this.column,
}) {
ItemsRepository({required this.column}) {
_init();
}
@@ -275,7 +264,8 @@ class ItemsRepository with ChangeNotifier {
try {
await Supabase.instance.client
.from('items')
.update({'isRead': read}).eq('id', itemId);
.update({'isRead': read})
.eq('id', itemId);
for (var i = 0; i < _items.length; i++) {
if (_items[i].id == itemId) {
_items[i].isRead = read;
@@ -305,7 +295,8 @@ class ItemsRepository with ChangeNotifier {
for (var i = 0; i < chunks.length; i++) {
await Supabase.instance.client
.from('items')
.update({'isRead': read}).inFilter('id', chunks[i]);
.update({'isRead': read})
.inFilter('id', chunks[i]);
for (var j = 0; j < _items.length; j++) {
if (chunks[i].contains(_items[j].id)) {
_items[j].isRead = read;
@@ -327,7 +318,8 @@ class ItemsRepository with ChangeNotifier {
try {
await Supabase.instance.client
.from('items')
.update({'isBookmarked': bookmarked}).eq('id', itemId);
.update({'isBookmarked': bookmarked})
.eq('id', itemId);
for (var i = 0; i < _items.length; i++) {
if (_items[i].id == itemId) {
_items[i].isBookmarked = bookmarked;
@@ -391,7 +383,7 @@ class ItemsRepositoryStore {
///
/// The best is to call the [set] function right before we call
/// `notifyListeners` in the repository.
set(
ItemsRepositoryStoreState set(
String columnId,
ItemsStatus status,
ItemsFilters filters,
@@ -407,7 +399,7 @@ class ItemsRepositoryStore {
/// [clear] deletes all the stored [_itemsRepositoryStoreStates] from the
/// store. This method can be used to clear the cache, e.g. when a user
/// changes the active deck or signes out.
clear() {
void clear() {
_itemsRepositoryStoreStates.clear();
}
}

View File

@@ -8,12 +8,10 @@ class Constants {
static const primary = Color(0xff49d3b4);
static const onPrimary = Color(0xff1f2229);
static const secondary = Color(0xff353a46);
static const onSecondary = Color(0xffe2e4e9);
static const onSecondary = Color(0xff49d3b4);
static const error = Color(0xffde4A40);
static const onError = Color(0xffe2e4e9);
static const background = Color(0xff1f2229);
static const onBackground = Color(0xffe2e4e9);
static const surface = Color(0xff353a46);
static const surface = Color(0xff1f2229);
static const onSurface = Color(0xffe2e4e9);
static const canvasColor = Color(0xff1f2229);
static const appBarBackgroundColor = Colors.transparent;
@@ -23,7 +21,7 @@ class Constants {
static const secondaryTextColor = Color(0xff9aa1b2);
static const dividerColor = Color(0xff2a2e38);
static const backgroundContainerBackgroundColor = Color(0xff14161a);
static const surfaceContainerBackgroundColor = Color(0xff14161a);
static const breakpoint = 600.0;
static const columnWidth = 352.0;

View File

@@ -4,24 +4,29 @@ import 'package:flutter/foundation.dart' show kIsWeb;
import 'package:url_launcher/url_launcher.dart';
/// [openUrl] can be used to open the given [url] in the platforms default
/// browser.
/// [openUrl] can be used to open the given [url] in the specified launch mode.
/// For iOS and Android we are using the In-App-Browser to launch the url, for
/// all other platforms we are using the external browser.
///
/// On Android we are not using the default launch mode
/// (`LaunchMode.platformDefault`), because the opened In-App-Browser is very
/// limited, so that we decided to use `LaunchMode.externalApplication` to open
/// the url.
/// We do not have to check if the launch mode is really supported, because
/// `launchUrl` will fallback to a supported launch mode, when our preferred
/// mode is not supported.
Future<void> openUrl(String url) async {
var launchMode = LaunchMode.platformDefault;
if (!kIsWeb) {
if (Platform.isAndroid) {
launchMode = LaunchMode.externalApplication;
}
if (kIsWeb) {
launchMode = LaunchMode.externalApplication;
} else if (Platform.isAndroid) {
launchMode = LaunchMode.inAppBrowserView;
} else if (Platform.isIOS) {
launchMode = LaunchMode.inAppBrowserView;
} else if (Platform.isMacOS) {
launchMode = LaunchMode.externalApplication;
} else if (Platform.isLinux) {
launchMode = LaunchMode.externalApplication;
} else if (Platform.isWindows) {
launchMode = LaunchMode.externalApplication;
}
await launchUrl(
Uri.parse(url),
mode: launchMode,
);
await launchUrl(Uri.parse(url), mode: launchMode);
}

View File

@@ -164,6 +164,8 @@ class _CreateColumnState extends State<CreateColumn> {
padding: const EdgeInsets.all(Constants.spacingMiddle),
child: ElevatedButton.icon(
style: ElevatedButton.styleFrom(
backgroundColor: Constants.secondary,
foregroundColor: Constants.onSecondary,
maximumSize: const Size.fromHeight(
Constants.elevatedButtonSize,
),

View File

@@ -101,7 +101,7 @@ class _ColumnLayoutHeaderState extends State<ColumnLayoutHeader> {
),
),
centerTitle: false,
backgroundColor: Constants.background,
backgroundColor: Constants.surface,
title: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
@@ -216,7 +216,7 @@ class _ColumnLayoutHeaderState extends State<ColumnLayoutHeader> {
width: double.infinity,
height: _showSettings,
decoration: const BoxDecoration(
color: Constants.backgroundContainerBackgroundColor,
color: Constants.surfaceContainerBackgroundColor,
),
padding: const EdgeInsets.all(Constants.spacingMiddle),
child: ColumnLayoutHeaderSettings(

View File

@@ -31,23 +31,22 @@ class _ColumnLayoutHeaderSettingsDeleteColumnState
/// [_showDeleteDialog] creates a new dialog, which is shown before the column
/// can be deleted. This is done to raise the awareness that the column,
/// sources and items which belongs to the column will also be deleted.
_showDeleteDialog() {
void _showDeleteDialog() {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
insetPadding: EdgeInsets.symmetric(
horizontal: MediaQuery.of(context).size.width >=
horizontal:
MediaQuery.of(context).size.width >=
(Constants.centeredFormMaxWidth +
2 * Constants.spacingMiddle)
? (MediaQuery.of(context).size.width -
Constants.centeredFormMaxWidth) /
2
Constants.centeredFormMaxWidth) /
2
: Constants.spacingMiddle,
),
title: const Text(
'Delete Column',
),
title: const Text('Delete Column'),
content: const Text(
'Do you really want to delete this column? This can not be undone and will also delete all sources, items and bookmarks related to this column.',
),
@@ -88,8 +87,10 @@ class _ColumnLayoutHeaderSettingsDeleteColumnState
});
try {
await Provider.of<AppRepository>(context, listen: false)
.deleteColumn(widget.column.id);
await Provider.of<AppRepository>(
context,
listen: false,
).deleteColumn(widget.column.id);
} catch (_) {
if (!mounted) return;
ScaffoldMessenger.of(context).showSnackBar(

View File

@@ -32,28 +32,66 @@ class ColumnLayoutHeaderSettingsSources extends StatefulWidget {
class _ColumnLayoutHeaderSettingsSourcesState
extends State<ColumnLayoutHeaderSettingsSources> {
/// [_proxyDecorator] is used to highlight the source which is currently
/// draged by the user.
Widget _proxyDecorator(Widget child, int index, Animation<double> animation) {
return Material(
elevation: 0,
color: Colors.transparent,
child: Stack(
children: [
Positioned(
top: 0,
left: 0,
right: 0,
bottom: 16,
child: Material(
borderRadius: BorderRadius.circular(16),
elevation: 24,
color: Colors.transparent,
),
),
child,
],
),
);
}
/// [_buildSourcesList] returns a list of all sources of the current column.
/// If the list of sources is empty it will return a [Container].
///
/// Each source in the list also contains a delete item, which can be used to
/// remove the source from the current column.
List<Widget> _buildSourcesList() {
Widget _buildSourcesList() {
if (widget.column.sources.isEmpty) {
return [Container()];
return Container();
}
List<Widget> columns = [];
return ReorderableListView.builder(
shrinkWrap: true,
buildDefaultDragHandles: false,
physics: const NeverScrollableScrollPhysics(),
onReorder: (int start, int current) {
final AppRepository appRepository = Provider.of<AppRepository>(
context,
listen: false,
);
for (var i = 0; i < widget.column.sources.length; i++) {
columns.add(
SourceListItem(
appRepository.updateSourcePositions(widget.column.id, start, current);
},
proxyDecorator: (Widget child, int index, Animation<double> animation) {
return _proxyDecorator(child, index, animation);
},
itemCount: widget.column.sources.length,
itemBuilder: (context, index) {
return SourceListItem(
key: Key(widget.column.sources[index].id),
columnId: widget.column.id,
source: widget.column.sources[i],
),
);
}
return columns;
sourceIndex: index,
source: widget.column.sources[index],
);
},
);
}
/// [_showAddSource] shows the [AddSource] widget within a modal bottom sheet
@@ -92,16 +130,16 @@ class _ColumnLayoutHeaderSettingsSourcesState
mainAxisAlignment: MainAxisAlignment.start,
children: [
ConstrainedBox(
constraints: const BoxConstraints(
maxHeight: 275,
),
constraints: const BoxConstraints(maxHeight: 275),
child: ListView(
padding: EdgeInsets.zero,
shrinkWrap: true,
children: [
..._buildSourcesList(),
_buildSourcesList(),
ElevatedButton.icon(
style: ElevatedButton.styleFrom(
backgroundColor: Constants.secondary,
foregroundColor: Constants.onSecondary,
maximumSize: const Size.fromHeight(
Constants.elevatedButtonSize,
),
@@ -114,9 +152,7 @@ class _ColumnLayoutHeaderSettingsSourcesState
),
label: const Text('Add Source'),
onPressed: () => _showAddSource(),
icon: const Icon(
Icons.add,
),
icon: const Icon(Icons.add),
),
],
),

View File

@@ -101,7 +101,7 @@ class _ColumnLayoutSearchState extends State<ColumnLayoutSearch> {
width: double.infinity,
height: _showFilters,
decoration: const BoxDecoration(
color: Constants.backgroundContainerBackgroundColor,
color: Constants.surfaceContainerBackgroundColor,
),
padding: const EdgeInsets.all(Constants.spacingMiddle),
child: Column(

View File

@@ -43,6 +43,8 @@ class _ConfirmationState extends State<Confirmation> {
case 'change-email-address':
return ElevatedButton.icon(
style: ElevatedButton.styleFrom(
backgroundColor: Constants.secondary,
foregroundColor: Constants.onSecondary,
maximumSize: const Size.fromHeight(
Constants.elevatedButtonSize,
),
@@ -57,6 +59,8 @@ class _ConfirmationState extends State<Confirmation> {
case 'confirm-signup':
return ElevatedButton.icon(
style: ElevatedButton.styleFrom(
backgroundColor: Constants.secondary,
foregroundColor: Constants.onSecondary,
maximumSize: const Size.fromHeight(
Constants.elevatedButtonSize,
),
@@ -71,6 +75,8 @@ class _ConfirmationState extends State<Confirmation> {
case 'reset-password':
return ElevatedButton.icon(
style: ElevatedButton.styleFrom(
backgroundColor: Constants.secondary,
foregroundColor: Constants.onSecondary,
maximumSize: const Size.fromHeight(
Constants.elevatedButtonSize,
),

View File

@@ -179,6 +179,10 @@ class _CreateDeckState extends State<CreateDeck> {
decoration: const InputDecoration(
border: OutlineInputBorder(),
labelText: 'Name',
hintText: 'e.g. News',
hintStyle: TextStyle(
color: Constants.secondaryTextColor,
),
),
validator: (value) => _validateDeckName(value),
onFieldSubmitted: (value) => _createDeck(),
@@ -189,6 +193,8 @@ class _CreateDeckState extends State<CreateDeck> {
),
ElevatedButton.icon(
style: ElevatedButton.styleFrom(
backgroundColor: Constants.secondary,
foregroundColor: Constants.onSecondary,
maximumSize: const Size.fromHeight(
Constants.elevatedButtonSize,
),

View File

@@ -110,7 +110,7 @@ class _SelectDeckState extends State<SelectDeck> {
@override
Widget build(BuildContext context) {
return Container(
color: Constants.background,
color: Constants.surface,
child: SafeArea(
child: Scaffold(
body: Center(

View File

@@ -30,7 +30,7 @@ class _DeckLayoutLargeState extends State<DeckLayoutLarge> {
/// [_openDrawer] opens the provided [widget] in the drawer of the scaffold,
/// by setting the [_drawer] state first and then opening the drawer.
_openDrawer(Widget widget) {
void _openDrawer(Widget widget) {
setState(() {
_drawer = widget;
});
@@ -63,20 +63,12 @@ class _DeckLayoutLargeState extends State<DeckLayoutLarge> {
size: 32,
),
label: Container(
padding: const EdgeInsets.only(
top: Constants.spacingExtraSmall,
),
constraints: const BoxConstraints(
minWidth: 54,
maxWidth: 54,
),
padding: const EdgeInsets.only(top: Constants.spacingExtraSmall),
constraints: const BoxConstraints(minWidth: 54, maxWidth: 54),
child: Text(
Characters(column.name)
.replaceAll(
Characters(''),
Characters('\u{200B}'),
)
.toString(),
Characters(
column.name,
).replaceAll(Characters(''), Characters('\u{200B}')).toString(),
textAlign: TextAlign.center,
style: const TextStyle(
fontSize: 10,
@@ -91,10 +83,7 @@ class _DeckLayoutLargeState extends State<DeckLayoutLarge> {
for (var i = widgets.length; i < 2; i++) {
widgets.add(
const NavigationRailDestination(
icon: Icon(
Icons.circle,
color: Colors.transparent,
),
icon: Icon(Icons.circle, color: Colors.transparent),
label: Text(''),
),
);
@@ -119,20 +108,13 @@ class _DeckLayoutLargeState extends State<DeckLayoutLarge> {
child: RichText(
textAlign: TextAlign.center,
text: const TextSpan(
style: TextStyle(
color: Constants.onSurface,
fontSize: 14.0,
),
style: TextStyle(color: Constants.onSurface, fontSize: 14.0),
children: [
TextSpan(
text: 'Add you first column by clicking on the plus icon (',
),
WidgetSpan(
child: Icon(Icons.add, size: 14.0),
),
TextSpan(
text: ') in the sidebar on the left side.',
),
WidgetSpan(child: Icon(Icons.add, size: 14.0)),
TextSpan(text: ') in the sidebar on the left side.'),
],
),
),
@@ -200,10 +182,7 @@ class _DeckLayoutLargeState extends State<DeckLayoutLarge> {
topRight: Radius.circular(Constants.spacingMiddle),
bottomRight: Radius.circular(Constants.spacingMiddle),
),
child: Drawer(
width: Constants.columnWidth,
child: _drawer,
),
child: Drawer(width: Constants.columnWidth, child: _drawer),
),
body: SafeArea(
child: Row(
@@ -211,7 +190,8 @@ class _DeckLayoutLargeState extends State<DeckLayoutLarge> {
SingleChildScrollView(
child: ConstrainedBox(
constraints: BoxConstraints(
minHeight: MediaQuery.of(context).size.height -
minHeight:
MediaQuery.of(context).size.height -
MediaQuery.of(context).padding.top -
MediaQuery.of(context).padding.bottom,
),
@@ -222,7 +202,7 @@ class _DeckLayoutLargeState extends State<DeckLayoutLarge> {
splashFactory: NoSplash.splashFactory,
),
child: NavigationRail(
backgroundColor: Constants.background,
backgroundColor: Constants.surface,
selectedIndex: null,
/// When a user selects a destination in the navigation
@@ -281,9 +261,7 @@ class _DeckLayoutLargeState extends State<DeckLayoutLarge> {
);
},
),
const SizedBox(
height: Constants.spacingMiddle,
),
const SizedBox(height: Constants.spacingMiddle),
],
),
),

View File

@@ -29,16 +29,15 @@ class DeckLayoutSmall extends StatelessWidget {
/// user before returning the index. If a column was deleted we reset the
/// index to 0.
int _getInitialIndex(BuildContext context, int columnsLength) {
final deckLayoutSmallInitialTabIndex = Provider.of<LayoutRepository>(
context,
listen: false,
).deckLayoutSmallInitialTabIndex;
final deckLayoutSmallInitialTabIndex =
Provider.of<LayoutRepository>(
context,
listen: false,
).deckLayoutSmallInitialTabIndex;
if (deckLayoutSmallInitialTabIndex >= columnsLength) {
Provider.of<LayoutRepository>(
context,
listen: false,
).deckLayoutSmallInitialTabIndex = 0;
Provider.of<LayoutRepository>(context, listen: false)
.deckLayoutSmallInitialTabIndex = 0;
return 0;
}
@@ -61,25 +60,20 @@ class DeckLayoutSmall extends StatelessWidget {
key: ValueKey(column.id),
height: 56,
icon: SourceIcon(
type: column.sources.isNotEmpty
? column.sources[0].type
: FDSourceType.none,
type:
column.sources.isNotEmpty
? column.sources[0].type
: FDSourceType.none,
icon: column.sources.isNotEmpty ? column.sources[0].icon : null,
size: 24,
),
iconMargin: const EdgeInsets.only(bottom: 0),
child: Container(
constraints: const BoxConstraints(
minWidth: 54,
maxWidth: 54,
),
constraints: const BoxConstraints(minWidth: 54, maxWidth: 54),
child: Text(
Characters(column.name)
.replaceAll(
Characters(''),
Characters('\u{200B}'),
)
.toString(),
Characters(
column.name,
).replaceAll(Characters(''), Characters('\u{200B}')).toString(),
textAlign: TextAlign.center,
style: const TextStyle(
fontSize: 10,
@@ -106,20 +100,13 @@ class DeckLayoutSmall extends StatelessWidget {
child: RichText(
textAlign: TextAlign.center,
text: const TextSpan(
style: TextStyle(
color: Constants.onSurface,
fontSize: 14.0,
),
style: TextStyle(color: Constants.onSurface, fontSize: 14.0),
children: [
TextSpan(
text: 'Add you first column by clicking on the plus icon (',
),
WidgetSpan(
child: Icon(Icons.add, size: 14.0),
),
TextSpan(
text: ') in the tab bar on the bottom.',
),
WidgetSpan(child: Icon(Icons.add, size: 14.0)),
TextSpan(text: ') in the tab bar on the bottom.'),
],
),
),
@@ -138,8 +125,17 @@ class DeckLayoutSmall extends StatelessWidget {
);
}
/// Return the TabBarView. Since it was requested in
/// https://github.com/feeddeck/feeddeck/issues/228 we removed the
/// `physics: const NeverScrollableScrollPhysics()` property, so that a user
/// can switch between tabs by swiping to the left and to the right.
///
/// After testing this didn't conflicted with the other scroll and swipe
/// gestures of the children, so it should be save to activate. In case this
/// doesn't workout well in the long term, we should re-add the `physics`
/// property to the widget.
return TabBarView(
physics: const NeverScrollableScrollPhysics(),
// physics: const NeverScrollableScrollPhysics(),
children: widgets,
);
}
@@ -157,10 +153,7 @@ class DeckLayoutSmall extends StatelessWidget {
child: Container(
decoration: const BoxDecoration(
border: Border(
top: BorderSide(
color: Constants.dividerColor,
width: 1,
),
top: BorderSide(color: Constants.dividerColor, width: 1),
),
),
child: Row(
@@ -170,8 +163,8 @@ class DeckLayoutSmall extends StatelessWidget {
child: Theme(
data: Theme.of(context).copyWith(
colorScheme: Theme.of(context).colorScheme.copyWith(
surfaceVariant: Colors.transparent,
),
surfaceContainerHighest: Colors.transparent,
),
),
child: TabBar(
isScrollable: true,
@@ -182,10 +175,8 @@ class DeckLayoutSmall extends StatelessWidget {
/// the [LayoutRepository] so that we can use it as
/// initial index when the widget is rebuild (e.g. when
/// a user switches between the large and small layout).
Provider.of<LayoutRepository>(
context,
listen: false,
).deckLayoutSmallInitialTabIndex = index;
Provider.of<LayoutRepository>(context, listen: false)
.deckLayoutSmallInitialTabIndex = index;
},
tabs: _buildTabs(context),
),
@@ -209,7 +200,7 @@ class DeckLayoutSmall extends StatelessWidget {
IconButton(
icon: const Icon(
Icons.add,
color: Constants.onSecondary,
color: Constants.onSurface,
),
onPressed: () {
showModalBottomSheet(
@@ -248,14 +239,15 @@ class DeckLayoutSmall extends StatelessWidget {
IconButton(
icon: const Icon(
Icons.settings,
color: Constants.onSecondary,
color: Constants.onSurface,
),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (BuildContext context) =>
const Settings(),
builder:
(BuildContext context) =>
const Settings(),
),
);
},
@@ -269,9 +261,7 @@ class DeckLayoutSmall extends StatelessWidget {
),
),
),
body: SafeArea(
child: _buildViews(context),
),
body: SafeArea(child: _buildViews(context)),
),
);
}

View File

@@ -169,6 +169,8 @@ class _FogotPasswordState extends State<FogotPassword> {
),
ElevatedButton.icon(
style: ElevatedButton.styleFrom(
backgroundColor: Constants.secondary,
foregroundColor: Constants.onSecondary,
maximumSize: const Size.fromHeight(
Constants.elevatedButtonSize,
),

View File

@@ -43,19 +43,21 @@ class _HomeState extends State<Home> {
if (uri
.toString()
.startsWith('app.feeddeck.feeddeck://signin-callback/')) {
Provider.of<AppRepository>(context, listen: false)
.signInWithCallback(uri)
.then((_) {
WidgetsBinding.instance.addPostFrameCallback((_) {
Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(
builder: (BuildContext context) => const DeckLayout(),
),
(route) => false,
);
});
}).catchError((_) {});
if (mounted) {
Provider.of<AppRepository>(context, listen: false)
.signInWithCallback(uri)
.then((_) {
WidgetsBinding.instance.addPostFrameCallback((_) {
Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(
builder: (BuildContext context) => const DeckLayout(),
),
(route) => false,
);
});
}).catchError((_) {});
}
}
});
}

View File

@@ -203,6 +203,8 @@ class ItemDetails extends StatelessWidget {
padding: const EdgeInsets.all(Constants.spacingMiddle),
child: ElevatedButton.icon(
style: ElevatedButton.styleFrom(
backgroundColor: Constants.secondary,
foregroundColor: Constants.onSecondary,
maximumSize: const Size.fromHeight(
Constants.elevatedButtonSize,
),

View File

@@ -1,5 +1,3 @@
library item_audio_player_init;
import 'item_audio_player_init_stub.dart'
if (dart.library.io) 'item_audio_player_init_native.dart'
if (dart.library.html) 'item_audio_player_init_web.dart';

View File

@@ -62,7 +62,7 @@ class _ItemAudioPlayerSeekBarState extends State<ItemAudioPlayerSeekBar> {
data: _sliderThemeData.copyWith(
thumbShape: HiddenThumbComponentShape(),
activeTrackColor: Constants.secondary,
inactiveTrackColor: Constants.backgroundContainerBackgroundColor,
inactiveTrackColor: Constants.surfaceContainerBackgroundColor,
),
child: ExcludeSemantics(
child: Slider(

View File

@@ -10,11 +10,7 @@ import 'package:feeddeck/widgets/utils/cached_network_image.dart';
/// The [DescriptionFormat] enum defines the source and target format of a
/// description.
enum DescriptionFormat {
html,
markdown,
plain,
}
enum DescriptionFormat { html, markdown, plain }
/// The [ItemDescription] widget displays the description of an item. The
/// provided [itemDescription] is converted from the [sourceFormat] to the
@@ -51,17 +47,10 @@ class ItemDescription extends StatelessWidget {
fontFamily: getMonospaceFontFamily(),
backgroundColor: Constants.secondary,
),
codeblockDecoration: const BoxDecoration(
color: Constants.secondary,
),
codeblockDecoration: const BoxDecoration(color: Constants.secondary),
blockquoteDecoration: const BoxDecoration(
color: Constants.secondary,
border: Border(
left: BorderSide(
color: Constants.primary,
width: 1,
),
),
border: Border(left: BorderSide(color: Constants.primary, width: 1)),
),
),
onTapLink: (text, href, title) {
@@ -69,15 +58,17 @@ class ItemDescription extends StatelessWidget {
_openUrl(href);
}
},
// TODO: The "flutter_markdown" package is deprecated and we have to
// replace it with an alternative.
// See: https://pub.dev/packages/flutter_markdown
// ignore: deprecated_member_use
imageBuilder: (uri, title, alt) {
if (disableImages == true) {
return Container();
}
return Container(
padding: const EdgeInsets.only(
bottom: Constants.spacingMiddle,
),
padding: const EdgeInsets.only(bottom: Constants.spacingMiddle),
child: MouseRegion(
cursor: SystemMouseCursors.click,
child: GestureDetector(
@@ -88,9 +79,7 @@ class ItemDescription extends StatelessWidget {
isDismissible: true,
useSafeArea: true,
backgroundColor: Colors.black,
constraints: const BoxConstraints(
maxWidth: double.infinity,
),
constraints: const BoxConstraints(maxWidth: double.infinity),
builder: (BuildContext context) {
return Scaffold(
backgroundColor: Colors.black,
@@ -108,9 +97,7 @@ class ItemDescription extends StatelessWidget {
top: Constants.spacingExtraSmall,
right: Constants.spacingExtraSmall,
child: IconButton(
icon: const Icon(
Icons.close,
),
icon: const Icon(Icons.close),
onPressed: () {
Navigator.of(context).pop();
},
@@ -141,10 +128,7 @@ class ItemDescription extends StatelessWidget {
return SelectableText(
content.trim(),
textAlign: TextAlign.left,
style: const TextStyle(
fontWeight: FontWeight.normal,
fontSize: 14,
),
style: const TextStyle(fontWeight: FontWeight.normal, fontSize: 14),
);
}

View File

@@ -1,5 +1,3 @@
library item_piped_video;
import 'package:flutter/material.dart';
import 'item_piped_video_stub.dart'

View File

@@ -1,9 +1,9 @@
import 'dart:html'; // ignore: avoid_web_libraries_in_flutter
import 'dart:ui' as ui;
import 'dart:ui_web' as ui;
import 'package:flutter/material.dart';
import 'package:web/web.dart';
import 'package:feeddeck/utils/constants.dart';
import 'item_piped_video.dart';
@@ -42,7 +42,7 @@ class ItemPipedVideoWeb extends StatefulWidget implements ItemPipedVideo {
}
class _ItemPipedVideoWebState extends State<ItemPipedVideoWeb> {
final IFrameElement _iframeElement = IFrameElement();
final HTMLIFrameElement _iframeElement = HTMLIFrameElement();
@override
void initState() {
@@ -52,7 +52,6 @@ class _ItemPipedVideoWebState extends State<ItemPipedVideoWeb> {
_iframeElement.style.border = 'none';
_iframeElement.allowFullscreen = true;
// ignore: undefined_prefixed_name
ui.platformViewRegistry.registerViewFactory(
widget.videoUrl,
(int viewId) => _iframeElement,
@@ -62,9 +61,7 @@ class _ItemPipedVideoWebState extends State<ItemPipedVideoWeb> {
@override
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.only(
bottom: Constants.spacingMiddle,
),
padding: const EdgeInsets.only(bottom: Constants.spacingMiddle),
child: LayoutBuilder(
builder: (context, constraints) {
return Center(
@@ -84,7 +81,4 @@ class _ItemPipedVideoWebState extends State<ItemPipedVideoWeb> {
}
ItemPipedVideo getItemPipedVideo(String? imageUrl, String videoUrl) =>
ItemPipedVideoWeb(
imageUrl: imageUrl,
videoUrl: videoUrl,
);
ItemPipedVideoWeb(imageUrl: imageUrl, videoUrl: videoUrl);

View File

@@ -12,10 +12,7 @@ import 'package:feeddeck/utils/constants.dart';
/// played by the user. If the [videos] list is empty or null, the widget will
/// not be displayed.
class ItemVideos extends StatelessWidget {
const ItemVideos({
super.key,
required this.videos,
});
const ItemVideos({super.key, required this.videos});
final List<String>? videos;
@@ -38,10 +35,7 @@ class ItemVideos extends StatelessWidget {
/// The [ItemVideoQuality] class is used to store the different qualities of a
/// video. It is used in combination with the [ItemVideoPlayer] widget.
class ItemVideoQuality {
const ItemVideoQuality({
required this.quality,
required this.video,
});
const ItemVideoQuality({required this.quality, required this.video});
final String quality;
final String video;
@@ -96,15 +90,13 @@ class _ItemVideoPlayerState extends State<ItemVideoPlayer> {
builder: (BuildContext context) {
return SafeArea(
child: Container(
margin: const EdgeInsets.all(
Constants.spacingMiddle,
),
margin: const EdgeInsets.all(Constants.spacingMiddle),
padding: const EdgeInsets.only(
left: Constants.spacingMiddle,
right: Constants.spacingMiddle,
),
decoration: const BoxDecoration(
color: Constants.background,
color: Constants.surface,
borderRadius: BorderRadius.all(
Radius.circular(Constants.spacingMiddle),
),
@@ -112,41 +104,42 @@ class _ItemVideoPlayerState extends State<ItemVideoPlayer> {
child: Wrap(
alignment: WrapAlignment.center,
crossAxisAlignment: WrapCrossAlignment.center,
children: widget.qualities!
.asMap()
.entries
.map((quality) {
if (quality.key == widget.qualities!.length - 1) {
return [
ListTile(
mouseCursor: SystemMouseCursors.click,
onTap: () async {
Navigator.of(context).pop();
await _playerOpen(quality.value.video);
},
title: Text(quality.value.quality),
),
];
}
children:
widget.qualities!
.asMap()
.entries
.map((quality) {
if (quality.key == widget.qualities!.length - 1) {
return [
ListTile(
mouseCursor: SystemMouseCursors.click,
onTap: () async {
Navigator.of(context).pop();
await _playerOpen(quality.value.video);
},
title: Text(quality.value.quality),
),
];
}
return [
ListTile(
mouseCursor: SystemMouseCursors.click,
onTap: () async {
Navigator.of(context).pop();
await _playerOpen(quality.value.video);
},
title: Text(quality.value.quality),
),
const Divider(
color: Constants.dividerColor,
height: 1,
thickness: 1,
),
];
})
.expand((e) => e)
.toList(),
return [
ListTile(
mouseCursor: SystemMouseCursors.click,
onTap: () async {
Navigator.of(context).pop();
await _playerOpen(quality.value.video);
},
title: Text(quality.value.quality),
),
const Divider(
color: Constants.dividerColor,
height: 1,
thickness: 1,
),
];
})
.expand((e) => e)
.toList(),
),
),
);
@@ -209,20 +202,13 @@ class _ItemVideoPlayerState extends State<ItemVideoPlayer> {
/// [_playerOpen] opens the video player with the provided [video] and sets
/// the audio track if it is provided via the [audio] parameter.
Future<void> _playerOpen(String video) async {
await player.open(
Media(video),
play: false,
);
await player.open(Media(video), play: false);
/// Load an external audio track when it is provided via the [audio]
/// parameter.
/// See: https://github.com/media-kit/media-kit?tab=readme-ov-file#load-external-audio-track
if (widget.audio != null) {
await player.setAudioTrack(
AudioTrack.uri(
widget.audio!,
),
);
await player.setAudioTrack(AudioTrack.uri(widget.audio!));
}
}
@@ -243,9 +229,7 @@ class _ItemVideoPlayerState extends State<ItemVideoPlayer> {
@override
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.only(
bottom: Constants.spacingMiddle,
),
padding: const EdgeInsets.only(bottom: Constants.spacingMiddle),
child: LayoutBuilder(
builder: (context, constraints) {
return Center(
@@ -274,12 +258,13 @@ class _ItemVideoPlayerState extends State<ItemVideoPlayer> {
),
child: Video(
controller: controller,
controls: kIsWeb ||
Platform.isLinux ||
Platform.isMacOS ||
Platform.isWindows
? MaterialDesktopVideoControls
: MaterialVideoControls,
controls:
kIsWeb ||
Platform.isLinux ||
Platform.isMacOS ||
Platform.isWindows
? MaterialDesktopVideoControls
: MaterialVideoControls,
),
),
),

View File

@@ -1,5 +1,3 @@
library item_youtube_video;
import 'package:flutter/material.dart';
import 'item_youtube_video_stub.dart'

View File

@@ -6,6 +6,15 @@ import 'package:feeddeck/widgets/item/details/utils/item_media.dart';
import 'package:feeddeck/widgets/item/details/utils/item_videos.dart';
import 'item_youtube_video.dart';
/// [FeFetchVideoUrlsResponse] is the model returned by the [_fetchVideoUrls]
/// function. It contains a list of [videos] and an optional [audio] file.
class FetchVideoUrlsResponse {
const FetchVideoUrlsResponse({required this.videos, required this.audio});
final List<ItemVideoQuality> videos;
final String? audio;
}
class ItemYoutubeVideoNative extends StatefulWidget
implements ItemYoutubeVideo {
const ItemYoutubeVideoNative({
@@ -23,21 +32,47 @@ class ItemYoutubeVideoNative extends StatefulWidget
class _ItemYoutubeVideoNativeState extends State<ItemYoutubeVideoNative> {
final yt = YoutubeExplode();
late Future<List<ItemVideoQuality>> _futureFetchVideoUrls;
late Future<FetchVideoUrlsResponse> _futureFetchVideoUrls;
Future<List<ItemVideoQuality>> _fetchVideoUrls() async {
/// [_fetchVideoUrls] fetches all video urls from YouTube via the
/// [youtube_explode_dart] package. If the `muxed` field contains any items,
/// we use them to return the video, because it contains the video and audio
/// file. If the list is empty we use the `videoOnly` list to get the list of
/// videos and the `audioOnly` field to get a corresponding audio track.
Future<FetchVideoUrlsResponse> _fetchVideoUrls() async {
final streamManifest = await yt.videos.streamsClient.getManifest(
widget.videoUrl,
);
return streamManifest.muxed
.sortByVideoQuality()
.map(
(element) => ItemVideoQuality(
quality: element.qualityLabel,
video: element.url.toString(),
),
)
.toList();
if (streamManifest.muxed.isNotEmpty) {
return FetchVideoUrlsResponse(
videos:
streamManifest.video
.sortByVideoQuality()
.map(
(element) => ItemVideoQuality(
quality: element.qualityLabel,
video: element.url.toString(),
),
)
.toList(),
audio: null,
);
}
return FetchVideoUrlsResponse(
videos:
streamManifest.videoOnly
.sortByVideoQuality()
.map(
(element) => ItemVideoQuality(
quality: element.qualityLabel,
video: element.url.toString(),
),
)
.toList(),
audio: streamManifest.audioOnly.sortByBitrate()[1].url.toString(),
);
}
@override
@@ -60,19 +95,20 @@ class _ItemYoutubeVideoNativeState extends State<ItemYoutubeVideoNative> {
future: _futureFetchVideoUrls,
builder: (
BuildContext context,
AsyncSnapshot<List<ItemVideoQuality>> snapshot,
AsyncSnapshot<FetchVideoUrlsResponse> snapshot,
) {
if (snapshot.connectionState == ConnectionState.none ||
snapshot.connectionState == ConnectionState.waiting ||
snapshot.hasError ||
snapshot.data == null ||
snapshot.data!.isEmpty) {
snapshot.data!.videos.isEmpty) {
return ItemMedia(itemMedia: widget.imageUrl);
}
return ItemVideoPlayer(
video: snapshot.data!.first.video,
qualities: snapshot.data,
video: snapshot.data!.videos.first.video,
audio: snapshot.data!.audio,
qualities: snapshot.data!.videos,
);
},
);
@@ -80,7 +116,4 @@ class _ItemYoutubeVideoNativeState extends State<ItemYoutubeVideoNative> {
}
ItemYoutubeVideo getItemYoutubeVideo(String? imageUrl, String videoUrl) =>
ItemYoutubeVideoNative(
imageUrl: imageUrl,
videoUrl: videoUrl,
);
ItemYoutubeVideoNative(imageUrl: imageUrl, videoUrl: videoUrl);

View File

@@ -1,9 +1,9 @@
import 'dart:html'; // ignore: avoid_web_libraries_in_flutter
import 'dart:ui' as ui;
import 'dart:ui_web' as ui;
import 'package:flutter/material.dart';
import 'package:web/web.dart';
import 'package:feeddeck/utils/constants.dart';
import 'item_youtube_video.dart';
@@ -18,17 +18,11 @@ String _convertVideoUrl(String videoUrl) {
}
if (videoUrl.startsWith('https://www.youtube.com/watch?v=')) {
return 'https://www.youtube-nocookie.com/embed/${videoUrl.replaceFirst(
'https://www.youtube.com/watch?v=',
'',
)}';
return 'https://www.youtube-nocookie.com/embed/${videoUrl.replaceFirst('https://www.youtube.com/watch?v=', '')}';
}
if (videoUrl.startsWith('https://m.youtube.com/watch?v=')) {
return 'https://www.youtube-nocookie.com/embed/${videoUrl.replaceFirst(
'https://m.youtube.com/watch?v=',
'',
)}';
return 'https://www.youtube-nocookie.com/embed/${videoUrl.replaceFirst('https://m.youtube.com/watch?v=', '')}';
}
return videoUrl;
@@ -49,7 +43,7 @@ class ItemYoutubeVideoWeb extends StatefulWidget implements ItemYoutubeVideo {
}
class _ItemYoutubeVideoWebState extends State<ItemYoutubeVideoWeb> {
final IFrameElement _iframeElement = IFrameElement();
final HTMLIFrameElement _iframeElement = HTMLIFrameElement();
@override
void initState() {
@@ -59,7 +53,6 @@ class _ItemYoutubeVideoWebState extends State<ItemYoutubeVideoWeb> {
_iframeElement.style.border = 'none';
_iframeElement.allowFullscreen = true;
// ignore: undefined_prefixed_name
ui.platformViewRegistry.registerViewFactory(
widget.videoUrl,
(int viewId) => _iframeElement,
@@ -69,9 +62,7 @@ class _ItemYoutubeVideoWebState extends State<ItemYoutubeVideoWeb> {
@override
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.only(
bottom: Constants.spacingMiddle,
),
padding: const EdgeInsets.only(bottom: Constants.spacingMiddle),
child: LayoutBuilder(
builder: (context, constraints) {
return Center(
@@ -91,7 +82,4 @@ class _ItemYoutubeVideoWebState extends State<ItemYoutubeVideoWeb> {
}
ItemYoutubeVideo getItemYoutubeVideo(String? imageUrl, String videoUrl) =>
ItemYoutubeVideoWeb(
imageUrl: imageUrl,
videoUrl: videoUrl,
);
ItemYoutubeVideoWeb(imageUrl: imageUrl, videoUrl: videoUrl);

View File

@@ -195,7 +195,7 @@ class _ItemActionsState extends State<ItemActions> {
right: Constants.spacingMiddle,
),
decoration: const BoxDecoration(
color: Constants.background,
color: Constants.surface,
borderRadius: BorderRadius.all(
Radius.circular(Constants.spacingMiddle),
),

View File

@@ -10,11 +10,7 @@ import 'package:feeddeck/widgets/utils/cached_network_image.dart';
/// The [DescriptionFormat] enum defines the source and target format of a
/// description.
enum DescriptionFormat {
html,
markdown,
plain,
}
enum DescriptionFormat { html, markdown, plain }
/// The [ItemDescription] widget displays the description of an item. The
/// provided [itemDescription] is converted from the [sourceFormat] to the
@@ -41,9 +37,7 @@ class ItemDescription extends StatelessWidget {
/// [_buildMarkdown] renders the provided [content] as markdown.
Widget _buildMarkdown(String content) {
return Container(
padding: const EdgeInsets.only(
bottom: Constants.spacingExtraSmall,
),
padding: const EdgeInsets.only(bottom: Constants.spacingExtraSmall),
child: MarkdownBody(
selectable: false,
data: content.trim(),
@@ -52,16 +46,11 @@ class ItemDescription extends StatelessWidget {
fontFamily: getMonospaceFontFamily(),
backgroundColor: Constants.secondary,
),
codeblockDecoration: const BoxDecoration(
color: Constants.secondary,
),
codeblockDecoration: const BoxDecoration(color: Constants.secondary),
blockquoteDecoration: const BoxDecoration(
color: Constants.secondary,
border: Border(
left: BorderSide(
color: Constants.primary,
width: 1,
),
left: BorderSide(color: Constants.primary, width: 1),
),
),
),
@@ -70,11 +59,13 @@ class ItemDescription extends StatelessWidget {
_openUrl(href);
}
},
// TODO: The "flutter_markdown" package is deprecated and we have to
// replace it with an alternative.
// See: https://pub.dev/packages/flutter_markdown
// ignore: deprecated_member_use
imageBuilder: (uri, title, alt) {
return Container(
padding: const EdgeInsets.only(
bottom: Constants.spacingExtraSmall,
),
padding: const EdgeInsets.only(bottom: Constants.spacingExtraSmall),
child: CachedNetworkImage(
width: double.infinity,
height: 200,
@@ -100,9 +91,7 @@ class ItemDescription extends StatelessWidget {
}
return Container(
padding: const EdgeInsets.only(
bottom: Constants.spacingExtraSmall,
),
padding: const EdgeInsets.only(bottom: Constants.spacingExtraSmall),
child: Text(
content.trim().split('\n').where((line) => line != '').join('\n'),
maxLines: 5,

View File

@@ -125,6 +125,8 @@ class _ResetPasswordState extends State<ResetPassword> {
),
ElevatedButton.icon(
style: ElevatedButton.styleFrom(
backgroundColor: Constants.secondary,
foregroundColor: Constants.onSecondary,
maximumSize: const Size.fromHeight(
Constants.elevatedButtonSize,
),
@@ -152,6 +154,8 @@ class _ResetPasswordState extends State<ResetPassword> {
),
ElevatedButton.icon(
style: ElevatedButton.styleFrom(
backgroundColor: Constants.secondary,
foregroundColor: Constants.onSecondary,
maximumSize: const Size.fromHeight(
Constants.elevatedButtonSize,
),

View File

@@ -235,6 +235,8 @@ class _SetSettingsState extends State<SetSettings> {
),
ElevatedButton.icon(
style: ElevatedButton.styleFrom(
backgroundColor: Constants.secondary,
foregroundColor: Constants.onSecondary,
maximumSize: const Size.fromHeight(
Constants.elevatedButtonSize,
),
@@ -253,6 +255,8 @@ class _SetSettingsState extends State<SetSettings> {
),
ElevatedButton.icon(
style: ElevatedButton.styleFrom(
backgroundColor: Constants.secondary,
foregroundColor: Constants.onSecondary,
maximumSize: const Size.fromHeight(
Constants.elevatedButtonSize,
),

View File

@@ -290,6 +290,8 @@ class _SettingsAccountsGithubAddState extends State<SettingsAccountsGithubAdd> {
padding: const EdgeInsets.all(Constants.spacingMiddle),
child: ElevatedButton.icon(
style: ElevatedButton.styleFrom(
backgroundColor: Constants.secondary,
foregroundColor: Constants.onSecondary,
maximumSize: const Size.fromHeight(
Constants.elevatedButtonSize,
),

View File

@@ -28,7 +28,7 @@ class SettingsAccountsActions extends StatelessWidget {
right: Constants.spacingMiddle,
),
decoration: const BoxDecoration(
color: Constants.background,
color: Constants.surface,
borderRadius: BorderRadius.all(
Radius.circular(Constants.spacingMiddle),
),

View File

@@ -0,0 +1,29 @@
import 'package:flutter/material.dart';
import 'package:feeddeck/utils/constants.dart';
import 'package:feeddeck/widgets/settings/app_settings/app_settings_export.dart';
import 'package:feeddeck/widgets/settings/app_settings/app_settings_import.dart';
/// The [SettSettingsAppSettings] widget is used to display a list of all
/// available app settings, which can be used to customize the app by the user
/// and to import and export data.
class SettingsAppSettings extends StatelessWidget {
const SettingsAppSettings({super.key});
@override
Widget build(BuildContext context) {
return const Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'App Settings',
style: TextStyle(fontSize: 20.0, fontWeight: FontWeight.bold),
),
SizedBox(height: Constants.spacingSmall),
SettingsAppSettingsExport(),
SettingsAppSettingsImport(),
SizedBox(height: Constants.spacingMiddle),
],
);
}
}

View File

@@ -0,0 +1,356 @@
import 'dart:convert';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:file_picker/file_picker.dart';
import 'package:provider/provider.dart';
import 'package:supabase_flutter/supabase_flutter.dart';
import 'package:xml/xml.dart';
import 'package:feeddeck/models/column.dart';
import 'package:feeddeck/models/deck.dart';
import 'package:feeddeck/models/source.dart';
import 'package:feeddeck/repositories/app_repository.dart';
import 'package:feeddeck/utils/constants.dart';
import 'package:feeddeck/widgets/general/elevated_button_progress_indicator.dart';
class SettingsAppSettingsExport extends StatelessWidget {
const SettingsAppSettingsExport({super.key});
@override
Widget build(BuildContext context) {
return MouseRegion(
cursor: SystemMouseCursors.click,
child: GestureDetector(
onTap: () {
showModalBottomSheet(
context: context,
isScrollControlled: true,
isDismissible: true,
useSafeArea: true,
backgroundColor: Colors.transparent,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(
top: Radius.circular(Constants.spacingMiddle),
),
),
clipBehavior: Clip.antiAliasWithSaveLayer,
constraints: const BoxConstraints(
maxWidth: Constants.centeredFormMaxWidth,
),
builder: (BuildContext context) {
return Export();
},
);
},
child: Card(
color: Constants.secondary,
margin: const EdgeInsets.only(bottom: Constants.spacingSmall),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Padding(
padding: const EdgeInsets.all(Constants.spacingMiddle),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
Characters('Export')
.replaceAll(
Characters(''),
Characters('\u{200B}'),
)
.toString(),
maxLines: 1,
style: const TextStyle(
overflow: TextOverflow.ellipsis,
),
),
],
),
),
Icon(Icons.download),
],
),
),
],
),
),
),
);
}
}
class Export extends StatefulWidget {
const Export({super.key});
@override
State<Export> createState() => _ExportState();
}
class _ExportState extends State<Export> {
FDDeck? _selectedDeck;
bool _isLoading = false;
String _success = '';
String _error = '';
/// [_export] is the function to export a deck as OPML file. In the first step
/// we have to get the columns for the selected deck and all sources for all
/// the columns of the deck. Afterwards we create the OPML file and save it.
Future<void> _export() async {
setState(() {
_isLoading = true;
_success = '';
_error = '';
});
/// If the [_selectedDeckId] is an empty string the user didn't selected a
/// deck which should be exported, so that we return an error.
if (_selectedDeck == null) {
setState(() {
_error = 'Please select a deck to export.';
_isLoading = false;
});
return;
}
try {
/// Get all the columns for the [_selectedDeckId].
final data = await Supabase.instance.client
.from('columns')
.select('id, name, position')
.eq('deckId', _selectedDeck!.id)
.order('position', ascending: true);
final columns = List<FDColumn>.from(
data.map((column) => FDColumn.fromJson(column)),
);
/// Loop through all the columns and get the sources for each column. The
/// sources are then added to the `sources` field of the column.
for (var i = 0; i < columns.length; i++) {
final data = await Supabase.instance.client
.from('sources')
.select('id, type, title, options, link, icon')
.eq('columnId', columns[i].id)
.order('position', ascending: true, nullsFirst: false)
.order('createdAt', ascending: true);
columns[i].sources = List<FDSource>.from(
data.map((source) => FDSource.fromJson(source)),
);
}
/// Build the OPML file. Here we only add the `opml` tag with the `head`
/// and `body` tags. The `head` tag contains the deck name within the
/// `title` tag. To fill the body we go through all columns to create a
/// `outline` tag for each column and a nested `outline` tag for each
/// souce. This is handled by the [toXml] methhod of the corresponding
/// models.
var builder = XmlBuilder();
builder.processing('xml', 'version="1.0" encoding="utf-8"');
builder.element(
'opml',
nest: () {
builder.attribute('version', '2.0');
builder.element(
'head',
nest: () {
builder.element(
'title',
nest: () {
builder.text(_selectedDeck!.name);
},
);
},
);
builder.element(
'body',
nest: () {
for (var i = 0; i < columns.length; i++) {
columns[i].toXml(builder);
}
},
);
},
);
final opml = builder.buildDocument().toXmlString(pretty: true);
/// On native platforms the file name should not contain the extension,
/// otherwise the extension is added twice. On the web the file name must
/// contain the extension.
String fileName = 'feeddeck-export-${_selectedDeck!.id}';
if (kIsWeb) {
fileName = 'feeddeck-export-${_selectedDeck!.id}.opml';
}
/// Open a file picker to let the user save the OPML file. When the file
/// is saved successfully the file picker will return the file path on
/// native platforms. If the file path is `null` the user aborted the
/// export. On the web the file path will always be empty, so that we can
/// directly display a [_success] message.
final filePath = await FilePicker.platform.saveFile(
allowedExtensions: ['opml'],
type: FileType.custom,
dialogTitle: 'Export',
fileName: fileName,
lockParentWindow: true,
bytes: utf8.encode(opml),
);
if (kIsWeb) {
setState(() {
_success = 'Export successful';
_isLoading = false;
});
return;
}
if (filePath == null) {
setState(() {
_isLoading = false;
});
return;
}
setState(() {
_success = 'Export successful: $filePath';
_isLoading = false;
});
} catch (err) {
setState(() {
_error = 'Export failed: ${err.toString()}';
_isLoading = false;
});
}
}
/// [_buildSuccess] returns a widget to display the [_success] when it is not
/// an empty string.
Widget _buildSuccess() {
if (_success != '') {
return Padding(
padding: const EdgeInsets.all(Constants.spacingMiddle),
child: Text(_success, style: const TextStyle(color: Constants.primary)),
);
}
return Container();
}
/// [_buildError] returns a widget to display the [_error] when it is not an
/// empty string.
Widget _buildError() {
if (_error != '') {
return Padding(
padding: const EdgeInsets.all(Constants.spacingMiddle),
child: Text(_error, style: const TextStyle(color: Constants.error)),
);
}
return Container();
}
@override
Widget build(BuildContext context) {
AppRepository app = Provider.of<AppRepository>(context, listen: true);
return Scaffold(
appBar: AppBar(
automaticallyImplyLeading: false,
shape: const Border(
bottom: BorderSide(color: Constants.dividerColor, width: 1),
),
title: Text('Export'),
actions: [
IconButton(
icon: const Icon(Icons.close),
onPressed: () {
Navigator.of(context).pop();
},
),
],
),
body: SafeArea(
child: Column(
children: [
Expanded(
child: Padding(
padding: const EdgeInsets.all(Constants.spacingMiddle),
child: SingleChildScrollView(
child: Column(
children: [
Text(
'Select a deck, which should be exported from the following list. Click the "Export" button afterwards to save the deck as OPML file.',
),
const SizedBox(height: Constants.spacingMiddle),
ListView.builder(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemCount: app.decks.length,
itemBuilder: (context, index) {
return RadioListTile(
title: Text(app.decks[index].name),
dense: true,
visualDensity: const VisualDensity(
horizontal: VisualDensity.minimumDensity,
vertical: VisualDensity.minimumDensity,
),
value: app.decks[index].id,
groupValue: _selectedDeck?.id,
onChanged: (String? deckId) {
if (deckId != null) {
setState(() {
_selectedDeck = app.decks[index];
});
}
},
);
},
),
],
),
),
),
),
const SizedBox(height: Constants.spacingSmall),
const Divider(
color: Constants.dividerColor,
height: 1,
thickness: 1,
),
_buildSuccess(),
_buildError(),
Padding(
padding: const EdgeInsets.all(Constants.spacingMiddle),
child: ElevatedButton.icon(
style: ElevatedButton.styleFrom(
backgroundColor: Constants.secondary,
foregroundColor: Constants.onSecondary,
maximumSize: const Size.fromHeight(
Constants.elevatedButtonSize,
),
minimumSize: const Size.fromHeight(
Constants.elevatedButtonSize,
),
),
label: const Text('Export'),
onPressed: _isLoading ? null : _export,
icon:
_isLoading
? const ElevatedButtonProgressIndicator()
: const Icon(Icons.download),
),
),
],
),
),
);
}
}

View File

@@ -0,0 +1,435 @@
import 'dart:convert';
import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:file_picker/file_picker.dart';
import 'package:provider/provider.dart';
import 'package:supabase_flutter/supabase_flutter.dart';
import 'package:xml/xml.dart';
import 'package:feeddeck/models/column.dart';
import 'package:feeddeck/models/deck.dart';
import 'package:feeddeck/models/source.dart';
import 'package:feeddeck/repositories/app_repository.dart';
import 'package:feeddeck/utils/constants.dart';
import 'package:feeddeck/widgets/general/elevated_button_progress_indicator.dart';
class SettingsAppSettingsImport extends StatelessWidget {
const SettingsAppSettingsImport({super.key});
@override
Widget build(BuildContext context) {
return MouseRegion(
cursor: SystemMouseCursors.click,
child: GestureDetector(
onTap: () {
showModalBottomSheet(
context: context,
isScrollControlled: true,
isDismissible: true,
useSafeArea: true,
backgroundColor: Colors.transparent,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(
top: Radius.circular(Constants.spacingMiddle),
),
),
clipBehavior: Clip.antiAliasWithSaveLayer,
constraints: const BoxConstraints(
maxWidth: Constants.centeredFormMaxWidth,
),
builder: (BuildContext context) {
return Import();
},
);
},
child: Card(
color: Constants.secondary,
margin: const EdgeInsets.only(bottom: Constants.spacingSmall),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Padding(
padding: const EdgeInsets.all(Constants.spacingMiddle),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
Characters('Import')
.replaceAll(
Characters(''),
Characters('\u{200B}'),
)
.toString(),
maxLines: 1,
style: const TextStyle(
overflow: TextOverflow.ellipsis,
),
),
],
),
),
Icon(Icons.upload),
],
),
),
],
),
),
),
);
}
}
class Import extends StatefulWidget {
const Import({super.key});
@override
State<Import> createState() => _ExportState();
}
class _ExportState extends State<Import> {
bool _isLoading = false;
String _success = '';
String _error = '';
int _progressMax = 0;
int _progressCurrent = 0;
/// [_import] is the function to import a deck from a OPML file. In the first
/// step we let the user select a file. Then we parse the file and create a
/// new deck with all it's columns and sources.
Future<void> _import() async {
setState(() {
_isLoading = true;
_success = '';
_error = '';
_progressMax = 0;
_progressCurrent = 0;
});
try {
/// Show a file picker, where the user can select an OPML file, which will
/// be parsed in the following.
///
/// - For Android we have to unset the [allowedExtensions] and [type],
/// because of https://github.com/miguelpruivo/flutter_file_picker/issues/1689
/// - For iOS we have to unset the [allowedExtensions] and [type],
/// otherwise we can not select files in the file browser.
final files =
(await FilePicker.platform.pickFiles(
allowedExtensions:
!kIsWeb && (Platform.isAndroid || Platform.isIOS)
? null
: ['opml'],
type:
!kIsWeb && (Platform.isAndroid || Platform.isIOS)
? FileType.any
: FileType.custom,
allowMultiple: false,
dialogTitle: 'Import',
lockParentWindow: true,
withData: true,
))?.files;
/// If the list of selected files is empty or doesn't has a length of 1 or
/// the selected file is empty we return here. This can happen if the user
/// aborted the import and closed the file picker without selecting a
/// file.
if (files == null || files.length != 1 || files[0].bytes == null) {
setState(() {
_isLoading = false;
});
return;
}
/// Parse the selected OPML file and get the name of the deck which should
/// be created and all the columns and sources.
final opml = XmlDocument.parse(utf8.decode(files[0].bytes!));
final deckName =
opml
.getElement('opml')
?.getElement('head')
?.getElement('title')
?.innerText ??
'Unknown';
final columns = <FDColumn>[];
final unknownColumn = FDColumn(
id: '',
name: 'Unknown',
position: 0,
sources: [],
);
opml
.getElement('opml')
?.getElement('body')
?.findElements('outline')
.forEach((outline) {
/// If the `outline` element contains a `type` attribute, it must be
/// a source. This can happen if an OPML file from another RSS
/// reader is imported, which doesn't categorize the RSS feed.
///
/// In this case we try to parse the `outline` element as source and
/// add the source to the [unknownColumn] column.
if (outline.getAttribute('type') != null) {
final source = FDSource.fromXml(outline);
if (source.type != FDSourceType.none) {
unknownColumn.sources.add(source);
}
return;
}
/// If the `outline` element doesn't contain a `type` attribute, it
/// must be a column. This is the case for all exports from FeedDeck
/// and for OPML files from other vendors, which categorize their
/// feeds.
///
/// In this case we parse the `outline` element as column and add it
/// to the [columns]. Within the column parsing we also try to parse
/// all sibling `outline` elements as source and add it to the
/// column.
final column = FDColumn.fromXml(outline);
columns.add(column);
return;
});
/// If we have added sources to the [unknownColumn] column, we add it to
/// the list of [columns]. Otherwise we can ignore it.
if (unknownColumn.sources.isNotEmpty) {
columns.add(unknownColumn);
}
setState(() {
_progressMax = columns
.map((column) => column.sources.length)
.reduce((a, b) => a + b);
});
/// Create a new deck with the name ([deckName]) we retrieved earlier from
/// the selected OPML file.
final newDeck = FDDeck.fromJson(
await Supabase.instance.client
.from('decks')
.insert({
'name': deckName,
'userId': Supabase.instance.client.auth.currentUser!.id,
})
.select()
.single(),
);
final errors = <String>[];
/// Go through all the columns and sources we got from the OPML file and
/// create them in the newly created deck. If this process throws an error
/// we do not abort the import, instead we add the error to the list of
/// [errors].
for (var i = 0; i < columns.length; i++) {
try {
final newColumn = FDColumn.fromJson(
await Supabase.instance.client
.from('columns')
.insert({
'deckId': newDeck.id,
'userId': Supabase.instance.client.auth.currentUser!.id,
'name': columns[i].name,
'position': i,
})
.select()
.single(),
);
for (var j = 0; j < columns[i].sources.length; j++) {
try {
final result = await Supabase.instance.client.functions.invoke(
'add-or-update-source-v1',
body: {
'source': {
'id': '',
'columnId': newColumn.id,
'userId': '',
'type': columns[i].sources[j].type.toShortString(),
'title': '',
'options': columns[i].sources[j].options?.toJson(),
},
},
);
if (result.status != 200) {
errors.add('Failed to create source: ${result.data['error']}');
}
} catch (err) {
errors.add('Failed to create source: ${err.toString()}');
} finally {
setState(() {
_progressCurrent++;
});
}
}
} catch (err) {
errors.add('Failed to create column: ${err.toString()}');
}
}
/// When we have created the new deck with all it's columns and sources,
/// we trigger an update of the decks in the [AppRepository] so that the
/// new deck is also visible in the UI.
if (mounted) {
await Provider.of<AppRepository>(
context,
listen: false,
).getDecksWithNotifiy();
}
/// While creating all columns and sources we add the errors to the
/// [errors] list. If the list is empty everthing went fine. If the list
/// contains an error we show the error to the user.
if (errors.isNotEmpty) {
setState(() {
_success = 'Import successfull, with ${errors.length} errors';
_isLoading = false;
});
return;
}
setState(() {
_success = 'Import successfull';
_isLoading = false;
});
} catch (err) {
setState(() {
_error = 'Import failed: ${err.toString()}';
_isLoading = false;
});
}
}
/// [_buildSuccess] returns a widget to display the [_success] when it is not
/// an empty string.
Widget _buildSuccess() {
if (_success != '') {
return Padding(
padding: const EdgeInsets.all(Constants.spacingMiddle),
child: Text(_success, style: const TextStyle(color: Constants.primary)),
);
}
return Container();
}
/// [_buildError] returns a widget to display the [_error] when it is not an
/// empty string.
Widget _buildError() {
if (_error != '') {
return Padding(
padding: const EdgeInsets.all(Constants.spacingMiddle),
child: Text(_error, style: const TextStyle(color: Constants.error)),
);
}
return Container();
}
/// [_buildProgress] returns a widget to display the progress when the
/// [_progressMax] value if not 0.
Widget _buildProgress() {
if (_progressMax > 0) {
return Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Importing source $_progressCurrent of $_progressMax',
style: const TextStyle(color: Constants.primary),
),
LinearProgressIndicator(value: _progressCurrent / _progressMax),
],
);
}
return Container();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
automaticallyImplyLeading: false,
shape: const Border(
bottom: BorderSide(color: Constants.dividerColor, width: 1),
),
title: Text('Import'),
actions: [
IconButton(
icon: const Icon(Icons.close),
onPressed: () {
Navigator.of(context).pop();
},
),
],
),
body: SafeArea(
child: Column(
children: [
Expanded(
child: Padding(
padding: const EdgeInsets.all(Constants.spacingMiddle),
child: SingleChildScrollView(
child: Column(
children: [
Text(
'Click the "Import" button to select an OPML file. This action will create a new deck containing all the columns and sources from the OPML file.',
),
const SizedBox(height: Constants.spacingMiddle),
_buildProgress(),
],
),
),
),
),
const SizedBox(height: Constants.spacingSmall),
const Divider(
color: Constants.dividerColor,
height: 1,
thickness: 1,
),
_buildSuccess(),
_buildError(),
Padding(
padding: const EdgeInsets.all(Constants.spacingMiddle),
child: ElevatedButton.icon(
style: ElevatedButton.styleFrom(
backgroundColor: Constants.secondary,
foregroundColor: Constants.onSecondary,
maximumSize: const Size.fromHeight(
Constants.elevatedButtonSize,
),
minimumSize: const Size.fromHeight(
Constants.elevatedButtonSize,
),
),
label: const Text('Import'),
onPressed: _isLoading ? null : _import,
icon:
_isLoading
? const ElevatedButtonProgressIndicator()
: const Icon(Icons.upload),
),
),
],
),
),
);
}
}

View File

@@ -77,18 +77,19 @@ class _SettingsDecksEditExistingState extends State<SettingsDecksEditExisting> {
/// [_showDeleteDialog] creates a new dialog, which is shown before the deck
/// can be deleted. This is done to raise the awareness that the deck,
/// columns, sources and items which belongs to the deck will also be deleted.
_showDeleteDialog() {
void _showDeleteDialog() {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
insetPadding: EdgeInsets.symmetric(
horizontal: MediaQuery.of(context).size.width >=
horizontal:
MediaQuery.of(context).size.width >=
(Constants.centeredFormMaxWidth +
2 * Constants.spacingMiddle)
? (MediaQuery.of(context).size.width -
Constants.centeredFormMaxWidth) /
2
Constants.centeredFormMaxWidth) /
2
: Constants.spacingMiddle,
),
title: const Text('Delete Deck'),
@@ -161,12 +162,7 @@ class _SettingsDecksEditExistingState extends State<SettingsDecksEditExisting> {
left: Constants.spacingMiddle,
right: Constants.spacingMiddle,
),
child: Text(
_error,
style: const TextStyle(
color: Constants.error,
),
),
child: Text(_error, style: const TextStyle(color: Constants.error)),
);
}
@@ -177,19 +173,13 @@ class _SettingsDecksEditExistingState extends State<SettingsDecksEditExisting> {
Widget build(BuildContext context) {
return Card(
color: Constants.secondary,
margin: const EdgeInsets.only(
bottom: Constants.spacingSmall,
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
margin: const EdgeInsets.only(bottom: Constants.spacingSmall),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Padding(
padding: const EdgeInsets.all(
Constants.spacingMiddle,
),
padding: const EdgeInsets.all(Constants.spacingMiddle),
child: Form(
key: _formKey,
child: Row(

View File

@@ -33,15 +33,13 @@ class _SettingsPremiumInAppState extends State<SettingsPremiumInApp> {
Future<Offering?> _fetchOfferings() async {
if (Platform.isAndroid) {
await Purchases.configure(
PurchasesConfiguration(
SettingsRepository().revenueCatGooglePlayKey,
)..appUserID = supabase.Supabase.instance.client.auth.currentUser!.id,
PurchasesConfiguration(SettingsRepository().revenueCatGooglePlayKey)
..appUserID = supabase.Supabase.instance.client.auth.currentUser!.id,
);
} else if (Platform.isMacOS || Platform.isIOS) {
await Purchases.configure(
PurchasesConfiguration(
SettingsRepository().revenueCatAppStoreKey,
)..appUserID = supabase.Supabase.instance.client.auth.currentUser!.id,
PurchasesConfiguration(SettingsRepository().revenueCatAppStoreKey)
..appUserID = supabase.Supabase.instance.client.auth.currentUser!.id,
);
}
@@ -62,16 +60,22 @@ class _SettingsPremiumInAppState extends State<SettingsPremiumInApp> {
_isLoading = true;
});
CustomerInfo customerInfo = await Purchases.purchasePackage(package);
final purchaseResult = await Purchases.purchasePackage(package);
setState(() {
_isLoading = false;
});
if (!customerInfo.entitlements.all.containsKey('FeedDeck Premium')) {
if (!purchaseResult.customerInfo.entitlements.all.containsKey(
'FeedDeck Premium',
)) {
throw Exception('FeedDeck Premium entitlement not found.');
}
if (customerInfo.entitlements.all['FeedDeck Premium']!.isActive) {
if (purchaseResult
.customerInfo
.entitlements
.all['FeedDeck Premium']!
.isActive) {
if (!mounted) return;
Provider.of<ProfileRepository>(
context,
@@ -149,17 +153,12 @@ class _SettingsPremiumInAppState extends State<SettingsPremiumInApp> {
appBar: AppBar(
automaticallyImplyLeading: false,
shape: const Border(
bottom: BorderSide(
color: Constants.dividerColor,
width: 1,
),
bottom: BorderSide(color: Constants.dividerColor, width: 1),
),
title: const Text('FeedDeck Premium'),
actions: [
IconButton(
icon: const Icon(
Icons.close,
),
icon: const Icon(Icons.close),
onPressed: () {
Navigator.of(context).pop();
},
@@ -169,17 +168,15 @@ class _SettingsPremiumInAppState extends State<SettingsPremiumInApp> {
body: SafeArea(
child: FutureBuilder(
future: _futureFetchOfferings,
builder: (
BuildContext context,
AsyncSnapshot<Offering?> snapshot,
) {
builder: (BuildContext context, AsyncSnapshot<Offering?> snapshot) {
return Column(
children: [
Expanded(
child: Padding(
padding: const EdgeInsets.all(Constants.spacingMiddle),
child: SingleChildScrollView(
child: snapshot.connectionState == ConnectionState.none ||
child:
snapshot.connectionState == ConnectionState.none ||
snapshot.connectionState ==
ConnectionState.waiting ||
snapshot.hasError ||
@@ -188,7 +185,8 @@ class _SettingsPremiumInAppState extends State<SettingsPremiumInApp> {
? const Text('Loading ...')
: MarkdownBody(
selectable: true,
data: '''
data:
'''
You are currently using the free version of FeedDeck, which allows you to add up
to 10 sources for the first 7 days. After that trial period your sources will
not be updated anymore.
@@ -202,9 +200,7 @@ canceled at any time.
),
),
),
const SizedBox(
height: Constants.spacingSmall,
),
const SizedBox(height: Constants.spacingSmall),
const Divider(
color: Constants.dividerColor,
height: 1,
@@ -230,15 +226,16 @@ canceled at any time.
),
onPressed:
snapshot.connectionState == ConnectionState.none ||
snapshot.connectionState ==
ConnectionState.waiting ||
snapshot.hasError ||
snapshot.data == null ||
snapshot.data?.monthly == null ||
_isLoading
? null
: () => _purchase(snapshot.data!.monthly!),
icon: snapshot.connectionState == ConnectionState.none ||
snapshot.connectionState ==
ConnectionState.waiting ||
snapshot.hasError ||
snapshot.data == null ||
snapshot.data?.monthly == null ||
_isLoading
? null
: () => _purchase(snapshot.data!.monthly!),
icon:
snapshot.connectionState == ConnectionState.none ||
snapshot.connectionState ==
ConnectionState.waiting ||
snapshot.hasError ||

View File

@@ -212,6 +212,8 @@ class _SettingsProfileCustomerPortalModalState
padding: const EdgeInsets.all(Constants.spacingMiddle),
child: ElevatedButton.icon(
style: ElevatedButton.styleFrom(
backgroundColor: Constants.secondary,
foregroundColor: Constants.onSecondary,
maximumSize: const Size.fromHeight(
Constants.elevatedButtonSize,
),

View File

@@ -24,18 +24,19 @@ class _SettingsProfileDeleteAccountState
/// [_showDeleteDialog] creates a new dialog, which is shown before the user
/// account is deleted. This is done to raise the awareness what it means to
/// delete the account and to avoid accidently deletions.
_showDeleteDialog() {
void _showDeleteDialog() {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
insetPadding: EdgeInsets.symmetric(
horizontal: MediaQuery.of(context).size.width >=
horizontal:
MediaQuery.of(context).size.width >=
(Constants.centeredFormMaxWidth +
2 * Constants.spacingMiddle)
? (MediaQuery.of(context).size.width -
Constants.centeredFormMaxWidth) /
2
Constants.centeredFormMaxWidth) /
2
: Constants.spacingMiddle,
),
title: const Text('Delete Account'),
@@ -94,9 +95,7 @@ class _SettingsProfileDeleteAccountState
if (!mounted) return;
Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(
builder: (BuildContext context) => const SignIn(),
),
MaterialPageRoute(builder: (BuildContext context) => const SignIn()),
(route) => false,
);
} on ApiException catch (err) {
@@ -136,9 +135,7 @@ class _SettingsProfileDeleteAccountState
onTap: () => _showDeleteDialog(),
child: Card(
color: Constants.secondary,
margin: const EdgeInsets.only(
bottom: Constants.spacingSmall,
),
margin: const EdgeInsets.only(bottom: Constants.spacingSmall),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
@@ -146,9 +143,7 @@ class _SettingsProfileDeleteAccountState
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Padding(
padding: const EdgeInsets.all(
Constants.spacingMiddle,
),
padding: const EdgeInsets.all(Constants.spacingMiddle),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
@@ -172,12 +167,7 @@ class _SettingsProfileDeleteAccountState
],
),
),
buildIcon(
const Icon(
Icons.delete,
color: Constants.error,
),
),
buildIcon(const Icon(Icons.delete, color: Constants.error)),
],
),
),

View File

@@ -162,7 +162,7 @@ class SettingsProfileSignOutActions extends StatelessWidget {
right: Constants.spacingMiddle,
),
decoration: const BoxDecoration(
color: Constants.background,
color: Constants.surface,
borderRadius: BorderRadius.all(
Radius.circular(Constants.spacingMiddle),
),

View File

@@ -5,6 +5,7 @@ import 'package:provider/provider.dart';
import 'package:feeddeck/repositories/profile_repository.dart';
import 'package:feeddeck/utils/constants.dart';
import 'package:feeddeck/widgets/settings/accounts/settings_accounts.dart';
import 'package:feeddeck/widgets/settings/app_settings/app_settings.dart';
import 'package:feeddeck/widgets/settings/decks/settings_decks.dart';
import 'package:feeddeck/widgets/settings/premium/settings_premium.dart';
import 'package:feeddeck/widgets/settings/profile/settings_profile.dart';
@@ -30,30 +31,27 @@ class _SettingsState extends State<Settings> {
/// call the function multiple times we set the `force` parameter to
/// `false`.
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
Provider.of<ProfileRepository>(context, listen: false)
.init(false)
.then((_) => {});
Provider.of<ProfileRepository>(
context,
listen: false,
).init(false).then((_) => {});
});
}
@override
Widget build(BuildContext context) {
return Container(
color: Constants.background,
color: Constants.surface,
child: SafeArea(
child: Scaffold(
appBar: AppBar(
title: const Text('Settings'),
),
appBar: AppBar(title: const Text('Settings')),
body: SingleChildScrollView(
child: Center(
child: Container(
constraints: const BoxConstraints(
maxWidth: Constants.centeredFormMaxWidth,
),
padding: const EdgeInsets.all(
Constants.spacingMiddle,
),
padding: const EdgeInsets.all(Constants.spacingMiddle),
child: const Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
@@ -75,6 +73,10 @@ class _SettingsState extends State<Settings> {
/// his account.
SettingsProfile(),
/// Display the app settings. Here the user can customize
/// the app and import / export data.
SettingsAppSettings(),
/// Display some general information about the app, like the
/// version and the link to our website.
SettingsInfo(),

View File

@@ -339,7 +339,10 @@ class _SignInState extends State<SignIn> {
onPressed: _isLoading ? null : () => _signInWithGoogle(),
icon: _isLoading
? const ElevatedButtonProgressIndicator()
: const Icon(FDIcons.google),
: const Icon(
FDIcons.google,
color: Color(0xffffffff),
),
),
const SizedBox(
height: Constants.spacingMiddle,
@@ -362,7 +365,10 @@ class _SignInState extends State<SignIn> {
onPressed: _isLoading ? null : () => _signInWithApple(),
icon: _isLoading
? const ElevatedButtonProgressIndicator()
: const Icon(FDIcons.apple),
: const Icon(
FDIcons.apple,
color: Color(0xff000000),
),
),
const SizedBox(
height: Constants.spacingMiddle,
@@ -395,7 +401,10 @@ class _SignInState extends State<SignIn> {
},
icon: _isLoading
? const ElevatedButtonProgressIndicator()
: const Icon(FDIcons.feeddeck),
: const Icon(
FDIcons.feeddeck,
color: Constants.onPrimary,
),
),
const SizedBox(
height: Constants.spacingMiddle,

View File

@@ -194,6 +194,8 @@ class _SignInWithFeedDeckState extends State<SignInWithFeedDeck> {
),
ElevatedButton.icon(
style: ElevatedButton.styleFrom(
backgroundColor: Constants.secondary,
foregroundColor: Constants.onSecondary,
maximumSize: const Size.fromHeight(
Constants.elevatedButtonSize,
),

View File

@@ -231,6 +231,8 @@ class _SignUpState extends State<SignUp> {
),
ElevatedButton.icon(
style: ElevatedButton.styleFrom(
backgroundColor: Constants.secondary,
foregroundColor: Constants.onSecondary,
maximumSize: const Size.fromHeight(
Constants.elevatedButtonSize,
),

View File

@@ -151,10 +151,7 @@ class _AddSourceState extends State<AddSource> {
style: TextStyle(
/// Since we are using the brand color as background
/// color, we are using the same color as for the icon
/// as text color (source_icon.dart). If we decide later
/// to use a generic color as background the following
/// line can be used:
/// color: Constants.onSecondary,
/// as text color (source_icon.dart).
color: _sourceTypeValues[index].fgColor,
),
),

View File

@@ -66,6 +66,8 @@ class AddSourceForm extends StatelessWidget {
padding: const EdgeInsets.all(Constants.spacingMiddle),
child: ElevatedButton.icon(
style: ElevatedButton.styleFrom(
backgroundColor: Constants.secondary,
foregroundColor: Constants.onSecondary,
maximumSize: const Size.fromHeight(
Constants.elevatedButtonSize,
),

View File

@@ -14,10 +14,12 @@ class SourceListItem extends StatefulWidget {
const SourceListItem({
super.key,
required this.columnId,
required this.sourceIndex,
required this.source,
});
final String columnId;
final int sourceIndex;
final FDSource source;
@override
State<SourceListItem> createState() => _SourceListItemState();
@@ -29,23 +31,22 @@ class _SourceListItemState extends State<SourceListItem> {
/// [_showDeleteDialog] creates a new dialog, which is shown before the column
/// can be deleted. This is done to raise the awareness that the column,
/// sources and items which belongs to the column will also be deleted.
_showDeleteDialog() {
void _showDeleteDialog() {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
insetPadding: EdgeInsets.symmetric(
horizontal: MediaQuery.of(context).size.width >=
horizontal:
MediaQuery.of(context).size.width >=
(Constants.centeredFormMaxWidth +
2 * Constants.spacingMiddle)
? (MediaQuery.of(context).size.width -
Constants.centeredFormMaxWidth) /
2
Constants.centeredFormMaxWidth) /
2
: Constants.spacingMiddle,
),
title: const Text(
'Delete Source',
),
title: const Text('Delete Source'),
content: const Text(
'Do you really want to delete this source? This can not be undone and will also delete all items and bookmarks related to this source.',
),
@@ -108,64 +109,63 @@ class _SourceListItemState extends State<SourceListItem> {
@override
Widget build(BuildContext context) {
return Card(
color: Constants.secondary,
margin: const EdgeInsets.only(
bottom: Constants.spacingSmall,
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Padding(
padding: const EdgeInsets.all(
Constants.spacingMiddle,
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
Characters(widget.source.title)
.replaceAll(Characters(''), Characters('\u{200B}'))
.toString(),
maxLines: 1,
style: const TextStyle(
overflow: TextOverflow.ellipsis,
return ReorderableDragStartListener(
index: widget.sourceIndex,
child: Card(
color: Constants.secondary,
margin: const EdgeInsets.only(bottom: Constants.spacingSmall),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Padding(
padding: const EdgeInsets.all(Constants.spacingMiddle),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
Characters(widget.source.title)
.replaceAll(
Characters(''),
Characters('\u{200B}'),
)
.toString(),
maxLines: 1,
style: const TextStyle(
overflow: TextOverflow.ellipsis,
),
),
),
Text(
Characters(
widget.source.type.toLocalizedString(),
)
.replaceAll(Characters(''), Characters('\u{200B}'))
.toString(),
maxLines: 1,
style: const TextStyle(
overflow: TextOverflow.ellipsis,
fontSize: 10.0,
Text(
Characters(widget.source.type.toLocalizedString())
.replaceAll(
Characters(''),
Characters('\u{200B}'),
)
.toString(),
maxLines: 1,
style: const TextStyle(
overflow: TextOverflow.ellipsis,
fontSize: 10.0,
),
),
),
],
],
),
),
),
IconButton(
onPressed: () => _showDeleteDialog(),
icon: _isLoading
? const ElevatedButtonProgressIndicator()
: const Icon(
Icons.delete,
),
),
],
IconButton(
onPressed: () => _showDeleteDialog(),
icon: _isLoading
? const ElevatedButtonProgressIndicator()
: const Icon(Icons.delete),
),
],
),
),
),
],
],
),
),
);
}

View File

@@ -4,7 +4,7 @@
<metadata_license>CC0-1.0</metadata_license>
<project_license>MIT</project_license>
<name>FeedDeck</name>
<summary>Feed reader</summary>
<summary>Rss and social media reader</summary>
<developer_name>Rico Berger</developer_name>
<url type="homepage">https://feeddeck.app</url>

View File

@@ -1,12 +1,10 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 4096 4096" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<g id="icon-linux">
<g id="bg" transform="matrix(2.30943,0,0,2.25704,-1582.56,-1114.43)">
<path d="M2339.78,621.098C2339.78,619.166 2338.24,617.598 2336.35,617.598L809.714,617.598C807.826,617.598 806.293,619.166 806.293,621.098L806.293,2183.17C806.293,2185.11 807.826,2186.67 809.714,2186.67L2336.35,2186.67C2338.24,2186.67 2339.78,2185.11 2339.78,2183.17L2339.78,621.098Z" style="fill:rgb(73,211,180);"/>
</g>
<g id="fg" transform="matrix(13.5357,0,0,13.0255,-2722.19,-2672.07)">
<path d="M443.567,272.226C438.383,276.258 434.063,278.274 430.607,278.274C423.695,278.274 416.783,274.146 409.871,265.89L369.263,293.826C362.927,298.434 359.759,304.194 359.759,311.106L359.759,429.186L359.471,429.474C359.471,432.354 358.559,435.234 356.735,438.114C354.911,440.994 352.943,442.434 350.831,442.434L350.255,442.434L350.255,439.554L347.951,442.722C345.071,442.53 337.583,439.17 325.487,432.642L325.487,432.93C313.199,425.826 302.927,422.274 294.671,422.274C286.223,422.274 278.447,425.442 271.343,431.778C268.079,434.658 265.439,438.162 263.423,442.29C261.407,446.418 260.111,451.266 259.535,456.834C263.759,451.842 268.943,449.058 275.087,448.482C276.239,448.482 277.007,448.386 277.391,448.194L277.967,448.194C282.191,448.194 290.351,450.594 302.447,455.394C308.207,457.698 315.215,458.85 323.471,458.85C334.991,458.85 347.471,455.778 360.911,449.634C376.271,442.53 385.871,434.082 389.711,424.29C390.287,422.946 390.575,421.602 390.575,420.258L390.863,370.722L410.735,370.722L410.735,431.778L421.391,431.778L421.391,301.314C425.231,300.354 428.687,298.482 431.759,295.698C434.831,292.914 437.807,289.314 440.687,284.898C443.183,281.058 444.431,278.274 444.431,276.546L444.719,276.258C444.719,275.49 444.911,274.53 445.295,273.378L443.567,272.226ZM356.015,297.282C350.447,298.242 345.503,299.874 341.183,302.178C336.863,304.482 332.975,307.266 329.519,310.53C321.647,317.634 317.711,326.562 317.711,337.314L317.711,338.754L317.999,339.042L317.999,340.194C317.231,340.194 316.655,340.098 316.271,339.906L313.679,339.906C298.127,339.906 290.351,347.874 290.351,363.81C290.351,368.418 291.695,372.498 294.383,376.05C297.071,379.602 300.719,381.378 305.327,381.378L305.327,379.362L305.039,379.074L305.039,377.922L304.751,377.634C304.751,373.218 308.015,371.01 314.543,371.01L316.559,371.01L317.135,371.298L318.287,371.298L318.287,413.634C318.095,414.018 317.951,414.498 317.855,415.074C317.759,415.65 317.615,416.13 317.423,416.514C317.039,417.282 316.703,418.194 316.415,419.25C316.127,420.306 315.887,421.026 315.695,421.41L318.575,421.41L319.151,421.122L319.727,421.122L320.015,420.834C322.703,420.834 326.351,419.202 330.959,415.938C344.399,407.106 351.119,396.93 351.119,385.41L351.119,310.818C351.119,308.706 351.647,306.45 352.703,304.05C353.759,301.65 355.055,300.162 356.591,299.586L356.015,297.282ZM375.023,266.754C370.415,270.978 365.231,273.09 359.471,273.09C351.407,273.09 345.647,272.226 342.191,270.498L341.615,270.498L341.327,270.21C338.063,269.634 335.375,269.106 333.263,268.626C331.151,268.146 329.615,267.81 328.655,267.618L325.775,267.618C320.207,267.042 317.231,266.562 316.847,266.178L314.831,267.042C298.319,267.426 286.799,273.186 280.271,284.322C277.391,289.314 275.951,293.73 275.951,297.57L275.951,300.162C282.671,295.938 286.991,293.826 288.911,293.826L290.063,293.826L290.351,293.538C294.767,293.538 302.063,294.594 312.239,296.706C321.839,298.818 329.039,299.874 333.839,299.874L334.127,300.162L335.279,300.162C344.687,300.162 353.615,297.09 362.063,290.946C371.087,284.418 376.079,276.642 377.039,267.618L375.023,266.754ZM409.583,301.89C409.775,301.89 409.919,301.938 410.015,302.034C410.111,302.13 410.351,302.082 410.735,301.89L410.735,340.482L390.863,340.482L390.863,294.402C397.967,299.394 404.207,301.89 409.583,301.89Z" style="fill:rgb(31,34,41);fill-rule:nonzero;"/>
</g>
<svg width="100%" height="100%" viewBox="0 0 129 128" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<g id="bg" transform="matrix(1,0,0,1,-122,-524)">
<path d="M237.505,544.419C237.505,540.046 233.954,536.495 229.581,536.495L142.419,536.495C138.046,536.495 134.495,540.046 134.495,544.419L134.495,631.581C134.495,635.954 138.046,639.505 142.419,639.505L229.581,639.505C233.954,639.505 237.505,635.954 237.505,631.581L237.505,544.419Z" style="fill:rgb(73,211,180);"/>
</g>
<g id="fg" transform="matrix(0.348583,0,0,0.335444,-58.1233,-58.1329)">
<path d="M443.567,272.226C438.383,276.258 434.063,278.274 430.607,278.274C423.695,278.274 416.783,274.146 409.871,265.89L369.263,293.826C362.927,298.434 359.759,304.194 359.759,311.106L359.759,429.186L359.471,429.474C359.471,432.354 358.559,435.234 356.735,438.114C354.911,440.994 352.943,442.434 350.831,442.434L350.255,442.434L350.255,439.554L347.951,442.722C345.071,442.53 337.583,439.17 325.487,432.642L325.487,432.93C313.199,425.826 302.927,422.274 294.671,422.274C286.223,422.274 278.447,425.442 271.343,431.778C268.079,434.658 265.439,438.162 263.423,442.29C261.407,446.418 260.111,451.266 259.535,456.834C263.759,451.842 268.943,449.058 275.087,448.482C276.239,448.482 277.007,448.386 277.391,448.194L277.967,448.194C282.191,448.194 290.351,450.594 302.447,455.394C308.207,457.698 315.215,458.85 323.471,458.85C334.991,458.85 347.471,455.778 360.911,449.634C376.271,442.53 385.871,434.082 389.711,424.29C390.287,422.946 390.575,421.602 390.575,420.258L390.863,370.722L410.735,370.722L410.735,431.778L421.391,431.778L421.391,301.314C425.231,300.354 428.687,298.482 431.759,295.698C434.831,292.914 437.807,289.314 440.687,284.898C443.183,281.058 444.431,278.274 444.431,276.546L444.719,276.258C444.719,275.49 444.911,274.53 445.295,273.378L443.567,272.226ZM356.015,297.282C350.447,298.242 345.503,299.874 341.183,302.178C336.863,304.482 332.975,307.266 329.519,310.53C321.647,317.634 317.711,326.562 317.711,337.314L317.711,338.754L317.999,339.042L317.999,340.194C317.231,340.194 316.655,340.098 316.271,339.906L313.679,339.906C298.127,339.906 290.351,347.874 290.351,363.81C290.351,368.418 291.695,372.498 294.383,376.05C297.071,379.602 300.719,381.378 305.327,381.378L305.327,379.362L305.039,379.074L305.039,377.922L304.751,377.634C304.751,373.218 308.015,371.01 314.543,371.01L316.559,371.01L317.135,371.298L318.287,371.298L318.287,413.634C318.095,414.018 317.951,414.498 317.855,415.074C317.759,415.65 317.615,416.13 317.423,416.514C317.039,417.282 316.703,418.194 316.415,419.25C316.127,420.306 315.887,421.026 315.695,421.41L318.575,421.41L319.151,421.122L319.727,421.122L320.015,420.834C322.703,420.834 326.351,419.202 330.959,415.938C344.399,407.106 351.119,396.93 351.119,385.41L351.119,310.818C351.119,308.706 351.647,306.45 352.703,304.05C353.759,301.65 355.055,300.162 356.591,299.586L356.015,297.282ZM375.023,266.754C370.415,270.978 365.231,273.09 359.471,273.09C351.407,273.09 345.647,272.226 342.191,270.498L341.615,270.498L341.327,270.21C338.063,269.634 335.375,269.106 333.263,268.626C331.151,268.146 329.615,267.81 328.655,267.618L325.775,267.618C320.207,267.042 317.231,266.562 316.847,266.178L314.831,267.042C298.319,267.426 286.799,273.186 280.271,284.322C277.391,289.314 275.951,293.73 275.951,297.57L275.951,300.162C282.671,295.938 286.991,293.826 288.911,293.826L290.063,293.826L290.351,293.538C294.767,293.538 302.063,294.594 312.239,296.706C321.839,298.818 329.039,299.874 333.839,299.874L334.127,300.162L335.279,300.162C344.687,300.162 353.615,297.09 362.063,290.946C371.087,284.418 376.079,276.642 377.039,267.618L375.023,266.754ZM409.583,301.89C409.775,301.89 409.919,301.938 410.015,302.034C410.111,302.13 410.351,302.082 410.735,301.89L410.735,340.482L390.863,340.482L390.863,294.402C397.967,299.394 404.207,301.89 409.583,301.89Z" style="fill:rgb(31,34,41);fill-rule:nonzero;"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 4.1 KiB

View File

@@ -9,8 +9,9 @@
#include <gtk/gtk_plugin.h>
#include <media_kit_libs_linux/media_kit_libs_linux_plugin.h>
#include <media_kit_video/media_kit_video_plugin.h>
#include <screen_retriever/screen_retriever_plugin.h>
#include <screen_retriever_linux/screen_retriever_linux_plugin.h>
#include <url_launcher_linux/url_launcher_plugin.h>
#include <volume_controller/volume_controller_plugin.h>
#include <window_manager/window_manager_plugin.h>
void fl_register_plugins(FlPluginRegistry* registry) {
@@ -23,12 +24,15 @@ void fl_register_plugins(FlPluginRegistry* registry) {
g_autoptr(FlPluginRegistrar) media_kit_video_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "MediaKitVideoPlugin");
media_kit_video_plugin_register_with_registrar(media_kit_video_registrar);
g_autoptr(FlPluginRegistrar) screen_retriever_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "ScreenRetrieverPlugin");
screen_retriever_plugin_register_with_registrar(screen_retriever_registrar);
g_autoptr(FlPluginRegistrar) screen_retriever_linux_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "ScreenRetrieverLinuxPlugin");
screen_retriever_linux_plugin_register_with_registrar(screen_retriever_linux_registrar);
g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin");
url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar);
g_autoptr(FlPluginRegistrar) volume_controller_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "VolumeControllerPlugin");
volume_controller_plugin_register_with_registrar(volume_controller_registrar);
g_autoptr(FlPluginRegistrar) window_manager_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "WindowManagerPlugin");
window_manager_plugin_register_with_registrar(window_manager_registrar);

View File

@@ -6,13 +6,13 @@ list(APPEND FLUTTER_PLUGIN_LIST
gtk
media_kit_libs_linux
media_kit_video
screen_retriever
screen_retriever_linux
url_launcher_linux
volume_controller
window_manager
)
list(APPEND FLUTTER_FFI_PLUGIN_LIST
media_kit_native_event_loop
)
set(PLUGIN_BUNDLED_LIBRARIES)

View File

@@ -8,18 +8,19 @@ import Foundation
import app_links
import audio_service
import audio_session
import file_picker
import just_audio
import media_kit_libs_macos_video
import media_kit_video
import package_info_plus
import path_provider_foundation
import purchases_flutter
import screen_brightness_macos
import screen_retriever
import screen_retriever_macos
import shared_preferences_foundation
import sign_in_with_apple
import sqflite
import url_launcher_macos
import volume_controller
import wakelock_plus
import window_manager
@@ -27,18 +28,19 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
AppLinksMacosPlugin.register(with: registry.registrar(forPlugin: "AppLinksMacosPlugin"))
AudioServicePlugin.register(with: registry.registrar(forPlugin: "AudioServicePlugin"))
AudioSessionPlugin.register(with: registry.registrar(forPlugin: "AudioSessionPlugin"))
FilePickerPlugin.register(with: registry.registrar(forPlugin: "FilePickerPlugin"))
JustAudioPlugin.register(with: registry.registrar(forPlugin: "JustAudioPlugin"))
MediaKitLibsMacosVideoPlugin.register(with: registry.registrar(forPlugin: "MediaKitLibsMacosVideoPlugin"))
MediaKitVideoPlugin.register(with: registry.registrar(forPlugin: "MediaKitVideoPlugin"))
FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin"))
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
PurchasesFlutterPlugin.register(with: registry.registrar(forPlugin: "PurchasesFlutterPlugin"))
ScreenBrightnessMacosPlugin.register(with: registry.registrar(forPlugin: "ScreenBrightnessMacosPlugin"))
ScreenRetrieverPlugin.register(with: registry.registrar(forPlugin: "ScreenRetrieverPlugin"))
ScreenRetrieverMacosPlugin.register(with: registry.registrar(forPlugin: "ScreenRetrieverMacosPlugin"))
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
SignInWithApplePlugin.register(with: registry.registrar(forPlugin: "SignInWithApplePlugin"))
SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin"))
UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))
VolumeControllerPlugin.register(with: registry.registrar(forPlugin: "VolumeControllerPlugin"))
WakelockPlusMacosPlugin.register(with: registry.registrar(forPlugin: "WakelockPlusMacosPlugin"))
WindowManagerPlugin.register(with: registry.registrar(forPlugin: "WindowManagerPlugin"))
}

View File

@@ -1,69 +1,34 @@
PODS:
- app_links (1.0.0):
- FlutterMacOS
- audio_service (0.14.1):
- FlutterMacOS
- audio_session (0.0.1):
- FlutterMacOS
- FlutterMacOS (1.0.0)
- just_audio (0.0.1):
- FlutterMacOS
- media_kit_libs_macos_video (1.0.4):
- FlutterMacOS
- media_kit_native_event_loop (1.0.0):
- FlutterMacOS
- media_kit_video (0.0.1):
- FlutterMacOS
- package_info_plus (0.0.1):
- purchases_flutter (9.1.0):
- FlutterMacOS
- path_provider_foundation (0.0.1):
- Flutter
- FlutterMacOS
- purchases_flutter (6.30.2):
- FlutterMacOS
- PurchasesHybridCommon (= 11.1.0)
- PurchasesHybridCommon (11.1.0):
- RevenueCat (= 4.43.2)
- RevenueCat (4.43.2)
- screen_brightness_macos (0.1.0):
- FlutterMacOS
- screen_retriever (0.0.1):
- FlutterMacOS
- shared_preferences_foundation (0.0.1):
- Flutter
- PurchasesHybridCommon (= 16.0.2)
- PurchasesHybridCommon (16.0.2):
- RevenueCat (= 5.33.1)
- RevenueCat (5.33.1)
- screen_retriever_macos (0.0.1):
- FlutterMacOS
- sign_in_with_apple (0.0.1):
- FlutterMacOS
- sqflite (0.0.3):
- Flutter
- FlutterMacOS
- url_launcher_macos (0.0.1):
- FlutterMacOS
- wakelock_plus (0.0.1):
- FlutterMacOS
- window_manager (0.2.0):
- FlutterMacOS
DEPENDENCIES:
- app_links (from `Flutter/ephemeral/.symlinks/plugins/app_links/macos`)
- audio_service (from `Flutter/ephemeral/.symlinks/plugins/audio_service/macos`)
- audio_session (from `Flutter/ephemeral/.symlinks/plugins/audio_session/macos`)
- FlutterMacOS (from `Flutter/ephemeral`)
- just_audio (from `Flutter/ephemeral/.symlinks/plugins/just_audio/macos`)
- media_kit_libs_macos_video (from `Flutter/ephemeral/.symlinks/plugins/media_kit_libs_macos_video/macos`)
- media_kit_native_event_loop (from `Flutter/ephemeral/.symlinks/plugins/media_kit_native_event_loop/macos`)
- media_kit_video (from `Flutter/ephemeral/.symlinks/plugins/media_kit_video/macos`)
- package_info_plus (from `Flutter/ephemeral/.symlinks/plugins/package_info_plus/macos`)
- path_provider_foundation (from `Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin`)
- purchases_flutter (from `Flutter/ephemeral/.symlinks/plugins/purchases_flutter/macos`)
- screen_brightness_macos (from `Flutter/ephemeral/.symlinks/plugins/screen_brightness_macos/macos`)
- screen_retriever (from `Flutter/ephemeral/.symlinks/plugins/screen_retriever/macos`)
- shared_preferences_foundation (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin`)
- screen_retriever_macos (from `Flutter/ephemeral/.symlinks/plugins/screen_retriever_macos/macos`)
- sign_in_with_apple (from `Flutter/ephemeral/.symlinks/plugins/sign_in_with_apple/macos`)
- sqflite (from `Flutter/ephemeral/.symlinks/plugins/sqflite/darwin`)
- url_launcher_macos (from `Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos`)
- wakelock_plus (from `Flutter/ephemeral/.symlinks/plugins/wakelock_plus/macos`)
- window_manager (from `Flutter/ephemeral/.symlinks/plugins/window_manager/macos`)
SPEC REPOS:
trunk:
@@ -71,68 +36,35 @@ SPEC REPOS:
- RevenueCat
EXTERNAL SOURCES:
app_links:
:path: Flutter/ephemeral/.symlinks/plugins/app_links/macos
audio_service:
:path: Flutter/ephemeral/.symlinks/plugins/audio_service/macos
audio_session:
:path: Flutter/ephemeral/.symlinks/plugins/audio_session/macos
FlutterMacOS:
:path: Flutter/ephemeral
just_audio:
:path: Flutter/ephemeral/.symlinks/plugins/just_audio/macos
media_kit_libs_macos_video:
:path: Flutter/ephemeral/.symlinks/plugins/media_kit_libs_macos_video/macos
media_kit_native_event_loop:
:path: Flutter/ephemeral/.symlinks/plugins/media_kit_native_event_loop/macos
media_kit_video:
:path: Flutter/ephemeral/.symlinks/plugins/media_kit_video/macos
package_info_plus:
:path: Flutter/ephemeral/.symlinks/plugins/package_info_plus/macos
path_provider_foundation:
:path: Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin
purchases_flutter:
:path: Flutter/ephemeral/.symlinks/plugins/purchases_flutter/macos
screen_brightness_macos:
:path: Flutter/ephemeral/.symlinks/plugins/screen_brightness_macos/macos
screen_retriever:
:path: Flutter/ephemeral/.symlinks/plugins/screen_retriever/macos
shared_preferences_foundation:
:path: Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin
screen_retriever_macos:
:path: Flutter/ephemeral/.symlinks/plugins/screen_retriever_macos/macos
sign_in_with_apple:
:path: Flutter/ephemeral/.symlinks/plugins/sign_in_with_apple/macos
sqflite:
:path: Flutter/ephemeral/.symlinks/plugins/sqflite/darwin
url_launcher_macos:
:path: Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos
wakelock_plus:
:path: Flutter/ephemeral/.symlinks/plugins/wakelock_plus/macos
window_manager:
:path: Flutter/ephemeral/.symlinks/plugins/window_manager/macos
SPEC CHECKSUMS:
app_links: 10e0a0ab602ffaf34d142cd4862f29d34b303b2a
audio_service: b88ff778e0e3915efd4cd1a5ad6f0beef0c950a9
audio_session: dea1f41890dbf1718f04a56f1d6150fd50039b72
FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24
just_audio: 9b67ca7b97c61cfc9784ea23cd8cc55eb226d489
media_kit_libs_macos_video: b3e2bbec2eef97c285f2b1baa7963c67c753fb82
media_kit_native_event_loop: 81fd5b45192b72f8b5b69eaf5b540f45777eb8d5
media_kit_video: c75b07f14d59706c775778e4dd47dd027de8d1e5
package_info_plus: fa739dd842b393193c5ca93c26798dff6e3d0e0c
path_provider_foundation: 3784922295ac71e43754bd15e0653ccfd36a147c
purchases_flutter: 3407100959d2aeb636507b2c98970d850dae57ae
PurchasesHybridCommon: 4022d5944cb30ec44ba5159e42aa161fe0e30175
RevenueCat: 3d934653b7e8b09af88fd47e9e84cfaf5d0a89ba
screen_brightness_macos: 2d6d3af2165592d9a55ffcd95b7550970e41ebda
screen_retriever: 59634572a57080243dd1bf715e55b6c54f241a38
shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78
sign_in_with_apple: a9e97e744e8edc36aefc2723111f652102a7a727
sqflite: 673a0e54cc04b7d6dba8d24fb8095b31c3a99eec
url_launcher_macos: d2691c7dd33ed713bf3544850a623080ec693d95
wakelock_plus: 4783562c9a43d209c458cb9b30692134af456269
window_manager: 3a1844359a6295ab1e47659b1a777e36773cd6e8
media_kit_libs_macos_video: 85a23e549b5f480e72cae3e5634b5514bc692f65
media_kit_video: fa6564e3799a0a28bff39442334817088b7ca758
purchases_flutter: 7655c5b1ec1236b102c30f02d3d0c7d87117bd2d
PurchasesHybridCommon: ae7a0a6e105ecdde3e8816a004e57f0a2a7b9261
RevenueCat: b0ed01125b05a45b8264a2951ad68acb61942038
screen_retriever_macos: 452e51764a9e1cdb74b3c541238795849f21557f
sign_in_with_apple: 6673c03c9e3643f6c8d33601943fbfa9ae99f94e
sqflite: c35dad70033b8862124f8337cc994a809fcd9fa3
wakelock_plus: 21ddc249ac4b8d018838dbdabd65c5976c308497
PODFILE CHECKSUM: 8d40c19d3cbdb380d870685c3a564c989f1efa52
COCOAPODS: 1.15.2
COCOAPODS: 1.16.2

View File

@@ -28,6 +28,7 @@
33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; };
553BE2622AC0648A002EA0C0 /* StoreKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 553BE2612AC0648A002EA0C0 /* StoreKit.framework */; };
FBF50439F2C4D0BF615EFED2 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 27D60858A3CD81E41E2CDBF2 /* Pods_Runner.framework */; };
78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */ = {isa = PBXBuildFile; productRef = 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@@ -83,6 +84,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */,
FBF50439F2C4D0BF615EFED2 /* Pods_Runner.framework in Frameworks */,
553BE2622AC0648A002EA0C0 /* StoreKit.framework in Frameworks */,
);
@@ -180,6 +182,9 @@
/* Begin PBXNativeTarget section */
33CC10EC2044A3C60003C045 /* Runner */ = {
packageProductDependencies = (
78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */,
);
isa = PBXNativeTarget;
buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */;
buildPhases = (
@@ -205,6 +210,9 @@
/* Begin PBXProject section */
33CC10E52044A3C60003C045 /* Project object */ = {
packageReferences = (
781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage" */,
);
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 0920;
@@ -645,6 +653,18 @@
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
/* Begin XCLocalSwiftPackageReference section */
781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage" */ = {
isa = XCLocalSwiftPackageReference;
relativePath = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage;
};
/* End XCLocalSwiftPackageReference section */
/* Begin XCSwiftPackageProductDependency section */
78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */ = {
isa = XCSwiftPackageProductDependency;
productName = FlutterGeneratedPluginSwiftPackage;
};
/* End XCSwiftPackageProductDependency section */
};
rootObject = 33CC10E52044A3C60003C045 /* Project object */;
}

View File

@@ -5,6 +5,24 @@
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<PreActions>
<ExecutionAction
ActionType = "Xcode.IDEStandardExecutionActionsCore.ExecutionActionType.ShellScriptAction">
<ActionContent
title = "Run Prepare Flutter Framework Script"
scriptText = "&quot;$FLUTTER_ROOT&quot;/packages/flutter_tools/bin/macos_assemble.sh prepare&#10;">
<EnvironmentBuildable>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "33CC10EC2044A3C60003C045"
BuildableName = "FeedDeck.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</EnvironmentBuildable>
</ActionContent>
</ExecutionAction>
</PreActions>
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
@@ -48,6 +66,7 @@
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
enableGPUValidationMode = "1"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">

View File

@@ -1,9 +1,13 @@
import Cocoa
import FlutterMacOS
@NSApplicationMain
@main
class AppDelegate: FlutterAppDelegate {
override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
return true
}
override func applicationSupportsSecureRestorableState(_ app: NSApplication) -> Bool {
return true
}
}

View File

@@ -10,6 +10,8 @@
<true/>
<key>com.apple.security.cs.allow-jit</key>
<true/>
<key>com.apple.security.files.user-selected.read-write</key>
<true/>
<key>com.apple.security.network.client</key>
<true/>
<key>com.apple.security.network.server</key>

Some files were not shown because too many files have changed in this diff Show More