Prepare v1.0.0 Release (#12)

- Adjust "Release" section in contributing guide.
- Disable "X" datasource, since it is not working after the latest API
  adjustments.
- Update "version" key and "msix_config.msix_version" key in
  "pubspec.yaml" file.
- Change user in "AddSourceReddit" widget help text.
- Enable macOS App Sandbox.
- Adjust logo for Windows version.
This commit is contained in:
Rico Berger
2023-09-17 18:39:42 +02:00
committed by GitHub
parent 23e7b25327
commit 4587a1c172
24 changed files with 203 additions and 148 deletions

View File

@@ -10,6 +10,7 @@
- [Run Release Build on a Device](#run-release-build-on-a-device) - [Run Release Build on a Device](#run-release-build-on-a-device)
- [Working with Supabase](#working-with-supabase) - [Working with Supabase](#working-with-supabase)
- [Working with Deno](#working-with-deno) - [Working with Deno](#working-with-deno)
- [Hosting](#hosting)
- [Release](#release) - [Release](#release)
Every contribution to FeedDeck is welcome, whether it is reporting a bug, Every contribution to FeedDeck is welcome, whether it is reporting a bug,
@@ -63,9 +64,9 @@ Tools • Dart 2.19.6 • DevTools 2.20.1
$ deno --version $ deno --version
deno 1.33.1 (release, aarch64-apple-darwin) deno 1.36.4 (release, aarch64-apple-darwin)
v8 11.4.183.1 v8 11.6.189.12
typescript 5.0.3 typescript 5.1.6
``` ```
### Working with Flutter ### Working with Flutter
@@ -301,7 +302,7 @@ docker-compose up --build
## Hosting ## Hosting
FeedDeck uses Supabase as it backend. For Supabase we can use FeedDeck uses Supabase as backend. For Supabase we can use
[Supabase Cloud](https://supabase.com/dashboard) or their [Supabase Cloud](https://supabase.com/dashboard) or their
[Self-Hosting](https://supabase.com/docs/guides/self-hosting) offer. [Self-Hosting](https://supabase.com/docs/guides/self-hosting) offer.
@@ -399,33 +400,37 @@ Android, macOS, Windows and Linux if you do not want to use the official ones.
## Release ## Release
```sh 1. Ensure that all secrets are updated in the Supabase project:
supabase link --project-ref <PROJECT-ID>
supabase secrets set --env-file supabase/.env.prod
supabase secrets list
```
### Web ```sh
supabase link --project-ref <PROJECT-ID>
supabase secrets set --env-file supabase/.env.prod
supabase secrets list
```
To create a new release for the web version, the following workflow can be used: 2. Update the `version` key and the `msix_config.msix_version` key in the
`pubspec.yaml` file.
1. Delete the `build/` and `.dart_tool/` directories: `flutter clean` 3. Delete the `build/` and `.dart_tool/` directories via the `flutter clean`
command.
2. Build a web application bundle: 4. Build the app for Web by running `flutter build web`. The build can be found
`flutter build web --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>` at `app/build/web` and must be uploaded to your hosting provider.
3. Upload the `app/build/web` folder to your CDN. 5. Build the app for Linux by running `flutter build linux --release`.
### macOS, Windows and Linux 6. Build the app for macOS by running `flutter build macos --release`. Open
Xcode and select **Product** > **Archive** to create and open the archive.
After that the **Validate App** and **Distribute App** options can be used to
upload the build to
[https://appstoreconnect.apple.com](https://appstoreconnect.apple.com).
### iOS and Android 7. Build the app for Windows by running `flutter build windows --release`. and
`flutter pub run msix:create --output-path build --output-name feeddeck`. The
build can be found at `app/build/feeddeck.msix` and must be uploaded to
[https://partner.microsoft.com/en-us/dashboard/products/9NPHPGRRCT5H/overview](https://partner.microsoft.com/en-us/dashboard/products/9NPHPGRRCT5H/overview).
To create a new release for Android and iOS which can be published in 8. Create a file `app/android/key.properties` with the following content:
[Google Play](https://play.google.com/store/apps/details?id=app.feeddeck.feeddeck)
and the [App Store](https://apps.apple.com/us/app/FeedDeck/TODO) the following
workflow can be used:
1. Create a file `app/android/key.properties` with the following content:
```plain ```plain
storePassword= storePassword=
@@ -434,20 +439,13 @@ workflow can be used:
storeFile= storeFile=
``` ```
2. Update the `version` key in the `pubspec.yaml` file 9. Build the app for Android by running `flutter build appbundle`. The build can
be found at `app/build/app/outputs/bundle/release/app-release.aab` and must
3. Delete all old builds by running `rm -rf build` be uploaded to
4. Build the app for Android by running
`flutter build appbundle --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>`.
The build can be found at
`app/build/app/outputs/bundle/release/app-release.aab` and must be uploaded
to
[https://play.google.com/apps/publish](https://play.google.com/apps/publish). [https://play.google.com/apps/publish](https://play.google.com/apps/publish).
5. Build the app for iOS by running 10. Build the app for iOS by running `flutter build ipa`. The build can be found
`flutter build ipa --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>`. at `app/build/ios/archive/Runner.xcarchive` and must be opened in Xcode. In
The build can be found at `app/build/ios/archive/Runner.xcarchive` and must Xcode the **Validate App** and **Distribute App** options can be used to
be opened in Xcode. In Xcode **Validate App** and **Distribute App** can be upload the build to
used to upload the build to [https://appstoreconnect.apple.com](https://appstoreconnect.apple.com).
[https://appstoreconnect.apple.com](https://appstoreconnect.apple.com).

View File

@@ -6,6 +6,12 @@ if (localPropertiesFile.exists()) {
} }
} }
def keystoreProperties = new Properties()
def keystorePropertiesFile = rootProject.file('key.properties')
if (keystorePropertiesFile.exists()) {
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
}
def flutterRoot = localProperties.getProperty('flutter.sdk') def flutterRoot = localProperties.getProperty('flutter.sdk')
if (flutterRoot == null) { if (flutterRoot == null) {
throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
@@ -50,16 +56,23 @@ android {
// minSdkVersion flutter.minSdkVersion // minSdkVersion flutter.minSdkVersion
// targetSdkVersion flutter.targetSdkVersion // targetSdkVersion flutter.targetSdkVersion
minSdkVersion 21 minSdkVersion 21
targetSdkVersion 31 targetSdkVersion 33
versionCode flutterVersionCode.toInteger() versionCode flutterVersionCode.toInteger()
versionName flutterVersionName versionName flutterVersionName
} }
signingConfigs {
release {
keyAlias keystoreProperties['keyAlias']
keyPassword keystoreProperties['keyPassword']
storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null
storePassword keystoreProperties['storePassword']
}
}
buildTypes { buildTypes {
release { release {
// TODO: Add your own signing config for the release build. signingConfig signingConfigs.release
// Signing with the debug keys for now, so `flutter run --release` works.
signingConfig signingConfigs.debug
} }
} }
} }

View File

@@ -13,6 +13,8 @@ PODS:
- FMDB/standard (2.7.5) - FMDB/standard (2.7.5)
- just_audio (0.0.1): - just_audio (0.0.1):
- Flutter - Flutter
- package_info_plus (0.4.5):
- Flutter
- path_provider_foundation (0.0.1): - path_provider_foundation (0.0.1):
- Flutter - Flutter
- FlutterMacOS - FlutterMacOS
@@ -36,6 +38,7 @@ DEPENDENCIES:
- Flutter (from `Flutter`) - Flutter (from `Flutter`)
- flutter_native_splash (from `.symlinks/plugins/flutter_native_splash/ios`) - flutter_native_splash (from `.symlinks/plugins/flutter_native_splash/ios`)
- just_audio (from `.symlinks/plugins/just_audio/ios`) - just_audio (from `.symlinks/plugins/just_audio/ios`)
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/ios`) - path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/ios`)
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/ios`) - shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/ios`)
- sign_in_with_apple (from `.symlinks/plugins/sign_in_with_apple/ios`) - sign_in_with_apple (from `.symlinks/plugins/sign_in_with_apple/ios`)
@@ -60,6 +63,8 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/flutter_native_splash/ios" :path: ".symlinks/plugins/flutter_native_splash/ios"
just_audio: just_audio:
:path: ".symlinks/plugins/just_audio/ios" :path: ".symlinks/plugins/just_audio/ios"
package_info_plus:
:path: ".symlinks/plugins/package_info_plus/ios"
path_provider_foundation: path_provider_foundation:
:path: ".symlinks/plugins/path_provider_foundation/ios" :path: ".symlinks/plugins/path_provider_foundation/ios"
shared_preferences_foundation: shared_preferences_foundation:
@@ -81,6 +86,7 @@ SPEC CHECKSUMS:
flutter_native_splash: 52501b97d1c0a5f898d687f1646226c1f93c56ef flutter_native_splash: 52501b97d1c0a5f898d687f1646226c1f93c56ef
FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a
just_audio: baa7252489dbcf47a4c7cc9ca663e9661c99aafa just_audio: baa7252489dbcf47a4c7cc9ca663e9661c99aafa
package_info_plus: fd030dabf36271f146f1f3beacd48f564b0f17f7
path_provider_foundation: c68054786f1b4f3343858c1e1d0caaded73f0be9 path_provider_foundation: c68054786f1b4f3343858c1e1d0caaded73f0be9
shared_preferences_foundation: 986fc17f3d3251412d18b0265f9c64113a8c2472 shared_preferences_foundation: 986fc17f3d3251412d18b0265f9c64113a8c2472
sign_in_with_apple: f3bf75217ea4c2c8b91823f225d70230119b8440 sign_in_with_apple: f3bf75217ea4c2c8b91823f225d70230119b8440

View File

@@ -35,7 +35,7 @@ enum FDSourceType {
rss, rss,
stackoverflow, stackoverflow,
tumblr, tumblr,
x, // x,
youtube, youtube,
none, none,
} }
@@ -72,8 +72,8 @@ extension FDSourceTypeExtension on FDSourceType {
return 'StackOverflow'; return 'StackOverflow';
case FDSourceType.tumblr: case FDSourceType.tumblr:
return 'Tumblr'; return 'Tumblr';
case FDSourceType.x: // case FDSourceType.x:
return 'X'; // return 'X';
case FDSourceType.youtube: case FDSourceType.youtube:
return 'YouTube'; return 'YouTube';
default: default:
@@ -105,8 +105,8 @@ extension FDSourceTypeExtension on FDSourceType {
return const Color(0xffef8236); return const Color(0xffef8236);
case FDSourceType.tumblr: case FDSourceType.tumblr:
return const Color(0xff34526f); return const Color(0xff34526f);
case FDSourceType.x: // case FDSourceType.x:
return const Color(0xff000000); // return const Color(0xff000000);
case FDSourceType.youtube: case FDSourceType.youtube:
return const Color(0xffff0000); return const Color(0xffff0000);
default: default:

View File

@@ -3,16 +3,21 @@ import 'package:supabase_flutter/supabase_flutter.dart';
import 'package:timeago/timeago.dart' as timeago; import 'package:timeago/timeago.dart' as timeago;
/// The [SettingsRepository] is a singleton class that is used to store the /// The [SettingsRepository] is a singleton class that is used to store the
/// settings of the app. This includes the url and anon key of the Supabase. The /// settings of the app and to initialize the `timeago` package and the Supabase
/// [SettingsRepository] must be initialized in our main function by calling the /// client. The [SettingsRepository] must be initialized in our main function by
/// [init] method. /// calling the [init] method.
class SettingsRepository { class SettingsRepository {
static final SettingsRepository _instance = SettingsRepository._internal(); static final SettingsRepository _instance = SettingsRepository._internal();
String supabaseUrl = ''; /// The [supabaseUrl], [supabaseAnonKey], [supabaseSiteUrl] and
String supabaseAnonKey = ''; /// [googleClientId] can be adjusted during build time or by a user during
String supabaseSiteUrl = ''; /// runtime. By default the values of our production instance will be used.
String googleClientId = ''; String supabaseUrl = 'https://ityjucpsrasavriepscr.supabase.co';
String supabaseAnonKey =
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Iml0eWp1Y3BzcmFzYXZyaWVwc2NyIiwicm9sZSI6ImFub24iLCJpYXQiOjE2OTQwMjY0NjIsImV4cCI6MjAwOTYwMjQ2Mn0.IDo7j9Kh8-5kHLtrZtHTvLf8lUkj7jiLynpIXSZbRFs';
String supabaseSiteUrl = 'https://app.feeddeck.app';
String googleClientId =
'420185423235-9ehth1eodl4lt3cdns7kaf2e89eo6rkq.apps.googleusercontent.com';
factory SettingsRepository() { factory SettingsRepository() {
return _instance; return _instance;
@@ -21,9 +26,10 @@ class SettingsRepository {
SettingsRepository._internal(); SettingsRepository._internal();
/// The [init] method initializes the [SettingsRepository] by reading the /// The [init] method initializes the [SettingsRepository] by reading the
/// Supabase url and anon key from the shared preferences. If the Supabase url /// the values which can be configured by the user from the shared preferences
/// and anon key are not stored in the shared preferences, the values from the /// and by reading the values from the environment variables. When all values
/// environment variables are used. /// were set by a user they will be used. If not we check if all environment
/// variables are set and use them. If not we use the default values.
Future<void> init() async { Future<void> init() async {
try { try {
timeago.setLocaleMessages('en', timeago.EnShortMessages()); timeago.setLocaleMessages('en', timeago.EnShortMessages());
@@ -35,10 +41,17 @@ class SettingsRepository {
final String? supabaseSiteUrlPrefs = prefs.getString('supabaseSiteUrl'); final String? supabaseSiteUrlPrefs = prefs.getString('supabaseSiteUrl');
final String? googleClientIdPrefs = prefs.getString('googleClientId'); final String? googleClientIdPrefs = prefs.getString('googleClientId');
const supabaseUrlEnv = String.fromEnvironment('SUPABASE_URL');
const supabaseAnonKeyEnv = String.fromEnvironment('SUPABASE_ANON_KEY');
const supabaseSiteUrlEnv = String.fromEnvironment('SUPABASE_SITE_URL');
const googleClientIdEnv = String.fromEnvironment('GOOGLE_CLIENT_ID');
if (supabaseUrlPrefs != null && if (supabaseUrlPrefs != null &&
supabaseAnonKeyPrefs != null && supabaseAnonKeyPrefs != null &&
supabaseSiteUrlPrefs != null && supabaseSiteUrlPrefs != null &&
googleClientIdPrefs != null) { googleClientIdPrefs != null) {
/// Store the user provided values within the [SettingsRepository] and
/// use them to initialize the Supabase client.
supabaseUrl = supabaseUrlPrefs; supabaseUrl = supabaseUrlPrefs;
supabaseAnonKey = supabaseAnonKeyPrefs; supabaseAnonKey = supabaseAnonKeyPrefs;
supabaseSiteUrl = supabaseSiteUrlPrefs; supabaseSiteUrl = supabaseSiteUrlPrefs;
@@ -48,12 +61,12 @@ class SettingsRepository {
url: supabaseUrlPrefs, url: supabaseUrlPrefs,
anonKey: supabaseAnonKeyPrefs, anonKey: supabaseAnonKeyPrefs,
); );
} else { } else if (supabaseUrlEnv != '' &&
const supabaseUrlEnv = String.fromEnvironment('SUPABASE_URL'); supabaseAnonKeyEnv != '' &&
const supabaseAnonKeyEnv = String.fromEnvironment('SUPABASE_ANON_KEY'); supabaseSiteUrlEnv != '' &&
const supabaseSiteUrlEnv = String.fromEnvironment('SUPABASE_SITE_URL'); googleClientIdEnv != '') {
const googleClientIdEnv = String.fromEnvironment('GOOGLE_CLIENT_ID'); /// Store the values provided during the build time within the
/// [SettingsRepository] and use them to initialize the Supabase client.
supabaseUrl = supabaseUrlEnv; supabaseUrl = supabaseUrlEnv;
supabaseAnonKey = supabaseAnonKeyEnv; supabaseAnonKey = supabaseAnonKeyEnv;
supabaseSiteUrl = supabaseSiteUrlEnv; supabaseSiteUrl = supabaseSiteUrlEnv;
@@ -63,10 +76,19 @@ class SettingsRepository {
url: supabaseUrlEnv, url: supabaseUrlEnv,
anonKey: supabaseAnonKeyEnv, anonKey: supabaseAnonKeyEnv,
); );
} else {
/// Use the default values to initialize the Supabase client.
await Supabase.initialize(
url: supabaseUrl,
anonKey: supabaseAnonKey,
);
} }
} catch (_) {} } catch (_) {}
} }
/// [save] can be used to store the user provided values within the shared
/// preferences. This will not automatically use the provided values for the
/// Supabase client and a user must restart the app first.
Future<void> save( Future<void> save(
String newSupabaseUrl, String newSupabaseUrl,
String newSupabaseAnonKey, String newSupabaseAnonKey,
@@ -80,6 +102,9 @@ class SettingsRepository {
await prefs.setString('googleClientId', newGoogleClientId); await prefs.setString('googleClientId', newGoogleClientId);
} }
/// [delete] can be used to delete all values from the shared preferences.
/// This will not automatically use the default values for the Supabase client
/// and a user must restart the app first.
Future<void> delete() async { Future<void> delete() async {
final SharedPreferences prefs = await SharedPreferences.getInstance(); final SharedPreferences prefs = await SharedPreferences.getInstance();
await prefs.remove('supabaseUrl'); await prefs.remove('supabaseUrl');

View File

@@ -15,7 +15,6 @@ import 'package:feeddeck/widgets/item/details/item_details_reddit.dart';
import 'package:feeddeck/widgets/item/details/item_details_rss.dart'; import 'package:feeddeck/widgets/item/details/item_details_rss.dart';
import 'package:feeddeck/widgets/item/details/item_details_stackoverflow.dart'; import 'package:feeddeck/widgets/item/details/item_details_stackoverflow.dart';
import 'package:feeddeck/widgets/item/details/item_details_tumblr.dart'; import 'package:feeddeck/widgets/item/details/item_details_tumblr.dart';
import 'package:feeddeck/widgets/item/details/item_details_x.dart';
import 'package:feeddeck/widgets/item/details/item_details_youtube.dart'; import 'package:feeddeck/widgets/item/details/item_details_youtube.dart';
class ItemDetails extends StatelessWidget { class ItemDetails extends StatelessWidget {
@@ -111,11 +110,11 @@ class ItemDetails extends StatelessWidget {
item: item, item: item,
source: source, source: source,
); );
case FDSourceType.x: // case FDSourceType.x:
return ItemDetailsX( // return ItemDetailsX(
item: item, // item: item,
source: source, // source: source,
); // );
case FDSourceType.youtube: case FDSourceType.youtube:
return ItemDetailsYoutube( return ItemDetailsYoutube(
item: item, item: item,

View File

@@ -15,7 +15,6 @@ import 'package:feeddeck/widgets/item/preview/item_preview_reddit.dart';
import 'package:feeddeck/widgets/item/preview/item_preview_rss.dart'; import 'package:feeddeck/widgets/item/preview/item_preview_rss.dart';
import 'package:feeddeck/widgets/item/preview/item_preview_stackoverflow.dart'; import 'package:feeddeck/widgets/item/preview/item_preview_stackoverflow.dart';
import 'package:feeddeck/widgets/item/preview/item_preview_tumblr.dart'; import 'package:feeddeck/widgets/item/preview/item_preview_tumblr.dart';
import 'package:feeddeck/widgets/item/preview/item_preview_x.dart';
import 'package:feeddeck/widgets/item/preview/item_preview_youtube.dart'; import 'package:feeddeck/widgets/item/preview/item_preview_youtube.dart';
/// The [ItemPreview] widget displays a preview for an item in a column based on /// The [ItemPreview] widget displays a preview for an item in a column based on
@@ -93,11 +92,11 @@ class ItemPreview extends StatelessWidget {
item: item, item: item,
source: source, source: source,
); );
case FDSourceType.x: // case FDSourceType.x:
return ItemPreviewX( // return ItemPreviewX(
item: item, // item: item,
source: source, // source: source,
); // );
case FDSourceType.youtube: case FDSourceType.youtube:
return ItemPreviewYoutube( return ItemPreviewYoutube(
item: item, item: item,

View File

@@ -13,7 +13,6 @@ import 'package:feeddeck/widgets/source/add/add_source_reddit.dart';
import 'package:feeddeck/widgets/source/add/add_source_rss.dart'; import 'package:feeddeck/widgets/source/add/add_source_rss.dart';
import 'package:feeddeck/widgets/source/add/add_source_stackoverflow.dart'; import 'package:feeddeck/widgets/source/add/add_source_stackoverflow.dart';
import 'package:feeddeck/widgets/source/add/add_source_tumblr.dart'; import 'package:feeddeck/widgets/source/add/add_source_tumblr.dart';
import 'package:feeddeck/widgets/source/add/add_source_x.dart';
import 'package:feeddeck/widgets/source/add/add_source_youtube.dart'; import 'package:feeddeck/widgets/source/add/add_source_youtube.dart';
import 'package:feeddeck/widgets/source/source_icon.dart'; import 'package:feeddeck/widgets/source/source_icon.dart';
@@ -80,9 +79,9 @@ class _AddSourceState extends State<AddSource> {
return AddSourceTumblr(column: widget.column); return AddSourceTumblr(column: widget.column);
} }
if (_sourceType == FDSourceType.x) { // if (_sourceType == FDSourceType.x) {
return AddSourceX(column: widget.column); // return AddSourceX(column: widget.column);
} // }
if (_sourceType == FDSourceType.stackoverflow) { if (_sourceType == FDSourceType.stackoverflow) {
return AddSourceStackOverflow(column: widget.column); return AddSourceStackOverflow(column: widget.column);

View File

@@ -15,7 +15,7 @@ const _helpText = '''
The Reddit source can be used to follow your favorite subreddits or users: The Reddit source can be used to follow your favorite subreddits or users:
- **Subreddit**: Provide the name of the subreddit (e.g. `/r/kubernetes`) - **Subreddit**: Provide the name of the subreddit (e.g. `/r/kubernetes`)
- **User**: Provide the name of the user (e.g. `/u/feeddeck`) - **User**: Provide the name of the user (e.g. `/u/reddit`)
- **Url**: Provide the url for a user or subbreddit (e.g. - **Url**: Provide the url for a user or subbreddit (e.g.
`https://www.reddit.com/r/kubernetes/` or `https://www.reddit.com/r/kubernetes.rss`) `https://www.reddit.com/r/kubernetes/` or `https://www.reddit.com/r/kubernetes.rss`)
'''; ''';

View File

@@ -1,11 +1,8 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_markdown/flutter_markdown.dart'; import 'package:flutter_markdown/flutter_markdown.dart';
import 'package:provider/provider.dart';
import 'package:feeddeck/models/column.dart'; import 'package:feeddeck/models/column.dart';
import 'package:feeddeck/models/source.dart';
import 'package:feeddeck/repositories/app_repository.dart';
import 'package:feeddeck/utils/api_exception.dart'; import 'package:feeddeck/utils/api_exception.dart';
import 'package:feeddeck/utils/constants.dart'; import 'package:feeddeck/utils/constants.dart';
import 'package:feeddeck/utils/openurl.dart'; import 'package:feeddeck/utils/openurl.dart';
@@ -44,14 +41,14 @@ class _AddSourceXState extends State<AddSourceX> {
}); });
try { try {
AppRepository app = Provider.of<AppRepository>(context, listen: false); // AppRepository app = Provider.of<AppRepository>(context, listen: false);
await app.addSource( // await app.addSource(
widget.column.id, // widget.column.id,
FDSourceType.x, // FDSourceType.x,
FDSourceOptions( // FDSourceOptions(
x: _xController.text, // x: _xController.text,
), // ),
); // );
setState(() { setState(() {
_isLoading = false; _isLoading = false;
_error = ''; _error = '';

View File

@@ -118,13 +118,13 @@ class SourceIcon extends StatelessWidget {
type.color, type.color,
const Color(0xffffffff), const Color(0xffffffff),
); );
case FDSourceType.x: // case FDSourceType.x:
return buildIcon( // return buildIcon(
FDIcons.x, // FDIcons.x,
iconSize, // iconSize,
type.color, // type.color,
const Color(0xffffffff), // const Color(0xffffffff),
); // );
case FDSourceType.youtube: case FDSourceType.youtube:
return buildIcon( return buildIcon(
FDIcons.youtube, FDIcons.youtube,

View File

@@ -11,6 +11,8 @@ PODS:
- FMDB/standard (2.7.5) - FMDB/standard (2.7.5)
- just_audio (0.0.1): - just_audio (0.0.1):
- FlutterMacOS - FlutterMacOS
- package_info_plus (0.0.1):
- FlutterMacOS
- path_provider_foundation (0.0.1): - path_provider_foundation (0.0.1):
- Flutter - Flutter
- FlutterMacOS - FlutterMacOS
@@ -35,6 +37,7 @@ DEPENDENCIES:
- audio_session (from `Flutter/ephemeral/.symlinks/plugins/audio_session/macos`) - audio_session (from `Flutter/ephemeral/.symlinks/plugins/audio_session/macos`)
- FlutterMacOS (from `Flutter/ephemeral`) - FlutterMacOS (from `Flutter/ephemeral`)
- just_audio (from `Flutter/ephemeral/.symlinks/plugins/just_audio/macos`) - just_audio (from `Flutter/ephemeral/.symlinks/plugins/just_audio/macos`)
- package_info_plus (from `Flutter/ephemeral/.symlinks/plugins/package_info_plus/macos`)
- path_provider_foundation (from `Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/macos`) - path_provider_foundation (from `Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/macos`)
- screen_retriever (from `Flutter/ephemeral/.symlinks/plugins/screen_retriever/macos`) - screen_retriever (from `Flutter/ephemeral/.symlinks/plugins/screen_retriever/macos`)
- shared_preferences_foundation (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/macos`) - shared_preferences_foundation (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/macos`)
@@ -58,6 +61,8 @@ EXTERNAL SOURCES:
:path: Flutter/ephemeral :path: Flutter/ephemeral
just_audio: just_audio:
:path: Flutter/ephemeral/.symlinks/plugins/just_audio/macos :path: Flutter/ephemeral/.symlinks/plugins/just_audio/macos
package_info_plus:
:path: Flutter/ephemeral/.symlinks/plugins/package_info_plus/macos
path_provider_foundation: path_provider_foundation:
:path: Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/macos :path: Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/macos
screen_retriever: screen_retriever:
@@ -80,6 +85,7 @@ SPEC CHECKSUMS:
FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24 FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24
FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a
just_audio: 9b67ca7b97c61cfc9784ea23cd8cc55eb226d489 just_audio: 9b67ca7b97c61cfc9784ea23cd8cc55eb226d489
package_info_plus: 02d7a575e80f194102bef286361c6c326e4c29ce
path_provider_foundation: c68054786f1b4f3343858c1e1d0caaded73f0be9 path_provider_foundation: c68054786f1b4f3343858c1e1d0caaded73f0be9
screen_retriever: 59634572a57080243dd1bf715e55b6c54f241a38 screen_retriever: 59634572a57080243dd1bf715e55b6c54f241a38
shared_preferences_foundation: 986fc17f3d3251412d18b0265f9c64113a8c2472 shared_preferences_foundation: 986fc17f3d3251412d18b0265f9c64113a8c2472

View File

@@ -57,7 +57,7 @@
27D60858A3CD81E41E2CDBF2 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 27D60858A3CD81E41E2CDBF2 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = "<group>"; }; 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = "<group>"; };
335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = "<group>"; }; 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = "<group>"; };
33CC10ED2044A3C60003C045 /* feeddeck.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = feeddeck.app; sourceTree = BUILT_PRODUCTS_DIR; }; 33CC10ED2044A3C60003C045 /* FeedDeck.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = FeedDeck.app; sourceTree = BUILT_PRODUCTS_DIR; };
33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; }; 33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = "<group>"; }; 33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = "<group>"; };
33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = "<group>"; }; 33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = "<group>"; };
@@ -94,7 +94,6 @@
46A27EFECA16837D10C377EF /* Pods-Runner.release.xcconfig */, 46A27EFECA16837D10C377EF /* Pods-Runner.release.xcconfig */,
1AC2239B5C64F660215E2FFD /* Pods-Runner.profile.xcconfig */, 1AC2239B5C64F660215E2FFD /* Pods-Runner.profile.xcconfig */,
); );
name = Pods;
path = Pods; path = Pods;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
@@ -123,7 +122,7 @@
33CC10EE2044A3C60003C045 /* Products */ = { 33CC10EE2044A3C60003C045 /* Products */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
33CC10ED2044A3C60003C045 /* feeddeck.app */, 33CC10ED2044A3C60003C045 /* FeedDeck.app */,
); );
name = Products; name = Products;
sourceTree = "<group>"; sourceTree = "<group>";
@@ -193,7 +192,7 @@
); );
name = Runner; name = Runner;
productName = Runner; productName = Runner;
productReference = 33CC10ED2044A3C60003C045 /* feeddeck.app */; productReference = 33CC10ED2044A3C60003C045 /* FeedDeck.app */;
productType = "com.apple.product-type.application"; productType = "com.apple.product-type.application";
}; };
/* End PBXNativeTarget section */ /* End PBXNativeTarget section */
@@ -422,8 +421,9 @@
CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements;
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES; COMBINE_HIDPI_IMAGES = YES;
DEVELOPMENT_TEAM = ""; DEVELOPMENT_TEAM = 75AP6HWLUD;
INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_FILE = Runner/Info.plist;
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.news";
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"@executable_path/../Frameworks", "@executable_path/../Frameworks",
@@ -549,8 +549,9 @@
CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements;
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES; COMBINE_HIDPI_IMAGES = YES;
DEVELOPMENT_TEAM = ""; DEVELOPMENT_TEAM = 75AP6HWLUD;
INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_FILE = Runner/Info.plist;
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.news";
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"@executable_path/../Frameworks", "@executable_path/../Frameworks",
@@ -570,8 +571,9 @@
CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements; CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements;
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES; COMBINE_HIDPI_IMAGES = YES;
DEVELOPMENT_TEAM = ""; DEVELOPMENT_TEAM = 75AP6HWLUD;
INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_FILE = Runner/Info.plist;
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.news";
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"@executable_path/../Frameworks", "@executable_path/../Frameworks",

