tx history improved layout

This commit is contained in:
Robert Malikowski
2026-06-26 01:40:34 +02:00
parent 7c7ddf8205
commit ac60a6ecce
21 changed files with 916 additions and 345 deletions
+115 -106
View File
@@ -96,111 +96,104 @@ abstract class DashboardViewModelBase with Store {
isShowFirstYatIntroduction = false,
isShowSecondYatIntroduction = false,
isShowThirdYatIntroduction = false,
filterItems = {
S.current.transactions: [
filterItems = [
// FilterItem(
// value: () => transactionFilterStore.displayAll,
// caption: S.current.all_transactions,
// onChanged: transactionFilterStore.toggleAll),
FilterItem(
value: () => transactionFilterStore.displayIncoming,
caption: S.current.send,
onChanged: transactionFilterStore.toggleIncoming),
FilterItem(
value: () => transactionFilterStore.displayOutgoing,
caption: S.current.receive,
onChanged: transactionFilterStore.toggleOutgoing),
if (appStore.wallet!.type == WalletType.bitcoin)
FilterItem(
value: () => transactionFilterStore.displayAll,
caption: S.current.all_transactions,
onChanged: transactionFilterStore.toggleAll),
FilterItem(
value: () => transactionFilterStore.displayIncoming,
caption: S.current.incoming,
onChanged: transactionFilterStore.toggleIncoming),
FilterItem(
value: () => transactionFilterStore.displayOutgoing,
caption: S.current.outgoing,
onChanged: transactionFilterStore.toggleOutgoing),
if (appStore.wallet!.type == WalletType.bitcoin)
FilterItem(
value: () => transactionFilterStore.displaySilentPayments,
caption: S.current.silent_payments,
onChanged: transactionFilterStore.toggleSilentPayments,
),
// FilterItem(
// value: () => false,
// caption: S.current.transactions_by_date,
// onChanged: null),
],
'Orders': [
FilterItem(
value: () => orderFilterStore.displayCakePay,
caption: 'Cake Pay',
onChanged: () =>
orderFilterStore.toggleDisplayOrder(OrderProviderDescription.cakePay)),
],
S.current.trades: [
FilterItem(
value: () => tradeFilterStore.displayAllTrades,
caption: S.current.all_trades,
onChanged: () =>
tradeFilterStore.toggleDisplayExchange(ExchangeProviderDescription.all)),
FilterItem(
value: () => tradeFilterStore.displayChangeNow,
caption: ExchangeProviderDescription.changeNow.title,
onChanged: () =>
tradeFilterStore.toggleDisplayExchange(ExchangeProviderDescription.changeNow)),
FilterItem(
value: () => tradeFilterStore.displaySideShift,
caption: ExchangeProviderDescription.sideShift.title,
onChanged: () =>
tradeFilterStore.toggleDisplayExchange(ExchangeProviderDescription.sideShift)),
FilterItem(
value: () => tradeFilterStore.displaySimpleSwap,
caption: ExchangeProviderDescription.simpleSwap.title,
onChanged: () =>
tradeFilterStore.toggleDisplayExchange(ExchangeProviderDescription.simpleSwap)),
FilterItem(
value: () => tradeFilterStore.displayTrocador,
caption: ExchangeProviderDescription.trocador.title,
onChanged: () =>
tradeFilterStore.toggleDisplayExchange(ExchangeProviderDescription.trocador)),
FilterItem(
value: () => tradeFilterStore.displayExolix,
caption: ExchangeProviderDescription.exolix.title,
onChanged: () =>
tradeFilterStore.toggleDisplayExchange(ExchangeProviderDescription.exolix)),
FilterItem(
value: () => tradeFilterStore.displayChainflip,
caption: ExchangeProviderDescription.chainflip.title,
onChanged: () =>
tradeFilterStore.toggleDisplayExchange(ExchangeProviderDescription.chainflip)),
FilterItem(
value: () => tradeFilterStore.displayThorChain,
caption: ExchangeProviderDescription.thorChain.title,
onChanged: () =>
tradeFilterStore.toggleDisplayExchange(ExchangeProviderDescription.thorChain)),
FilterItem(
value: () => tradeFilterStore.displayLetsExchange,
caption: ExchangeProviderDescription.letsExchange.title,
onChanged: () => tradeFilterStore
.toggleDisplayExchange(ExchangeProviderDescription.letsExchange)),
FilterItem(
value: () => tradeFilterStore.displayStealthEx,
caption: ExchangeProviderDescription.stealthEx.title,
onChanged: () =>
tradeFilterStore.toggleDisplayExchange(ExchangeProviderDescription.stealthEx)),
FilterItem(
value: () => tradeFilterStore.displayXOSwap,
caption: ExchangeProviderDescription.xoSwap.title,
onChanged: () =>
tradeFilterStore.toggleDisplayExchange(ExchangeProviderDescription.xoSwap)),
FilterItem(
value: () => tradeFilterStore.displaySwapTrade,
caption: ExchangeProviderDescription.swapTrade.title,
onChanged: () =>
tradeFilterStore.toggleDisplayExchange(ExchangeProviderDescription.swapTrade)),
FilterItem(
value: () => tradeFilterStore.displaySwapXyz,
caption: ExchangeProviderDescription.swapsXyz.title,
onChanged: () =>
tradeFilterStore.toggleDisplayExchange(ExchangeProviderDescription.swapsXyz)),
FilterItem(
value: () => tradeFilterStore.displayNearIntents,
caption: ExchangeProviderDescription.nearIntents.title,
onChanged: () => tradeFilterStore
.toggleDisplayExchange(ExchangeProviderDescription.nearIntents)),
]
},
value: () => transactionFilterStore.displaySilentPayments,
caption: S.current.silent_payments,
onChanged: transactionFilterStore.toggleSilentPayments,
),
SwapFilterItem(
enabledProviders: () => tradeFilterStore.enabledProviders,
allEnabled: () => tradeFilterStore.displayAllTrades,
value: () => tradeFilterStore.displayAllTrades,
onChanged: () =>
tradeFilterStore.toggleDisplayExchange(ExchangeProviderDescription.all)),
FilterItem(
value: () => orderFilterStore.displayCakePay,
caption: 'Cake Pay',
onChanged: () =>
orderFilterStore.toggleDisplayOrder(OrderProviderDescription.cakePay)),
],
exchangeFilterItems = [
SwapProviderFilterItem(
providerDescription: ExchangeProviderDescription.changeNow,
value: () => tradeFilterStore.displayChangeNow,
onChanged: () =>
tradeFilterStore.toggleDisplayExchange(ExchangeProviderDescription.changeNow)),
SwapProviderFilterItem(
providerDescription: ExchangeProviderDescription.sideShift,
value: () => tradeFilterStore.displaySideShift,
onChanged: () =>
tradeFilterStore.toggleDisplayExchange(ExchangeProviderDescription.sideShift)),
SwapProviderFilterItem(
providerDescription: ExchangeProviderDescription.simpleSwap,
value: () => tradeFilterStore.displaySimpleSwap,
onChanged: () =>
tradeFilterStore.toggleDisplayExchange(ExchangeProviderDescription.simpleSwap)),
SwapProviderFilterItem(
providerDescription: ExchangeProviderDescription.trocador,
value: () => tradeFilterStore.displayTrocador,
onChanged: () =>
tradeFilterStore.toggleDisplayExchange(ExchangeProviderDescription.trocador)),
SwapProviderFilterItem(
providerDescription: ExchangeProviderDescription.exolix,
value: () => tradeFilterStore.displayExolix,
onChanged: () =>
tradeFilterStore.toggleDisplayExchange(ExchangeProviderDescription.exolix)),
SwapProviderFilterItem(
providerDescription: ExchangeProviderDescription.chainflip,
value: () => tradeFilterStore.displayChainflip,
onChanged: () =>
tradeFilterStore.toggleDisplayExchange(ExchangeProviderDescription.chainflip)),
SwapProviderFilterItem(
providerDescription: ExchangeProviderDescription.thorChain,
value: () => tradeFilterStore.displayThorChain,
onChanged: () =>
tradeFilterStore.toggleDisplayExchange(ExchangeProviderDescription.thorChain)),
SwapProviderFilterItem(
providerDescription: ExchangeProviderDescription.letsExchange,
value: () => tradeFilterStore.displayLetsExchange,
onChanged: () =>
tradeFilterStore.toggleDisplayExchange(ExchangeProviderDescription.letsExchange)),
SwapProviderFilterItem(
providerDescription: ExchangeProviderDescription.stealthEx,
value: () => tradeFilterStore.displayStealthEx,
onChanged: () =>
tradeFilterStore.toggleDisplayExchange(ExchangeProviderDescription.stealthEx)),
SwapProviderFilterItem(
providerDescription: ExchangeProviderDescription.xoSwap,
value: () => tradeFilterStore.displayXOSwap,
onChanged: () =>
tradeFilterStore.toggleDisplayExchange(ExchangeProviderDescription.xoSwap)),
SwapProviderFilterItem(
providerDescription: ExchangeProviderDescription.swapTrade,
value: () => tradeFilterStore.displaySwapTrade,
onChanged: () =>
tradeFilterStore.toggleDisplayExchange(ExchangeProviderDescription.swapTrade)),
SwapProviderFilterItem(
providerDescription: ExchangeProviderDescription.swapsXyz,
value: () => tradeFilterStore.displaySwapXyz,
onChanged: () =>
tradeFilterStore.toggleDisplayExchange(ExchangeProviderDescription.swapsXyz)),
SwapProviderFilterItem(
providerDescription: ExchangeProviderDescription.nearIntents,
value: () => tradeFilterStore.displayNearIntents,
onChanged: () =>
tradeFilterStore.toggleDisplayExchange(ExchangeProviderDescription.nearIntents)),
],
subname = '',
name = appStore.wallet!.name,
type = appStore.wallet!.type,
@@ -406,6 +399,15 @@ abstract class DashboardViewModelBase with Store {
return false;
}
@action
void changeAllFilterItems(bool value) {
for (final item in filterItems) {
if (item.value() != value) {
item.onChanged();
}
}
}
@action
Future<void> loadCardDesigns() async {
final accountStyleSettings =
@@ -719,7 +721,10 @@ abstract class DashboardViewModelBase with Store {
static const shortHistoryLength = 3;
@computed
List<ActionListItem> get itemsShort => items.where((item)=>item is! DateSectionItem).take(3).toList();
List<ActionListItem> get itemsShort => items
.where((item) => item is! DateSectionItem)
.take(shortHistoryLength)
.toList();
@observable
WalletBase<Balance, TransactionHistoryBase<TransactionInfo>, TransactionInfo> wallet;
@@ -1129,7 +1134,11 @@ abstract class DashboardViewModelBase with Store {
PayjoinTransactionsStore payjoinTransactionsStore;
Map<String, List<FilterItem>> filterItems;
// Map<String, List<FilterItem>> filterItems;
List<FilterItem> filterItems;
List<FilterItem> exchangeFilterItems;
bool get isBuyEnabled => settingsStore.isBitcoinBuyEnabled;
@@ -1,8 +1,36 @@
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/view_model/dashboard/action_list_item.dart';
class DateSectionItem extends ActionListItem {
DateSectionItem(this.date, {required super.key});
@override
final DateTime date;
}
}
abstract class SpecificDateSectionItem extends DateSectionItem {
SpecificDateSectionItem(super.date, {required super.key});
String get text;
}
class Last30daysTransactionItem extends SpecificDateSectionItem {
Last30daysTransactionItem(super.date, {required super.key});
@override
String get text => S.current.last_30_days;
}
class Last7daysTransactionItem extends SpecificDateSectionItem {
Last7daysTransactionItem(super.date, {required super.key});
@override
String get text => S.current.last_7_days;
}
class TodayTransactionItem extends SpecificDateSectionItem {
TodayTransactionItem(super.date, {required super.key});
@override
String get text => S.current.today;
}
+29 -1
View File
@@ -1,4 +1,4 @@
import 'package:mobx/mobx.dart';
import 'package:cake_wallet/exchange/exchange_provider_description.dart';
class FilterItem {
FilterItem({
@@ -9,4 +9,32 @@ class FilterItem {
bool Function() value;
String caption;
Function onChanged;
}
class SwapFilterItem extends FilterItem {
SwapFilterItem({
required this.enabledProviders,
required this.allEnabled,
required super.value,
super.caption = "Swap",
required super.onChanged,
});
int Function() enabledProviders;
bool Function() allEnabled;
}
class SwapProviderFilterItem extends FilterItem {
SwapProviderFilterItem({
required super.value,
required super.onChanged,
required this.providerDescription,
super.caption = ""
});
@override
String get caption => providerDescription.title;
final ExchangeProviderDescription providerDescription;
}
@@ -1,45 +1,82 @@
import 'package:cake_wallet/view_model/dashboard/action_list_item.dart';
import 'package:cake_wallet/view_model/dashboard/date_section_item.dart';
import 'package:flutter/foundation.dart';
import "package:cake_wallet/view_model/dashboard/action_list_item.dart";
import "package:cake_wallet/view_model/dashboard/date_section_item.dart";
import "package:flutter/foundation.dart";
enum _DateBucket { recent, last7Days, last30Days, byMonth }
List<ActionListItem> formattedItemsList(List<ActionListItem> items) {
final formattedList = <ActionListItem>[];
DateTime? lastDate;
items.sort((a, b) => b.date.compareTo(a.date));
for (var i = 0; i < items.length; i++) {
final transaction = items[i];
final now = DateTime.now();
final last24hThreshold = now.subtract(const Duration(hours: 24));
final last7daysThreshold = now.subtract(const Duration(days: 7));
final last30daysThreshold = now.subtract(const Duration(days: 30));
if (lastDate == null) {
lastDate = transaction.date;
formattedList.add(
DateSectionItem(
transaction.date,
key: ValueKey('date_section_item_${transaction.date.microsecondsSinceEpoch}_key'),
),
);
formattedList.add(transaction);
continue;
_DateBucket? lastBucket;
DateTime? lastMonthDate;
for (final transaction in items) {
final date = transaction.date;
final bucket = date.isAfter(last24hThreshold)
? _DateBucket.recent
: date.isAfter(last7daysThreshold)
? _DateBucket.last7Days
: date.isAfter(last30daysThreshold)
? _DateBucket.last30Days
: _DateBucket.byMonth;
switch (bucket) {
case _DateBucket.recent:
if (lastBucket != _DateBucket.recent) {
formattedList.add(
TodayTransactionItem(
date,
key: const ValueKey("last_7_days_section_item_key"),
),
);
}
break;
case _DateBucket.last7Days:
if (lastBucket != _DateBucket.last7Days) {
formattedList.add(
Last7daysTransactionItem(
date,
key: const ValueKey("last_7_days_section_item_key"),
),
);
}
break;
case _DateBucket.last30Days:
if (lastBucket != _DateBucket.last30Days) {
formattedList.add(
Last30daysTransactionItem(
date,
key: const ValueKey("last_30_days_section_item_key"),
),
);
}
break;
case _DateBucket.byMonth:
final isNewMonth = lastMonthDate == null ||
lastMonthDate.year != date.year ||
lastMonthDate.month != date.month;
if (isNewMonth) {
lastMonthDate = date;
formattedList.add(
DateSectionItem(
date,
key: ValueKey("date_section_item_${date.year}_${date.month}_key"),
),
);
}
break;
}
final isCurrentDay = lastDate.year == transaction.date.year &&
lastDate.month == transaction.date.month &&
lastDate.day == transaction.date.day;
if (isCurrentDay) {
formattedList.add(transaction);
continue;
}
lastDate = transaction.date;
formattedList.add(
DateSectionItem(
transaction.date,
key: ValueKey('date_section_item_${transaction.date.microsecondsSinceEpoch}_key'),
),
);
lastBucket = bucket;
formattedList.add(transaction);
}
return formattedList;
}
}