Skip to content

Commit

Permalink
Merge pull request #7 from kackogut/feature/token_picker
Browse files Browse the repository at this point in the history
Feature/token picker
  • Loading branch information
kackogut authored Sep 25, 2023
2 parents 9d83665 + 0976d5b commit 5523f07
Show file tree
Hide file tree
Showing 28 changed files with 465 additions and 111 deletions.
3 changes: 2 additions & 1 deletion assets/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,6 @@
"empty_amount_error_label": "Amount must be higher than 0 if present",
"field_missing_error_label": "Field is required",
"key_not_base58_encoded_error_label": "Invalid value, must be base58 encoded",
"key_length_invalid_error_label": "Key value must be between 32 and 44 characters"
"key_length_invalid_error_label": "Key value must be between 32 and 44 characters",
"token_picker_title": "Select token"
}
2 changes: 1 addition & 1 deletion lib/data/error/input_error.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import 'package:easy_localization/easy_localization.dart';

import '../../util/strings.dart';

abstract class InputError {
sealed class InputError {
abstract String text;
}

Expand Down
4 changes: 2 additions & 2 deletions lib/data/solana_pay_request.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@ class SolanaPayRequest {
this.amount,
this.reference,
this.memo,
this.splToken,
this.token,
});

final String address;
final String? label;
final String? splToken;
final String? token;
final String? message;
final String? amount;
final String? reference;
Expand Down
13 changes: 13 additions & 0 deletions lib/data/token/spl_token.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
class TokenResponse {
TokenResponse({
required this.id,
required this.imageUrl,
required this.symbol,
this.address,
});

final String id;
final String symbol;
final String? address;
final String imageUrl;
}
4 changes: 0 additions & 4 deletions lib/data/token/spl_tokens.dart

This file was deleted.

25 changes: 25 additions & 0 deletions lib/data/token/tokens_repository.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import 'spl_token.dart';

abstract class TokensRepository {
List<TokenResponse> getTokens();
}