View File

@@ -15,7 +15,7 @@
<BuildableReference <BuildableReference
BuildableIdentifier = "primary" BuildableIdentifier = "primary"
BlueprintIdentifier = "33CC10EC2044A3C60003C045" BlueprintIdentifier = "33CC10EC2044A3C60003C045"
BuildableName = "feeddeck.app" BuildableName = "FeedDeck.app"
BlueprintName = "Runner" BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj"> ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference> </BuildableReference>
@@ -31,7 +31,7 @@
<BuildableReference <BuildableReference
BuildableIdentifier = "primary" BuildableIdentifier = "primary"
BlueprintIdentifier = "33CC10EC2044A3C60003C045" BlueprintIdentifier = "33CC10EC2044A3C60003C045"
BuildableName = "feeddeck.app" BuildableName = "FeedDeck.app"
BlueprintName = "Runner" BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj"> ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference> </BuildableReference>
@@ -54,7 +54,7 @@
<BuildableReference <BuildableReference
BuildableIdentifier = "primary" BuildableIdentifier = "primary"
BlueprintIdentifier = "33CC10EC2044A3C60003C045" BlueprintIdentifier = "33CC10EC2044A3C60003C045"
BuildableName = "feeddeck.app" BuildableName = "FeedDeck.app"
BlueprintName = "Runner" BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj"> ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference> </BuildableReference>
@@ -71,7 +71,7 @@
<BuildableReference <BuildableReference
BuildableIdentifier = "primary" BuildableIdentifier = "primary"
BlueprintIdentifier = "33CC10EC2044A3C60003C045" BlueprintIdentifier = "33CC10EC2044A3C60003C045"
BuildableName = "feeddeck.app" BuildableName = "FeedDeck.app"
BlueprintName = "Runner" BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj"> ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference> </BuildableReference>

