move common subscription widget in util
This commit is contained in:
parent
43f1ade544
commit
05e15bbf90
|
@ -17,6 +17,7 @@ import 'package:photos/ui/common/dialogs.dart';
|
||||||
import 'package:photos/ui/loading_widget.dart';
|
import 'package:photos/ui/loading_widget.dart';
|
||||||
import 'package:photos/ui/payment/payment_web_page.dart';
|
import 'package:photos/ui/payment/payment_web_page.dart';
|
||||||
import 'package:photos/ui/payment/skip_subscription_widget.dart';
|
import 'package:photos/ui/payment/skip_subscription_widget.dart';
|
||||||
|
import 'package:photos/ui/payment/subscription_common_widgets.dart';
|
||||||
import 'package:photos/ui/payment/subscription_plan_widget.dart';
|
import 'package:photos/ui/payment/subscription_plan_widget.dart';
|
||||||
import 'package:photos/ui/progress_dialog.dart';
|
import 'package:photos/ui/progress_dialog.dart';
|
||||||
import 'package:photos/utils/data_util.dart';
|
import 'package:photos/utils/data_util.dart';
|
||||||
|
@ -54,14 +55,11 @@ class _StripeSubscriptionPageState extends State<StripeSubscriptionPage> {
|
||||||
bool _hasLoadedData = false;
|
bool _hasLoadedData = false;
|
||||||
bool _isActiveStripeSubscriber;
|
bool _isActiveStripeSubscriber;
|
||||||
|
|
||||||
// based on this flag, we would show ente payment page with stripe plans
|
|
||||||
bool _isIndependentApk;
|
|
||||||
bool _showYearlyPlan = false;
|
bool _showYearlyPlan = false;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
_billingService.setIsOnSubscriptionPage(true);
|
_billingService.setIsOnSubscriptionPage(true);
|
||||||
_isIndependentApk = UpdateService.instance.isIndependentFlavor();
|
|
||||||
_fetchSub();
|
_fetchSub();
|
||||||
_dialog = createProgressDialog(context, "please wait...");
|
_dialog = createProgressDialog(context, "please wait...");
|
||||||
super.initState();
|
super.initState();
|
||||||
|
@ -119,10 +117,9 @@ class _StripeSubscriptionPageState extends State<StripeSubscriptionPage> {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool _showStripePlans() {
|
bool _showStripePlans() {
|
||||||
return _isActiveStripeSubscriber || _isIndependentApk;
|
return _isActiveStripeSubscriber;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
super.dispose();
|
super.dispose();
|
||||||
|
@ -148,76 +145,28 @@ class _StripeSubscriptionPageState extends State<StripeSubscriptionPage> {
|
||||||
|
|
||||||
Widget _buildPlans() {
|
Widget _buildPlans() {
|
||||||
final widgets = <Widget>[];
|
final widgets = <Widget>[];
|
||||||
if (widget.isOnboarding) {
|
|
||||||
widgets.add(Padding(
|
widgets.add(SubscriptionHeaderWidget(
|
||||||
padding: const EdgeInsets.fromLTRB(20, 20, 20, 24),
|
isOnboarding: widget.isOnboarding,
|
||||||
child: Text(
|
usageFuture: _usageFuture,
|
||||||
"ente preserves your memories, so they're always available to you, even if you lose your device",
|
));
|
||||||
style: TextStyle(
|
|
||||||
color: Colors.white54,
|
|
||||||
height: 1.2,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
));
|
|
||||||
} else {
|
|
||||||
widgets.add(
|
|
||||||
SizedBox(
|
|
||||||
height: 50,
|
|
||||||
child: FutureBuilder(
|
|
||||||
future: _usageFuture,
|
|
||||||
builder: (BuildContext context, AsyncSnapshot snapshot) {
|
|
||||||
if (snapshot.hasData) {
|
|
||||||
return Padding(
|
|
||||||
padding: const EdgeInsets.all(16.0),
|
|
||||||
child: Text("current usage is " + formatBytes(snapshot.data)),
|
|
||||||
);
|
|
||||||
} else if (snapshot.hasError) {
|
|
||||||
return Container();
|
|
||||||
} else {
|
|
||||||
return Padding(
|
|
||||||
padding: const EdgeInsets.all(16.0),
|
|
||||||
child: loadWidget,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
widgets.addAll([
|
widgets.addAll([
|
||||||
Column(
|
Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children:_getStripePlanWidgets()
|
children: _getStripePlanWidgets()),
|
||||||
),
|
|
||||||
Padding(padding: EdgeInsets.all(8)),
|
Padding(padding: EdgeInsets.all(8)),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
widgets.add(_showSubscriptionToggle());
|
widgets.add(_showSubscriptionToggle());
|
||||||
|
|
||||||
if (_hasActiveSubscription) {
|
if (_hasActiveSubscription) {
|
||||||
var endDate = getDateAndMonthAndYear(
|
widgets.add(ValidityWidget(currentSubscription: _currentSubscription));
|
||||||
DateTime.fromMicrosecondsSinceEpoch(_currentSubscription.expiryTime));
|
|
||||||
var message = "renews on $endDate";
|
|
||||||
if (_currentSubscription.productID == kFreeProductID) {
|
|
||||||
message = "free plan valid till $endDate";
|
|
||||||
} else if (_isAutoReviewCancelled) {
|
|
||||||
message = "your subscription will be cancelled on $endDate";
|
|
||||||
}
|
|
||||||
widgets.add(
|
|
||||||
Text(
|
|
||||||
message,
|
|
||||||
style: TextStyle(
|
|
||||||
color: Colors.white.withOpacity(0.6),
|
|
||||||
fontSize: 14,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_isIndependentApk &&
|
if (_hasActiveSubscription &&
|
||||||
_hasActiveSubscription &&
|
|
||||||
_isActiveStripeSubscriber) {
|
_isActiveStripeSubscriber) {
|
||||||
widgets.add(_stripeSubscriptionToggleButton(_isAutoReviewCancelled));
|
widgets.add(_stripeRenewOrCancelButton());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_hasActiveSubscription &&
|
if (_hasActiveSubscription &&
|
||||||
|
@ -228,12 +177,8 @@ class _StripeSubscriptionPageState extends State<StripeSubscriptionPage> {
|
||||||
child: GestureDetector(
|
child: GestureDetector(
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
if (_isActiveStripeSubscriber) {
|
if (_isActiveStripeSubscriber) {
|
||||||
if (_isIndependentApk) {
|
|
||||||
await _launchStripePortal();
|
await _launchStripePortal();
|
||||||
return;
|
return;
|
||||||
} else {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (Platform.isAndroid) {
|
if (Platform.isAndroid) {
|
||||||
launch(
|
launch(
|
||||||
|
@ -250,7 +195,7 @@ class _StripeSubscriptionPageState extends State<StripeSubscriptionPage> {
|
||||||
children: [
|
children: [
|
||||||
RichText(
|
RichText(
|
||||||
text: TextSpan(
|
text: TextSpan(
|
||||||
text: _isActiveStripeSubscriber && !_isIndependentApk
|
text: _isActiveStripeSubscriber
|
||||||
? "visit web.ente.io to manage your subscription"
|
? "visit web.ente.io to manage your subscription"
|
||||||
: "payment details",
|
: "payment details",
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
|
@ -332,43 +277,45 @@ class _StripeSubscriptionPageState extends State<StripeSubscriptionPage> {
|
||||||
await _dialog.hide();
|
await _dialog.hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _stripeSubscriptionToggleButton(bool isCurrentlyCancelled) {
|
Widget _stripeRenewOrCancelButton() {
|
||||||
|
bool isRenewCancelled =
|
||||||
|
_currentSubscription.attributes?.isCancelled ?? false;
|
||||||
return TextButton(
|
return TextButton(
|
||||||
child: Text(
|
child: Text(
|
||||||
isCurrentlyCancelled ? "renew subscription" : "cancel subscription",
|
isRenewCancelled ? "renew subscription" : "cancel subscription",
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: isCurrentlyCancelled ? Colors.greenAccent : Colors.redAccent,
|
color: isRenewCancelled ? Colors.greenAccent : Colors.redAccent,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
var result = await showChoiceDialog(
|
var result = await showChoiceDialog(
|
||||||
context,
|
context,
|
||||||
isCurrentlyCancelled
|
isRenewCancelled
|
||||||
? 'subscription renewal'
|
? 'subscription renewal'
|
||||||
: 'subscription cancellation',
|
: 'subscription cancellation',
|
||||||
isCurrentlyCancelled
|
isRenewCancelled
|
||||||
? 'are you sure you want to renew?'
|
? 'are you sure you want to renew?'
|
||||||
: 'are you sure you want to cancel?',
|
: 'are you sure you want to cancel?',
|
||||||
firstAction: 'yes',
|
firstAction: 'yes',
|
||||||
secondAction: 'no');
|
secondAction: 'no');
|
||||||
if (result == DialogUserChoice.firstChoice) {
|
if (result == DialogUserChoice.firstChoice) {
|
||||||
toggleStripeSubscription(isCurrentlyCancelled);
|
toggleStripeSubscription(isRenewCancelled);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> toggleStripeSubscription(bool isCurrentlyCancelled) async {
|
Future<void> toggleStripeSubscription(bool isRenewCancelled) async {
|
||||||
await _dialog.show();
|
await _dialog.show();
|
||||||
try {
|
try {
|
||||||
if (isCurrentlyCancelled) {
|
if (isRenewCancelled) {
|
||||||
await _billingService.activateStripeSubscription();
|
await _billingService.activateStripeSubscription();
|
||||||
} else {
|
} else {
|
||||||
await _billingService.cancelStripeSubscription();
|
await _billingService.cancelStripeSubscription();
|
||||||
}
|
}
|
||||||
await _fetchSub();
|
await _fetchSub();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
showToast(isCurrentlyCancelled ? 'failed to renew' : 'failed to cancel');
|
showToast(isRenewCancelled ? 'failed to renew' : 'failed to cancel');
|
||||||
}
|
}
|
||||||
await _dialog.hide();
|
await _dialog.hide();
|
||||||
}
|
}
|
||||||
|
@ -393,9 +340,9 @@ class _StripeSubscriptionPageState extends State<StripeSubscriptionPage> {
|
||||||
if (isActive) {
|
if (isActive) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (_isActiveStripeSubscriber && !_isIndependentApk) {
|
if (!_isActiveStripeSubscriber) {
|
||||||
showErrorDialog(context, "sorry",
|
showErrorDialog(context, "sorry",
|
||||||
"please visit web.ente.io to manage your subscription");
|
"please cancel your existing subscription from ${_currentSubscription.paymentProvider} first");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
await _dialog.show();
|
await _dialog.show();
|
||||||
|
|
87
lib/ui/payment/subscription_common_widgets.dart
Normal file
87
lib/ui/payment/subscription_common_widgets.dart
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/widgets.dart';
|
||||||
|
import 'package:photos/models/subscription.dart';
|
||||||
|
import 'package:photos/utils/data_util.dart';
|
||||||
|
import 'package:photos/ui/loading_widget.dart';
|
||||||
|
import 'package:photos/utils/date_time_util.dart';
|
||||||
|
|
||||||
|
class SubscriptionHeaderWidget extends StatefulWidget {
|
||||||
|
final bool isOnboarding;
|
||||||
|
final Future<int> usageFuture;
|
||||||
|
|
||||||
|
const SubscriptionHeaderWidget({Key key, this.isOnboarding, this.usageFuture})
|
||||||
|
: super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<StatefulWidget> createState() {
|
||||||
|
return _SubscriptionHeaderWidgetState();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _SubscriptionHeaderWidgetState extends State<SubscriptionHeaderWidget> {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
if (widget.isOnboarding) {
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.fromLTRB(20, 20, 20, 24),
|
||||||
|
child: Text(
|
||||||
|
"ente preserves your memories, so they're always available to you, even if you lose your device",
|
||||||
|
style: TextStyle(
|
||||||
|
color: Colors.white54,
|
||||||
|
height: 1.2,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return SizedBox(
|
||||||
|
height: 50,
|
||||||
|
child: FutureBuilder(
|
||||||
|
future: widget.usageFuture,
|
||||||
|
builder: (BuildContext context, AsyncSnapshot snapshot) {
|
||||||
|
if (snapshot.hasData) {
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.all(16.0),
|
||||||
|
child: Text("current usage is " + formatBytes(snapshot.data)),
|
||||||
|
);
|
||||||
|
} else if (snapshot.hasError) {
|
||||||
|
return Container();
|
||||||
|
} else {
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.all(16.0),
|
||||||
|
child: loadWidget,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ValidityWidget extends StatelessWidget {
|
||||||
|
final Subscription currentSubscription;
|
||||||
|
|
||||||
|
const ValidityWidget({Key key, this.currentSubscription}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
if (currentSubscription == null) {
|
||||||
|
return Container();
|
||||||
|
}
|
||||||
|
var endDate = getDateAndMonthAndYear(
|
||||||
|
DateTime.fromMicrosecondsSinceEpoch(currentSubscription.expiryTime));
|
||||||
|
var message = "renews on $endDate";
|
||||||
|
if (currentSubscription.productID == kFreeProductID) {
|
||||||
|
message = "free plan valid till $endDate";
|
||||||
|
} else if (currentSubscription.attributes?.isCancelled ?? false) {
|
||||||
|
message = "your subscription will be cancelled on $endDate";
|
||||||
|
}
|
||||||
|
return Text(
|
||||||
|
message,
|
||||||
|
style: TextStyle(
|
||||||
|
color: Colors.white.withOpacity(0.6),
|
||||||
|
fontSize: 14,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -12,13 +12,11 @@ import 'package:photos/models/billing_plan.dart';
|
||||||
import 'package:photos/models/subscription.dart';
|
import 'package:photos/models/subscription.dart';
|
||||||
import 'package:photos/services/billing_service.dart';
|
import 'package:photos/services/billing_service.dart';
|
||||||
import 'package:photos/ui/billing_questions_widget.dart';
|
import 'package:photos/ui/billing_questions_widget.dart';
|
||||||
import 'package:photos/ui/common_elements.dart';
|
|
||||||
import 'package:photos/ui/loading_widget.dart';
|
import 'package:photos/ui/loading_widget.dart';
|
||||||
import 'package:photos/ui/payment/skip_subscription_widget.dart';
|
import 'package:photos/ui/payment/skip_subscription_widget.dart';
|
||||||
|
import 'package:photos/ui/payment/subscription_common_widgets.dart';
|
||||||
import 'package:photos/ui/payment/subscription_plan_widget.dart';
|
import 'package:photos/ui/payment/subscription_plan_widget.dart';
|
||||||
import 'package:photos/ui/progress_dialog.dart';
|
import 'package:photos/ui/progress_dialog.dart';
|
||||||
import 'package:photos/utils/data_util.dart';
|
|
||||||
import 'package:photos/utils/date_time_util.dart';
|
|
||||||
import 'package:photos/utils/dialog_util.dart';
|
import 'package:photos/utils/dialog_util.dart';
|
||||||
import 'package:photos/utils/toast_util.dart';
|
import 'package:photos/utils/toast_util.dart';
|
||||||
import 'package:url_launcher/url_launcher.dart';
|
import 'package:url_launcher/url_launcher.dart';
|
||||||
|
@ -67,7 +65,6 @@ class _SubscriptionPageState extends State<SubscriptionPage> {
|
||||||
return productID != null && productID.isNotEmpty;
|
return productID != null && productID.isNotEmpty;
|
||||||
}).toList();
|
}).toList();
|
||||||
_freePlan = billingPlans.freePlan;
|
_freePlan = billingPlans.freePlan;
|
||||||
|
|
||||||
_usageFuture = _billingService.fetchUsage();
|
_usageFuture = _billingService.fetchUsage();
|
||||||
_hasLoadedData = true;
|
_hasLoadedData = true;
|
||||||
setState(() {});
|
setState(() {});
|
||||||
|
@ -162,42 +159,10 @@ class _SubscriptionPageState extends State<SubscriptionPage> {
|
||||||
|
|
||||||
Widget _buildPlans() {
|
Widget _buildPlans() {
|
||||||
final widgets = <Widget>[];
|
final widgets = <Widget>[];
|
||||||
if (widget.isOnboarding) {
|
widgets.add(SubscriptionHeaderWidget(
|
||||||
widgets.add(Padding(
|
isOnboarding: widget.isOnboarding,
|
||||||
padding: const EdgeInsets.fromLTRB(20, 20, 20, 24),
|
usageFuture: _usageFuture,
|
||||||
child: Text(
|
));
|
||||||
"ente preserves your memories, so they're always available to you, even if you lose your device",
|
|
||||||
style: TextStyle(
|
|
||||||
color: Colors.white54,
|
|
||||||
height: 1.2,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
));
|
|
||||||
} else {
|
|
||||||
widgets.add(
|
|
||||||
SizedBox(
|
|
||||||
height: 50,
|
|
||||||
child: FutureBuilder(
|
|
||||||
future: _usageFuture,
|
|
||||||
builder: (BuildContext context, AsyncSnapshot snapshot) {
|
|
||||||
if (snapshot.hasData) {
|
|
||||||
return Padding(
|
|
||||||
padding: const EdgeInsets.all(16.0),
|
|
||||||
child: Text("current usage is " + formatBytes(snapshot.data)),
|
|
||||||
);
|
|
||||||
} else if (snapshot.hasError) {
|
|
||||||
return Container();
|
|
||||||
} else {
|
|
||||||
return Padding(
|
|
||||||
padding: const EdgeInsets.all(16.0),
|
|
||||||
child: loadWidget,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
widgets.addAll([
|
widgets.addAll([
|
||||||
Column(
|
Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
@ -209,17 +174,7 @@ class _SubscriptionPageState extends State<SubscriptionPage> {
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if (_hasActiveSubscription) {
|
if (_hasActiveSubscription) {
|
||||||
widgets.add(
|
widgets.add(ValidityWidget(currentSubscription: _currentSubscription));
|
||||||
Text(
|
|
||||||
"valid till " +
|
|
||||||
getDateAndMonthAndYear(DateTime.fromMicrosecondsSinceEpoch(
|
|
||||||
_currentSubscription.expiryTime)),
|
|
||||||
style: TextStyle(
|
|
||||||
color: Colors.white.withOpacity(0.6),
|
|
||||||
fontSize: 14,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_hasActiveSubscription &&
|
if (_hasActiveSubscription &&
|
||||||
|
|
Loading…
Reference in a new issue