Skip to content

Commit

Permalink
feat: token details page (#1501)
Browse files Browse the repository at this point in the history
Co-authored-by: Justin Enerio <[email protected]>
Co-authored-by: ookami-kb <[email protected]>
Co-authored-by: Vlad Sumin <[email protected]>
  • Loading branch information
4 people authored Jan 14, 2025
1 parent 7809e99 commit 3bf600a
Show file tree
Hide file tree
Showing 20 changed files with 1,210 additions and 77 deletions.
14 changes: 11 additions & 3 deletions packages/espressocash_app/lib/data/db/db.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import 'package:drift/drift.dart';
import 'package:injectable/injectable.dart';

import '../../features/activities/models/transaction.dart';
import '../../features/currency/models/currency.dart';
import '../../features/incoming_link_payments/data/ilp_repository.dart';
import '../../features/outgoing_direct_payments/data/repository.dart';
import '../../features/outgoing_link_payments/data/repository.dart';
Expand All @@ -24,7 +25,7 @@ class OutgoingTransferRows extends Table {
Set<Column<Object>> get primaryKey => {id};
}

const int latestVersion = 60;
const int latestVersion = 61;

const _tables = [
OutgoingTransferRows,
Expand Down Expand Up @@ -117,11 +118,9 @@ class MyDatabase extends _$MyDatabase {
if (from < 51) {
await m.addColumn(transactionRows, transactionRows.amount);
}

if (from < 52) {
await m.createTable(tokenBalanceRows);
}

if (from < 53) {
await m.addColumn(onRampOrderRows, onRampOrderRows.authToken);
await m.addColumn(onRampOrderRows, onRampOrderRows.moreInfoUrl);
Expand Down Expand Up @@ -171,6 +170,14 @@ class MyDatabase extends _$MyDatabase {
if (from >= 39 && from < 60) {
await m.addColumn(iLPRows, iLPRows.receiveAmount);
}
if (from < 61) {
await m.addColumn(transactionRows, transactionRows.token);

await customStatement(
'UPDATE ${transactionRows.actualTableName} SET token = ?',
[Currency.usdc.token.address],
);
}
},
);
}
Expand Down Expand Up @@ -306,6 +313,7 @@ class TransactionRows extends Table {
TextColumn get encodedTx => text()();
IntColumn get status => intEnum<TxCommonStatus>()();
IntColumn get amount => integer().nullable()();
TextColumn get token => text().nullable()();

@override
Set<Column<Object>> get primaryKey => {id};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,19 @@ import 'package:dfunc/dfunc.dart';
import 'package:drift/drift.dart';
import 'package:fast_immutable_collections/fast_immutable_collections.dart';
import 'package:injectable/injectable.dart';
import 'package:intl/intl.dart';
import 'package:rxdart/rxdart.dart';
import 'package:solana/encoder.dart';

import '../../../data/db/db.dart';
import '../../../di.dart';
import '../../currency/models/amount.dart';
import '../../currency/models/currency.dart';
import '../../outgoing_direct_payments/data/repository.dart';
import '../../outgoing_link_payments/data/repository.dart';
import '../../payment_request/data/repository.dart';
import '../../tokens/data/token_repository.dart';
import '../../tokens/token.dart';
import '../../transaction_request/service/tr_service.dart';
import '../models/activity.dart';
import '../models/transaction.dart';
Expand All @@ -32,6 +36,38 @@ class TransactionRepository {
return query.map((row) => row.id).watch().map((event) => event.toIList());
}

Stream<IList<String>> watchByAddress(String tokenAddress) {
final query = _db.select(_db.transactionRows)
..where((t) => t.token.equals(tokenAddress))
..orderBy([(t) => OrderingTerm.desc(t.created)]);

return query.map((row) => row.id).watch().map((event) => event.toIList());
}

Stream<Map<String, IList<TxCommon>>> watchGroupedByDate(String tokenAddress) {
final query = _db.select(_db.transactionRows)
..where((t) => t.token.equals(tokenAddress))
..orderBy([(t) => OrderingTerm.desc(t.created)]);

return query.watch().asyncMap((rows) async {
final grouped = <String, IList<TxCommon>>{};
for (final row in rows) {
final model = await row.toModel();
final created = model.created;
if (created != null) {
final date = DateFormat('yyyy-MM-dd').format(created);
grouped.update(
date,
(list) => list.add(model),
ifAbsent: () => IList([model]),
);
}
}

return grouped;
});
}

Stream<IList<String>> watchCount(int count) {
final query = _db.select(_db.transactionRows)
..limit(count)
Expand All @@ -44,7 +80,9 @@ class TransactionRepository {
final query = _db.select(_db.transactionRows)
..where((tbl) => tbl.id.equals(id));

return query.watchSingle().asyncExpand((row) => _match(row.toModel()));
return query
.watchSingle()
.asyncMap((row) => row.toModel().then((value) => _match(value).first));
}

Future<void> saveAll(
Expand Down Expand Up @@ -147,14 +185,26 @@ class TransactionRepository {
}

extension TransactionRowExt on TransactionRow {
TxCommon toModel() => TxCommon(
SignedTx.decode(encodedTx),
created: created,
status: status,
amount: amount?.let(
(it) => CryptoAmount(value: it, cryptoCurrency: Currency.usdc),
Future<TxCommon> toModel() async {
final tokenAddress = this.token;
Token? token;

if (tokenAddress != null) {
token = await sl<TokenRepository>().getToken(tokenAddress);
}

return TxCommon(
SignedTx.decode(encodedTx),
created: created,
status: status,
amount: amount?.let(
(it) => CryptoAmount(
value: it,
cryptoCurrency: CryptoCurrency(token: token ?? Token.unk),
),
);
),
);
}
}

extension on TxCommon {
Expand All @@ -164,6 +214,7 @@ extension on TxCommon {
encodedTx: tx.encode(),
status: status,
amount: amount?.value,
token: amount?.cryptoCurrency.token.address,
);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import 'package:fast_immutable_collections/fast_immutable_collections.dart';
import 'package:injectable/injectable.dart';

import '../data/transaction_repository.dart';
import '../models/transaction.dart';

@injectable
class TokenActivitiesRepository {
const TokenActivitiesRepository(this._repository);

final TransactionRepository _repository;

Stream<List<ActivityGroup>> watchTokenActivities(String tokenAddress) =>
_repository.watchGroupedByDate(tokenAddress).map(_prepareActivityGroups);

List<ActivityGroup> _prepareActivityGroups(
Map<String, IList<TxCommon>> data,
) {
final sortedDates = data.keys.toList()..sort((a, b) => b.compareTo(a));

return sortedDates.map((date) {
final transactions = data[date] ?? IList<TxCommon>();

final sortedTxs = transactions.sort((a, b) {
final aCreated = a.created;
final bCreated = b.created;

return (aCreated != null && bCreated != null)
? bCreated.compareTo(aCreated)
: 0;
});

return ActivityGroup(date: date, transactions: sortedTxs);
}).toList();
}
}

class ActivityGroup {
const ActivityGroup({
required this.date,
required this.transactions,
});

final String date;
final IList<TxCommon> transactions;
}
Loading

0 comments on commit 3bf600a

Please sign in to comment.