View File

@@ -2,9 +2,13 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0"> <plist version="1.0">
<dict> <dict>
<key>com.apple.security.app-sandbox</key>
<true/>
<key>com.apple.security.cs.allow-jit</key> <key>com.apple.security.cs.allow-jit</key>
<true/> <true/>
<key>com.apple.security.network.client</key> <key>com.apple.security.network.client</key>
<true/> <true/>
<key>com.apple.security.network.server</key>
<true/>
</dict> </dict>
</plist> </plist>

View File

@@ -33,5 +33,7 @@
<key>NSAllowsArbitraryLoads</key> <key>NSAllowsArbitraryLoads</key>
<true/> <true/>
</dict> </dict>
<key>LSApplicationCategoryType</key>
<string>public.app-category.news</string>
</dict> </dict>
</plist> </plist>

View File

@@ -2,7 +2,11 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0"> <plist version="1.0">
<dict> <dict>
<key>com.apple.security.app-sandbox</key>
<true/>
<key>com.apple.security.network.client</key> <key>com.apple.security.network.client</key>
<true/> <true/>
<key>com.apple.security.network.server</key>
<true/>
</dict> </dict>
</plist> </plist>

View File

@@ -16,7 +16,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
# In Windows, build-name is used as the major, minor, and patch parts # In Windows, build-name is used as the major, minor, and patch parts
# of the product and file versions while build-number is used as the build suffix. # of the product and file versions while build-number is used as the build suffix.
version: 0.1.0+1 version: 1.0.0+2
environment: environment:
sdk: '>=2.19.6 <3.0.0' sdk: '>=2.19.6 <3.0.0'
@@ -160,7 +160,8 @@ msix_config:
publisher_display_name: Rico Berger publisher_display_name: Rico Berger
identity_name: 26077RicoBerger.FeedDeck identity_name: 26077RicoBerger.FeedDeck
publisher: CN=7740451A-C179-450A-B346-7231CA231332 publisher: CN=7740451A-C179-450A-B346-7231CA231332
msix_version: 0.1.0.1 msix_version: 1.0.0.0
logo_path: templates/app-icon/windows.png
languages: en-us languages: en-us
capabilities: internetClient capabilities: internetClient
protocol_activation: http,https protocol_activation: http,https

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

