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",
"createVoucherDesc": "Wähle den Wert des Gutscheins. Der Wert des Gutschein wird von deinem twonly-Guthaben abgezogen.",
"redeemVoucher": "Gutschein einlösen",
"redeemUserInviteCodeTitle": "twonly-Code einlösen",
"redeemUserInviteCodeSuccess": "Dein Plan wurde erfolgreich angepasst.",
"voucherCreated": "Gutschein wurde erstellt",
"openVouchers": "Offene Gutscheine",
"enterVoucherCode": "Gutschein Code eingeben",

View file

@ -336,7 +336,8 @@
"familyFeature1": "✓ Unlimited media file uploads",
"familyFeature2": "4 additional Plus 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",
"plusFeature1": "✓ Unlimited media file uploads",
"transactionHistory": "Your transaction history",

View file

@ -1079,11 +1079,17 @@ abstract class AppLocalizations {
/// **'4 additional Free users'**
String get familyFeature3;
/// No description provided for @redeemUserInviteCode.
/// No description provided for @redeemUserInviteCodeTitle.
///
/// In en, this message translates to:
/// **'Or redeem an additional user invite code.'**
String get redeemUserInviteCode;
/// **'Redeem twonly-Code'**
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.
///

View file

@ -513,7 +513,10 @@ class AppLocalizationsDe extends AppLocalizations {
String get familyFeature3 => '4 zusätzliche kostenlose Benutzer';
@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
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';
@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
String get freeFeature1 => '3 Media file uploads per day';

View file

@ -486,6 +486,13 @@ class ApiProvider {
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 {
var get = ApplicationData_UpdateGoogleFcmToken()..googleFcm = googleFcm;
var appData = ApplicationData()..updategooglefcmtoken = get;

View file

@ -72,8 +72,10 @@ int calculateRefund(Response_PlanBallance current) {
// => 5
refund = (((YEARLY_PAYMENT_DAYS - elapsedDays) / YEARLY_PAYMENT_DAYS) *
getPlanPrice("Pro", false))
.ceil();
getPlanPrice("Pro", false) /
100)
.ceil() *
100;
}
}
return refund;
@ -211,11 +213,17 @@ class _SubscriptionViewState extends State<SubscriptionView> {
if (currentPlan != "Free")
PlanCard(
planId: "Free",
onTap: () {},
onTap: () async {
await redeemUserInviteCode(context, "Free");
initAsync();
},
),
PlanCard(
planId: "Plus",
onTap: () {},
onTap: () async {
await redeemUserInviteCode(context, "Plus");
initAsync();
},
),
],
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),
),
],
);
},
);
}