redeem twonly-codes

This commit is contained in:
otsmr 2025-05-10 17:13:17 +02:00
parent 24821c6cdc
commit db43a1d7f8
7 changed files with 110 additions and 10 deletions

View file

@ -193,6 +193,8 @@
"createVoucher": "Gutschein kaufen", "createVoucher": "Gutschein kaufen",
"createVoucherDesc": "Wähle den Wert des Gutscheins. Der Wert des Gutschein wird von deinem twonly-Guthaben abgezogen.", "createVoucherDesc": "Wähle den Wert des Gutscheins. Der Wert des Gutschein wird von deinem twonly-Guthaben abgezogen.",
"redeemVoucher": "Gutschein einlösen", "redeemVoucher": "Gutschein einlösen",
"redeemUserInviteCodeTitle": "twonly-Code einlösen",
"redeemUserInviteCodeSuccess": "Dein Plan wurde erfolgreich angepasst.",
"voucherCreated": "Gutschein wurde erstellt", "voucherCreated": "Gutschein wurde erstellt",
"openVouchers": "Offene Gutscheine", "openVouchers": "Offene Gutscheine",
"enterVoucherCode": "Gutschein Code eingeben", "enterVoucherCode": "Gutschein Code eingeben",

View file

@ -336,7 +336,8 @@
"familyFeature1": "✓ Unlimited media file uploads", "familyFeature1": "✓ Unlimited media file uploads",
"familyFeature2": "4 additional Plus users", "familyFeature2": "4 additional Plus users",
"familyFeature3": "4 additional Free users", "familyFeature3": "4 additional Free users",
"redeemUserInviteCode": "Or redeem an additional user invite code.", "redeemUserInviteCodeTitle": "Redeem twonly-Code",
"redeemUserInviteCodeSuccess": "Your plan has been successfully adjusted.",
"freeFeature1": "3 Media file uploads per day", "freeFeature1": "3 Media file uploads per day",
"plusFeature1": "✓ Unlimited media file uploads", "plusFeature1": "✓ Unlimited media file uploads",
"transactionHistory": "Your transaction history", "transactionHistory": "Your transaction history",

View file

@ -1079,11 +1079,17 @@ abstract class AppLocalizations {
/// **'4 additional Free users'** /// **'4 additional Free users'**
String get familyFeature3; String get familyFeature3;
/// No description provided for @redeemUserInviteCode. /// No description provided for @redeemUserInviteCodeTitle.
/// ///
/// In en, this message translates to: /// In en, this message translates to:
/// **'Or redeem an additional user invite code.'** /// **'Redeem twonly-Code'**
String get redeemUserInviteCode; String get redeemUserInviteCodeTitle;
/// No description provided for @redeemUserInviteCodeSuccess.
///
/// In en, this message translates to:
/// **'Your plan has been successfully adjusted.'**
String get redeemUserInviteCodeSuccess;
/// No description provided for @freeFeature1. /// No description provided for @freeFeature1.
/// ///

View file

@ -513,7 +513,10 @@ class AppLocalizationsDe extends AppLocalizations {
String get familyFeature3 => '4 zusätzliche kostenlose Benutzer'; String get familyFeature3 => '4 zusätzliche kostenlose Benutzer';
@override @override
String get redeemUserInviteCode => 'Oder löse einen zusätzlichen twonly-Code ein.'; String get redeemUserInviteCodeTitle => 'twonly-Code einlösen';
@override
String get redeemUserInviteCodeSuccess => 'Dein Plan wurde erfolgreich angepasst.';
@override @override
String get freeFeature1 => '3 Medien-Datei-Uploads pro Tag'; String get freeFeature1 => '3 Medien-Datei-Uploads pro Tag';

View file

@ -513,7 +513,10 @@ class AppLocalizationsEn extends AppLocalizations {
String get familyFeature3 => '4 additional Free users'; String get familyFeature3 => '4 additional Free users';
@override @override
String get redeemUserInviteCode => 'Or redeem an additional user invite code.'; String get redeemUserInviteCodeTitle => 'Redeem twonly-Code';
@override
String get redeemUserInviteCodeSuccess => 'Your plan has been successfully adjusted.';
@override @override
String get freeFeature1 => '3 Media file uploads per day'; String get freeFeature1 => '3 Media file uploads per day';

View file

@ -486,6 +486,13 @@ class ApiProvider {
return await sendRequestSync(req); return await sendRequestSync(req);
} }
Future<Result> redeemUserInviteCode(String inviteCode) async {
var get = ApplicationData_RedeemAdditionalCode()..inviteCode = inviteCode;
var appData = ApplicationData()..redeemadditionalcode = get;
var req = createClientToServerFromApplicationData(appData);
return await sendRequestSync(req);
}
Future<Result> updateFCMToken(String googleFcm) async { Future<Result> updateFCMToken(String googleFcm) async {
var get = ApplicationData_UpdateGoogleFcmToken()..googleFcm = googleFcm; var get = ApplicationData_UpdateGoogleFcmToken()..googleFcm = googleFcm;
var appData = ApplicationData()..updategooglefcmtoken = get; var appData = ApplicationData()..updategooglefcmtoken = get;

View file

@ -72,8 +72,10 @@ int calculateRefund(Response_PlanBallance current) {
// => 5 // => 5
refund = (((YEARLY_PAYMENT_DAYS - elapsedDays) / YEARLY_PAYMENT_DAYS) * refund = (((YEARLY_PAYMENT_DAYS - elapsedDays) / YEARLY_PAYMENT_DAYS) *
getPlanPrice("Pro", false)) getPlanPrice("Pro", false) /
.ceil(); 100)
.ceil() *
100;
} }
} }
return refund; return refund;
@ -211,11 +213,17 @@ class _SubscriptionViewState extends State<SubscriptionView> {
if (currentPlan != "Free") if (currentPlan != "Free")
PlanCard( PlanCard(
planId: "Free", planId: "Free",
onTap: () {}, onTap: () async {
await redeemUserInviteCode(context, "Free");
initAsync();
},
), ),
PlanCard( PlanCard(
planId: "Plus", planId: "Plus",
onTap: () {}, onTap: () async {
await redeemUserInviteCode(context, "Plus");
initAsync();
},
), ),
], ],
SizedBox(height: 10), SizedBox(height: 10),
@ -433,3 +441,73 @@ class PlanCard extends StatelessWidget {
); );
} }
} }
Future redeemUserInviteCode(BuildContext context, String newPlan) async {
String inviteCode = '';
await showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text(context.lang.redeemUserInviteCodeTitle),
content: StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
return SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Padding(
padding: const EdgeInsets.symmetric(vertical: 16.0),
child: TextField(
onChanged: (value) {
// Convert to uppercase
setState(() {
inviteCode = value.toUpperCase();
});
},
decoration: InputDecoration(
labelText: context.lang.registerTwonlyCodeLabel,
border: OutlineInputBorder(),
),
// Set the text to be uppercase
textCapitalization: TextCapitalization.characters,
),
),
],
),
);
},
),
actions: [
TextButton(
onPressed: () {
Navigator.of(context).pop();
},
child: Text(context.lang.cancel),
),
TextButton(
onPressed: () async {
final res = await apiProvider.redeemUserInviteCode(inviteCode);
if (!context.mounted) return;
if (res.isSuccess) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(context.lang.redeemUserInviteCodeSuccess)),
);
// reconnect to load new plan.
apiProvider.close(() {
apiProvider.connect();
});
} else {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(errorCodeToText(context, res.error))),
);
}
Navigator.of(context).pop();
},
child: Text(context.lang.ok),
),
],
);
},
);
}