transaction history

This commit is contained in:
otsmr 2025-05-09 17:43:05 +02:00
parent c1cc9dd3c5
commit a795aea308
13 changed files with 268 additions and 76 deletions

View file

@ -196,5 +196,12 @@
"enterVoucherCode": "Gutschein Code eingeben",
"voucherRedeemed": "Gutschein eingelöst",
"requestedVouchers": "Beantragte Gutscheine",
"redeemedVouchers": "Eingelöste Gutscheine"
"redeemedVouchers": "Eingelöste Gutscheine",
"transactionCash": "Bargeldtransaktion",
"transactionPlanUpgrade": "Planupgrade",
"transactionRefund": "Rückerstattung",
"transactionThanksForTesting": "Danke fürs Testen",
"transactionUnknown": "Unbekannte Transaktion",
"transactionVoucherCreated": "Gutschein erstellt",
"transactionVoucherRedeemed": "Gutschein eingelöst"
}

View file

@ -354,5 +354,12 @@
"enterVoucherCode": "Enter Voucher Code",
"requestedVouchers": "Requested vouchers",
"redeemedVouchers": "Redeemed vouchers",
"buy": "Buy"
"buy": "Buy",
"transactionCash": "Cash transaction",
"transactionPlanUpgrade": "Plan upgrade",
"transactionRefund": "Refund transaction",
"transactionThanksForTesting": "Thank you for testing",
"transactionUnknown": "Unknown transaction",
"transactionVoucherCreated": "Voucher created",
"transactionVoucherRedeemed": "Voucher redeemed"
}

View file

