Surface breakdown on storage bonus (#1481)
This commit is contained in:
commit
aba7f5d4b5
11 changed files with 326 additions and 49 deletions
9
lib/generated/intl/messages_en.dart
generated
9
lib/generated/intl/messages_en.dart
generated
|
@ -187,6 +187,8 @@ class MessageLookup extends MessageLookupByLibrary {
|
|||
static String m59(count) =>
|
||||
"${Intl.plural(count, zero: '', one: '1 day', other: '${count} days')}";
|
||||
|
||||
static String m64(endDate) => "Valid till ${endDate}";
|
||||
|
||||
static String m60(email) => "Verify ${email}";
|
||||
|
||||
static String m61(email) => "We have sent a mail to <green>${email}</green>";
|
||||
|
@ -218,6 +220,9 @@ class MessageLookup extends MessageLookupByLibrary {
|
|||
"addLocation": MessageLookupByLibrary.simpleMessage("Add location"),
|
||||
"addLocationButton": MessageLookupByLibrary.simpleMessage("Add"),
|
||||
"addMore": MessageLookupByLibrary.simpleMessage("Add more"),
|
||||
"addOnPageSubtitle":
|
||||
MessageLookupByLibrary.simpleMessage("Break up of add on storage"),
|
||||
"addOns": MessageLookupByLibrary.simpleMessage("Add ons"),
|
||||
"addPhotos": MessageLookupByLibrary.simpleMessage("Add photos"),
|
||||
"addSelected": MessageLookupByLibrary.simpleMessage("Add selected"),
|
||||
"addToAlbum": MessageLookupByLibrary.simpleMessage("Add to album"),
|
||||
|
@ -694,8 +699,6 @@ class MessageLookup extends MessageLookupByLibrary {
|
|||
MessageLookupByLibrary.simpleMessage("Group nearby photos"),
|
||||
"hearUsExplanation": MessageLookupByLibrary.simpleMessage(
|
||||
"We don\'t track app installs. It\'d help if you told us where you found us!"),
|
||||
"hearUsHint": MessageLookupByLibrary.simpleMessage(
|
||||
"friend, reddit, ad, search, etc."),
|
||||
"hearUsWhereTitle": MessageLookupByLibrary.simpleMessage(
|
||||
"How did you hear about Ente? (optional)"),
|
||||
"hidden": MessageLookupByLibrary.simpleMessage("Hidden"),
|
||||
|
@ -1325,6 +1328,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
|||
"useSelectedPhoto":
|
||||
MessageLookupByLibrary.simpleMessage("Use selected photo"),
|
||||
"usedSpace": MessageLookupByLibrary.simpleMessage("Used space"),
|
||||
"validTill": m64,
|
||||
"verificationFailedPleaseTryAgain":
|
||||
MessageLookupByLibrary.simpleMessage(
|
||||
"Verification failed, please try again"),
|
||||
|
@ -1342,6 +1346,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
|||
"videoSmallCase": MessageLookupByLibrary.simpleMessage("video"),
|
||||
"viewActiveSessions":
|
||||
MessageLookupByLibrary.simpleMessage("View active sessions"),
|
||||
"viewAddOnButton": MessageLookupByLibrary.simpleMessage("View Add-ons"),
|
||||
"viewAll": MessageLookupByLibrary.simpleMessage("View all"),
|
||||
"viewAllExifData":
|
||||
MessageLookupByLibrary.simpleMessage("View all EXIF data"),
|
||||
|
|
50
lib/generated/l10n.dart
generated
50
lib/generated/l10n.dart
generated
|
@ -3914,6 +3914,16 @@ class S {
|
|||
);
|
||||
}
|
||||
|
||||
/// `Valid till {endDate}`
|
||||
String validTill(Object endDate) {
|
||||
return Intl.message(
|
||||
'Valid till $endDate',
|
||||
name: 'validTill',
|
||||
desc: '',
|
||||
args: [endDate],
|
||||
);
|
||||
}
|
||||
|
||||
/// `Free trial valid till {endDate}.\nYou can choose a paid plan afterwards.`
|
||||
String playStoreFreeTrialValidTill(Object endDate) {
|
||||
return Intl.message(
|
||||
|
@ -7725,16 +7735,6 @@ class S {
|
|||
);
|
||||
}
|
||||
|
||||
/// `friend, reddit, ad, search, etc.`
|
||||
String get hearUsHint {
|
||||
return Intl.message(
|
||||
'friend, reddit, ad, search, etc.',
|
||||
name: 'hearUsHint',
|
||||
desc: '',
|
||||
args: [],
|
||||
);
|
||||
}
|
||||
|
||||
/// `We don't track app installs. It'd help if you told us where you found us!`
|
||||
String get hearUsExplanation {
|
||||
return Intl.message(
|
||||
|
@ -7744,6 +7744,36 @@ class S {
|
|||
args: [],
|
||||
);
|
||||
}
|
||||
|
||||
/// `View Add-ons`
|
||||
String get viewAddOnButton {
|
||||
return Intl.message(
|
||||
'View Add-ons',
|
||||
name: 'viewAddOnButton',
|
||||
desc: '',
|
||||
args: [],
|
||||
);
|
||||
}
|
||||
|
||||
/// `Add ons`
|
||||
String get addOns {
|
||||
return Intl.message(
|
||||
'Add ons',
|
||||
name: 'addOns',
|
||||
desc: '',
|
||||
args: [],
|
||||
);
|
||||
}
|
||||
|
||||
/// `Break up of add on storage`
|
||||
String get addOnPageSubtitle {
|
||||
return Intl.message(
|
||||
'Break up of add on storage',
|
||||
name: 'addOnPageSubtitle',
|
||||
desc: '',
|
||||
args: [],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class AppLocalizationDelegate extends LocalizationsDelegate<S> {
|
||||
|
|
|
@ -557,6 +557,7 @@
|
|||
"faqs": "FAQs",
|
||||
"renewsOn": "Renews on {endDate}",
|
||||
"freeTrialValidTill": "Free trial valid till {endDate}",
|
||||
"validTill": "Valid till {endDate}",
|
||||
"playStoreFreeTrialValidTill": "Free trial valid till {endDate}.\nYou can choose a paid plan afterwards.",
|
||||
"subWillBeCancelledOn": "Your subscription will be cancelled on {endDate}",
|
||||
"subscription": "Subscription",
|
||||
|
@ -1104,5 +1105,8 @@
|
|||
"moveToHiddenAlbum": "Move to hidden album",
|
||||
"deleteConfirmDialogBody": "This account is linked to other ente apps, if you use any.\\n\\nYour uploaded data, across all ente apps, will be scheduled for deletion, and your account will be permanently deleted.",
|
||||
"hearUsWhereTitle": "How did you hear about Ente? (optional)",
|
||||
"hearUsExplanation": "We don't track app installs. It'd help if you told us where you found us!"
|
||||
}
|
||||
"hearUsExplanation": "We don't track app installs. It'd help if you told us where you found us!",
|
||||
"viewAddOnButton": "View add-ons",
|
||||
"addOns": "Add-ons",
|
||||
"addOnPageSubtitle": "Details of add-ons"
|
||||
}
|
||||
|
|
60
lib/models/api/storage_bonus/bonus.dart
Normal file
60
lib/models/api/storage_bonus/bonus.dart
Normal file
|
@ -0,0 +1,60 @@
|
|||
class Bonus {
|
||||
int storage;
|
||||
String type;
|
||||
int validTill;
|
||||
bool isRevoked;
|
||||
|
||||
Bonus(this.storage, this.type, this.validTill, this.isRevoked);
|
||||
|
||||
factory Bonus.fromJson(Map<String, dynamic> json) {
|
||||
return Bonus(
|
||||
json['storage'],
|
||||
json['type'],
|
||||
json['validTill'],
|
||||
json['isRevoked'],
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'storage': storage,
|
||||
'type': type,
|
||||
'validTill': validTill,
|
||||
'isRevoked': isRevoked,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
class BonusData {
|
||||
static Set<String> signUpBonusTypes = {'SIGN_UP', 'REFERRAL'};
|
||||
final List<Bonus> storageBonuses;
|
||||
|
||||
BonusData(this.storageBonuses);
|
||||
|
||||
List<Bonus> getAddOnBonuses() {
|
||||
return storageBonuses
|
||||
.where((b) => !signUpBonusTypes.contains(b.type))
|
||||
.toList();
|
||||
}
|
||||
|
||||
int totalAddOnBonus() {
|
||||
return getAddOnBonuses().fold(0, (sum, bonus) => sum + bonus.storage);
|
||||
}
|
||||
|
||||
factory BonusData.fromJson(Map<String, dynamic>? json) {
|
||||
if (json == null || json['storageBonuses'] == null) {
|
||||
return BonusData([]);
|
||||
}
|
||||
return BonusData(
|
||||
(json['storageBonuses'] as List)
|
||||
.map((bonus) => Bonus.fromJson(bonus))
|
||||
.toList(),
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'storageBonuses': storageBonuses.map((bonus) => bonus.toJson()).toList(),
|
||||
};
|
||||
}
|
||||
}
|
|
@ -1,3 +1,5 @@
|
|||
import "package:photos/models/api/storage_bonus/bonus.dart";
|
||||
|
||||
class ReferralView {
|
||||
PlanInfo planInfo;
|
||||
String code;
|
||||
|
@ -86,34 +88,6 @@ class ReferralStat {
|
|||
}
|
||||
}
|
||||
|
||||
class Bonus {
|
||||
int storage;
|
||||
String type;
|
||||
int validTill;
|
||||
bool isRevoked;
|
||||
|
||||
Bonus(this.storage, this.type, this.validTill, this.isRevoked);
|
||||
|
||||
// fromJson
|
||||
factory Bonus.fromJson(Map<String, dynamic> json) {
|
||||
return Bonus(
|
||||
json['storage'],
|
||||
json['type'],
|
||||
json['validTill'],
|
||||
json['isRevoked'],
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'storage': storage,
|
||||
'type': type,
|
||||
'validTill': validTill,
|
||||
'isRevoked': isRevoked,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
class BonusDetails {
|
||||
List<ReferralStat> referralStats;
|
||||
List<Bonus> bonuses;
|
||||
|
|
|
@ -2,6 +2,7 @@ import 'dart:convert';
|
|||
import 'dart:math';
|
||||
|
||||
import 'package:collection/collection.dart';
|
||||
import "package:photos/models/api/storage_bonus/bonus.dart";
|
||||
import 'package:photos/models/file/file_type.dart';
|
||||
import 'package:photos/models/subscription.dart';
|
||||
|
||||
|
@ -14,6 +15,7 @@ class UserDetails {
|
|||
final Subscription subscription;
|
||||
final FamilyData? familyData;
|
||||
final ProfileData? profileData;
|
||||
final BonusData? bonusData;
|
||||
|
||||
const UserDetails(
|
||||
this.email,
|
||||
|
@ -24,6 +26,7 @@ class UserDetails {
|
|||
this.subscription,
|
||||
this.familyData,
|
||||
this.profileData,
|
||||
this.bonusData,
|
||||
);
|
||||
|
||||
bool isPartOfFamily() {
|
||||
|
@ -55,6 +58,12 @@ class UserDetails {
|
|||
storageBonus;
|
||||
}
|
||||
|
||||
// This is the total storage for which user has paid for.
|
||||
int getPlanPlusAddonStorage() {
|
||||
return (isPartOfFamily() ? familyData!.storage : subscription.storage) +
|
||||
bonusData!.totalAddOnBonus();
|
||||
}
|
||||
|
||||
factory UserDetails.fromMap(Map<String, dynamic> map) {
|
||||
return UserDetails(
|
||||
map['email'] as String,
|
||||
|
@ -65,6 +74,7 @@ class UserDetails {
|
|||
Subscription.fromMap(map['subscription']),
|
||||
FamilyData.fromMap(map['familyData']),
|
||||
ProfileData.fromJson(map['profileData']),
|
||||
BonusData.fromJson(map['bonusData']),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -78,6 +88,7 @@ class UserDetails {
|
|||
'subscription': subscription.toMap(),
|
||||
'familyData': familyData?.toMap(),
|
||||
'profileData': profileData?.toJson(),
|
||||
'bonusData': bonusData?.toJson(),
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -123,6 +134,7 @@ class FamilyMember {
|
|||
factory FamilyMember.fromJson(String source) =>
|
||||
FamilyMember.fromMap(json.decode(source));
|
||||
}
|
||||
|
||||
class ProfileData {
|
||||
bool canDisableEmailMFA;
|
||||
bool isEmailMFAEnabled;
|
||||
|
@ -135,7 +147,6 @@ class ProfileData {
|
|||
this.isTwoFactorEnabled = false,
|
||||
});
|
||||
|
||||
|
||||
// Factory method to create ProfileData instance from JSON
|
||||
factory ProfileData.fromJson(Map<String, dynamic>? json) {
|
||||
return ProfileData(
|
||||
|
@ -153,6 +164,7 @@ class ProfileData {
|
|||
'isTwoFactorEnabled': isTwoFactorEnabled,
|
||||
};
|
||||
}
|
||||
|
||||
String toJsonString() => json.encode(toJson());
|
||||
}
|
||||
|
||||
|
|
|
@ -122,12 +122,14 @@ class _StorageDetailsScreenState extends State<StorageDetailsScreen> {
|
|||
leftValue: convertBytesToAbsoluteGBs(
|
||||
min(
|
||||
widget.referralView.claimedStorage,
|
||||
widget.userDetails.getTotalStorage(),
|
||||
widget.userDetails
|
||||
.getPlanPlusAddonStorage(),
|
||||
),
|
||||
),
|
||||
leftUnitName: "GB",
|
||||
rightValue: convertBytesToAbsoluteGBs(
|
||||
widget.userDetails.getTotalStorage(),
|
||||
widget.userDetails
|
||||
.getPlanPlusAddonStorage(),
|
||||
),
|
||||
rightUnitName: "GB",
|
||||
),
|
||||
|
|
123
lib/ui/payment/add_on_page.dart
Normal file
123
lib/ui/payment/add_on_page.dart
Normal file
|
@ -0,0 +1,123 @@
|
|||
import "package:flutter/material.dart";
|
||||
import "package:intl/intl.dart";
|
||||
import "package:photos/generated/l10n.dart";
|
||||
import "package:photos/models/api/storage_bonus/bonus.dart";
|
||||
import "package:photos/theme/ente_theme.dart";
|
||||
import 'package:photos/ui/components/buttons/icon_button_widget.dart';
|
||||
import "package:photos/ui/components/title_bar_title_widget.dart";
|
||||
import "package:photos/ui/components/title_bar_widget.dart";
|
||||
import "package:photos/utils/data_util.dart";
|
||||
|
||||
class AddOnPage extends StatelessWidget {
|
||||
final BonusData bonusData;
|
||||
|
||||
const AddOnPage(this.bonusData, {super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
body: CustomScrollView(
|
||||
primary: false,
|
||||
slivers: <Widget>[
|
||||
TitleBarWidget(
|
||||
flexibleSpaceTitle: TitleBarTitleWidget(
|
||||
title: S.of(context).addOns,
|
||||
),
|
||||
flexibleSpaceCaption: S.of(context).addOnPageSubtitle,
|
||||
actionIcons: [
|
||||
IconButtonWidget(
|
||||
icon: Icons.close_outlined,
|
||||
iconButtonType: IconButtonType.secondary,
|
||||
onTap: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
SliverPadding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 16),
|
||||
sliver: SliverList(
|
||||
delegate: SliverChildBuilderDelegate(
|
||||
(delegateBuildContext, index) {
|
||||
Bonus bonus = bonusData.getAddOnBonuses()[index];
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 4),
|
||||
child: AddOnViewSection(
|
||||
sectionName: bonus.type == 'ADD_ON_BF_2023'
|
||||
? "Black friday 2023"
|
||||
: bonus.type.replaceAll('_', ' '),
|
||||
bonus: bonus,
|
||||
),
|
||||
);
|
||||
},
|
||||
childCount: bonusData?.getAddOnBonuses().length ?? 0,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class AddOnViewSection extends StatelessWidget {
|
||||
final String sectionName;
|
||||
final Bonus bonus;
|
||||
|
||||
const AddOnViewSection({
|
||||
super.key,
|
||||
required this.sectionName,
|
||||
required this.bonus,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final colorScheme = getEnteColorScheme(context);
|
||||
final textStyle = getEnteTextTheme(context);
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
sectionName,
|
||||
style: textStyle.body.copyWith(
|
||||
color: colorScheme.textMuted,
|
||||
),
|
||||
),
|
||||
if (bonus.validTill != 0)
|
||||
Text(
|
||||
S.of(context).validTill(
|
||||
DateFormat.yMMMd(
|
||||
Localizations.localeOf(context).languageCode,
|
||||
)
|
||||
.format(
|
||||
DateTime.fromMicrosecondsSinceEpoch(
|
||||
bonus.validTill,
|
||||
),
|
||||
)
|
||||
.toString(),
|
||||
),
|
||||
style: textStyle.body.copyWith(
|
||||
color: colorScheme.textMuted,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 2),
|
||||
RichText(
|
||||
text: TextSpan(
|
||||
children: [
|
||||
TextSpan(
|
||||
text: convertBytesToReadableFormat(bonus.storage).toString(),
|
||||
style: textStyle.h3,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
|
@ -25,6 +25,8 @@ import 'package:photos/ui/payment/child_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/view_add_on_widget.dart";
|
||||
import "package:photos/utils/data_util.dart";
|
||||
import 'package:photos/utils/dialog_util.dart';
|
||||
import 'package:photos/utils/toast_util.dart';
|
||||
import 'package:url_launcher/url_launcher_string.dart';
|
||||
|
@ -290,7 +292,7 @@ class _StoreSubscriptionPageState extends State<StoreSubscriptionPage> {
|
|||
if (!widget.isOnboarding) {
|
||||
widgets.add(
|
||||
Padding(
|
||||
padding: const EdgeInsets.fromLTRB(16, 0, 16, 80),
|
||||
padding: const EdgeInsets.fromLTRB(16, 0, 16, 0),
|
||||
child: MenuItemWidget(
|
||||
captionedTextWidget: CaptionedTextWidget(
|
||||
title: _isFreePlanUser()
|
||||
|
@ -310,6 +312,8 @@ class _StoreSubscriptionPageState extends State<StoreSubscriptionPage> {
|
|||
),
|
||||
),
|
||||
);
|
||||
widgets.add(ViewAddOnButton(_userDetails.bonusData));
|
||||
widgets.add(const SizedBox(height: 80));
|
||||
}
|
||||
return SingleChildScrollView(
|
||||
child: Column(
|
||||
|
@ -490,7 +494,16 @@ class _StoreSubscriptionPageState extends State<StoreSubscriptionPage> {
|
|||
if (isActive) {
|
||||
return;
|
||||
}
|
||||
if (_userDetails.getFamilyOrPersonalUsage() > plan.storage) {
|
||||
final int addOnBonus =
|
||||
_userDetails.bonusData?.totalAddOnBonus() ?? 0;
|
||||
if (_userDetails.getFamilyOrPersonalUsage() >
|
||||
(plan.storage + addOnBonus)) {
|
||||
_logger.warning(
|
||||
" familyUsage ${convertBytesToReadableFormat(_userDetails.getFamilyOrPersonalUsage())}"
|
||||
" plan storage ${convertBytesToReadableFormat(plan.storage)} "
|
||||
"addOnBonus ${convertBytesToReadableFormat(addOnBonus)},"
|
||||
"overshooting by ${convertBytesToReadableFormat(_userDetails.getFamilyOrPersonalUsage() - (plan.storage + addOnBonus))}",
|
||||
);
|
||||
showErrorDialog(
|
||||
context,
|
||||
S.of(context).sorry,
|
||||
|
|
|
@ -25,6 +25,8 @@ import 'package:photos/ui/payment/payment_web_page.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/view_add_on_widget.dart";
|
||||
import "package:photos/utils/data_util.dart";
|
||||
import 'package:photos/utils/dialog_util.dart';
|
||||
import 'package:photos/utils/toast_util.dart';
|
||||
import 'package:step_progress_indicator/step_progress_indicator.dart';
|
||||
|
@ -252,7 +254,7 @@ class _StripeSubscriptionPageState extends State<StripeSubscriptionPage> {
|
|||
if (!widget.isOnboarding) {
|
||||
widgets.add(
|
||||
Padding(
|
||||
padding: const EdgeInsets.fromLTRB(16, 0, 16, 80),
|
||||
padding: const EdgeInsets.fromLTRB(16, 0, 16, 0),
|
||||
child: MenuItemWidget(
|
||||
captionedTextWidget: CaptionedTextWidget(
|
||||
title: S.of(context).manageFamily,
|
||||
|
@ -270,6 +272,8 @@ class _StripeSubscriptionPageState extends State<StripeSubscriptionPage> {
|
|||
),
|
||||
),
|
||||
);
|
||||
widgets.add(ViewAddOnButton(_userDetails.bonusData));
|
||||
widgets.add(const SizedBox(height: 80));
|
||||
}
|
||||
|
||||
return SingleChildScrollView(
|
||||
|
@ -446,7 +450,16 @@ class _StripeSubscriptionPageState extends State<StripeSubscriptionPage> {
|
|||
);
|
||||
return;
|
||||
}
|
||||
if (_userDetails.getFamilyOrPersonalUsage() > plan.storage) {
|
||||
final int addOnBonus =
|
||||
_userDetails.bonusData?.totalAddOnBonus() ?? 0;
|
||||
if (_userDetails.getFamilyOrPersonalUsage() >
|
||||
(plan.storage + addOnBonus)) {
|
||||
logger.warning(
|
||||
" familyUsage ${convertBytesToReadableFormat(_userDetails.getFamilyOrPersonalUsage())}"
|
||||
" plan storage ${convertBytesToReadableFormat(plan.storage)} "
|
||||
"addOnBonus ${convertBytesToReadableFormat(addOnBonus)},"
|
||||
"overshooting by ${convertBytesToReadableFormat(_userDetails.getFamilyOrPersonalUsage() - (plan.storage + addOnBonus))}",
|
||||
);
|
||||
showErrorDialog(
|
||||
context,
|
||||
S.of(context).sorry,
|
||||
|
|
41
lib/ui/payment/view_add_on_widget.dart
Normal file
41
lib/ui/payment/view_add_on_widget.dart
Normal file
|
@ -0,0 +1,41 @@
|
|||
import "package:flutter/material.dart";
|
||||
import "package:photos/generated/l10n.dart";
|
||||
import "package:photos/models/api/storage_bonus/bonus.dart";
|
||||
import "package:photos/theme/colors.dart";
|
||||
import "package:photos/theme/ente_theme.dart";
|
||||
import "package:photos/ui/components/captioned_text_widget.dart";
|
||||
import "package:photos/ui/components/menu_item_widget/menu_item_widget.dart";
|
||||
import "package:photos/ui/payment/add_on_page.dart";
|
||||
import "package:photos/utils/navigation_util.dart";
|
||||
|
||||
class ViewAddOnButton extends StatelessWidget {
|
||||
final BonusData? bonusData;
|
||||
|
||||
const ViewAddOnButton(this.bonusData, {super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (bonusData?.getAddOnBonuses().isEmpty ?? true) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
final EnteColorScheme colorScheme = getEnteColorScheme(context);
|
||||
return Padding(
|
||||
padding: const EdgeInsets.fromLTRB(16, 4, 16, 0),
|
||||
child: MenuItemWidget(
|
||||
captionedTextWidget: CaptionedTextWidget(
|
||||
title: S.of(context).viewAddOnButton,
|
||||
),
|
||||
menuItemColor: colorScheme.fillFaint,
|
||||
trailingWidget: Icon(
|
||||
Icons.chevron_right_outlined,
|
||||
color: colorScheme.strokeBase,
|
||||
),
|
||||
singleBorderRadius: 4,
|
||||
alignCaptionedTextToLeft: true,
|
||||
onTap: () async {
|
||||
routeToPage(context, AddOnPage(bonusData!));
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue