Skip to content

Commit

Permalink
Merge pull request #1856 from get10101/feat/trading-screen
Browse files Browse the repository at this point in the history
feat: tradescreen layout
  • Loading branch information
bonomat authored Jan 20, 2024
2 parents 2b88fce + cc41eef commit 7addfa4
Show file tree
Hide file tree
Showing 13 changed files with 549 additions and 78 deletions.
44 changes: 44 additions & 0 deletions webapp/frontend/lib/common/amount_text.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import 'package:flutter/material.dart';
import 'package:get_10101/common/model.dart';
import 'package:intl/intl.dart';

class AmountText extends StatelessWidget {
final Amount amount;
final TextStyle textStyle;

const AmountText({super.key, required this.amount, this.textStyle = const TextStyle()});

@override
Widget build(BuildContext context) {
return Text(formatAmount(AmountDenomination.satoshi, amount), style: textStyle);
}
}

String formatAmount(AmountDenomination denomination, Amount amount) {
switch (denomination) {
case AmountDenomination.bitcoin:
return formatBtc(amount);
case AmountDenomination.satoshi:
return formatSats(amount);
}
}

String formatBtc(Amount amount) {
final formatter = NumberFormat("##,##0.00000000", "en");
return "${formatter.format(amount.btc)} BTC";
}

String formatSats(Amount amount) {
final formatter = NumberFormat("#,###,###,###,###", "en");
return "${formatter.format(amount.sats)} sats";
}

String formatUsd(Usd usd) {
final formatter = NumberFormat("\$ #,###,###,###,###", "en");
return formatter.format(usd.usd);
}

String formatPrice(Price price) {
final formatter = NumberFormat("\$ #,###,###,###,###", "en");
return formatter.format(price.usd);
}
50 changes: 34 additions & 16 deletions webapp/frontend/lib/common/amount_text_input_form_field.dart
Original file line number Diff line number Diff line change
@@ -1,31 +1,43 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:get_10101/common/amount.dart';
import 'package:get_10101/common/color.dart';
import 'package:get_10101/common/model.dart';
import 'package:get_10101/common/numeric_text_formatter.dart';

class AmountInputField extends StatelessWidget {
const AmountInputField(
{super.key,
this.enabled = true,
this.label = '',
this.hint = '',
this.onChanged,
required this.value,
this.controller,
this.validator,
this.decoration,
this.style,
this.onTap});
/// If `decoration` is passed, then `isLoading`, `hint`, `label`, `infoText`,
/// and `isLoading` are overriden.
const AmountInputField({
super.key,
this.enabled = true,
this.label = '',
this.hint = '',
this.onChanged,
this.value,
this.isLoading = false,
this.infoText,
this.controller,
this.validator,
this.decoration,
this.style,
this.onTap,
this.textAlign = TextAlign.left,
this.suffixIcon,
});

final TextEditingController? controller;
final TextStyle? style;
final Amount value;
final Formattable? value;
final bool enabled;
final String label;
final String hint;
final String? infoText;
final bool isLoading;
final Function(String)? onChanged;
final Function()? onTap;
final InputDecoration? decoration;
final TextAlign textAlign;
final Widget? suffixIcon;

final String? Function(String?)? validator;

Expand All @@ -35,19 +47,25 @@ class AmountInputField extends StatelessWidget {
style: style ?? const TextStyle(color: Colors.black87),
enabled: enabled,
controller: controller,
initialValue: controller != null ? null : value.formatted(),
textAlign: textAlign,
initialValue: controller != null
? null
: value != null
? value!.formatted()
: null,
keyboardType: TextInputType.number,
decoration: decoration ??
InputDecoration(
border: const OutlineInputBorder(),
hintText: hint,
labelText: label,
labelStyle: const TextStyle(color: Colors.black87),
labelStyle: const TextStyle(color: tenTenOnePurple),
filled: true,
fillColor: enabled ? Colors.white : Colors.grey[50],
errorStyle: TextStyle(
color: Colors.red[900],
),
suffixIcon: isLoading ? const CircularProgressIndicator() : suffixIcon,
),
inputFormatters: <TextInputFormatter>[
FilteringTextInputFormatter.digitsOnly,
Expand Down
2 changes: 1 addition & 1 deletion webapp/frontend/lib/common/balance.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import 'package:get_10101/common/amount.dart';
import 'package:get_10101/common/model.dart';

class Balance {
final Amount offChain;
Expand Down
204 changes: 204 additions & 0 deletions webapp/frontend/lib/common/model.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
import 'package:decimal/decimal.dart';
import 'package:decimal/intl.dart';
import 'package:get_10101/common/amount_text.dart';
import 'package:intl/intl.dart';

abstract class Formattable {
String formatted();
}

enum AmountDenomination { bitcoin, satoshi }

class Amount implements Formattable {
Decimal _sats = Decimal.zero;

Amount(int sats) {
_sats = Decimal.fromInt(sats);
}

// TODO: this is bad for precision
Amount.fromBtc(double btc) {
_sats = Decimal.fromInt((btc * (100000000.0)).round());
}

int get sats => _sats.toBigInt().toInt();

int get toInt => _sats.toBigInt().toInt();

double get btc => _sats.shift(-8).toDouble();

double asDouble() => _sats.toDouble();

Amount.parse(dynamic value) : _sats = Decimal.parse(value);

Amount.zero() : _sats = Decimal.zero;

Amount add(Amount amount) {
return Amount(sats + amount.sats);
}

Amount sub(Amount amount) {
return Amount(sats - amount.sats);
}

Amount.parseAmount(String? value) {
if (value == null || value.isEmpty) {
_sats = Decimal.zero;
return;
}

try {
final f = NumberFormat("#,###");
int amount =
// remove any comma and dot from text formatting the users input.
int.parse(value.replaceAll(f.symbols.GROUP_SEP, ''));

_sats = Decimal.fromInt(amount);
} on Exception {
_sats = Decimal.zero;
}
}

@override
String formatted() {
final formatter = NumberFormat("#,###,###,###,###", "en");
return formatter.format(sats);
}

@override
String toString() {
return formatSats(this);
}

String formatSats(Amount amount) {
final formatter = NumberFormat("#,###,###,###,###", "en");
return "${formatter.format(amount.sats)} sats";
}
}

class Usd implements Formattable {
Decimal _usd = Decimal.zero;

Usd(int usd) {
_usd = Decimal.fromInt(usd);
}

int get usd => _usd.toBigInt().toInt();

int get toInt => _usd.toBigInt().toInt();

Decimal get toDecimal => _usd;

double get asDouble => _usd.toDouble();

Usd.zero() : _usd = Decimal.zero;

Usd.parse(dynamic value) : _usd = Decimal.parse(value);

Usd.parseString(String? value) {
if (value == null || value.isEmpty) {
_usd = Decimal.zero;
return;
}

try {
final f = NumberFormat("#,###");
int amount =
// remove any comma and dot from text formatting the users input.
int.parse(value.replaceAll(f.symbols.GROUP_SEP, ''));

_usd = Decimal.fromInt(amount);
} on Exception {
_usd = Decimal.zero;
}
}

@override
String formatted() {
final formatter = NumberFormat("#,###,###,###,###", "en");
return formatter.format(_usd.toDouble());
}

@override
String toString() {
return formatUsd(this);
}
}

class Price implements Formattable {
Decimal _usd = Decimal.zero;

Price(double usd) {
_usd = Decimal.parse(usd.toString());
}

int get usd => _usd.toBigInt().toInt();

int get toInt => _usd.toBigInt().toInt();

Decimal get toDecimal => _usd;

Price.zero() : _usd = Decimal.zero;

double get asDouble => _usd.toDouble();

Price.parse(dynamic value) : _usd = Decimal.parse(value);

Price.parseString(String? value) {
if (value == null || value.isEmpty) {
_usd = Decimal.zero;
return;
}

try {
final f = NumberFormat("#,###");
double amount =
// remove any comma and dot from text formatting the users input.
double.parse(value.replaceAll(f.symbols.GROUP_SEP, ''));

_usd = Decimal.parse(value);
} on Exception {
_usd = Decimal.zero;
}
}

@override
String formatted() {
final formatter = NumberFormat("#,##0.00", "en_US");
return formatter.format(DecimalIntl(_usd));
}

@override
String toString() {
return formatPrice(this);
}
}

class Leverage implements Formattable {
int _leverage = 1;

Leverage.one() : _leverage = 1;

int get toInt => _leverage;

double get asDouble => _leverage as double;

Leverage(int leverage) {
_leverage = leverage;
}

@override
String formatted() {
return _leverage.toString();
}
}

class Quote {
Price _bid;
Price _ask;

Price? get bid => _bid;
Price? get ask => _ask;

Quote(this._bid, this._ask);
}
1 change: 0 additions & 1 deletion webapp/frontend/lib/common/scaffold_with_nav.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import 'package:flutter/material.dart';
import 'package:get_10101/common/balance.dart';
import 'package:get_10101/common/version_service.dart';
import 'package:get_10101/wallet/wallet_service.dart';

import 'package:go_router/go_router.dart';
import 'package:provider/provider.dart';

Expand Down
3 changes: 3 additions & 0 deletions webapp/frontend/lib/common/theme.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ class TenTenOneTheme extends ThemeExtension<TenTenOneTheme> {
static const Color red600 = Color(0xFFE53935);

final Color disabled = Colors.grey;
static const Color grey300 = Color(0xFF939191);

final Color buy;
final Color sell;
Expand All @@ -22,12 +23,14 @@ class TenTenOneTheme extends ThemeExtension<TenTenOneTheme> {
final Color leverageMinusButtonColor;
final Color leverageInactiveSliderTrackColor;
final Color leverageInactiveTicksColor;
final Color inactiveButtonColor;

const TenTenOneTheme(
{this.buy = green600,
this.sell = red600,
this.profit = Colors.green,
this.loss = Colors.red,
this.inactiveButtonColor = Colors.grey,
this.tabColor = tenTenOnePurple,
this.leveragePlusButtonColor = tenTenOnePurple,
this.leverageMinusButtonColor = tenTenOnePurple,
Expand Down
Loading

0 comments on commit 7addfa4

Please sign in to comment.