View File

@@ -19,7 +19,7 @@
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta content="IE=Edge" http-equiv="X-UA-Compatible"> <meta content="IE=Edge" http-equiv="X-UA-Compatible">
<meta name="description" content="A new Flutter project."> <meta name="description" content="Follow your RSS and Social Media Feeds">
<!-- iOS meta tags & icons --> <!-- iOS meta tags & icons -->
<meta name="apple-mobile-web-app-capable" content="yes"> <meta name="apple-mobile-web-app-capable" content="yes">
@@ -73,4 +73,4 @@
</body> </body>
</html> </html>

View File

@@ -1,35 +1,35 @@
{ {
"name": "FeedDeck", "name": "FeedDeck",
"short_name": "FeedDeck", "short_name": "FeedDeck",
"start_url": ".", "start_url": ".",
"display": "standalone", "display": "standalone",
"background_color": "#49d3b4", "background_color": "#49d3b4",
"theme_color": "#49d3b4", "theme_color": "#49d3b4",
"description": "A new Flutter project.", "description": "Follow your RSS and Social Media Feeds",
"orientation": "portrait-primary", "orientation": "portrait-primary",
"prefer_related_applications": false, "prefer_related_applications": false,
"icons": [ "icons": [
{ {
"src": "icons/Icon-192.png", "src": "icons/Icon-192.png",
"sizes": "192x192", "sizes": "192x192",
"type": "image/png" "type": "image/png"
}, },
{ {
"src": "icons/Icon-512.png", "src": "icons/Icon-512.png",
"sizes": "512x512", "sizes": "512x512",
"type": "image/png" "type": "image/png"
}, },
{ {
"src": "icons/Icon-maskable-192.png", "src": "icons/Icon-maskable-192.png",
"sizes": "192x192", "sizes": "192x192",
"type": "image/png", "type": "image/png",
"purpose": "maskable" "purpose": "maskable"
}, },
{ {
"src": "icons/Icon-maskable-512.png", "src": "icons/Icon-maskable-512.png",
"sizes": "512x512", "sizes": "512x512",
"type": "image/png", "type": "image/png",
"purpose": "maskable" "purpose": "maskable"
} }
] ]
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 13 KiB

View File

@@ -97,8 +97,8 @@ export const getFeed = async (
); );
case "tumblr": case "tumblr":
return await getTumblrFeed(supabaseClient, redisClient, profile, source); return await getTumblrFeed(supabaseClient, redisClient, profile, source);
case "x": // case "x":
return await getXFeed(supabaseClient, redisClient, profile, source); // return await getXFeed(supabaseClient, redisClient, profile, source);
case "youtube": case "youtube":
return await getYoutubeFeed(supabaseClient, redisClient, profile, source); return await getYoutubeFeed(supabaseClient, redisClient, profile, source);
default: default: