From 9a206d5638e7241e352bd85cf15039fff293b181 Mon Sep 17 00:00:00 2001 From: Tien Do Nam Date: Wed, 6 Dec 2023 18:52:10 +0100 Subject: [PATCH] feat: FOSS version --- .github/workflows/compile_apk.yml | 76 +++++++++++++++++++ .github/workflows/release.yml | 3 + app/lib/init.dart | 5 +- app/lib/model/state/purchase_state.dart | 3 +- .../model/state/purchase_state.mapper.dart | 18 ++--- app/lib/pages/donation/donation_page.dart | 7 +- app/lib/pages/donation/donation_page_vm.dart | 23 +++++- app/lib/provider/purchase_provider.dart | 2 +- app/pubspec.yaml | 2 +- scripts/remove_proprietary_dependencies.sh | 30 ++++++++ 10 files changed, 148 insertions(+), 21 deletions(-) create mode 100644 .github/workflows/compile_apk.yml create mode 100755 scripts/remove_proprietary_dependencies.sh diff --git a/.github/workflows/compile_apk.yml b/.github/workflows/compile_apk.yml new file mode 100644 index 00000000..b50483c6 --- /dev/null +++ b/.github/workflows/compile_apk.yml @@ -0,0 +1,76 @@ +name: Compile APK + +on: + workflow_dispatch: + +env: + FLUTTER_VERSION: "3.16.2" + APK_BUILD_DIR: "/tmp/build" + +jobs: + build: + runs-on: ubuntu-20.04 + outputs: + version: ${{ steps.get_version.outputs.version }} + + steps: + - uses: actions/checkout@v4 + + - name: Get version from pubspec.yaml + id: get_version + run: | + VERSION=$(sed -n 's/^version: \([0-9]*\.[0-9]*\.[0-9]*\).*/\1/p' app/pubspec.yaml) + echo "version=$VERSION" >> $GITHUB_OUTPUT + + build_apk: + needs: build + runs-on: ubuntu-22.04 + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Remove proprietary dependencies + run: sh scripts/remove_proprietary_dependencies.sh + + - name: Copy files to env.APK_BUILD_DIR + run: | + mkdir -p $APK_BUILD_DIR + cp -r . $APK_BUILD_DIR + + - name: Decode key.properties file + working-directory: ${{ env.APK_BUILD_DIR }} + env: + ENCODED_STRING: ${{ secrets.ANDROID_KEY_PROPERTIES }} + run: echo $ENCODED_STRING | base64 -di > app/android/key.properties + + - name: Decode android-keystore.jks file + working-directory: ${{ env.APK_BUILD_DIR }} + env: + ENCODED_STRING: ${{ secrets.ANDROID_KEY_STORE }} + run: mkdir secrets && echo $ENCODED_STRING | base64 -di > secrets/android-keystore.jks + + - name: Set up JDK 11 + uses: actions/setup-java@v4 + with: + distribution: 'temurin' + java-version: '11' + + - name: Install Flutter + uses: subosito/flutter-action@v2 + with: + flutter-version: ${{ env.FLUTTER_VERSION }} + + - name: Dependencies + working-directory: ${{ env.APK_BUILD_DIR }}/app + run: flutter pub get + + - name: Build APK + working-directory: ${{ env.APK_BUILD_DIR }}/app + run: flutter build apk + + - name: Upload APK + uses: actions/upload-artifact@v3 + with: + name: apk-result + path: ${{ env.APK_BUILD_DIR }}/app/build/app/outputs/flutter-apk/app-release.apk diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 03838ad8..47282335 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -30,6 +30,9 @@ jobs: - name: Checkout repository uses: actions/checkout@v4 + - name: Remove proprietary dependencies + run: sh scripts/remove_proprietary_dependencies.sh + - name: Copy files to env.APK_BUILD_DIR run: | mkdir -p $APK_BUILD_DIR diff --git a/app/lib/init.dart b/app/lib/init.dart index b002c44f..f199c462 100644 --- a/app/lib/init.dart +++ b/app/lib/init.dart @@ -15,7 +15,9 @@ import 'package:localsend_app/provider/dio_provider.dart'; import 'package:localsend_app/provider/network/nearby_devices_provider.dart'; import 'package:localsend_app/provider/network/server/server_provider.dart'; import 'package:localsend_app/provider/persistence_provider.dart'; +// [FOSS_REMOVE_START] import 'package:localsend_app/provider/purchase_provider.dart'; +// [FOSS_REMOVE_END] import 'package:localsend_app/provider/selection/selected_sending_files_provider.dart'; import 'package:localsend_app/provider/tv_provider.dart'; import 'package:localsend_app/provider/window_dimensions_provider.dart'; @@ -175,11 +177,12 @@ Future postInit(BuildContext context, Ref ref, bool appStart, void Functio ref.dispatchAsync(ClearCacheAction()); // ignore: unawaited_futures } - + // [FOSS_REMOVE_START] if (checkPlatformSupportPayment()) { // ignore: unawaited_futures ref.redux(purchaseProvider).dispatchAsync(InitPurchaseStream()); } + // [FOSS_REMOVE_END] } class _HandleShareIntentAction extends AsyncGlobalAction { diff --git a/app/lib/model/state/purchase_state.dart b/app/lib/model/state/purchase_state.dart index 37ae5723..45416692 100644 --- a/app/lib/model/state/purchase_state.dart +++ b/app/lib/model/state/purchase_state.dart @@ -1,6 +1,5 @@ import 'package:dart_mappable/dart_mappable.dart'; import 'package:flutter/foundation.dart'; -import 'package:in_app_purchase/in_app_purchase.dart'; part 'purchase_state.mapper.dart'; @@ -36,7 +35,7 @@ enum PurchaseItem { @MappableClass() class PurchaseState with PurchaseStateMappable { final Map prices; - final Map purchases; + final Set purchases; final bool pending; const PurchaseState({ diff --git a/app/lib/model/state/purchase_state.mapper.dart b/app/lib/model/state/purchase_state.mapper.dart index 67830be5..cee1462e 100644 --- a/app/lib/model/state/purchase_state.mapper.dart +++ b/app/lib/model/state/purchase_state.mapper.dart @@ -23,10 +23,9 @@ class PurchaseStateMapper extends ClassMapperBase { static Map _$prices(PurchaseState v) => v.prices; static const Field> _f$prices = Field('prices', _$prices); - static Map _$purchases(PurchaseState v) => - v.purchases; - static const Field> - _f$purchases = Field('purchases', _$purchases); + static Set _$purchases(PurchaseState v) => v.purchases; + static const Field> _f$purchases = + Field('purchases', _$purchases); static bool _$pending(PurchaseState v) => v.pending; static const Field _f$pending = Field('pending', _$pending); @@ -102,11 +101,9 @@ abstract class PurchaseStateCopyWith<$R, $In extends PurchaseState, $Out> implements ClassCopyWith<$R, $In, $Out> { MapCopyWith<$R, PurchaseItem, String, ObjectCopyWith<$R, String, String>> get prices; - MapCopyWith<$R, PurchaseItem, PurchaseDetails, - ObjectCopyWith<$R, PurchaseDetails, PurchaseDetails>> get purchases; $R call( {Map? prices, - Map? purchases, + Set? purchases, bool? pending}); PurchaseStateCopyWith<$R2, $In, $Out2> $chain<$R2, $Out2>(Then<$Out2, $R2> t); } @@ -124,14 +121,9 @@ class _PurchaseStateCopyWithImpl<$R, $Out> get prices => MapCopyWith($value.prices, (v, t) => ObjectCopyWith(v, $identity, t), (v) => call(prices: v)); @override - MapCopyWith<$R, PurchaseItem, PurchaseDetails, - ObjectCopyWith<$R, PurchaseDetails, PurchaseDetails>> - get purchases => MapCopyWith($value.purchases, - (v, t) => ObjectCopyWith(v, $identity, t), (v) => call(purchases: v)); - @override $R call( {Map? prices, - Map? purchases, + Set? purchases, bool? pending}) => $apply(FieldCopyWithData({ if (prices != null) #prices: prices, diff --git a/app/lib/pages/donation/donation_page.dart b/app/lib/pages/donation/donation_page.dart index 725f6830..27e3159a 100644 --- a/app/lib/pages/donation/donation_page.dart +++ b/app/lib/pages/donation/donation_page.dart @@ -2,8 +2,9 @@ import 'package:flutter/material.dart'; import 'package:localsend_app/gen/strings.g.dart'; import 'package:localsend_app/model/state/purchase_state.dart'; import 'package:localsend_app/pages/donation/donation_page_vm.dart'; +// [FOSS_REMOVE_START] import 'package:localsend_app/provider/purchase_provider.dart'; -import 'package:localsend_app/util/native/platform_check.dart'; +// [FOSS_REMOVE_END] import 'package:localsend_app/widget/responsive_list_view.dart'; import 'package:refena_flutter/refena_flutter.dart'; import 'package:url_launcher/url_launcher.dart'; @@ -15,7 +16,9 @@ class DonationPage extends StatelessWidget { Widget build(BuildContext context) { return ViewModelBuilder( provider: donationPageVmProvider, + // [FOSS_REMOVE_START] init: (context, ref) => ref.redux(purchaseProvider).dispatchAsync(FetchPricesAndPurchasesAction()), // ignore: discarded_futures + // [FOSS_REMOVE_END] builder: (context, vm) { return Scaffold( appBar: AppBar( @@ -45,7 +48,7 @@ class DonationPage extends StatelessWidget { ), ), ), - if (checkPlatformSupportPayment()) _StoreDonation(vm) else const _LinkDonation(), + if (vm.platformSupportPayment) _StoreDonation(vm) else const _LinkDonation(), ], ), if (vm.pending) diff --git a/app/lib/pages/donation/donation_page_vm.dart b/app/lib/pages/donation/donation_page_vm.dart index b60e2232..9a7387cc 100644 --- a/app/lib/pages/donation/donation_page_vm.dart +++ b/app/lib/pages/donation/donation_page_vm.dart @@ -1,8 +1,12 @@ import 'package:localsend_app/model/state/purchase_state.dart'; +// [FOSS_REMOVE_START] import 'package:localsend_app/provider/purchase_provider.dart'; +// [FOSS_REMOVE_END] +import 'package:localsend_app/util/native/platform_check.dart'; import 'package:refena_flutter/refena_flutter.dart'; class DonationPageVm { + final bool platformSupportPayment; final Map prices; final Set purchased; final bool pending; @@ -10,6 +14,7 @@ class DonationPageVm { final void Function() restore; DonationPageVm({ + required this.platformSupportPayment, required this.prices, required this.purchased, required this.pending, @@ -18,13 +23,29 @@ class DonationPageVm { }); } +// [FOSS_REMOVE_START] final donationPageVmProvider = ViewProvider((ref) { final state = ref.watch(purchaseProvider); return DonationPageVm( + platformSupportPayment: checkPlatformSupportPayment(), prices: state.prices, - purchased: state.purchases.keys.toSet(), + purchased: state.purchases, pending: state.pending, purchase: (item) => ref.redux(purchaseProvider).dispatchAsync(PurchaseAction(item)), restore: () => ref.redux(purchaseProvider).dispatchAsync(PurchaseRestoreAction()), ); }); +// [FOSS_REMOVE_END] + +/// This is a noop version of the original view model. +/// Used to compile the FOSS version of the app by removing the original provider above. +final donationPageNoopVmProvider = ViewProvider((ref) { + return DonationPageVm( + platformSupportPayment: false, + prices: {}, + purchased: {}, + pending: false, + purchase: (_) {}, + restore: () {}, + ); +}); diff --git a/app/lib/provider/purchase_provider.dart b/app/lib/provider/purchase_provider.dart index 45d61d19..d86cb585 100644 --- a/app/lib/provider/purchase_provider.dart +++ b/app/lib/provider/purchase_provider.dart @@ -123,7 +123,7 @@ class AddPurchaseAction extends ReduxAction { return state.copyWith( purchases: { ...state.purchases, - item: purchase, + item, }, ); } diff --git a/app/pubspec.yaml b/app/pubspec.yaml index d8a96584..7fa4d8f5 100644 --- a/app/pubspec.yaml +++ b/app/pubspec.yaml @@ -32,7 +32,7 @@ dependencies: flutter_markdown: 0.6.18+2 gal: 2.1.4 image_picker: 1.0.4 - in_app_purchase: 3.1.11 + in_app_purchase: 3.1.11 # [FOSS_REMOVE] intl: ^0.18.0 # allow newer versions, so it can compile with newer Flutter versions launch_at_startup: 0.2.2 logging: 1.2.0 diff --git a/scripts/remove_proprietary_dependencies.sh b/scripts/remove_proprietary_dependencies.sh new file mode 100755 index 00000000..93483a2d --- /dev/null +++ b/scripts/remove_proprietary_dependencies.sh @@ -0,0 +1,30 @@ +#!/bin/sh + +# This script removes proprietary dependencies from the project. + +cd app + +REGEX_A="s/\/\/ \[FOSS_REMOVE_START\]/\/*/" +REGEX_B="s/\/\/ \[FOSS_REMOVE_END\]/\*\//" + +# Remove lines from pubspec.yaml +sed -i '/# \[FOSS_REMOVE\]/d' pubspec.yaml + +# Comment out parts in Dart files +sed -i "$REGEX_A" lib/init.dart +sed -i "$REGEX_B" lib/init.dart + +sed -i "$REGEX_A" lib/pages/donation/donation_page.dart +sed -i "$REGEX_B" lib/pages/donation/donation_page.dart + +sed -i "$REGEX_A" lib/pages/donation/donation_page_vm.dart +sed -i "$REGEX_B" lib/pages/donation/donation_page_vm.dart + +# Remove files completely +rm lib/provider/purchase_provider.dart + +# Refer to donationPageNoopVmProvider instead of donationPageVmProvider +sed -i 's/donationPageVmProvider/donationPageNoopVmProvider/g' lib/pages/donation/donation_page.dart + +cd .. +echo "Proprietary dependencies removed."