class LocalTokensRepository extends TokensRepository {
@override
List<TokenResponse> getTokens() => [
TokenResponse(
id: "1",
symbol: "SOL",
address: null,
imageUrl:
"https://upload.wikimedia.org/wikipedia/en/b/b9/Solana_logo.png",
),
TokenResponse(
id: "2",
symbol: "USDC",
address: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
imageUrl:
"https://s2.coinmarketcap.com/static/img/coins/200x200/3408.png",
)
];
}
4 changes: 2 additions & 2 deletions lib/data/transfer/transfer_request_repository.dart
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ class DefaultTransferRequestRepository extends TransferRequestRepository {
if (solanaPayRequest.amount?.isNotEmpty == true) {
queryParameters["amount"] = solanaPayRequest.amount!;
}
if (solanaPayRequest.splToken?.isNotEmpty == true) {
queryParameters["spl-token"] = solanaPayRequest.splToken!;
if (solanaPayRequest.token?.isNotEmpty == true) {
queryParameters["spl-token"] = solanaPayRequest.token!;
}
if (solanaPayRequest.reference?.isNotEmpty == true) {
queryParameters["reference"] = solanaPayRequest.reference;
Expand Down
7 changes: 3 additions & 4 deletions lib/design/input/base_input.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ class BaseInput extends StatelessWidget {
final String _labelText;
final ValueChanged<String>? _onChanged;
final TextInputType? _keyboardType;
final bool _focusable;
final String? _error;

const BaseInput({
Expand All @@ -14,22 +13,22 @@ class BaseInput extends StatelessWidget {
keyboardType,
focusable,
error,
onTap,
initialValue,
}) : _labelText = labelText,
_onChanged = onChanged,
_keyboardType = keyboardType,
_focusable = focusable ?? true,
_error = error;

@override
Widget build(BuildContext context) {
return TextField(
return TextFormField(
decoration: InputDecoration(
border: const OutlineInputBorder(),
labelText: _labelText,
errorText: _error),
onChanged: _onChanged,
keyboardType: _keyboardType,
focusNode: _focusable ? null : AlwaysDisabledFocusNode(),
);
}
}
Expand Down
25 changes: 25 additions & 0 deletions lib/design/token/token_row.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import 'package:flutter/cupertino.dart';

class TokenPickerListItem extends StatelessWidget {
final String _imageUrl;
final String _symbol;

const TokenPickerListItem({super.key, required imageUrl, required symbol})
: _imageUrl = imageUrl,
_symbol = symbol;

@override
Widget build(BuildContext context) {
return Row(
children: [
Image.network(
_imageUrl,
width: 32,
height: 32,
),
const Padding(padding: EdgeInsets.all(8)),
Text(_symbol),
],
);
}
}
11 changes: 9 additions & 2 deletions lib/di/blocs_providers.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:sol_pay_gen/domain/generate_transfer_request_qr_use_case.dart';
import 'package:sol_pay_gen/domain/token/get_spl_tokens_use_case.dart';
import 'package:sol_pay_gen/domain/transfer/generate_transfer_request_qr_use_case.dart';
import 'package:sol_pay_gen/feature/qr/bloc/qr_generator_cubit.dart';
import 'package:sol_pay_gen/feature/token/bloc/tokens_cubit.dart';
import 'package:sol_pay_gen/validator/keys_validator.dart';
import 'package:sol_pay_gen/validator/number_validator.dart';

Expand All @@ -11,10 +13,15 @@ import '../feature/input/bloc/parameters_input_cubit.dart';
MultiBlocProvider getBlocProviders({required StatelessWidget child}) {
return MultiBlocProvider(
providers: [
BlocProvider<TokensCubit>(
create: (BuildContext context) =>
TokensCubit(getTokensUseCase: context.read<GetTokensUseCase>()),
),
BlocProvider<ParametersInputCubit>(
create: (BuildContext context) => ParametersInputCubit(
context.read<NumberValidator>(),
context.read<KeysValidator>(),
context.read<TokensCubit>(),
),
),
BlocProvider<QrGeneratorCubit>(
Expand All @@ -24,7 +31,7 @@ MultiBlocProvider getBlocProviders({required StatelessWidget child}) {
),
parametersInputCubit: context.read<ParametersInputCubit>(),
),
)
),
],
child: child,
);
Expand Down
12 changes: 11 additions & 1 deletion lib/di/repositories_providers.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:sol_pay_gen/data/token/tokens_repository.dart';
import 'package:sol_pay_gen/data/transfer/transfer_request_repository.dart';
import 'package:sol_pay_gen/domain/token/get_spl_tokens_use_case.dart';
import 'package:sol_pay_gen/validator/keys_validator.dart';
import 'package:sol_pay_gen/validator/number_validator.dart';

Expand All @@ -16,7 +19,14 @@ MultiRepositoryProvider getRepositoryProviders({
),
RepositoryProvider<KeysValidator>(
create: (_) => DefaultKeysValidator(),
)
),
RepositoryProvider<TokensRepository>(
create: (_) => LocalTokensRepository()),
RepositoryProvider<GetTokensUseCase>(
create: (BuildContext context) => GetTokensUseCase(
context.read<TokensRepository>(),
),
),
],
child: blocProviders,
);
Expand Down
16 changes: 16 additions & 0 deletions lib/domain/token/get_spl_tokens_use_case.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import 'package:sol_pay_gen/data/token/tokens_repository.dart';
import 'package:sol_pay_gen/domain/token/spl_token_data.dart';
import 'package:sol_pay_gen/domain/token/spl_token_mapper.dart';

class GetTokensUseCase {
GetTokensUseCase(this._tokensRepository);

final TokensRepository _tokensRepository;

List<TokenData> execute() {
return _tokensRepository
.getTokens()
.map((tokenResponse) => tokenResponse.toDomainModel())
.toList();
}
}
13 changes: 13 additions & 0 deletions lib/domain/token/spl_token_data.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
class TokenData {
TokenData({
required this.id,
required this.imageUrl,
required this.symbol,
this.address,
});

final String id;
final String symbol;
final String? address;
final String imageUrl;
}
13 changes: 13 additions & 0 deletions lib/domain/token/spl_token_mapper.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import 'package:sol_pay_gen/data/token/spl_token.dart';
import 'package:sol_pay_gen/domain/token/spl_token_data.dart';

extension TokenMapper on TokenResponse {
TokenData toDomainModel() {
return TokenData(
id: id,
imageUrl: imageUrl,
symbol: symbol,
address: address,
);
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import 'package:sol_pay_gen/data/solana_pay_request.dart';

import '../data/transfer/transfer_request_repository.dart';
import '../../data/transfer/transfer_request_repository.dart';

class GenerateTransferRequestQrUseCase {
GenerateTransferRequestQrUseCase(this._transferRequestRepository);
Expand Down
51 changes: 38 additions & 13 deletions lib/feature/input/bloc/parameters_input_cubit.dart
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:sol_pay_gen/data/base/text_value.dart';
import 'package:sol_pay_gen/domain/token/spl_token_data.dart';
import 'package:sol_pay_gen/feature/input/bloc/parameters_input_state.dart';
import 'package:sol_pay_gen/feature/token/model/selectable_token_display_mapper.dart';

import '../../../data/error/input_error.dart';
import '../../../validator/keys_validator.dart';
import '../../../validator/number_validator.dart';
import '../../token/bloc/tokens_cubit.dart';

class ParametersInputCubit extends Cubit<ParametersInputState> {
final NumberValidator _numberValidator;
final KeysValidator _keysValidator;

ParametersInputCubit(
this._numberValidator,
this._keysValidator,
this._tokensCubit,
) : super(
ParametersInputState(
address: TextValue(),
Expand All @@ -21,9 +22,16 @@ class ParametersInputCubit extends Cubit<ParametersInputState> {
memo: null,
message: null,
label: null,
splTokenAddress: null,
selectedToken: null,
selectableTokens: List.empty(),
),
);
) {
onSelectedTokenChange(null);
}

final NumberValidator _numberValidator;
final KeysValidator _keysValidator;
final TokensCubit _tokensCubit;

void onAddressChange(String address) {
emit(state.copyWith(
Expand Down Expand Up @@ -60,20 +68,37 @@ class ParametersInputCubit extends Cubit<ParametersInputState> {
));
}

void onSplTokenChange(String token) {
emit(state.copyWith(splTokenAddress: token));
}

void onMemoChange(String memo) {
emit(state.copyWith(memo: memo));
}

void onSelectedTokenChange(String? tokenId) {
List<TokenData> tokens = _tokensCubit.state.tokens;
TokenData selectedToken = tokenId != null
? tokens.firstWhere((token) => token.id == tokenId)
: tokens.first;

emit(
state.copyWith(
selectedToken: selectedToken,
selectableTokens: tokens
.map(
(token) =>
token.toSelectableTokenModel(selectedToken.id == token.id),
)
.toList(),
),
);
}

void onValidate() {
emit(state.copyWith(
address: state.address.copyWith(
error: _validateAddress(state.address.text),
emit(
state.copyWith(
address: state.address.copyWith(
error: _validateAddress(state.address.text),
),
),
));
);
}

InputError? _validateAddress(String address) {
Expand Down
Loading

0 comments on commit 5523f07

Please sign in to comment.