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", "enterVoucherCode": "Gutschein Code eingeben",
"voucherRedeemed": "Gutschein eingelöst", "voucherRedeemed": "Gutschein eingelöst",
"requestedVouchers": "Beantragte Gutscheine", "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", "enterVoucherCode": "Enter Voucher Code",
"requestedVouchers": "Requested vouchers", "requestedVouchers": "Requested vouchers",
"redeemedVouchers": "Redeemed 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: /// In en, this message translates to:
/// **'Buy'** /// **'Buy'**
String get 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> { class _AppLocalizationsDelegate extends LocalizationsDelegate<AppLocalizations> {

View file

@ -568,4 +568,25 @@ class AppLocalizationsDe extends AppLocalizations {
@override @override
String get buy => 'Kaufen'; 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 @override
String get buy => 'Buy'; 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; bool? storeMediaFilesInGallery;
List<String>? lastUsedEditorEmojis; List<String>? lastUsedEditorEmojis;
String? lastPlanBallance;
final int userId; final int userId;
factory UserData.fromJson(Map<String, dynamic> json) => 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? ..storeMediaFilesInGallery = json['storeMediaFilesInGallery'] as bool?
..lastUsedEditorEmojis = (json['lastUsedEditorEmojis'] as List<dynamic>?) ..lastUsedEditorEmojis = (json['lastUsedEditorEmojis'] as List<dynamic>?)
?.map((e) => e as String) ?.map((e) => e as String)
.toList(); .toList()
..lastPlanBallance = json['lastPlanBallance'] as String?;
Map<String, dynamic> _$UserDataToJson(UserData instance) => <String, dynamic>{ Map<String, dynamic> _$UserDataToJson(UserData instance) => <String, dynamic>{
'username': instance.username, 'username': instance.username,
@ -45,6 +46,7 @@ Map<String, dynamic> _$UserDataToJson(UserData instance) => <String, dynamic>{
'autoDownloadOptions': instance.autoDownloadOptions, 'autoDownloadOptions': instance.autoDownloadOptions,
'storeMediaFilesInGallery': instance.storeMediaFilesInGallery, 'storeMediaFilesInGallery': instance.storeMediaFilesInGallery,
'lastUsedEditorEmojis': instance.lastUsedEditorEmojis, 'lastUsedEditorEmojis': instance.lastUsedEditorEmojis,
'lastPlanBallance': instance.lastPlanBallance,
'userId': instance.userId, 'userId': instance.userId,
}; };

View file

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

View file

@ -9,3 +9,34 @@
// ignore_for_file: non_constant_identifier_names, prefer_final_fields // ignore_for_file: non_constant_identifier_names, prefer_final_fields
// ignore_for_file: unnecessary_import, unnecessary_this, unused_import // 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'}, {'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], '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': [ '8': [
{'1': 'Response'}, {'1': 'Response'},
], ],
@ -153,7 +154,7 @@ const Response_Transaction$json = {
'1': 'Transaction', '1': 'Transaction',
'2': [ '2': [
{'1': 'deposit_cents', '3': 1, '4': 1, '5': 3, '10': 'depositCents'}, {'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'}, {'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`. /// Descriptor for `Response`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List responseDescriptor = $convert.base64Decode( final $typed_data.Uint8List responseDescriptor = $convert.base64Decode(
'CghSZXNwb25zZRIvCgJvaxgBIAEoCzIdLnNlcnZlcl90b19jbGllbnQuUmVzcG9uc2UuT2tIAF' 'CghSZXNwb25zZRIvCgJvaxgBIAEoCzIdLnNlcnZlcl90b19jbGllbnQuUmVzcG9uc2UuT2tIAF'
@ -293,48 +308,52 @@ final $typed_data.Uint8List responseDescriptor = $convert.base64Decode(
'xpZW50LlJlc3BvbnNlLlBsYW5SBXBsYW5zGk0KEUFkZEFjY291bnRzSW52aXRlEhcKB3BsYW5f' 'xpZW50LlJlc3BvbnNlLlBsYW5SBXBsYW5zGk0KEUFkZEFjY291bnRzSW52aXRlEhcKB3BsYW5f'
'aWQYASABKAlSBnBsYW5JZBIfCgtpbnZpdGVfY29kZRgCIAEoCVIKaW52aXRlQ29kZRpcChJBZG' 'aWQYASABKAlSBnBsYW5JZBIfCgtpbnZpdGVfY29kZRgCIAEoCVIKaW52aXRlQ29kZRpcChJBZG'
'RBY2NvdW50c0ludml0ZXMSRgoHaW52aXRlcxgBIAMoCzIsLnNlcnZlcl90b19jbGllbnQuUmVz' 'RBY2NvdW50c0ludml0ZXMSRgoHaW52aXRlcxgBIAMoCzIsLnNlcnZlcl90b19jbGllbnQuUmVz'
'cG9uc2UuQWRkQWNjb3VudHNJbnZpdGVSB2ludml0ZXMamAEKC1RyYW5zYWN0aW9uEiMKDWRlcG' 'cG9uc2UuQWRkQWNjb3VudHNJbnZpdGVSB2ludml0ZXMaxQEKC1RyYW5zYWN0aW9uEiMKDWRlcG'
'9zaXRfY2VudHMYASABKANSDGRlcG9zaXRDZW50cxIpChB0cmFuc2FjdGlvbl90eXBlGAIgASgJ' '9zaXRfY2VudHMYASABKANSDGRlcG9zaXRDZW50cxJWChB0cmFuc2FjdGlvbl90eXBlGAIgASgO'
'Ug90cmFuc2FjdGlvblR5cGUSOQoZY3JlYXRlZF9hdF91bml4X3RpbWVzdGFtcBgDIAEoA1IWY3' 'Misuc2VydmVyX3RvX2NsaWVudC5SZXNwb25zZS5UcmFuc2FjdGlvblR5cGVzUg90cmFuc2FjdG'
'JlYXRlZEF0VW5peFRpbWVzdGFtcBpFChFBZGRpdGlvbmFsQWNjb3VudBIXCgd1c2VyX2lkGAEg' 'lvblR5cGUSOQoZY3JlYXRlZF9hdF91bml4X3RpbWVzdGFtcBgDIAEoA1IWY3JlYXRlZEF0VW5p'
'ASgDUgZ1c2VySWQSFwoHcGxhbl9pZBgDIAEoCVIGcGxhbklkGr4BCgdWb3VjaGVyEh0KCnZvdW' 'eFRpbWVzdGFtcBpFChFBZGRpdGlvbmFsQWNjb3VudBIXCgd1c2VyX2lkGAEgASgDUgZ1c2VySW'
'NoZXJfaWQYASABKAlSCXZvdWNoZXJJZBIfCgt2YWx1ZV9jZW50cxgCIAEoA1IKdmFsdWVDZW50' 'QSFwoHcGxhbl9pZBgDIAEoCVIGcGxhbklkGr4BCgdWb3VjaGVyEh0KCnZvdWNoZXJfaWQYASAB'
'cxIaCghyZWRlZW1lZBgDIAEoCFIIcmVkZWVtZWQSHAoJcmVxdWVzdGVkGAQgASgIUglyZXF1ZX' 'KAlSCXZvdWNoZXJJZBIfCgt2YWx1ZV9jZW50cxgCIAEoA1IKdmFsdWVDZW50cxIaCghyZWRlZW'
'N0ZWQSOQoZY3JlYXRlZF9hdF91bml4X3RpbWVzdGFtcBgFIAEoA1IWY3JlYXRlZEF0VW5peFRp' '1lZBgDIAEoCFIIcmVkZWVtZWQSHAoJcmVxdWVzdGVkGAQgASgIUglyZXF1ZXN0ZWQSOQoZY3Jl'
'bWVzdGFtcBpKCghWb3VjaGVycxI+Cgh2b3VjaGVycxgBIAMoCzIiLnNlcnZlcl90b19jbGllbn' 'YXRlZF9hdF91bml4X3RpbWVzdGFtcBgFIAEoA1IWY3JlYXRlZEF0VW5peFRpbWVzdGFtcBpKCg'
'QuUmVzcG9uc2UuVm91Y2hlclIIdm91Y2hlcnMa+gMKDFBsYW5CYWxsYW5jZRJACh11c2VkX2Rh' 'hWb3VjaGVycxI+Cgh2b3VjaGVycxgBIAMoCzIiLnNlcnZlcl90b19jbGllbnQuUmVzcG9uc2Uu'
'aWx5X21lZGlhX3VwbG9hZF9saW1pdBgBIAEoA1IZdXNlZERhaWx5TWVkaWFVcGxvYWRMaW1pdB' 'Vm91Y2hlclIIdm91Y2hlcnMa+gMKDFBsYW5CYWxsYW5jZRJACh11c2VkX2RhaWx5X21lZGlhX3'
'I+Chx1c2VkX3VwbG9hZF9tZWRpYV9zaXplX2xpbWl0GAIgASgDUhh1c2VkVXBsb2FkTWVkaWFT' 'VwbG9hZF9saW1pdBgBIAEoA1IZdXNlZERhaWx5TWVkaWFVcGxvYWRMaW1pdBI+Chx1c2VkX3Vw'
'aXplTGltaXQSMwoTcGF5bWVudF9wZXJpb2RfZGF5cxgDIAEoA0gAUhFwYXltZW50UGVyaW9kRG' 'bG9hZF9tZWRpYV9zaXplX2xpbWl0GAIgASgDUhh1c2VkVXBsb2FkTWVkaWFTaXplTGltaXQSMw'
'F5c4gBARJLCiBsYXN0X3BheW1lbnRfZG9uZV91bml4X3RpbWVzdGFtcBgEIAEoA0gBUhxsYXN0' 'oTcGF5bWVudF9wZXJpb2RfZGF5cxgDIAEoA0gAUhFwYXltZW50UGVyaW9kRGF5c4gBARJLCiBs'
'UGF5bWVudERvbmVVbml4VGltZXN0YW1wiAEBEkoKDHRyYW5zYWN0aW9ucxgFIAMoCzImLnNlcn' 'YXN0X3BheW1lbnRfZG9uZV91bml4X3RpbWVzdGFtcBgEIAEoA0gBUhxsYXN0UGF5bWVudERvbm'
'Zlcl90b19jbGllbnQuUmVzcG9uc2UuVHJhbnNhY3Rpb25SDHRyYW5zYWN0aW9ucxJdChNhZGRp' 'VVbml4VGltZXN0YW1wiAEBEkoKDHRyYW5zYWN0aW9ucxgFIAMoCzImLnNlcnZlcl90b19jbGll'
'dGlvbmFsX2FjY291bnRzGAYgAygLMiwuc2VydmVyX3RvX2NsaWVudC5SZXNwb25zZS5BZGRpdG' 'bnQuUmVzcG9uc2UuVHJhbnNhY3Rpb25SDHRyYW5zYWN0aW9ucxJdChNhZGRpdGlvbmFsX2FjY2'
'lvbmFsQWNjb3VudFISYWRkaXRpb25hbEFjY291bnRzQhYKFF9wYXltZW50X3BlcmlvZF9kYXlz' '91bnRzGAYgAygLMiwuc2VydmVyX3RvX2NsaWVudC5SZXNwb25zZS5BZGRpdGlvbmFsQWNjb3Vu'
'QiMKIV9sYXN0X3BheW1lbnRfZG9uZV91bml4X3RpbWVzdGFtcBpOCghMb2NhdGlvbhIWCgZjb3' 'dFISYWRkaXRpb25hbEFjY291bnRzQhYKFF9wYXltZW50X3BlcmlvZF9kYXlzQiMKIV9sYXN0X3'
'VudHkYASABKAlSBmNvdW50eRIWCgZyZWdpb24YAiABKAlSBnJlZ2lvbhISCgRjaXR5GAMgASgJ' 'BheW1lbnRfZG9uZV91bml4X3RpbWVzdGFtcBpOCghMb2NhdGlvbhIWCgZjb3VudHkYASABKAlS'
'UgRjaXR5GjAKBlByZUtleRIOCgJpZBgBIAEoA1ICaWQSFgoGcHJla2V5GAIgASgMUgZwcmVrZX' 'BmNvdW50eRIWCgZyZWdpb24YAiABKAlSBnJlZ2lvbhISCgRjaXR5GAMgASgJUgRjaXR5GjAKBl'
'katAMKCFVzZXJEYXRhEhcKB3VzZXJfaWQYASABKANSBnVzZXJJZBI7CgdwcmVrZXlzGAIgAygL' 'ByZUtleRIOCgJpZBgBIAEoA1ICaWQSFgoGcHJla2V5GAIgASgMUgZwcmVrZXkatAMKCFVzZXJE'
'MiEuc2VydmVyX3RvX2NsaWVudC5SZXNwb25zZS5QcmVLZXlSB3ByZWtleXMSHwoIdXNlcm5hbW' 'YXRhEhcKB3VzZXJfaWQYASABKANSBnVzZXJJZBI7CgdwcmVrZXlzGAIgAygLMiEuc2VydmVyX3'
'UYByABKAxIAFIIdXNlcm5hbWWIAQESMwoTcHVibGljX2lkZW50aXR5X2tleRgDIAEoDEgBUhFw' 'RvX2NsaWVudC5SZXNwb25zZS5QcmVLZXlSB3ByZWtleXMSHwoIdXNlcm5hbWUYByABKAxIAFII'
'dWJsaWNJZGVudGl0eUtleYgBARIoCg1zaWduZWRfcHJla2V5GAQgASgMSAJSDHNpZ25lZFByZW' 'dXNlcm5hbWWIAQESMwoTcHVibGljX2lkZW50aXR5X2tleRgDIAEoDEgBUhFwdWJsaWNJZGVudG'
'tleYgBARI7ChdzaWduZWRfcHJla2V5X3NpZ25hdHVyZRgFIAEoDEgDUhVzaWduZWRQcmVrZXlT' 'l0eUtleYgBARIoCg1zaWduZWRfcHJla2V5GAQgASgMSAJSDHNpZ25lZFByZWtleYgBARI7Chdz'
'aWduYXR1cmWIAQESLQoQc2lnbmVkX3ByZWtleV9pZBgGIAEoA0gEUg5zaWduZWRQcmVrZXlJZI' 'aWduZWRfcHJla2V5X3NpZ25hdHVyZRgFIAEoDEgDUhVzaWduZWRQcmVrZXlTaWduYXR1cmWIAQ'
'gBAUILCglfdXNlcm5hbWVCFgoUX3B1YmxpY19pZGVudGl0eV9rZXlCEAoOX3NpZ25lZF9wcmVr' 'ESLQoQc2lnbmVkX3ByZWtleV9pZBgGIAEoA0gEUg5zaWduZWRQcmVrZXlJZIgBAUILCglfdXNl'
'ZXlCGgoYX3NpZ25lZF9wcmVrZXlfc2lnbmF0dXJlQhMKEV9zaWduZWRfcHJla2V5X2lkGlkKC1' 'cm5hbWVCFgoUX3B1YmxpY19pZGVudGl0eV9rZXlCEAoOX3NpZ25lZF9wcmVrZXlCGgoYX3NpZ2'
'VwbG9hZFRva2VuEiEKDHVwbG9hZF90b2tlbhgBIAEoDFILdXBsb2FkVG9rZW4SJwoPZG93bmxv' '5lZF9wcmVrZXlfc2lnbmF0dXJlQhMKEV9zaWduZWRfcHJla2V5X2lkGlkKC1VwbG9hZFRva2Vu'
'YWRfdG9rZW5zGAIgAygMUg5kb3dubG9hZFRva2VucxrTBQoCT2sSFAoETm9uZRgBIAEoCEgAUg' 'EiEKDHVwbG9hZF90b2tlbhgBIAEoDFILdXBsb2FkVG9rZW4SJwoPZG93bmxvYWRfdG9rZW5zGA'
'ROb25lEhgKBnVzZXJpZBgCIAEoA0gAUgZ1c2VyaWQSJgoNYXV0aGNoYWxsZW5nZRgDIAEoDEgA' 'IgAygMUg5kb3dubG9hZFRva2VucxrTBQoCT2sSFAoETm9uZRgBIAEoCEgAUgROb25lEhgKBnVz'
'Ug1hdXRoY2hhbGxlbmdlEkoKC3VwbG9hZHRva2VuGAQgASgLMiYuc2VydmVyX3RvX2NsaWVudC' 'ZXJpZBgCIAEoA0gAUgZ1c2VyaWQSJgoNYXV0aGNoYWxsZW5nZRgDIAEoDEgAUg1hdXRoY2hhbG'
'5SZXNwb25zZS5VcGxvYWRUb2tlbkgAUgt1cGxvYWR0b2tlbhJBCgh1c2VyZGF0YRgFIAEoCzIj' 'xlbmdlEkoKC3VwbG9hZHRva2VuGAQgASgLMiYuc2VydmVyX3RvX2NsaWVudC5SZXNwb25zZS5V'
'LnNlcnZlcl90b19jbGllbnQuUmVzcG9uc2UuVXNlckRhdGFIAFIIdXNlcmRhdGESHgoJYXV0aH' 'cGxvYWRUb2tlbkgAUgt1cGxvYWR0b2tlbhJBCgh1c2VyZGF0YRgFIAEoCzIjLnNlcnZlcl90b1'
'Rva2VuGAYgASgMSABSCWF1dGh0b2tlbhJBCghsb2NhdGlvbhgHIAEoCzIjLnNlcnZlcl90b19j' '9jbGllbnQuUmVzcG9uc2UuVXNlckRhdGFIAFIIdXNlcmRhdGESHgoJYXV0aHRva2VuGAYgASgM'
'bGllbnQuUmVzcG9uc2UuTG9jYXRpb25IAFIIbG9jYXRpb24SUAoNYXV0aGVudGljYXRlZBgIIA' 'SABSCWF1dGh0b2tlbhJBCghsb2NhdGlvbhgHIAEoCzIjLnNlcnZlcl90b19jbGllbnQuUmVzcG'
'EoCzIoLnNlcnZlcl90b19jbGllbnQuUmVzcG9uc2UuQXV0aGVudGljYXRlZEgAUg1hdXRoZW50' '9uc2UuTG9jYXRpb25IAFIIbG9jYXRpb24SUAoNYXV0aGVudGljYXRlZBgIIAEoCzIoLnNlcnZl'
'aWNhdGVkEjgKBXBsYW5zGAkgASgLMiAuc2VydmVyX3RvX2NsaWVudC5SZXNwb25zZS5QbGFuc0' 'cl90b19jbGllbnQuUmVzcG9uc2UuQXV0aGVudGljYXRlZEgAUg1hdXRoZW50aWNhdGVkEjgKBX'
'gAUgVwbGFucxJNCgxwbGFuYmFsbGFuY2UYCiABKAsyJy5zZXJ2ZXJfdG9fY2xpZW50LlJlc3Bv' 'BsYW5zGAkgASgLMiAuc2VydmVyX3RvX2NsaWVudC5SZXNwb25zZS5QbGFuc0gAUgVwbGFucxJN'
'bnNlLlBsYW5CYWxsYW5jZUgAUgxwbGFuYmFsbGFuY2USQQoIdm91Y2hlcnMYCyABKAsyIy5zZX' 'CgxwbGFuYmFsbGFuY2UYCiABKAsyJy5zZXJ2ZXJfdG9fY2xpZW50LlJlc3BvbnNlLlBsYW5CYW'
'J2ZXJfdG9fY2xpZW50LlJlc3BvbnNlLlZvdWNoZXJzSABSCHZvdWNoZXJzEl8KEmFkZGFjY291' 'xsYW5jZUgAUgxwbGFuYmFsbGFuY2USQQoIdm91Y2hlcnMYCyABKAsyIy5zZXJ2ZXJfdG9fY2xp'
'bnRzaW52aXRlcxgMIAEoCzItLnNlcnZlcl90b19jbGllbnQuUmVzcG9uc2UuQWRkQWNjb3VudH' 'ZW50LlJlc3BvbnNlLlZvdWNoZXJzSABSCHZvdWNoZXJzEl8KEmFkZGFjY291bnRzaW52aXRlcx'
'NJbnZpdGVzSABSEmFkZGFjY291bnRzaW52aXRlc0IECgJPa0IKCghSZXNwb25zZQ=='); 'gMIAEoCzItLnNlcnZlcl90b19jbGllbnQuUmVzcG9uc2UuQWRkQWNjb3VudHNJbnZpdGVzSABS'
'EmFkZGFjY291bnRzaW52aXRlc0IECgJPayKFAQoQVHJhbnNhY3Rpb25UeXBlcxIKCgZSZWZ1bm'
'QQABITCg9Wb3VjaGVyUmVkZWVtZWQQARISCg5Wb3VjaGVyQ3JlYXRlZBACEggKBENhc2gQAxIP'
'CgtQbGFuVXBncmFkZRAEEgsKB1Vua25vd24QBRIUChBUaGFua3NGb3JUZXN0aW5nEAZCCgoIUm'
'VzcG9uc2U=');

View file

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

View file

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

View file

@ -6,7 +6,7 @@ import 'package:twonly/src/utils/misc.dart';
class TransactionView extends StatefulWidget { class TransactionView extends StatefulWidget {
const TransactionView( const TransactionView(
{super.key, required this.transactions, required this.formattedBalance}); {super.key, required this.transactions, required this.formattedBalance});
final List<Response_Transaction> transactions; final List<Response_Transaction>? transactions;
final String formattedBalance; final String formattedBalance;
@override @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> { 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 @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final myLocale = Localizations.localeOf(context); final myLocale = Localizations.localeOf(context);
@ -98,7 +119,7 @@ class _TransactionCardState extends State<TransactionCard> {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text( Text(
widget.transaction.transactionType, typeToText(widget.transaction.transactionType),
style: TextStyle( style: TextStyle(
fontSize: 18, fontSize: 18,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,