Jelajahi Sumber

Fix events on sign in

vishnukvmd 2 tahun lalu
induk
melakukan
8d7cbc7c01

+ 1 - 1
.vscode/launch.json

@@ -14,7 +14,7 @@
       "request": "launch",
       "type": "dart",
       "program": "lib/main.dart",
-      "args": ["--dart-define", "endpoint=http://192.168.1.33:8080"]
+      "args": ["--dart-define", "endpoint=http://192.168.1.3:8080"]
     },
     {
       "name": "Prod",

+ 8 - 9
lib/app/view/app.dart

@@ -6,8 +6,8 @@ import 'package:adaptive_theme/adaptive_theme.dart';
 import 'package:ente_auth/core/configuration.dart';
 import 'package:ente_auth/core/event_bus.dart';
 import 'package:ente_auth/ente_theme_data.dart';
-import 'package:ente_auth/events/account_configured_event.dart';
-import 'package:ente_auth/events/user_logged_out_event.dart';
+import 'package:ente_auth/events/signed_in_event.dart';
+import 'package:ente_auth/events/signed_out_event.dart';
 import "package:ente_auth/l10n/l10n.dart";
 import "package:ente_auth/onboarding/view/onboarding_page.dart";
 import 'package:ente_auth/ui/home_page.dart';
@@ -24,18 +24,17 @@ class App extends StatefulWidget {
 }
 
 class _AppState extends State<App> {
-  StreamSubscription<UserLoggedOutEvent> _loggedOutEvent;
-  StreamSubscription<AccountConfiguredEvent> _accountConfiguredEvent;
+  StreamSubscription<SignedOutEvent> _signedOutEvent;
+  StreamSubscription<SignedInEvent> _signedInEvent;
 
   @override
   void initState() {
-    _loggedOutEvent = Bus.instance.on<UserLoggedOutEvent>().listen((event) {
+    _signedOutEvent = Bus.instance.on<SignedOutEvent>().listen((event) {
       if (mounted) {
         setState(() {});
       }
     });
-    _accountConfiguredEvent =
-        Bus.instance.on<AccountConfiguredEvent>().listen((event) {
+    _signedInEvent = Bus.instance.on<SignedInEvent>().listen((event) {
       if (mounted) {
         setState(() {});
       }
@@ -46,8 +45,8 @@ class _AppState extends State<App> {
   @override
   void dispose() {
     super.dispose();
-    _loggedOutEvent.cancel();
-    _accountConfiguredEvent.cancel();
+    _signedOutEvent.cancel();
+    _signedInEvent.cancel();
   }
 
   @override

+ 2 - 2
lib/core/configuration.dart

@@ -8,7 +8,7 @@ import 'package:ente_auth/core/constants.dart';
 import 'package:ente_auth/core/errors.dart';
 import 'package:ente_auth/core/event_bus.dart';
 import 'package:ente_auth/events/signed_in_event.dart';
-import 'package:ente_auth/events/user_logged_out_event.dart';
+import 'package:ente_auth/events/signed_out_event.dart';
 import 'package:ente_auth/models/key_attributes.dart';
 import 'package:ente_auth/models/key_gen_result.dart';
 import 'package:ente_auth/models/private_key_attributes.dart';
@@ -130,7 +130,7 @@ class Configuration {
     _key = null;
     _cachedToken = null;
     _secretKey = null;
-    Bus.instance.fire(UserLoggedOutEvent());
+    Bus.instance.fire(SignedOutEvent());
   }
 
   Future<KeyGenResult> generateKey(String password) async {

+ 0 - 3
lib/events/account_configured_event.dart

@@ -1,3 +0,0 @@
-import 'package:ente_auth/events/event.dart';
-
-class AccountConfiguredEvent extends Event {}

+ 1 - 1
lib/events/user_logged_out_event.dart → lib/events/signed_out_event.dart

@@ -1,3 +1,3 @@
 import 'package:ente_auth/events/event.dart';
 
-class UserLoggedOutEvent extends Event {}
+class SignedOutEvent extends Event {}

+ 0 - 3
lib/events/subscription_purchased_event.dart

@@ -1,3 +0,0 @@
-import 'package:ente_auth/events/event.dart';
-
-class SubscriptionPurchasedEvent extends Event {}

+ 0 - 7
lib/events/two_factor_status_change_event.dart

@@ -1,7 +0,0 @@
-import 'package:ente_auth/events/event.dart';
-
-class TwoFactorStatusChangeEvent extends Event {
-  final bool status;
-
-  TwoFactorStatusChangeEvent(this.status);
-}

+ 12 - 4
lib/services/authenticator_service.dart

@@ -6,7 +6,8 @@ import 'package:ente_auth/core/configuration.dart';
 import 'package:ente_auth/core/errors.dart';
 import 'package:ente_auth/core/event_bus.dart';
 import 'package:ente_auth/core/network.dart';
-import 'package:ente_auth/events/account_configured_event.dart';
+import 'package:ente_auth/events/codes_updated_event.dart';
+import 'package:ente_auth/events/signed_in_event.dart';
 import 'package:ente_auth/gateway/authenticator.dart';
 import 'package:ente_auth/models/authenticator/auth_entity.dart';
 import 'package:ente_auth/models/authenticator/auth_key.dart';
@@ -38,7 +39,7 @@ class AuthenticatorService {
     if (Configuration.instance.hasConfiguredAccount()) {
       unawaited(sync());
     }
-    Bus.instance.on<AccountConfiguredEvent>().listen((event) {
+    Bus.instance.on<SignedInEvent>().listen((event) {
       unawaited(sync());
     });
   }
@@ -107,7 +108,10 @@ class AuthenticatorService {
     try {
       _logger.info("Sync");
       await _remoteToLocalSync();
+      _logger.info("remote fetch completed");
       await _localToRemoteSync();
+      _logger.info("local push completed");
+      Bus.instance.fire(CodesUpdatedEvent());
     } catch (e) {
       _logger.severe("Failed to sync with remote", e);
     }
@@ -120,8 +124,9 @@ class AuthenticatorService {
     final List<AuthEntity> result =
         await _gateway.getDiff(lastSyncTime, limit: fetchLimit);
     if (result.isEmpty) {
-      _logger.info('remote fetch completed');
       return;
+    } else {
+      _logger.info(result.length.toString() + " entries fetched from remote");
     }
     final maxSyncTime = result.map((e) => e.updatedAt).reduce(max);
     List<String> deletedIDs =
@@ -138,11 +143,14 @@ class AuthenticatorService {
   }
 
   Future<void> _localToRemoteSync() async {
-    _logger.info('Initiating  local to remote sync');
+    _logger.info('Initiating local to remote sync');
     final List<LocalAuthEntity> result = await _db.getAll();
     final List<LocalAuthEntity> pendingUpdate = result
         .where((element) => element.shouldSync || element.id == null)
         .toList();
+    _logger.info(
+      pendingUpdate.length.toString() + " entries to be updated at remote",
+    );
     for (LocalAuthEntity entity in pendingUpdate) {
       if (entity.id == null) {
         _logger.info("Adding new entry");

+ 0 - 5
lib/ui/account/password_entry_page.dart

@@ -1,9 +1,6 @@
 // @dart=2.9
 
 import 'package:ente_auth/core/configuration.dart';
-import 'package:ente_auth/core/event_bus.dart';
-import 'package:ente_auth/events/account_configured_event.dart';
-import 'package:ente_auth/events/subscription_purchased_event.dart';
 import 'package:ente_auth/services/user_service.dart';
 import 'package:ente_auth/ui/account/recovery_key_page.dart';
 import 'package:ente_auth/ui/common/dynamic_fab.dart';
@@ -393,7 +390,6 @@ class _PasswordEntryPageState extends State<PasswordEntryPage> {
       showShortToast(context, "Password changed successfully");
       Navigator.of(context).pop();
       if (widget.mode == PasswordEntryMode.reset) {
-        Bus.instance.fire(SubscriptionPurchasedEvent());
         Navigator.of(context).popUntil((route) => route.isFirst);
       }
     } catch (e, s) {
@@ -417,7 +413,6 @@ class _PasswordEntryPageState extends State<PasswordEntryPage> {
         try {
           await UserService.instance.setAttributes(result);
           await dialog.hide();
-          Bus.instance.fire(AccountConfiguredEvent());
           Navigator.of(context).pushAndRemoveUntil(
             MaterialPageRoute(
               builder: (BuildContext context) {

+ 0 - 3
lib/ui/account/password_reentry_page.dart

@@ -2,8 +2,6 @@
 
 import 'package:ente_auth/core/configuration.dart';
 import 'package:ente_auth/core/errors.dart';
-import 'package:ente_auth/core/event_bus.dart';
-import 'package:ente_auth/events/subscription_purchased_event.dart';
 import 'package:ente_auth/models/key_attributes.dart';
 import 'package:ente_auth/ui/account/recovery_page.dart';
 import 'package:ente_auth/ui/common/dialogs.dart';
@@ -127,7 +125,6 @@ class _PasswordReentryPageState extends State<PasswordReentryPage> {
             return;
           }
           await dialog.hide();
-          Bus.instance.fire(SubscriptionPurchasedEvent());
           Navigator.of(context).pushAndRemoveUntil(
             MaterialPageRoute(
               builder: (BuildContext context) {

+ 0 - 51
lib/ui/payment/skip_subscription_widget.dart

@@ -1,51 +0,0 @@
-// @dart=2.9
-
-import 'package:ente_auth/core/event_bus.dart';
-import 'package:ente_auth/events/subscription_purchased_event.dart';
-import 'package:ente_auth/models/billing_plan.dart';
-import 'package:ente_auth/models/subscription.dart';
-import 'package:ente_auth/onboarding/view/onboarding_page.dart';
-import 'package:ente_auth/services/billing_service.dart';
-import 'package:flutter/material.dart';
-
-class SkipSubscriptionWidget extends StatelessWidget {
-  const SkipSubscriptionWidget({
-    Key key,
-    @required this.freePlan,
-  }) : super(key: key);
-
-  final FreePlan freePlan;
-
-  @override
-  Widget build(BuildContext context) {
-    return Container(
-      width: double.infinity,
-      height: 64,
-      margin: const EdgeInsets.fromLTRB(0, 30, 0, 0),
-      padding: const EdgeInsets.fromLTRB(20, 0, 20, 0),
-      child: OutlinedButton(
-        style: Theme.of(context).outlinedButtonTheme.style.copyWith(
-          textStyle: MaterialStateProperty.resolveWith<TextStyle>(
-            (Set<MaterialState> states) {
-              return Theme.of(context).textTheme.subtitle1;
-            },
-          ),
-        ),
-        onPressed: () async {
-          Bus.instance.fire(SubscriptionPurchasedEvent());
-          Navigator.of(context).pushAndRemoveUntil(
-            MaterialPageRoute(
-              builder: (BuildContext context) {
-                return const OnboardingPage();
-              },
-            ),
-            (route) => false,
-          );
-          BillingService.instance
-              .verifySubscription(freeProductID, "", paymentProvider: "ente");
-        },
-        child: const Text("Continue on free plan"),
-      ),
-    );
-  }
-}

+ 0 - 571
lib/ui/payment/stripe_subscription_page.dart

@@ -1,571 +0,0 @@
-// @dart=2.9
-
-import 'dart:async';
-
-import 'package:ente_auth/ente_theme_data.dart';
-import 'package:ente_auth/models/billing_plan.dart';
-import 'package:ente_auth/models/subscription.dart';
-import 'package:ente_auth/models/user_details.dart';
-import 'package:ente_auth/services/billing_service.dart';
-import 'package:ente_auth/services/user_service.dart';
-import 'package:ente_auth/ui/common/bottom_shadow.dart';
-import 'package:ente_auth/ui/common/dialogs.dart';
-import 'package:ente_auth/ui/common/loading_widget.dart';
-import 'package:ente_auth/ui/common/progress_dialog.dart';
-import 'package:ente_auth/ui/common/web_page.dart';
-import 'package:ente_auth/ui/payment/child_subscription_widget.dart';
-import 'package:ente_auth/ui/payment/payment_web_page.dart';
-import 'package:ente_auth/ui/payment/skip_subscription_widget.dart';
-import 'package:ente_auth/ui/payment/subscription_common_widgets.dart';
-import 'package:ente_auth/ui/payment/subscription_plan_widget.dart';
-import 'package:ente_auth/utils/dialog_util.dart';
-import 'package:ente_auth/utils/toast_util.dart';
-import 'package:flutter/material.dart';
-import 'package:logging/logging.dart';
-import 'package:step_progress_indicator/step_progress_indicator.dart';
-import 'package:url_launcher/url_launcher_string.dart';
-
-class StripeSubscriptionPage extends StatefulWidget {
-  final bool isOnboarding;
-
-  const StripeSubscriptionPage({
-    this.isOnboarding = false,
-    Key key,
-  }) : super(key: key);
-
-  @override
-  State<StripeSubscriptionPage> createState() => _StripeSubscriptionPageState();
-}
-
-class _StripeSubscriptionPageState extends State<StripeSubscriptionPage> {
-  final _logger = Logger("StripeSubscriptionPage");
-  final _billingService = BillingService.instance;
-  final _userService = UserService.instance;
-  Subscription _currentSubscription;
-  ProgressDialog _dialog;
-  UserDetails _userDetails;
-
-  // indicates if user's subscription plan is still active
-  bool _hasActiveSubscription;
-  FreePlan _freePlan;
-  List<BillingPlan> _plans = [];
-  bool _hasLoadedData = false;
-  bool _isLoading = false;
-  bool _isStripeSubscriber = false;
-  bool _showYearlyPlan = false;
-
-  @override
-  void initState() {
-    super.initState();
-  }
-
-  Future<void> _fetchSub() async {
-    return _userService
-        .getUserDetailsV2(memoryCount: false)
-        .then((userDetails) async {
-      _userDetails = userDetails;
-      _currentSubscription = userDetails.subscription;
-      _showYearlyPlan = _currentSubscription.isYearlyPlan();
-      _hasActiveSubscription = _currentSubscription.isValid();
-      _isStripeSubscriber = _currentSubscription.paymentProvider == stripe;
-      return _filterStripeForUI().then((value) {
-        _hasLoadedData = true;
-        setState(() {});
-      });
-    });
-  }
-
-  // _filterPlansForUI is used for initializing initState & plan toggle states
-  Future<void> _filterStripeForUI() async {
-    final billingPlans = await _billingService.getBillingPlans();
-    _freePlan = billingPlans.freePlan;
-    _plans = billingPlans.plans.where((plan) {
-      if (plan.stripeID == null || plan.stripeID.isEmpty) {
-        return false;
-      }
-      final isYearlyPlan = plan.period == 'year';
-      return isYearlyPlan == _showYearlyPlan;
-    }).toList();
-    setState(() {});
-  }
-
-  FutureOr onWebPaymentGoBack(dynamic value) async {
-    // refresh subscription
-    await _dialog.show();
-    try {
-      await _fetchSub();
-    } catch (e) {
-      showToast(context, "Failed to refresh subscription");
-    }
-    await _dialog.hide();
-
-    // verify user has subscribed before redirecting to main page
-    if (widget.isOnboarding &&
-        _currentSubscription != null &&
-        _currentSubscription.isValid() &&
-        _currentSubscription.productID != freeProductID) {
-      Navigator.of(context).popUntil((route) => route.isFirst);
-    }
-  }
-
-  @override
-  void dispose() {
-    super.dispose();
-  }
-
-  @override
-  Widget build(BuildContext context) {
-    final appBar = PreferredSize(
-      preferredSize: const Size(double.infinity, 60),
-      child: Container(
-        decoration: BoxDecoration(
-          boxShadow: [
-            BoxShadow(
-              color: Theme.of(context).backgroundColor,
-              blurRadius: 16,
-              offset: const Offset(0, 8),
-            )
-          ],
-        ),
-        child: widget.isOnboarding
-            ? AppBar(
-                elevation: 0,
-                title: Hero(
-                  tag: "subscription",
-                  child: StepProgressIndicator(
-                    totalSteps: 4,
-                    currentStep: 4,
-                    selectedColor:
-                        Theme.of(context).colorScheme.alternativeColor,
-                    roundedEdges: const Radius.circular(10),
-                    unselectedColor: Theme.of(context)
-                        .colorScheme
-                        .stepProgressUnselectedColor,
-                  ),
-                ),
-              )
-            : AppBar(
-                elevation: 0,
-                title: const Text("Subscription"),
-              ),
-      ),
-    );
-    return Scaffold(
-      appBar: appBar,
-      body: Stack(
-        alignment: Alignment.bottomCenter,
-        children: [
-          _getBody(),
-          const BottomShadowWidget(
-            offsetDy: 40,
-          )
-        ],
-      ),
-    );
-  }
-
-  Widget _getBody() {
-    if (!_isLoading) {
-      _isLoading = true;
-      _dialog = createProgressDialog(context, "Please wait...");
-      _fetchSub();
-    }
-    if (_hasLoadedData) {
-      if (_userDetails.isPartOfFamily() && !_userDetails.isFamilyAdmin()) {
-        return ChildSubscriptionWidget(userDetails: _userDetails);
-      } else {
-        return _buildPlans();
-      }
-    }
-    return const EnteLoadingWidget();
-  }
-
-  Widget _buildPlans() {
-    final widgets = <Widget>[];
-
-    widgets.add(
-      SubscriptionHeaderWidget(
-        isOnboarding: widget.isOnboarding,
-        currentUsage: _userDetails.getFamilyOrPersonalUsage(),
-      ),
-    );
-
-    widgets.addAll([
-      Column(
-        mainAxisAlignment: MainAxisAlignment.center,
-        children: _getStripePlanWidgets(),
-      ),
-      const Padding(padding: EdgeInsets.all(4)),
-    ]);
-
-    widgets.add(_showSubscriptionToggle());
-
-    if (_hasActiveSubscription) {
-      widgets.add(ValidityWidget(currentSubscription: _currentSubscription));
-    }
-
-    if (_currentSubscription.productID == freeProductID) {
-      if (widget.isOnboarding) {
-        widgets.add(SkipSubscriptionWidget(freePlan: _freePlan));
-      }
-      widgets.add(const SubFaqWidget());
-    }
-
-    // only active subscription can be renewed/canceled
-    if (_hasActiveSubscription && _isStripeSubscriber) {
-      widgets.add(_stripeRenewOrCancelButton());
-    }
-
-    if (_currentSubscription.productID != freeProductID) {
-      widgets.addAll([
-        Align(
-          alignment: Alignment.center,
-          child: GestureDetector(
-            onTap: () async {
-              final String paymentProvider =
-                  _currentSubscription.paymentProvider;
-              switch (_currentSubscription.paymentProvider) {
-                case stripe:
-                  await _launchStripePortal();
-                  break;
-                case playStore:
-                  launchUrlString(
-                    "https://play.google.com/store/account/subscriptions?sku=" +
-                        _currentSubscription.productID +
-                        "&package=io.ente.auth",
-                  );
-                  break;
-                case appStore:
-                  launchUrlString("https://apps.apple.com/account/billing");
-                  break;
-                default:
-                  final String capitalizedWord = paymentProvider.isNotEmpty
-                      ? '${paymentProvider[0].toUpperCase()}${paymentProvider.substring(1).toLowerCase()}'
-                      : '';
-                  showErrorDialog(
-                    context,
-                    "Sorry",
-                    "Please contact us at support@ente.io to manage your "
-                        "$capitalizedWord subscription.",
-                  );
-              }
-            },
-            child: Container(
-              padding: const EdgeInsets.fromLTRB(40, 80, 40, 20),
-              child: Column(
-                children: [
-                  RichText(
-                    text: TextSpan(
-                      text: "Payment details",
-                      style: TextStyle(
-                        color: Theme.of(context).colorScheme.onSurface,
-                        fontFamily: 'Inter-Medium',
-                        fontSize: 14,
-                        decoration: TextDecoration.underline,
-                      ),
-                    ),
-                    textAlign: TextAlign.center,
-                  ),
-                ],
-              ),
-            ),
-          ),
-        ),
-      ]);
-    }
-
-    if (!widget.isOnboarding) {
-      widgets.addAll([
-        Align(
-          alignment: Alignment.topCenter,
-          child: GestureDetector(
-            onTap: () async {
-              await _launchFamilyPortal();
-            },
-            child: Container(
-              padding: const EdgeInsets.fromLTRB(40, 0, 40, 80),
-              child: Column(
-                children: [
-                  RichText(
-                    text: TextSpan(
-                      text: "Manage family",
-                      style: Theme.of(context).textTheme.overline,
-                    ),
-                    textAlign: TextAlign.center,
-                  ),
-                ],
-              ),
-            ),
-          ),
-        ),
-      ]);
-    }
-
-    return SingleChildScrollView(
-      child: Column(
-        mainAxisAlignment: MainAxisAlignment.spaceEvenly,
-        children: widgets,
-      ),
-    );
-  }
-
-  Future<void> _launchStripePortal() async {
-    await _dialog.show();
-    try {
-      final String url = await _billingService.getStripeCustomerPortalUrl();
-      Navigator.of(context).push(
-        MaterialPageRoute(
-          builder: (BuildContext context) {
-            return WebPage("Payment details", url);
-          },
-        ),
-      ).then((value) => onWebPaymentGoBack);
-    } catch (e) {
-      await _dialog.hide();
-      showGenericErrorDialog(context);
-    }
-    await _dialog.hide();
-  }
-
-  Future<void> _launchFamilyPortal() async {
-    if (_userDetails.subscription.productID == freeProductID) {
-      await showErrorDialog(
-        context,
-        "Now you can share your storage plan with your family members!",
-        "Customers on paid plans can add up to 5 family members without paying extra. Each member gets their own private space.",
-      );
-      return;
-    }
-    await _dialog.show();
-    try {
-      final String jwtToken = await _userService.getFamiliesToken();
-      final bool familyExist = _userDetails.isPartOfFamily();
-      Navigator.of(context).push(
-        MaterialPageRoute(
-          builder: (BuildContext context) {
-            return WebPage(
-              "Family",
-              '$kFamilyPlanManagementUrl?token=$jwtToken&isFamilyCreated=$familyExist',
-            );
-          },
-        ),
-      ).then((value) => onWebPaymentGoBack);
-    } catch (e) {
-      await _dialog.hide();
-      showGenericErrorDialog(context);
-    }
-    await _dialog.hide();
-  }
-
-  Widget _stripeRenewOrCancelButton() {
-    final bool isRenewCancelled =
-        _currentSubscription.attributes?.isCancelled ?? false;
-    final String title =
-        isRenewCancelled ? "Renew subscription" : "Cancel subscription";
-    return TextButton(
-      child: Text(
-        title,
-        style: TextStyle(
-          color: (isRenewCancelled
-                  ? Colors.greenAccent
-                  : Theme.of(context).colorScheme.onSurface)
-              .withOpacity(isRenewCancelled ? 1.0 : 0.2),
-        ),
-      ),
-      onPressed: () async {
-        bool confirmAction = false;
-        if (isRenewCancelled) {
-          final choice = await showChoiceDialog(
-            context,
-            title,
-            "Are you sure you want to renew?",
-            firstAction: "No",
-            secondAction: "Yes",
-          );
-          confirmAction = choice == DialogUserChoice.secondChoice;
-        } else {
-          final choice = await showChoiceDialog(
-            context,
-            title,
-            'Are you sure you want to cancel?',
-            firstAction: 'Yes, cancel',
-            secondAction: 'No',
-            actionType: ActionType.critical,
-          );
-          confirmAction = choice == DialogUserChoice.firstChoice;
-        }
-        if (confirmAction) {
-          toggleStripeSubscription(isRenewCancelled);
-        }
-      },
-    );
-  }
-
-  Future<void> toggleStripeSubscription(bool isRenewCancelled) async {
-    await _dialog.show();
-    try {
-      isRenewCancelled
-          ? await _billingService.activateStripeSubscription()
-          : await _billingService.cancelStripeSubscription();
-      await _fetchSub();
-    } catch (e) {
-      showToast(
-        context,
-        isRenewCancelled ? 'failed to renew' : 'failed to cancel',
-      );
-    }
-    await _dialog.hide();
-  }
-
-  List<Widget> _getStripePlanWidgets() {
-    final List<Widget> planWidgets = [];
-    bool foundActivePlan = false;
-    for (final plan in _plans) {
-      final productID = plan.stripeID;
-      if (productID == null || productID.isEmpty) {
-        continue;
-      }
-      final isActive =
-          _hasActiveSubscription && _currentSubscription.productID == productID;
-      if (isActive) {
-        foundActivePlan = true;
-      }
-      planWidgets.add(
-        Material(
-          child: InkWell(
-            onTap: () async {
-              if (isActive) {
-                return;
-              }
-              // prompt user to cancel their active subscription form other
-              // payment providers
-              if (!_isStripeSubscriber &&
-                  _hasActiveSubscription &&
-                  _currentSubscription.productID != freeProductID) {
-                showErrorDialog(
-                  context,
-                  "Sorry",
-                  "Please cancel your existing subscription from "
-                      "${_currentSubscription.paymentProvider} first",
-                );
-                return;
-              }
-              if (_userDetails.getFamilyOrPersonalUsage() > plan.storage) {
-                showErrorDialog(
-                  context,
-                  "Sorry",
-                  "You cannot downgrade to this plan",
-                );
-                return;
-              }
-              String stripPurChaseAction = 'buy';
-              if (_isStripeSubscriber && _hasActiveSubscription) {
-                // confirm if user wants to change plan or not
-                final result = await showChoiceDialog(
-                  context,
-                  "Confirm plan change",
-                  "Are you sure you want to change your plan?",
-                  firstAction: "No",
-                  secondAction: 'Yes',
-                );
-                if (result != DialogUserChoice.secondChoice) {
-                  return;
-                }
-                stripPurChaseAction = 'update';
-              }
-              Navigator.push(
-                context,
-                MaterialPageRoute(
-                  builder: (BuildContext context) {
-                    return PaymentWebPage(
-                      planId: plan.stripeID,
-                      actionType: stripPurChaseAction,
-                    );
-                  },
-                ),
-              ).then((value) => onWebPaymentGoBack(value));
-            },
-            child: SubscriptionPlanWidget(
-              storage: plan.storage,
-              price: plan.price,
-              period: plan.period,
-              isActive: isActive,
-            ),
-          ),
-        ),
-      );
-    }
-    if (!foundActivePlan && _hasActiveSubscription) {
-      _addCurrentPlanWidget(planWidgets);
-    }
-    return planWidgets;
-  }
-
-  Widget _showSubscriptionToggle() {
-    Widget _planText(String title, bool reduceOpacity) {
-      return Padding(
-        padding: const EdgeInsets.only(left: 4, right: 4),
-        child: Text(
-          title,
-          style: TextStyle(
-            color: Theme.of(context)
-                .colorScheme
-                .onSurface
-                .withOpacity(reduceOpacity ? 0.5 : 1.0),
-          ),
-        ),
-      );
-    }
-
-    return Container(
-      padding: const EdgeInsets.only(left: 8, right: 8, top: 4, bottom: 4),
-      margin: const EdgeInsets.only(bottom: 12),
-      // color: Color.fromRGBO(10, 40, 40, 0.3),
-      child: Row(
-        mainAxisAlignment: MainAxisAlignment.center,
-        children: [
-          _planText("Monthly", _showYearlyPlan),
-          Switch(
-            value: _showYearlyPlan,
-            activeColor: Colors.white,
-            inactiveThumbColor: Colors.white,
-            onChanged: (value) async {
-              _showYearlyPlan = value;
-              await _filterStripeForUI();
-            },
-          ),
-          _planText("Yearly", !_showYearlyPlan)
-        ],
-      ),
-    );
-  }
-
-  void _addCurrentPlanWidget(List<Widget> planWidgets) {
-    // don't add current plan if it's monthly plan but UI is showing yearly plans
-    // and vice versa.
-    if (_showYearlyPlan != _currentSubscription.isYearlyPlan() &&
-        _currentSubscription.productID != freeProductID) {
-      return;
-    }
-    int activePlanIndex = 0;
-    for (; activePlanIndex < _plans.length; activePlanIndex++) {
-      if (_plans[activePlanIndex].storage > _currentSubscription.storage) {
-        break;
-      }
-    }
-    planWidgets.insert(
-      activePlanIndex,
-      Material(
-        child: InkWell(
-          onTap: () {},
-          child: SubscriptionPlanWidget(
-            storage: _currentSubscription.storage,
-            price: _currentSubscription.price,
-            period: _currentSubscription.period,
-            isActive: true,
-          ),
-        ),
-      ),
-    );
-  }
-}

+ 0 - 25
lib/ui/payment/subscription.dart

@@ -1,25 +0,0 @@
-// @dart=2.9
-import 'package:ente_auth/core/configuration.dart';
-import 'package:ente_auth/services/update_service.dart';
-import 'package:ente_auth/ui/payment/stripe_subscription_page.dart';
-import 'package:ente_auth/ui/payment/subscription_page.dart';
-import 'package:flutter/cupertino.dart';
-
-StatefulWidget getSubscriptionPage({bool isOnBoarding = false}) {
-  if (UpdateService.instance.isIndependentFlavor()) {
-    return StripeSubscriptionPage(isOnboarding: isOnBoarding);
-  }
-  if (_isUserCreatedPostStripeSupport()) {
-    return StripeSubscriptionPage(isOnboarding: isOnBoarding);
-  } else {
-    return SubscriptionPage(isOnboarding: isOnBoarding);
-  }
-}
-
-// return true if the user was created after we added support for stripe payment
-// on frame. We do this check to avoid showing Stripe payment option for earlier
-// users who might have paid via playStore. This method should be removed once
-// we have better handling for active play/app store subscription & stripe plans.
-bool _isUserCreatedPostStripeSupport() {
-  return Configuration.instance.getUserID() > 1580559962386460;
-}

+ 0 - 516
lib/ui/payment/subscription_page.dart

@@ -1,516 +0,0 @@
-// @dart=2.9
-
-import 'dart:async';
-import 'dart:io';
-
-import 'package:ente_auth/core/errors.dart';
-import 'package:ente_auth/core/event_bus.dart';
-import 'package:ente_auth/events/subscription_purchased_event.dart';
-import 'package:ente_auth/models/billing_plan.dart';
-import 'package:ente_auth/models/subscription.dart';
-import 'package:ente_auth/models/user_details.dart';
-import 'package:ente_auth/services/billing_service.dart';
-import 'package:ente_auth/services/user_service.dart';
-import 'package:ente_auth/ui/common/loading_widget.dart';
-import 'package:ente_auth/ui/common/progress_dialog.dart';
-import 'package:ente_auth/ui/common/web_page.dart';
-import 'package:ente_auth/ui/payment/child_subscription_widget.dart';
-import 'package:ente_auth/ui/payment/skip_subscription_widget.dart';
-import 'package:ente_auth/ui/payment/subscription_common_widgets.dart';
-import 'package:ente_auth/ui/payment/subscription_plan_widget.dart';
-import 'package:ente_auth/utils/dialog_util.dart';
-import 'package:ente_auth/utils/toast_util.dart';
-import 'package:flutter/material.dart';
-import 'package:in_app_purchase/in_app_purchase.dart';
-import 'package:logging/logging.dart';
-import 'package:url_launcher/url_launcher_string.dart';
-
-class SubscriptionPage extends StatefulWidget {
-  final bool isOnboarding;
-
-  const SubscriptionPage({
-    this.isOnboarding = false,
-    Key key,
-  }) : super(key: key);
-
-  @override
-  State<SubscriptionPage> createState() => _SubscriptionPageState();
-}
-
-class _SubscriptionPageState extends State<SubscriptionPage> {
-  final _logger = Logger("SubscriptionPage");
-  final _billingService = BillingService.instance;
-  final _userService = UserService.instance;
-  Subscription _currentSubscription;
-  StreamSubscription _purchaseUpdateSubscription;
-  ProgressDialog _dialog;
-  UserDetails _userDetails;
-  bool _hasActiveSubscription;
-  FreePlan _freePlan;
-  List<BillingPlan> _plans;
-  bool _hasLoadedData = false;
-  bool _isLoading = false;
-  bool _isActiveStripeSubscriber;
-
-  @override
-  void initState() {
-    _billingService.setIsOnSubscriptionPage(true);
-    _setupPurchaseUpdateStreamListener();
-    super.initState();
-  }
-
-  void _setupPurchaseUpdateStreamListener() {
-    _purchaseUpdateSubscription = InAppPurchaseConnection
-        .instance.purchaseUpdatedStream
-        .listen((purchases) async {
-      if (!_dialog.isShowing()) {
-        await _dialog.show();
-      }
-      for (final purchase in purchases) {
-        _logger.info("Purchase status " + purchase.status.toString());
-        if (purchase.status == PurchaseStatus.purchased) {
-          try {
-            final newSubscription = await _billingService.verifySubscription(
-              purchase.productID,
-              purchase.verificationData.serverVerificationData,
-            );
-            await InAppPurchaseConnection.instance.completePurchase(purchase);
-            String text = "Thank you for subscribing!";
-            if (!widget.isOnboarding) {
-              final isUpgrade = _hasActiveSubscription &&
-                  newSubscription.storage > _currentSubscription.storage;
-              final isDowngrade = _hasActiveSubscription &&
-                  newSubscription.storage < _currentSubscription.storage;
-              if (isUpgrade) {
-                text = "Your plan was successfully upgraded";
-              } else if (isDowngrade) {
-                text = "Your plan was successfully downgraded";
-              }
-            }
-            showToast(context, text);
-            _currentSubscription = newSubscription;
-            _hasActiveSubscription = _currentSubscription.isValid();
-            setState(() {});
-            await _dialog.hide();
-            Bus.instance.fire(SubscriptionPurchasedEvent());
-            if (widget.isOnboarding) {
-              Navigator.of(context).popUntil((route) => route.isFirst);
-            }
-          } on SubscriptionAlreadyClaimedError catch (e) {
-            _logger.warning("subscription is already claimed ", e);
-            await _dialog.hide();
-            final String title = "${Platform.isAndroid ? "Play" : "App"}"
-                "Store subscription";
-            final String id =
-                Platform.isAndroid ? "Google Play ID" : "Apple ID";
-            final String message = '''Your $id is already linked to another
-             ente account.\nIf you would like to use your $id with this 
-             account, please contact our support''';
-            showErrorDialog(context, title, message);
-            return;
-          } catch (e) {
-            _logger.warning("Could not complete payment ", e);
-            await _dialog.hide();
-            showErrorDialog(
-              context,
-              "Payment failed",
-              "Please talk to " +
-                  (Platform.isAndroid ? "PlayStore" : "AppStore") +
-                  " support if you were charged",
-            );
-            return;
-          }
-        } else if (Platform.isIOS && purchase.pendingCompletePurchase) {
-          await InAppPurchaseConnection.instance.completePurchase(purchase);
-          await _dialog.hide();
-        } else if (purchase.status == PurchaseStatus.error) {
-          await _dialog.hide();
-        }
-      }
-    });
-  }
-
-  @override
-  void dispose() {
-    _purchaseUpdateSubscription.cancel();
-    _billingService.setIsOnSubscriptionPage(false);
-    super.dispose();
-  }
-
-  @override
-  Widget build(BuildContext context) {
-    if (!_isLoading) {
-      _isLoading = true;
-      _fetchSubData();
-    }
-    _dialog = createProgressDialog(context, "Please wait...");
-    final appBar = AppBar(
-      title: widget.isOnboarding ? null : const Text("Subscription"),
-    );
-    return Scaffold(
-      appBar: appBar,
-      body: _getBody(),
-    );
-  }
-
-  Future<void> _fetchSubData() async {
-    _userService.getUserDetailsV2(memoryCount: false).then((userDetails) async {
-      _userDetails = userDetails;
-      _currentSubscription = userDetails.subscription;
-      _hasActiveSubscription = _currentSubscription.isValid();
-      final billingPlans = await _billingService.getBillingPlans();
-      _isActiveStripeSubscriber =
-          _currentSubscription.paymentProvider == stripe &&
-              _currentSubscription.isValid();
-      _plans = billingPlans.plans.where((plan) {
-        final productID = _isActiveStripeSubscriber
-            ? plan.stripeID
-            : Platform.isAndroid
-                ? plan.androidID
-                : plan.iosID;
-        return productID != null && productID.isNotEmpty;
-      }).toList();
-      _freePlan = billingPlans.freePlan;
-      _hasLoadedData = true;
-      setState(() {});
-    });
-  }
-
-  Widget _getBody() {
-    if (_hasLoadedData) {
-      if (_userDetails.isPartOfFamily() && !_userDetails.isFamilyAdmin()) {
-        return ChildSubscriptionWidget(userDetails: _userDetails);
-      } else {
-        return _buildPlans();
-      }
-    }
-    return const EnteLoadingWidget();
-  }
-
-  Widget _buildPlans() {
-    final widgets = <Widget>[];
-    widgets.add(
-      SubscriptionHeaderWidget(
-        isOnboarding: widget.isOnboarding,
-        currentUsage: _userDetails.getFamilyOrPersonalUsage(),
-      ),
-    );
-
-    widgets.addAll([
-      Column(
-        mainAxisAlignment: MainAxisAlignment.center,
-        children: _isActiveStripeSubscriber
-            ? _getStripePlanWidgets()
-            : _getMobilePlanWidgets(),
-      ),
-      const Padding(padding: EdgeInsets.all(8)),
-    ]);
-
-    if (_hasActiveSubscription) {
-      widgets.add(ValidityWidget(currentSubscription: _currentSubscription));
-    }
-
-    if (_currentSubscription.productID == freeProductID) {
-      if (widget.isOnboarding) {
-        widgets.add(SkipSubscriptionWidget(freePlan: _freePlan));
-      }
-      widgets.add(const SubFaqWidget());
-    }
-
-    if (_hasActiveSubscription &&
-        _currentSubscription.productID != freeProductID) {
-      widgets.addAll([
-        Align(
-          alignment: Alignment.center,
-          child: GestureDetector(
-            onTap: () {
-              final String paymentProvider =
-                  _currentSubscription.paymentProvider;
-              if (paymentProvider == appStore && !Platform.isAndroid) {
-                launchUrlString("https://apps.apple.com/account/billing");
-              } else if (paymentProvider == playStore && Platform.isAndroid) {
-                launchUrlString(
-                  "https://play.google.com/store/account/subscriptions?sku=" +
-                      _currentSubscription.productID +
-                      "&package=io.ente.auth",
-                );
-              } else if (paymentProvider == stripe) {
-                showErrorDialog(
-                  context,
-                  "Sorry",
-                  "Visit web.ente.io to manage your subscription",
-                );
-              } else {
-                final String capitalizedWord = paymentProvider.isNotEmpty
-                    ? '${paymentProvider[0].toUpperCase()}${paymentProvider.substring(1).toLowerCase()}'
-                    : '';
-                showErrorDialog(
-                  context,
-                  "Sorry",
-                  "Please contact us at support@ente.io to manage your "
-                      "$capitalizedWord subscription.",
-                );
-              }
-            },
-            child: Container(
-              padding: const EdgeInsets.fromLTRB(40, 80, 40, 20),
-              child: Column(
-                children: [
-                  RichText(
-                    text: TextSpan(
-                      text: _isActiveStripeSubscriber
-                          ? "Visit web.ente.io to manage your subscription"
-                          : "Payment details",
-                      style: TextStyle(
-                        color: Theme.of(context).colorScheme.onSurface,
-                        fontFamily: 'Inter-Medium',
-                        fontSize: 14,
-                        decoration: _isActiveStripeSubscriber
-                            ? TextDecoration.none
-                            : TextDecoration.underline,
-                      ),
-                    ),
-                    textAlign: TextAlign.center,
-                  ),
-                ],
-              ),
-            ),
-          ),
-        ),
-      ]);
-    }
-    if (!widget.isOnboarding) {
-      widgets.addAll([
-        Align(
-          alignment: Alignment.topCenter,
-          child: GestureDetector(
-            onTap: () async {
-              _launchFamilyPortal();
-            },
-            child: Container(
-              padding: const EdgeInsets.fromLTRB(40, 0, 40, 80),
-              child: Column(
-                children: [
-                  RichText(
-                    text: TextSpan(
-                      text: "Manage family",
-                      style: Theme.of(context).textTheme.overline,
-                    ),
-                    textAlign: TextAlign.center,
-                  ),
-                ],
-              ),
-            ),
-          ),
-        ),
-      ]);
-    }
-    return SingleChildScrollView(
-      child: Column(
-        mainAxisAlignment: MainAxisAlignment.spaceEvenly,
-        children: widgets,
-      ),
-    );
-  }
-
-  List<Widget> _getStripePlanWidgets() {
-    final List<Widget> planWidgets = [];
-    bool foundActivePlan = false;
-    for (final plan in _plans) {
-      final productID = plan.stripeID;
-      if (productID == null || productID.isEmpty) {
-        continue;
-      }
-      final isActive =
-          _hasActiveSubscription && _currentSubscription.productID == productID;
-      if (isActive) {
-        foundActivePlan = true;
-      }
-      planWidgets.add(
-        Material(
-          color: Colors.transparent,
-          child: InkWell(
-            onTap: () async {
-              if (isActive) {
-                return;
-              }
-              showErrorDialog(
-                context,
-                "Sorry",
-                "Please visit web.ente.io to manage your subscription",
-              );
-            },
-            child: SubscriptionPlanWidget(
-              storage: plan.storage,
-              price: plan.price,
-              period: plan.period,
-              isActive: isActive,
-            ),
-          ),
-        ),
-      );
-    }
-    if (!foundActivePlan && _hasActiveSubscription) {
-      _addCurrentPlanWidget(planWidgets);
-    }
-    return planWidgets;
-  }
-
-  List<Widget> _getMobilePlanWidgets() {
-    bool foundActivePlan = false;
-    final List<Widget> planWidgets = [];
-    if (_hasActiveSubscription &&
-        _currentSubscription.productID == freeProductID) {
-      foundActivePlan = true;
-      planWidgets.add(
-        SubscriptionPlanWidget(
-          storage: _freePlan.storage,
-          price: "free",
-          period: "",
-          isActive: true,
-        ),
-      );
-    }
-    for (final plan in _plans) {
-      final productID = Platform.isAndroid ? plan.androidID : plan.iosID;
-      final isActive =
-          _hasActiveSubscription && _currentSubscription.productID == productID;
-      if (isActive) {
-        foundActivePlan = true;
-      }
-      planWidgets.add(
-        Material(
-          child: InkWell(
-            onTap: () async {
-              if (isActive) {
-                return;
-              }
-              if (_userDetails.getFamilyOrPersonalUsage() > plan.storage) {
-                showErrorDialog(
-                  context,
-                  "Sorry",
-                  "you cannot downgrade to this plan",
-                );
-                return;
-              }
-              await _dialog.show();
-              final ProductDetailsResponse response =
-                  await InAppPurchaseConnection.instance
-                      .queryProductDetails({productID});
-              if (response.notFoundIDs.isNotEmpty) {
-                _logger.severe(
-                  "Could not find products: " + response.notFoundIDs.toString(),
-                );
-                await _dialog.hide();
-                showGenericErrorDialog(context);
-                return;
-              }
-              final isCrossGradingOnAndroid = Platform.isAndroid &&
-                  _hasActiveSubscription &&
-                  _currentSubscription.productID != freeProductID &&
-                  _currentSubscription.productID != plan.androidID;
-              if (isCrossGradingOnAndroid) {
-                final existingProductDetailsResponse =
-                    await InAppPurchaseConnection.instance
-                        .queryProductDetails({_currentSubscription.productID});
-                if (existingProductDetailsResponse.notFoundIDs.isNotEmpty) {
-                  _logger.severe(
-                    "Could not find existing products: " +
-                        response.notFoundIDs.toString(),
-                  );
-                  await _dialog.hide();
-                  showGenericErrorDialog(context);
-                  return;
-                }
-                final subscriptionChangeParam = ChangeSubscriptionParam(
-                  oldPurchaseDetails: PurchaseDetails(
-                    purchaseID: null,
-                    productID: _currentSubscription.productID,
-                    verificationData: null,
-                    transactionDate: null,
-                  ),
-                );
-                await InAppPurchaseConnection.instance.buyNonConsumable(
-                  purchaseParam: PurchaseParam(
-                    productDetails: response.productDetails[0],
-                    changeSubscriptionParam: subscriptionChangeParam,
-                  ),
-                );
-              } else {
-                await InAppPurchaseConnection.instance.buyNonConsumable(
-                  purchaseParam: PurchaseParam(
-                    productDetails: response.productDetails[0],
-                  ),
-                );
-              }
-            },
-            child: SubscriptionPlanWidget(
-              storage: plan.storage,
-              price: plan.price,
-              period: plan.period,
-              isActive: isActive,
-            ),
-          ),
-        ),
-      );
-    }
-    if (!foundActivePlan && _hasActiveSubscription) {
-      _addCurrentPlanWidget(planWidgets);
-    }
-    return planWidgets;
-  }
-
-  void _addCurrentPlanWidget(List<Widget> planWidgets) {
-    int activePlanIndex = 0;
-    for (; activePlanIndex < _plans.length; activePlanIndex++) {
-      if (_plans[activePlanIndex].storage > _currentSubscription.storage) {
-        break;
-      }
-    }
-    planWidgets.insert(
-      activePlanIndex,
-      Material(
-        child: InkWell(
-          onTap: () {},
-          child: SubscriptionPlanWidget(
-            storage: _currentSubscription.storage,
-            price: _currentSubscription.price,
-            period: _currentSubscription.period,
-            isActive: true,
-          ),
-        ),
-      ),
-    );
-  }
-
-  // todo: refactor manage family in common widget
-  Future<void> _launchFamilyPortal() async {
-    if (_userDetails.subscription.productID == freeProductID) {
-      await showErrorDialog(
-        context,
-        "Share your storage plan with your family members!",
-        "Customers on paid plans can add up to 5 family members without paying extra. Each member gets their own private space.",
-      );
-      return;
-    }
-    await _dialog.show();
-    try {
-      final String jwtToken = await _userService.getFamiliesToken();
-      final bool familyExist = _userDetails.isPartOfFamily();
-      Navigator.of(context).push(
-        MaterialPageRoute(
-          builder: (BuildContext context) {
-            return WebPage(
-              "Family",
-              '$kFamilyPlanManagementUrl?token=$jwtToken&isFamilyCreated=$familyExist',
-            );
-          },
-        ),
-      );
-    } catch (e) {
-      await _dialog.hide();
-      showGenericErrorDialog(context);
-    }
-    await _dialog.hide();
-  }
-}

+ 0 - 12
lib/ui/settings/security_section_widget.dart

@@ -1,12 +1,9 @@
 // @dart=2.9
 
-import 'dart:async';
 import 'dart:io';
 
 import 'package:ente_auth/core/configuration.dart';
-import 'package:ente_auth/core/event_bus.dart';
 import 'package:ente_auth/ente_theme_data.dart';
-import 'package:ente_auth/events/two_factor_status_change_event.dart';
 import 'package:ente_auth/services/local_authentication_service.dart';
 import 'package:ente_auth/theme/ente_theme.dart';
 import 'package:ente_auth/ui/account/sessions_page.dart';
@@ -28,22 +25,13 @@ class SecuritySectionWidget extends StatefulWidget {
 class _SecuritySectionWidgetState extends State<SecuritySectionWidget> {
   final _config = Configuration.instance;
 
-  StreamSubscription<TwoFactorStatusChangeEvent> _twoFactorStatusChangeEvent;
-
   @override
   void initState() {
     super.initState();
-    _twoFactorStatusChangeEvent =
-        Bus.instance.on<TwoFactorStatusChangeEvent>().listen((event) async {
-      if (mounted) {
-        setState(() {});
-      }
-    });
   }
 
   @override
   void dispose() {
-    _twoFactorStatusChangeEvent.cancel();
     super.dispose();
   }