@ -1192,6 +1192,48 @@ abstract class AppLocalizations {
/// In en, this message translates to:
/// **'Buy'**
String get buy;
/// No description provided for @transactionCash.
///
/// In en, this message translates to:
/// **'Cash transaction'**
String get transactionCash;
/// No description provided for @transactionPlanUpgrade.
///
/// In en, this message translates to:
/// **'Plan upgrade'**
String get transactionPlanUpgrade;
/// No description provided for @transactionRefund.
///
/// In en, this message translates to:
/// **'Refund transaction'**
String get transactionRefund;
/// No description provided for @transactionThanksForTesting.
///
/// In en, this message translates to:
/// **'Thank you for testing'**
String get transactionThanksForTesting;
/// No description provided for @transactionUnknown.
///
/// In en, this message translates to:
/// **'Unknown transaction'**
String get transactionUnknown;
/// No description provided for @transactionVoucherCreated.
///
/// In en, this message translates to:
/// **'Voucher created'**
String get transactionVoucherCreated;
/// No description provided for @transactionVoucherRedeemed.
///
/// In en, this message translates to:
/// **'Voucher redeemed'**
String get transactionVoucherRedeemed;
}
class _AppLocalizationsDelegate extends LocalizationsDelegate<AppLocalizations> {

View file

@ -568,4 +568,25 @@ class AppLocalizationsDe extends AppLocalizations {
@override
String get buy => 'Kaufen';
@override
String get transactionCash => 'Bargeldtransaktion';
@override
String get transactionPlanUpgrade => 'Planupgrade';
@override
String get transactionRefund => 'Rückerstattung';
@override
String get transactionThanksForTesting => 'Danke fürs Testen';
@override
String get transactionUnknown => 'Unbekannte Transaktion';
@override
String get transactionVoucherCreated => 'Gutschein erstellt';
@override
String get transactionVoucherRedeemed => 'Gutschein eingelöst';
}

View file

@ -568,4 +568,25 @@ class AppLocalizationsEn extends AppLocalizations {
@override
String get buy => 'Buy';
@override
String get transactionCash => 'Cash transaction';
@override
String get transactionPlanUpgrade => 'Plan upgrade';
@override
String get transactionRefund => 'Refund transaction';
@override
String get transactionThanksForTesting => 'Thank you for testing';
@override
String get transactionUnknown => 'Unknown transaction';
@override
String get transactionVoucherCreated => 'Voucher created';
@override
String get transactionVoucherRedeemed => 'Voucher redeemed';
}

View file

@ -28,6 +28,8 @@ class UserData {
bool? storeMediaFilesInGallery;
List<String>? lastUsedEditorEmojis;
String? lastPlanBallance;
final int userId;
factory UserData.fromJson(Map<String, dynamic> json) =>

View file

@ -29,7 +29,8 @@ UserData _$UserDataFromJson(Map<String, dynamic> json) => UserData(
..storeMediaFilesInGallery = json['storeMediaFilesInGallery'] as bool?
..lastUsedEditorEmojis = (json['lastUsedEditorEmojis'] as List<dynamic>?)
?.map((e) => e as String)
.toList();
.toList()
..lastPlanBallance = json['lastPlanBallance'] as String?;
Map<String, dynamic> _$UserDataToJson(UserData instance) => <String, dynamic>{
'username': instance.username,
@ -45,6 +46,7 @@ Map<String, dynamic> _$UserDataToJson(UserData instance) => <String, dynamic>{
'autoDownloadOptions': instance.autoDownloadOptions,
'storeMediaFilesInGallery': instance.storeMediaFilesInGallery,
'lastUsedEditorEmojis': instance.lastUsedEditorEmojis,
'lastPlanBallance': instance.lastPlanBallance,
'userId': instance.userId,
};

View file

@ -15,6 +15,9 @@ import 'package:fixnum/fixnum.dart' as $fixnum;
import 'package:protobuf/protobuf.dart' as $pb;
import 'error.pbenum.dart' as $0;
import 'server_to_client.pbenum.dart';
export 'server_to_client.pbenum.dart';
enum ServerToClient_V {
v0,
@ -765,7 +768,7 @@ class Response_AddAccountsInvites extends $pb.GeneratedMessage {
class Response_Transaction extends $pb.GeneratedMessage {
factory Response_Transaction({
$fixnum.Int64? depositCents,
$core.String? transactionType,
Response_TransactionTypes? transactionType,
$fixnum.Int64? createdAtUnixTimestamp,
}) {
final $result = create();
@ -786,7 +789,7 @@ class Response_Transaction extends $pb.GeneratedMessage {
static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'Response.Transaction', package: const $pb.PackageName(_omitMessageNames ? '' : 'server_to_client'), createEmptyInstance: create)
..aInt64(1, _omitFieldNames ? '' : 'depositCents')
..aOS(2, _omitFieldNames ? '' : 'transactionType')
..e<Response_TransactionTypes>(2, _omitFieldNames ? '' : 'transactionType', $pb.PbFieldType.OE, defaultOrMaker: Response_TransactionTypes.Refund, valueOf: Response_TransactionTypes.valueOf, enumValues: Response_TransactionTypes.values)
..aInt64(3, _omitFieldNames ? '' : 'createdAtUnixTimestamp')
..hasRequiredFields = false
;
@ -822,9 +825,9 @@ class Response_Transaction extends $pb.GeneratedMessage {
void clearDepositCents() => clearField(1);
@$pb.TagNumber(2)
$core.String get transactionType => $_getSZ(1);
Response_TransactionTypes get transactionType => $_getN(1);
@$pb.TagNumber(2)
set transactionType($core.String v) { $_setString(1, v); }
set transactionType(Response_TransactionTypes v) { setField(2, v); }
@$pb.TagNumber(2)
$core.bool hasTransactionType() => $_has(1);
@$pb.TagNumber(2)

View file

@ -9,3 +9,34 @@
// ignore_for_file: non_constant_identifier_names, prefer_final_fields
// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
import 'dart:core' as $core;
import 'package:protobuf/protobuf.dart' as $pb;
class Response_TransactionTypes extends $pb.ProtobufEnum {
static const Response_TransactionTypes Refund = Response_TransactionTypes._(0, _omitEnumNames ? '' : 'Refund');
static const Response_TransactionTypes VoucherRedeemed = Response_TransactionTypes._(1, _omitEnumNames ? '' : 'VoucherRedeemed');
static const Response_TransactionTypes VoucherCreated = Response_TransactionTypes._(2, _omitEnumNames ? '' : 'VoucherCreated');
static const Response_TransactionTypes Cash = Response_TransactionTypes._(3, _omitEnumNames ? '' : 'Cash');
static const Response_TransactionTypes PlanUpgrade = Response_TransactionTypes._(4, _omitEnumNames ? '' : 'PlanUpgrade');
static const Response_TransactionTypes Unknown = Response_TransactionTypes._(5, _omitEnumNames ? '' : 'Unknown');
static const Response_TransactionTypes ThanksForTesting = Response_TransactionTypes._(6, _omitEnumNames ? '' : 'ThanksForTesting');
static const $core.List<Response_TransactionTypes> values = <Response_TransactionTypes> [
Refund,
VoucherRedeemed,
VoucherCreated,
Cash,
PlanUpgrade,
Unknown,
ThanksForTesting,
];
static final $core.Map<$core.int, Response_TransactionTypes> _byValue = $pb.ProtobufEnum.initByValue(values);
static Response_TransactionTypes? valueOf($core.int value) => _byValue[value];
const Response_TransactionTypes._($core.int v, $core.String n) : super(v, n);
}
const _omitEnumNames = $core.bool.fromEnvironment('protobuf.omit_enum_names');

View file

@ -93,6 +93,7 @@ const Response$json = {
{'1': 'error', '3': 2, '4': 1, '5': 14, '6': '.error.ErrorCode', '9': 0, '10': 'error'},
],
'3': [Response_Authenticated$json, Response_Plan$json, Response_Plans$json, Response_AddAccountsInvite$json, Response_AddAccountsInvites$json, Response_Transaction$json, Response_AdditionalAccount$json, Response_Voucher$json, Response_Vouchers$json, Response_PlanBallance$json, Response_Location$json, Response_PreKey$json, Response_UserData$json, Response_UploadToken$json, Response_Ok$json],
'4': [Response_TransactionTypes$json],
'8': [
{'1': 'Response'},
],
@ -153,7 +154,7 @@ const Response_Transaction$json = {
'1': 'Transaction',
'2': [
{'1': 'deposit_cents', '3': 1, '4': 1, '5': 3, '10': 'depositCents'},
{'1': 'transaction_type', '3': 2, '4': 1, '5': 9, '10': 'transactionType'},
{'1': 'transaction_type', '3': 2, '4': 1, '5': 14, '6': '.server_to_client.Response.TransactionTypes', '10': 'transactionType'},
{'1': 'created_at_unix_timestamp', '3': 3, '4': 1, '5': 3, '10': 'createdAtUnixTimestamp'},
],
};
@ -275,6 +276,20 @@ const Response_Ok$json = {
],
};
@$core.Deprecated('Use responseDescriptor instead')
const Response_TransactionTypes$json = {
'1': 'TransactionTypes',
'2': [
{'1': 'Refund', '2': 0},
{'1': 'VoucherRedeemed', '2': 1},
{'1': 'VoucherCreated', '2': 2},
{'1': 'Cash', '2': 3},
{'1': 'PlanUpgrade', '2': 4},
{'1': 'Unknown', '2': 5},
{'1': 'ThanksForTesting', '2': 6},
],
};
/// Descriptor for `Response`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List responseDescriptor = $convert.base64Decode(
'CghSZXNwb25zZRIvCgJvaxgBIAEoCzIdLnNlcnZlcl90b19jbGllbnQuUmVzcG9uc2UuT2tIAF'
@ -293,48 +308,52 @@ final $typed_data.Uint8List responseDescriptor = $convert.base64Decode(
'xpZW50LlJlc3BvbnNlLlBsYW5SBXBsYW5zGk0KEUFkZEFjY291bnRzSW52aXRlEhcKB3BsYW5f'
'aWQYASABKAlSBnBsYW5JZBIfCgtpbnZpdGVfY29kZRgCIAEoCVIKaW52aXRlQ29kZRpcChJBZG'
'RBY2NvdW50c0ludml0ZXMSRgoHaW52aXRlcxgBIAMoCzIsLnNlcnZlcl90b19jbGllbnQuUmVz'
'cG9uc2UuQWRkQWNjb3VudHNJbnZpdGVSB2ludml0ZXMamAEKC1RyYW5zYWN0aW9uEiMKDWRlcG'
'9zaXRfY2VudHMYASABKANSDGRlcG9zaXRDZW50cxIpChB0cmFuc2FjdGlvbl90eXBlGAIgASgJ'
'Ug90cmFuc2FjdGlvblR5cGUSOQoZY3JlYXRlZF9hdF91bml4X3RpbWVzdGFtcBgDIAEoA1IWY3'
'JlYXRlZEF0VW5peFRpbWVzdGFtcBpFChFBZGRpdGlvbmFsQWNjb3VudBIXCgd1c2VyX2lkGAEg'
'ASgDUgZ1c2VySWQSFwoHcGxhbl9pZBgDIAEoCVIGcGxhbklkGr4BCgdWb3VjaGVyEh0KCnZvdW'
'NoZXJfaWQYASABKAlSCXZvdWNoZXJJZBIfCgt2YWx1ZV9jZW50cxgCIAEoA1IKdmFsdWVDZW50'
'cxIaCghyZWRlZW1lZBgDIAEoCFIIcmVkZWVtZWQSHAoJcmVxdWVzdGVkGAQgASgIUglyZXF1ZX'
'N0ZWQSOQoZY3JlYXRlZF9hdF91bml4X3RpbWVzdGFtcBgFIAEoA1IWY3JlYXRlZEF0VW5peFRp'
'bWVzdGFtcBpKCghWb3VjaGVycxI+Cgh2b3VjaGVycxgBIAMoCzIiLnNlcnZlcl90b19jbGllbn'
'QuUmVzcG9uc2UuVm91Y2hlclIIdm91Y2hlcnMa+gMKDFBsYW5CYWxsYW5jZRJACh11c2VkX2Rh'
'aWx5X21lZGlhX3VwbG9hZF9saW1pdBgBIAEoA1IZdXNlZERhaWx5TWVkaWFVcGxvYWRMaW1pdB'
'I+Chx1c2VkX3VwbG9hZF9tZWRpYV9zaXplX2xpbWl0GAIgASgDUhh1c2VkVXBsb2FkTWVkaWFT'
'aXplTGltaXQSMwoTcGF5bWVudF9wZXJpb2RfZGF5cxgDIAEoA0gAUhFwYXltZW50UGVyaW9kRG'
'F5c4gBARJLCiBsYXN0X3BheW1lbnRfZG9uZV91bml4X3RpbWVzdGFtcBgEIAEoA0gBUhxsYXN0'
'UGF5bWVudERvbmVVbml4VGltZXN0YW1wiAEBEkoKDHRyYW5zYWN0aW9ucxgFIAMoCzImLnNlcn'
'Zlcl90b19jbGllbnQuUmVzcG9uc2UuVHJhbnNhY3Rpb25SDHRyYW5zYWN0aW9ucxJdChNhZGRp'
'dGlvbmFsX2FjY291bnRzGAYgAygLMiwuc2VydmVyX3RvX2NsaWVudC5SZXNwb25zZS5BZGRpdG'
'lvbmFsQWNjb3VudFISYWRkaXRpb25hbEFjY291bnRzQhYKFF9wYXltZW50X3BlcmlvZF9kYXlz'
'QiMKIV9sYXN0X3BheW1lbnRfZG9uZV91bml4X3RpbWVzdGFtcBpOCghMb2NhdGlvbhIWCgZjb3'
'VudHkYASABKAlSBmNvdW50eRIWCgZyZWdpb24YAiABKAlSBnJlZ2lvbhISCgRjaXR5GAMgASgJ'
'UgRjaXR5GjAKBlByZUtleRIOCgJpZBgBIAEoA1ICaWQSFgoGcHJla2V5GAIgASgMUgZwcmVrZX'
'katAMKCFVzZXJEYXRhEhcKB3VzZXJfaWQYASABKANSBnVzZXJJZBI7CgdwcmVrZXlzGAIgAygL'
'MiEuc2VydmVyX3RvX2NsaWVudC5SZXNwb25zZS5QcmVLZXlSB3ByZWtleXMSHwoIdXNlcm5hbW'
'UYByABKAxIAFIIdXNlcm5hbWWIAQESMwoTcHVibGljX2lkZW50aXR5X2tleRgDIAEoDEgBUhFw'
'dWJsaWNJZGVudGl0eUtleYgBARIoCg1zaWduZWRfcHJla2V5GAQgASgMSAJSDHNpZ25lZFByZW'
'tleYgBARI7ChdzaWduZWRfcHJla2V5X3NpZ25hdHVyZRgFIAEoDEgDUhVzaWduZWRQcmVrZXlT'
'aWduYXR1cmWIAQESLQoQc2lnbmVkX3ByZWtleV9pZBgGIAEoA0gEUg5zaWduZWRQcmVrZXlJZI'
'gBAUILCglfdXNlcm5hbWVCFgoUX3B1YmxpY19pZGVudGl0eV9rZXlCEAoOX3NpZ25lZF9wcmVr'
'ZXlCGgoYX3NpZ25lZF9wcmVrZXlfc2lnbmF0dXJlQhMKEV9zaWduZWRfcHJla2V5X2lkGlkKC1'
'VwbG9hZFRva2VuEiEKDHVwbG9hZF90b2tlbhgBIAEoDFILdXBsb2FkVG9rZW4SJwoPZG93bmxv'
'YWRfdG9rZW5zGAIgAygMUg5kb3dubG9hZFRva2VucxrTBQoCT2sSFAoETm9uZRgBIAEoCEgAUg'
'ROb25lEhgKBnVzZXJpZBgCIAEoA0gAUgZ1c2VyaWQSJgoNYXV0aGNoYWxsZW5nZRgDIAEoDEgA'
'Ug1hdXRoY2hhbGxlbmdlEkoKC3VwbG9hZHRva2VuGAQgASgLMiYuc2VydmVyX3RvX2NsaWVudC'
'5SZXNwb25zZS5VcGxvYWRUb2tlbkgAUgt1cGxvYWR0b2tlbhJBCgh1c2VyZGF0YRgFIAEoCzIj'
'LnNlcnZlcl90b19jbGllbnQuUmVzcG9uc2UuVXNlckRhdGFIAFIIdXNlcmRhdGESHgoJYXV0aH'
'Rva2VuGAYgASgMSABSCWF1dGh0b2tlbhJBCghsb2NhdGlvbhgHIAEoCzIjLnNlcnZlcl90b19j'
'bGllbnQuUmVzcG9uc2UuTG9jYXRpb25IAFIIbG9jYXRpb24SUAoNYXV0aGVudGljYXRlZBgIIA'
'EoCzIoLnNlcnZlcl90b19jbGllbnQuUmVzcG9uc2UuQXV0aGVudGljYXRlZEgAUg1hdXRoZW50'
'aWNhdGVkEjgKBXBsYW5zGAkgASgLMiAuc2VydmVyX3RvX2NsaWVudC5SZXNwb25zZS5QbGFuc0'
'gAUgVwbGFucxJNCgxwbGFuYmFsbGFuY2UYCiABKAsyJy5zZXJ2ZXJfdG9fY2xpZW50LlJlc3Bv'
'bnNlLlBsYW5CYWxsYW5jZUgAUgxwbGFuYmFsbGFuY2USQQoIdm91Y2hlcnMYCyABKAsyIy5zZX'
'J2ZXJfdG9fY2xpZW50LlJlc3BvbnNlLlZvdWNoZXJzSABSCHZvdWNoZXJzEl8KEmFkZGFjY291'
'bnRzaW52aXRlcxgMIAEoCzItLnNlcnZlcl90b19jbGllbnQuUmVzcG9uc2UuQWRkQWNjb3VudH'
'NJbnZpdGVzSABSEmFkZGFjY291bnRzaW52aXRlc0IECgJPa0IKCghSZXNwb25zZQ==');
'cG9uc2UuQWRkQWNjb3VudHNJbnZpdGVSB2ludml0ZXMaxQEKC1RyYW5zYWN0aW9uEiMKDWRlcG'
'9zaXRfY2VudHMYASABKANSDGRlcG9zaXRDZW50cxJWChB0cmFuc2FjdGlvbl90eXBlGAIgASgO'
'Misuc2VydmVyX3RvX2NsaWVudC5SZXNwb25zZS5UcmFuc2FjdGlvblR5cGVzUg90cmFuc2FjdG'
'lvblR5cGUSOQoZY3JlYXRlZF9hdF91bml4X3RpbWVzdGFtcBgDIAEoA1IWY3JlYXRlZEF0VW5p'
'eFRpbWVzdGFtcBpFChFBZGRpdGlvbmFsQWNjb3VudBIXCgd1c2VyX2lkGAEgASgDUgZ1c2VySW'
'QSFwoHcGxhbl9pZBgDIAEoCVIGcGxhbklkGr4BCgdWb3VjaGVyEh0KCnZvdWNoZXJfaWQYASAB'
'KAlSCXZvdWNoZXJJZBIfCgt2YWx1ZV9jZW50cxgCIAEoA1IKdmFsdWVDZW50cxIaCghyZWRlZW'
'1lZBgDIAEoCFIIcmVkZWVtZWQSHAoJcmVxdWVzdGVkGAQgASgIUglyZXF1ZXN0ZWQSOQoZY3Jl'
'YXRlZF9hdF91bml4X3RpbWVzdGFtcBgFIAEoA1IWY3JlYXRlZEF0VW5peFRpbWVzdGFtcBpKCg'
'hWb3VjaGVycxI+Cgh2b3VjaGVycxgBIAMoCzIiLnNlcnZlcl90b19jbGllbnQuUmVzcG9uc2Uu'
'Vm91Y2hlclIIdm91Y2hlcnMa+gMKDFBsYW5CYWxsYW5jZRJACh11c2VkX2RhaWx5X21lZGlhX3'
'VwbG9hZF9saW1pdBgBIAEoA1IZdXNlZERhaWx5TWVkaWFVcGxvYWRMaW1pdBI+Chx1c2VkX3Vw'
'bG9hZF9tZWRpYV9zaXplX2xpbWl0GAIgASgDUhh1c2VkVXBsb2FkTWVkaWFTaXplTGltaXQSMw'
'oTcGF5bWVudF9wZXJpb2RfZGF5cxgDIAEoA0gAUhFwYXltZW50UGVyaW9kRGF5c4gBARJLCiBs'
'YXN0X3BheW1lbnRfZG9uZV91bml4X3RpbWVzdGFtcBgEIAEoA0gBUhxsYXN0UGF5bWVudERvbm'
'VVbml4VGltZXN0YW1wiAEBEkoKDHRyYW5zYWN0aW9ucxgFIAMoCzImLnNlcnZlcl90b19jbGll'
'bnQuUmVzcG9uc2UuVHJhbnNhY3Rpb25SDHRyYW5zYWN0aW9ucxJdChNhZGRpdGlvbmFsX2FjY2'
'91bnRzGAYgAygLMiwuc2VydmVyX3RvX2NsaWVudC5SZXNwb25zZS5BZGRpdGlvbmFsQWNjb3Vu'
'dFISYWRkaXRpb25hbEFjY291bnRzQhYKFF9wYXltZW50X3BlcmlvZF9kYXlzQiMKIV9sYXN0X3'
'BheW1lbnRfZG9uZV91bml4X3RpbWVzdGFtcBpOCghMb2NhdGlvbhIWCgZjb3VudHkYASABKAlS'
'BmNvdW50eRIWCgZyZWdpb24YAiABKAlSBnJlZ2lvbhISCgRjaXR5GAMgASgJUgRjaXR5GjAKBl'
'ByZUtleRIOCgJpZBgBIAEoA1ICaWQSFgoGcHJla2V5GAIgASgMUgZwcmVrZXkatAMKCFVzZXJE'
'YXRhEhcKB3VzZXJfaWQYASABKANSBnVzZXJJZBI7CgdwcmVrZXlzGAIgAygLMiEuc2VydmVyX3'
'RvX2NsaWVudC5SZXNwb25zZS5QcmVLZXlSB3ByZWtleXMSHwoIdXNlcm5hbWUYByABKAxIAFII'
'dXNlcm5hbWWIAQESMwoTcHVibGljX2lkZW50aXR5X2tleRgDIAEoDEgBUhFwdWJsaWNJZGVudG'
'l0eUtleYgBARIoCg1zaWduZWRfcHJla2V5GAQgASgMSAJSDHNpZ25lZFByZWtleYgBARI7Chdz'
'aWduZWRfcHJla2V5X3NpZ25hdHVyZRgFIAEoDEgDUhVzaWduZWRQcmVrZXlTaWduYXR1cmWIAQ'
'ESLQoQc2lnbmVkX3ByZWtleV9pZBgGIAEoA0gEUg5zaWduZWRQcmVrZXlJZIgBAUILCglfdXNl'
'cm5hbWVCFgoUX3B1YmxpY19pZGVudGl0eV9rZXlCEAoOX3NpZ25lZF9wcmVrZXlCGgoYX3NpZ2'
'5lZF9wcmVrZXlfc2lnbmF0dXJlQhMKEV9zaWduZWRfcHJla2V5X2lkGlkKC1VwbG9hZFRva2Vu'
'EiEKDHVwbG9hZF90b2tlbhgBIAEoDFILdXBsb2FkVG9rZW4SJwoPZG93bmxvYWRfdG9rZW5zGA'
'IgAygMUg5kb3dubG9hZFRva2VucxrTBQoCT2sSFAoETm9uZRgBIAEoCEgAUgROb25lEhgKBnVz'
'ZXJpZBgCIAEoA0gAUgZ1c2VyaWQSJgoNYXV0aGNoYWxsZW5nZRgDIAEoDEgAUg1hdXRoY2hhbG'
'xlbmdlEkoKC3VwbG9hZHRva2VuGAQgASgLMiYuc2VydmVyX3RvX2NsaWVudC5SZXNwb25zZS5V'
'cGxvYWRUb2tlbkgAUgt1cGxvYWR0b2tlbhJBCgh1c2VyZGF0YRgFIAEoCzIjLnNlcnZlcl90b1'
'9jbGllbnQuUmVzcG9uc2UuVXNlckRhdGFIAFIIdXNlcmRhdGESHgoJYXV0aHRva2VuGAYgASgM'
'SABSCWF1dGh0b2tlbhJBCghsb2NhdGlvbhgHIAEoCzIjLnNlcnZlcl90b19jbGllbnQuUmVzcG'
'9uc2UuTG9jYXRpb25IAFIIbG9jYXRpb24SUAoNYXV0aGVudGljYXRlZBgIIAEoCzIoLnNlcnZl'
'cl90b19jbGllbnQuUmVzcG9uc2UuQXV0aGVudGljYXRlZEgAUg1hdXRoZW50aWNhdGVkEjgKBX'
'BsYW5zGAkgASgLMiAuc2VydmVyX3RvX2NsaWVudC5SZXNwb25zZS5QbGFuc0gAUgVwbGFucxJN'
'CgxwbGFuYmFsbGFuY2UYCiABKAsyJy5zZXJ2ZXJfdG9fY2xpZW50LlJlc3BvbnNlLlBsYW5CYW'
'xsYW5jZUgAUgxwbGFuYmFsbGFuY2USQQoIdm91Y2hlcnMYCyABKAsyIy5zZXJ2ZXJfdG9fY2xp'
'ZW50LlJlc3BvbnNlLlZvdWNoZXJzSABSCHZvdWNoZXJzEl8KEmFkZGFjY291bnRzaW52aXRlcx'
'gMIAEoCzItLnNlcnZlcl90b19jbGllbnQuUmVzcG9uc2UuQWRkQWNjb3VudHNJbnZpdGVzSABS'
'EmFkZGFjY291bnRzaW52aXRlc0IECgJPayKFAQoQVHJhbnNhY3Rpb25UeXBlcxIKCgZSZWZ1bm'
'QQABITCg9Wb3VjaGVyUmVkZWVtZWQQARISCg5Wb3VjaGVyQ3JlYXRlZBACEggKBENhc2gQAxIP'
'CgtQbGFuVXBncmFkZRAEEgsKB1Vua25vd24QBRIUChBUaGFua3NGb3JUZXN0aW5nEAZCCgoIUm'
'VzcG9uc2U=');

View file

@ -135,6 +135,7 @@ Future startDownloadMedia(Message message, bool force) async {
await apiProvider.triggerDownload(content.downloadToken!, offset);
if (res.isError) {
if (res.error == ErrorCode.InvalidDownloadToken) {
// TODO: notfy the sender about this issue
await twonlyDatabase.messagesDao.updateMessageByMessageId(
media.messageId,
MessagesCompanion(

View file

@ -2,11 +2,13 @@ import 'package:collection/collection.dart';
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:intl/intl.dart';
import 'package:logging/logging.dart';
import 'package:provider/provider.dart';
import 'package:twonly/globals.dart';
import 'package:twonly/src/model/protobuf/api/server_to_client.pb.dart';
import 'package:twonly/src/providers/connection_provider.dart';
import 'package:twonly/src/utils/misc.dart';
import 'package:twonly/src/utils/storage.dart';
import 'package:twonly/src/views/components/better_list_title.dart';
import 'package:twonly/src/views/settings/subscription/transaction_view.dart';
import 'package:twonly/src/views/settings/subscription/voucher_view.dart';
@ -20,8 +22,6 @@ class SubscriptionView extends StatefulWidget {
class _SubscriptionViewState extends State<SubscriptionView> {
bool loaded = false;
int ballanceInCents = 0;
DateTime? nextPayment;
Response_PlanBallance? ballance;
@override
@ -31,29 +31,43 @@ class _SubscriptionViewState extends State<SubscriptionView> {
}
Future initAsync() async {
final user = await getUser();
if (user == null) return;
ballance = await apiProvider.getPlanBallance();
if (ballance != null) {
setState(() {
DateTime lastPaymentDateTime = DateTime.fromMillisecondsSinceEpoch(
ballance!.lastPaymentDoneUnixTimestamp.toInt() * 1000);
nextPayment = lastPaymentDateTime
.add(Duration(days: ballance!.paymentPeriodDays.toInt()));
ballanceInCents =
ballance!.transactions.map((a) => a.depositCents.toInt()).sum;
loaded = true;
});
return;
user.lastPlanBallance = ballance!.writeToJson();
await updateUser(user);
} else if (user.lastPlanBallance != null) {
try {
ballance = Response_PlanBallance.fromJson(
user.lastPlanBallance!,
);
} catch (e) {
Logger("subscription_view.dart").shout("from json: $e");
}
}
setState(() {});
}
@override
Widget build(BuildContext context) {
Locale myLocale = Localizations.localeOf(context);
String formattedBalance = NumberFormat.currency(
String? formattedBalance;
DateTime? nextPayment;
if (ballance != null) {
DateTime lastPaymentDateTime = DateTime.fromMillisecondsSinceEpoch(
ballance!.lastPaymentDoneUnixTimestamp.toInt() * 1000);
nextPayment = lastPaymentDateTime
.add(Duration(days: ballance!.paymentPeriodDays.toInt()));
int ballanceInCents =
ballance!.transactions.map((a) => a.depositCents.toInt()).sum;
formattedBalance = NumberFormat.currency(
locale: myLocale.toString(),
symbol: '',
decimalDigits: 2,
).format(ballanceInCents / 100);
}
String currentPlan = context.read<CustomChangeProvider>().plan;
@ -155,21 +169,22 @@ class _SubscriptionViewState extends State<SubscriptionView> {
text: "Manage your subscription",
subtitle: (nextPayment != null)
? Text(
"Next payment: ${DateFormat.yMMMMd(myLocale.toString()).format(nextPayment!)}")
"Next payment: ${DateFormat.yMMMMd(myLocale.toString()).format(nextPayment)}")
: null,
onTap: () {},
),
BetterListTile(
icon: FontAwesomeIcons.moneyBillTransfer,
text: context.lang.transactionHistory,
subtitle: (loaded)
subtitle: (formattedBalance != null)
? Text("${context.lang.currentBalance}: $formattedBalance")
: null,
onTap: () {
if (formattedBalance == null) return;
Navigator.push(context, MaterialPageRoute(builder: (context) {
return TransactionView(
transactions: ballance!.transactions,
formattedBalance: formattedBalance,
transactions: ballance?.transactions,
formattedBalance: formattedBalance!,
);
}));
},

View file

@ -6,7 +6,7 @@ import 'package:twonly/src/utils/misc.dart';
class TransactionView extends StatefulWidget {
const TransactionView(
{super.key, required this.transactions, required this.formattedBalance});
final List<Response_Transaction> transactions;
final List<Response_Transaction>? transactions;
final String formattedBalance;
@override
@ -53,7 +53,8 @@ class _TransactionViewState extends State<TransactionView> {
),
),
),
...widget.transactions.map((x) => TransactionCard(transaction: x))
if (widget.transactions != null)
...widget.transactions!.map((x) => TransactionCard(transaction: x))
],
),
);
@ -70,6 +71,26 @@ class TransactionCard extends StatefulWidget {
}
class _TransactionCardState extends State<TransactionCard> {
String typeToText(Response_TransactionTypes type) {
switch (type) {
case Response_TransactionTypes.Cash:
return context.lang.transactionCash;
case Response_TransactionTypes.PlanUpgrade:
return context.lang.transactionPlanUpgrade;
case Response_TransactionTypes.Refund:
return context.lang.transactionRefund;
case Response_TransactionTypes.ThanksForTesting:
return context.lang.transactionThanksForTesting;
case Response_TransactionTypes.Unknown:
return context.lang.transactionUnknown;
case Response_TransactionTypes.VoucherCreated:
return context.lang.transactionVoucherCreated;
case Response_TransactionTypes.VoucherRedeemed:
return context.lang.transactionVoucherRedeemed;
}
return type.toString();
}
@override
Widget build(BuildContext context) {
final myLocale = Localizations.localeOf(context);
@ -98,7 +119,7 @@ class _TransactionCardState extends State<TransactionCard> {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
widget.transaction.transactionType,
typeToText(widget.transaction.transactionType),
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,