diff --git a/.env.example b/.env.example index cfeb3124a..16b1b811f 100644 --- a/.env.example +++ b/.env.example @@ -58,3 +58,8 @@ SELENDRA_API= DOERS_API= # For Image IPFS_API= + +# Exolix +EXOLIX_URL= +EXOLIX_API= +EXOLIX_TOKEN= \ No newline at end of file diff --git a/lib/data/api/get_api.dart b/lib/data/api/get_api.dart index 7239a44a5..dfcf23fcc 100644 --- a/lib/data/api/get_api.dart +++ b/lib/data/api/get_api.dart @@ -117,4 +117,39 @@ class GetRequest { }); } + /*--------------- EXOLIX API FUNCTION ---------------*/ + static Future getExolixExStatusByTxId(String id) async { + var url = dotenv.get('EXOLIX_URL'); + var api = dotenv.get('EXOLIX_API'); + var uri = Uri.parse("$url/$api/transactions/$id"); + + return await http.get( + uri, + headers: conceteHeader() + ); + } + + static Future getExolixExchangeCoin() async { + var url = dotenv.get('EXOLIX_URL'); + var api = dotenv.get('EXOLIX_API'); + var uri = Uri.parse("$url/$api/currencies?all=true&withNetworks=true&networksList=BTC,BSC,ETH"); + + return await http.get( + uri, + headers: conceteHeader() + ); + } + + Future exolixTwoCoinInfo(Map queryParameters) async { + var url = dotenv.get('EXOLIX_URL'); + var api = dotenv.get('EXOLIX_API'); + var token = dotenv.get('EXOLIX_TOKEN'); + queryParameters.addAll({ 'apiToken': token }); + var uri = Uri.parse("$url/$api/rate").replace(queryParameters: queryParameters); + + return await http.get( + uri, + headers: conceteHeader() + ); + } } diff --git a/lib/data/api/post_api.dart b/lib/data/api/post_api.dart index 06c520973..24ab19908 100644 --- a/lib/data/api/post_api.dart +++ b/lib/data/api/post_api.dart @@ -86,4 +86,18 @@ class PostRequest { ); // return http.Response(json.encode(data), 200); } + + Future exolixSwap(Map mapData) async { + + var url = dotenv.get('EXOLIX_URL'); + var api = dotenv.get('EXOLIX_API'); + var token = dotenv.get('EXOLIX_TOKEN'); + var uri = Uri.parse("$url/$api/transactions"); + + return await http.post( + uri, + body: json.encode(mapData), + headers: conceteHeader(key: "Authorization", value: "Bearer $token") + ); + } } \ No newline at end of file diff --git a/lib/data/repository/exolix_ex_repo/exolix_ex_repo.dart b/lib/data/repository/exolix_ex_repo/exolix_ex_repo.dart new file mode 100644 index 000000000..b538f645b --- /dev/null +++ b/lib/data/repository/exolix_ex_repo/exolix_ex_repo.dart @@ -0,0 +1,9 @@ +import 'package:bitriel_wallet/domain/model/exolix_ex_coin_m.dart'; +import 'package:bitriel_wallet/index.dart'; + +abstract class ExolixExchangeRepository { + Future> getExolixExchangeCoin(); + Future getExolixExStatusByTxId(String txId); + Future exolixTwoCoinInfo(Map jsn); + Future exolixSwap(Map mapData); +} \ No newline at end of file diff --git a/lib/data/repository/exolix_ex_repo/exolix_ex_repo_impl.dart b/lib/data/repository/exolix_ex_repo/exolix_ex_repo_impl.dart new file mode 100644 index 000000000..28e9777f0 --- /dev/null +++ b/lib/data/repository/exolix_ex_repo/exolix_ex_repo_impl.dart @@ -0,0 +1,44 @@ +import 'package:bitriel_wallet/data/api/post_api.dart'; +import 'package:bitriel_wallet/data/repository/exolix_ex_repo/exolix_ex_repo.dart'; +import 'package:bitriel_wallet/domain/model/exolix_ex_coin_m.dart'; +import 'package:bitriel_wallet/index.dart'; + +class ExolixExchangeRepoImpl implements ExolixExchangeRepository { + + List lstExoCoin = []; + + @override + Future> getExolixExchangeCoin() async { + + await GetRequest.getExolixExchangeCoin().then((value) { + + if (value.statusCode == 200) { + + List json = jsonDecode(value.body)['data']; + + for (dynamic jsonExoCoin in json){ + + lstExoCoin.add(ExolixExchangeCoin.fromJson(jsonExoCoin)); + } + } + }); + + return lstExoCoin; + + } + + @override + Future exolixSwap(Map mapData) async { + return await PostRequest().exolixSwap(mapData); + } + + @override + Future exolixTwoCoinInfo(Map jsn) async { + return await PostRequest().twoCoinInfo(jsn); + } + + @override + Future getExolixExStatusByTxId(String txId) async { + return await GetRequest.getLetsExStatusByTxId(txId); + } +} \ No newline at end of file diff --git a/lib/domain/model/exolix_ex_coin_m.dart b/lib/domain/model/exolix_ex_coin_m.dart new file mode 100644 index 000000000..44c52f7ae --- /dev/null +++ b/lib/domain/model/exolix_ex_coin_m.dart @@ -0,0 +1,119 @@ +// To parse this JSON data, do +// +// final exolixExchangeCoin = exolixExchangeCoinFromJson(jsonString); + +import 'package:bitriel_wallet/index.dart'; + +class ExolixCoin { + + String? coinCode; + String? coinName; + String? network; + String? networkName; + String? networkShortName; + String? icon; + String? memoName; + + ExolixCoin({ + this.coinCode, + this.coinName, + this.network, + this.networkName, + this.networkShortName, + this.icon, + this.memoName, + }); + + ExolixCoin.fromJson(Map jsn){ + coinCode = jsn['coinCode']; + coinName = jsn['coinName']; + network = jsn['network']; + networkName = jsn['networkName']; + networkShortName = jsn['networkShortName']; + icon = jsn['icon']; + memoName = jsn['memoName']; + } + +} + +class ExolixExchangeCoin { + + final String? code; + final String? icon; + final String? name; + final List? networks; + + ExolixExchangeCoin({ + this.code, + this.icon, + this.name, + this.networks, + }); + + static String? exolixUrl = dotenv.get('EXOLIX_URL'); + + factory ExolixExchangeCoin.fromRawJson(String str) => ExolixExchangeCoin.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory ExolixExchangeCoin.fromJson(Map json) => ExolixExchangeCoin( + code: json["code"], + icon: exolixUrl! + json["icon"], + name: json["name"], + networks: json["networks"] == null ? [] : List.from(json["networks"]!.map((x) => ExolixExchangeCoinNetwork.fromJson(x))), + ); + + Map toJson() => { + "code": code, + "icon": icon, + "name": name, + "networks": networks == null ? [] : List.from(networks!.map((x) => x.toJson())), + }; +} + +class ExolixExCoinByNetworkModel { + + bool? isActive = false; + String? title = ''; + String? networkCode = ''; + String? subtitle = ''; + String? balance = ''; + String? network = ''; + Widget? image = const SizedBox(); + + ExolixExCoinByNetworkModel({this.networkCode, this.image, this.title, this.subtitle, this.balance, this.network, this.isActive}); +} + +class ExolixExchangeCoinNetwork { + + final String? name; + final String? network; + final String? blockExplorer; + final String? shortName; + + ExolixExchangeCoinNetwork({ + this.name, + this.network, + this.blockExplorer, + this.shortName, + }); + + factory ExolixExchangeCoinNetwork.fromRawJson(String str) => ExolixExchangeCoinNetwork.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory ExolixExchangeCoinNetwork.fromJson(Map json) => ExolixExchangeCoinNetwork( + name: json["name"], + network: json["network"], + blockExplorer: json["blockExplorer"], + shortName: json["shortName"], + ); + + Map toJson() => { + "name": name, + "network": network, + "blockExplorer": blockExplorer, + "shortName": shortName, + }; + +} diff --git a/lib/domain/model/swap_m.dart b/lib/domain/model/swap_m.dart index 6107a44ec..9d0fd51e3 100644 --- a/lib/domain/model/swap_m.dart +++ b/lib/domain/model/swap_m.dart @@ -1,3 +1,4 @@ +import 'package:bitriel_wallet/domain/model/exolix_ex_coin_m.dart'; import 'package:bitriel_wallet/index.dart'; class SwapModel { @@ -36,6 +37,37 @@ class SwapModel { } } +class ExolixSwapModel { + + String? coinFrom; + String? coinTo; + String? networkFrom; + String? networkTo; + String? withdrawalAddress; + ValueNotifier? amt; + + ExolixSwapModel(){ + coinFrom = ""; + coinTo = ""; + networkFrom = ""; + networkTo = ""; + amt = ValueNotifier(""); + } + + // Return Encode Json + Map toJson(){ + + return { + "coinFrom": coinFrom, + "coinTo": coinTo, + "networkFrom": networkFrom, + "networkTo": networkTo, + "amount": amt!.value, + "withdrawalAddress": withdrawalAddress, + }; + } +} + class SwapResModel { bool? is_float; @@ -125,7 +157,7 @@ class SwapResModel { List> toJson(List lstSwapRes){ - return lstSwapRes!.map((e) => { + return lstSwapRes.map((e) => { 'is_float': e!.is_float, 'status': e.status, 'coin_from': e.coin_from, @@ -167,4 +199,72 @@ class SwapResModel { } +} + +class ExolixSwapResModel { + + String? id; + String? amount; + String? amountTo; + ExolixCoin? coinFrom; + ExolixCoin? coinTo; + String? comment; + String? createdAt; + String? depositAddress; + String? depositExtraId; + String? withdrawalAddress; + String? withdrawalExtraId; + String? refundAddress; + String? refundExtraId; + dynamic rate; + String? rateType; + String? status; + String? email; + + ExolixSwapResModel(); + + ExolixSwapResModel.fromJson(Map jsn){ + id = jsn['id']; + status = jsn['status']; + coinFrom = ExolixCoin.fromJson(jsn['coinFrom']); + coinTo = ExolixCoin.fromJson(jsn['coinTo']); + comment = jsn['comment']; + createdAt = jsn['createdAt']; + amount = jsn['amount'].toString(); + amountTo = jsn['amountTo'].toString(); + depositAddress = jsn['depositAddress']; + depositExtraId = jsn['depositExtraId']; + withdrawalAddress = jsn['withdrawalAddress']; + withdrawalExtraId = jsn['withdrawalExtraId']; + refundAddress = jsn['refundAddress']; + refundExtraId = jsn['refundExtraId']; + rate = jsn['rate']; + rateType = jsn['rateType']; + email = jsn['email']; + } + + List> toJson(List lstSwapRes){ + + return lstSwapRes.map((e) => { + "id": e!.id, + "status": e.status, + "coinFrom": e.coinFrom, + "coinTo": e.coinTo, + "comment": e.comment, + "createdAt": e.createdAt, + "amount": e.amount, + "amountTo": e.amountTo, + "depositAddress": e.depositAddress, + "depositExtraId": e.depositExtraId, + "withdrawalAddress": e.withdrawalAddress, + "withdrawalExtraId": e.withdrawalExtraId, + "refundAddress": e.refundAddress, + "refundExtraId": e.refundExtraId, + "rate": e.rate, + "rateType": e.rateType, + "email": e.email, + }).toList(); + + } + } \ No newline at end of file diff --git a/lib/domain/usecases/app_uc/app_impl.dart b/lib/domain/usecases/app_uc/app_impl.dart index afc577d0f..06b9845c9 100644 --- a/lib/domain/usecases/app_uc/app_impl.dart +++ b/lib/domain/usecases/app_uc/app_impl.dart @@ -60,7 +60,7 @@ class AppUsecasesImpl implements AppUsecases { if(value == true) { Navigator.pushAndRemoveUntil( context, - MaterialPageRoute(builder: (context) => const MainScreen()), + MaterialPageRoute(builder: (context) => MainScreen()), (route) => false ); } @@ -125,12 +125,12 @@ class AppUsecasesImpl implements AppUsecases { if (sdkProvider!.getSdkImpl.getKeyring.allAccounts.isNotEmpty){ await Future.delayed(const Duration(milliseconds: 200), (){ + Navigator.pushAndRemoveUntil( _context!, - MaterialPageRoute(builder: (context) => const MainScreen()), + MaterialPageRoute(builder: (context) => MainScreen()), (route) => false ); - }); } else { diff --git a/lib/domain/usecases/swap_uc/exolix_uc/exolix_ex_uc.dart b/lib/domain/usecases/swap_uc/exolix_uc/exolix_ex_uc.dart new file mode 100644 index 000000000..391d55a1e --- /dev/null +++ b/lib/domain/usecases/swap_uc/exolix_uc/exolix_ex_uc.dart @@ -0,0 +1,10 @@ +import 'package:bitriel_wallet/index.dart'; + +abstract class ExolixExchangeUseCases { + Future getExolixExchangeCoin(); + void onDeleteTxt(); + void formatDouble(String value); + Future exolixSwap(); + Future exolixConfirmSwap(int index); + Future exolixSwapping(ExolixSwapResModel swapResModel); +} \ No newline at end of file diff --git a/lib/domain/usecases/swap_uc/exolix_uc/exolix_ex_uc_impl.dart b/lib/domain/usecases/swap_uc/exolix_uc/exolix_ex_uc_impl.dart new file mode 100644 index 000000000..7671b08ea --- /dev/null +++ b/lib/domain/usecases/swap_uc/exolix_uc/exolix_ex_uc_impl.dart @@ -0,0 +1,380 @@ +import 'package:bitriel_wallet/data/repository/exolix_ex_repo/exolix_ex_repo_impl.dart'; +import 'package:bitriel_wallet/domain/model/exolix_ex_coin_m.dart'; +import 'package:bitriel_wallet/domain/usecases/swap_uc/exolix_uc/exolix_ex_uc.dart'; +import 'package:bitriel_wallet/index.dart'; +import 'package:bitriel_wallet/presentation/screen/swap_exolix_ex/select_swap_token_screen.dart' as exo_swap_screen; +import 'package:bitriel_wallet/presentation/screen/swap_exolix_ex/confirm_swap_ex.dart' as exo_confirm_swap; + +Map map = {"id":"excbb7dadcd446","amount":0.028,"amountTo":0.21790163,"coinFrom":{"coinCode":"ETH","coinName":"Ethereum","network":"BSC","networkName":"BNB Smart Chain (BEP20)","networkShortName":"BEP20","icon":"https://exolix.com/icons/coins/ETH.png","memoName":""},"coinTo":{"coinCode":"BNB","coinName":"BNB","network":"BSC","networkName":"BNB Smart Chain (BEP20)","networkShortName":"BEP20","icon":"https://exolix.com/icons/coins/BNB.png","memoName":""},"comment":null,"createdAt":"2023-10-26T16:38:18.576Z","depositAddress":"0xF8Aa60E01dd625Ccc9Ce2DEb267ad91c9a8a80ad","depositExtraId":null,"withdrawalAddress":"0x8b8aa19ad5fa4e08980de2285e2038d50844f83a","withdrawalExtraId":null,"refundAddress":null,"refundExtraId":null,"hashIn":{"hash":null,"link":null},"hashOut":{"hash":null,"link":null},"rate":7.78220107,"rateType":"fixed","affiliateToken":null,"status":"wait","email":null}; + +class ExolixExchangeUCImpl implements ExolixExchangeUseCases { + + BuildContext? _context; + + ValueNotifier coin1 = ValueNotifier(ExolixExCoinByNetworkModel()); + + ValueNotifier coin2 = ValueNotifier(ExolixExCoinByNetworkModel()); + + ValueNotifier isLstCoinReady = ValueNotifier(false); + + ValueNotifier receiveAmt = ValueNotifier(""); + + final ExolixExchangeRepoImpl _exolixExchangeRepoImpl = ExolixExchangeRepoImpl(); + + List defaultLstCoins = []; + + Widget? imgConversion; + + ExolixSwapModel swapModel = ExolixSwapModel(); + + final PaymentUcImpl _paymentUcImpl = PaymentUcImpl(); + + ValueNotifier> lstLECoin = ValueNotifier([]); + + ValueNotifier> lstTx = ValueNotifier([null]); + + ValueNotifier isReady = ValueNotifier(false); + + int? index; + + set setContext(BuildContext ctx){ + _context = ctx; + _paymentUcImpl.setBuildContext = ctx; + } + + final SecureStorageImpl _secureStorageImpl = SecureStorageImpl(); + + @override + Future getExolixExchangeCoin() async { + + print("getExolixExchangeCoin"); + + if(defaultLstCoins.isEmpty){ + defaultLstCoins = await _exolixExchangeRepoImpl.getExolixExchangeCoin(); + } + + if (lstTx.value[0] == null){ + + _secureStorageImpl.readSecure(DbKey.lstTxIds)!.then( (localLstTx){ + + lstTx.value.clear(); + + // ignore: unnecessary_null_comparison + if (localLstTx.isNotEmpty){ + + lstTx.value = List>.from((json.decode(localLstTx))).map((e) { + return ExolixSwapResModel.fromJson(e); + }).toList(); + } + + // ignore: invalid_use_of_protected_member, invalid_use_of_visible_for_testing_member + lstTx.notifyListeners(); + + }); + } + + lstCoinExtract(); + + } + + void lstCoinExtract() { + + for(int i = 0; i < defaultLstCoins.length; i++){ + + for (int j = 0; j < defaultLstCoins[i].networks!.length; j++){ + addCoinByIndex(i, j); + } + + } + + isLstCoinReady.value = true; + + } + + void addCoinByIndex(int i, int j) { + + if ( + defaultLstCoins[i].networks![j].network == "BTC" || + defaultLstCoins[i].networks![j].network == "BSC" || + defaultLstCoins[i].networks![j].network == "ETH" + ){ + + lstLECoin.value.add( + ExolixExCoinByNetworkModel( + title: defaultLstCoins[i].code, + subtitle: defaultLstCoins[i].name, + image: Container(),//imgConversion!, + network: defaultLstCoins[i].networks![j].name!, + networkCode: defaultLstCoins[i].networks![j].network, + balance: "0"//contractProvider!.sortListContract[i].balance, + + ) + ); + } + + } + + + @override + void onDeleteTxt() { + + final formattedValue = formatCurrencyText(swapModel.amt!.value); + + swapModel.amt!.value = formattedValue; + + if (swapModel.amt!.value.isNotEmpty) { + swapModel.amt!.value = swapModel.amt!.value.substring(0, swapModel.amt!.value.length - 1); + } + + } + + String formatCurrencyText(String value) { + return value; + } + + @override + void formatDouble(String value) { + + if (swapModel.amt!.value.replaceAll(".", "").length < 10){ + // Value Equal Empty & Not Contains "." + if (value.contains(".") && !(swapModel.amt!.value.contains(".")) && swapModel.amt!.value.isEmpty){ + + swapModel.amt!.value = "0."; + + } + // Prevent Add "." Multiple Time. + // Reject Input "." Evertime + else if ( !(value.contains("."))) { + + swapModel.amt!.value = swapModel.amt!.value + value; + + } + // Add "." For Only one time. + else if ( !(swapModel.amt!.value.contains(".")) ){ + + swapModel.amt!.value = swapModel.amt!.value + value; + + } + + queryEstimateAmt(); + + if (Validator.swapValidator(swapModel.coinFrom!, swapModel.coinTo!, swapModel.amt!.value) == true){ + isReady.value = true; + } else if (isReady.value == true){ + isReady.value = false; + } + } + + } + + void queryEstimateAmt() { + + if (swapModel.coinFrom!.isNotEmpty && swapModel.coinTo!.isNotEmpty){ + EasyDebounce.debounce("tag", const Duration(milliseconds: 500), () async { + await _exolixExchangeRepoImpl.exolixTwoCoinInfo({ + "coinFrom": swapModel.coinFrom, + "coinTo": swapModel.coinTo, + "coinFromNetwork": swapModel.networkFrom, + "coinToNetwork": swapModel.networkTo, + "amount": swapModel.amt!.value, + "rateType": "fixed" + }).then((value) { + + if (value.statusCode == 200) { + receiveAmt.value = (json.decode(value.body))['toAmount'].toString(); + } + }); + }); + } + } + + void setCoin(BuildContext context, bool isFrom){ + + Navigator.push( + context, + MaterialPageRoute(builder: (context) => exo_swap_screen.SelectSwapToken(itemLE: lstLECoin.value)) + ).then((res) { + + if (res != null){ + + if (isFrom == true){ + + coin1.value = lstLECoin.value[res]; + swapModel.coinFrom = coin1.value.title; + swapModel.networkFrom = coin1.value.networkCode; + + } else { + + coin2.value = lstLECoin.value[res]; + swapModel.coinTo = coin2.value.title; + swapModel.networkTo = coin2.value.networkCode; + } + + swapModel.withdrawalAddress = Provider.of(context, listen: false).getSdkImpl.evmAddress; + + queryEstimateAmt(); + + if (Validator.swapValidator(swapModel.coinFrom!, swapModel.coinTo!, swapModel.amt!.value) == true){ + isReady.value = true; + } else if (isReady.value == false) { + isReady.value = false; + } + + } + }); + } + + @override + Future exolixSwap() async { + + try { + + // Response value = Response(json.encode(map), 200); + + dialogLoading(_context!); + + await _exolixExchangeRepoImpl.exolixSwap(swapModel.toJson()).then((value) async { + + print("Value ${value.body}"); + + if (value.statusCode == 401){ + throw json.decode(value.body)['error']; + } + // Unprocessable entity + else if (value.statusCode == 422) { + throw "Such exchange pair is not available"; + } + + else if (value.statusCode == 201) { + + lstTx.value.add(ExolixSwapResModel.fromJson(json.decode(value.body))); + // ignore: invalid_use_of_protected_member, invalid_use_of_visible_for_testing_member + lstTx.notifyListeners(); + + await SecureStorageImpl().writeSecure(DbKey.lstTxIds, value.body); + + // Close Dialog + Navigator.pop(_context!); + + await QuickAlert.show( + context: _context!, + type: QuickAlertType.success, + showCancelBtn: true, + cancelBtnText: "Close", + cancelBtnTextStyle: TextStyle(fontSize: 14, color: hexaCodeToColor(AppColors.primaryBtn)), + confirmBtnText: "Confirm", + text: 'Swap Successfully!', + onConfirmBtnTap: () async { + await exolixConfirmSwap(lstTx.value.length-1); + }, + ); + } else { + throw json.decode(value.body); + } + }); + + } catch (e) { + + print(e); + + // Close Dialog + Navigator.pop(_context!); + + await QuickAlert.show( + context: _context!, + type: QuickAlertType.error, + text: '$e', + ); + } + } + + // Index Of List + Future paySwap(int index) async { + + Navigator.push( + _context!, + MaterialPageRoute(builder: (context) => const PincodeScreen(title: '', label: PinCodeLabel.fromSendTx,)) + ).then((value) async { + + _paymentUcImpl.recipientController.text = lstTx.value[index]!.depositAddress!; + _paymentUcImpl.amountController.text = lstTx.value[index]!.amount!; + + if (value != null){ + await _paymentUcImpl.sendBep20(); + } + }); + + } + + @override + Future exolixConfirmSwap(int indx) async { + index = indx; + Navigator.push( + _context!, + MaterialPageRoute(builder: (context) => exo_confirm_swap.ConfirmSwapExchange(swapResModel: lstTx.value[indx], confirmSwap: exolixSwapping, getStatus: getStatus)) + ); + } + + @override + Future exolixSwapping(ExolixSwapResModel swapResModel) async { + + int index = Provider.of(_context!, listen: false).sortListContract!.indexWhere((model) { + + if ( swapResModel.coinFrom!.coinCode!.toLowerCase() == model.symbol!.toLowerCase() ){ + isReady.value = true; + return true; + } + + return false; + + }); + + if (index != -1){ + + await Navigator.pushReplacement( + _context!, + MaterialPageRoute(builder: (context) => TokenPayment(index: index, address: swapResModel.withdrawalAddress, amt: swapResModel.amount,)) + ); + + } else { + + await QuickAlert.show( + context: _context!, + type: QuickAlertType.warning, + showCancelBtn: true, + cancelBtnText: "Close", + cancelBtnTextStyle: TextStyle(fontSize: 14, color: hexaCodeToColor(AppColors.primaryBtn)), + text: '${swapResModel.coinFrom!.coinCode!} (${swapResModel.coinFrom!.network}) is not found. Please add contract token !', + confirmBtnText: 'Add Contract', + onConfirmBtnTap: (){ + Navigator.pushReplacement( + _context!, + MaterialPageRoute(builder: (context) => AddAsset(index: swapResModel.coinFrom!.network == "BSC" ? 0 : 1,)) + ); + } + ); + + } + } + + /// This function for update status inside details + Future getStatus() async { + + dialogLoading(_context!, content: "Checking Status"); + + await _exolixExchangeRepoImpl.getExolixExStatusByTxId(lstTx.value[index!]!.id!).then((value) { + + lstTx.value[index!] = ExolixSwapResModel.fromJson(json.decode(value.body)); + + }); + + // ignore: invalid_use_of_protected_member, invalid_use_of_visible_for_testing_member + lstTx.notifyListeners(); + + await SecureStorageImpl().writeSecure(DbKey.lstTxIds, json.encode(ExolixSwapResModel().toJson(lstTx.value))); + + // Close Dialog + Navigator.pop(_context!); + } + +} \ No newline at end of file diff --git a/lib/presentation/provider/PROVIDER.md b/lib/presentation/provider/PROVIDER.md index e69de29bb..f9c362fc1 100644 --- a/lib/presentation/provider/PROVIDER.md +++ b/lib/presentation/provider/PROVIDER.md @@ -0,0 +1 @@ +The presentation layer is responsible for displaying the user interface and handling user interactions. The provider folder contains the code that provides the data and state to the widgets in the presentation layer. \ No newline at end of file diff --git a/lib/presentation/screen/home_screen.dart b/lib/presentation/screen/home_screen.dart index a7ceab17f..79acb8773 100644 --- a/lib/presentation/screen/home_screen.dart +++ b/lib/presentation/screen/home_screen.dart @@ -1,4 +1,5 @@ import 'package:bitriel_wallet/index.dart'; +import 'package:bitriel_wallet/presentation/screen/swap_exolix_ex/swap_ex_screen.dart'; class HomeScreen extends StatelessWidget { @@ -23,7 +24,6 @@ class HomeScreen extends StatelessWidget { walletProvider.marketUCImpl.backToTop.value = walletProvider.marketUCImpl.scrollController.offset > 400 ? true : false; }); - return Scaffold( body: SingleChildScrollView( controller: walletProvider.marketUCImpl.scrollController, @@ -64,8 +64,8 @@ class HomeScreen extends StatelessWidget { : const SizedBox(); Widget _menuItems(BuildContext context) { + return Container( - // padding: const EdgeInsets.all(14), margin: const EdgeInsets.all(14), decoration: BoxDecoration( color: hexaCodeToColor(AppColors.cardColor), @@ -77,6 +77,7 @@ class HomeScreen extends StatelessWidget { padding: const EdgeInsets.only(top: 14, right: 14, left: 14, bottom: 14 / 2 ), child: Column( children: [ + Padding( padding: const EdgeInsets.symmetric(vertical: 5), child: Row( @@ -90,7 +91,8 @@ class HomeScreen extends StatelessWidget { action: () { Navigator.push( context, - MaterialPageRoute(builder: (builder) => const SwapExchange()) + // MaterialPageRoute(builder: (builder) => SwapExchange()) + MaterialPageRoute(builder: (builder) => SwapExolicExchange()) ); }, ), @@ -115,6 +117,7 @@ class HomeScreen extends StatelessWidget { ], ), ), + Padding( padding: const EdgeInsets.symmetric(vertical: 5), child: Row( @@ -153,25 +156,12 @@ class HomeScreen extends StatelessWidget { ), ], ), - ), + ) + ], ), ), - // Padding( - // padding: const EdgeInsets.only(right: 14, left: 14, bottom: 14 / 2 ), - // child: Divider( - // color: hexaCodeToColor("#78839C").withOpacity(0.25), - // ), - // ), - - // SizedBox( - // height: 30, - // child: _listScrollMenuItem() - // ), - - // const SizedBox(height: 14,), - ], ), ); diff --git a/lib/presentation/screen/main_screen.dart b/lib/presentation/screen/main_screen.dart index dced124b2..0dc02f4cf 100644 --- a/lib/presentation/screen/main_screen.dart +++ b/lib/presentation/screen/main_screen.dart @@ -1,14 +1,15 @@ import 'package:bitriel_wallet/index.dart'; class MainScreen extends StatelessWidget { - const MainScreen({super.key}); + + MainScreen({super.key}); - @override - Widget build(BuildContext context) { + final NavbarUsecaseImpl navbarUsecaseImpl = NavbarUsecaseImpl(); - final NavbarUsecaseImpl navbarUsecaseImpl = NavbarUsecaseImpl(); + final MultiAccountImpl multiAccountImpl = MultiAccountImpl(); - final MultiAccountImpl multiAccountImpl = MultiAccountImpl(); + @override + Widget build(BuildContext context) { return ValueListenableBuilder( valueListenable: navbarUsecaseImpl.currentIndex, diff --git a/lib/presentation/screen/swap_exolix_ex/confirm_swap_ex.dart b/lib/presentation/screen/swap_exolix_ex/confirm_swap_ex.dart new file mode 100644 index 000000000..eb7c02b93 --- /dev/null +++ b/lib/presentation/screen/swap_exolix_ex/confirm_swap_ex.dart @@ -0,0 +1,340 @@ +import 'package:bitriel_wallet/index.dart'; + +class ConfirmSwapExchange extends StatelessWidget { + + final ExolixSwapResModel? swapResModel; + + final Function? confirmSwap; + + final Function? getStatus; + + const ConfirmSwapExchange({super.key, required this.swapResModel, required this.confirmSwap, this.getStatus}); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: appBar(context, title: "Swap"), + body: Column( + children: [ + + _swapTokenInfo(swapResModel), + + _trxExchangeInfo(context, swapResModel, getStatus!), + + Expanded( + child: Container() + ), + + swapResModel!.status!.toLowerCase() != "success" ? MyButton( + edgeMargin: const EdgeInsets.all(paddingSize), + textButton: "Confirm", + action: () { + confirmSwap!(swapResModel); + }, + ) : const SizedBox(), + + ], + ), + ); + } + + Widget _swapTokenInfo(ExolixSwapResModel? swapResModel) { + return Padding( + padding: const EdgeInsets.all(15), + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + + Padding( + padding: const EdgeInsets.symmetric(vertical: 10.0), + child: Row( + children: [ + const SizedBox( + height: 50, + width: 50, + child: CircleAvatar() + ), + + const SizedBox(width: 10.0), + + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + MyTextConstant( + text: "You Swap", + color2: hexaCodeToColor(AppColors.grey), + fontWeight: FontWeight.w600, + ), + + MyTextConstant( + text: "${swapResModel!.amount} ${swapResModel.coinFrom!.coinCode}", + fontSize: 18, + fontWeight: FontWeight.w700, + ) + ], + ) + ], + ), + ), + + Align( + alignment: Alignment.centerLeft, + child: IconButton( + onPressed: (){ + + }, + icon: Icon(Iconsax.arrow_down, color: hexaCodeToColor(AppColors.primary), size: 35,) + ), + ), + + Padding( + padding: const EdgeInsets.symmetric(vertical: 10.0), + child: Row( + children: [ + const SizedBox( + height: 50, + width: 50, + child: CircleAvatar() + ), + + const SizedBox(width: 10.0), + + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + MyTextConstant( + text: "You Will Get", + color2: hexaCodeToColor(AppColors.grey), + fontWeight: FontWeight.w600, + ), + + MyTextConstant( + text: swapResModel.amountTo, + fontSize: 18, + fontWeight: FontWeight.w700, + ) + ], + ) + ], + ), + ), + + ], + ), + ); + } + + Widget _trxExchangeInfo(BuildContext context, ExolixSwapResModel? swapResModel, Function getStatus) { + return Padding( + padding: const EdgeInsets.all(15), + child: Column( + children: [ + + Container( + padding: const EdgeInsets.all(10), + decoration: BoxDecoration( + color: hexaCodeToColor(AppColors.background), + borderRadius: const BorderRadius.all(Radius.circular(18), + ), + ), + child: Column( + children: [ + + Row( + children: [ + MyTextConstant( + text: "From Address", + fontWeight: FontWeight.w600, + color2: hexaCodeToColor(AppColors.darkGrey), + ), + + const Spacer(), + + MyTextConstant( + text: swapResModel!.withdrawalAddress!.replaceRange(6, swapResModel.withdrawalAddress!.length - 6, "......."), + fontWeight: FontWeight.w600, + ), + + IconButton( + icon: Icon(Iconsax.copy, color: hexaCodeToColor(AppColors.primary), size: 20), + onPressed: () async { + Clipboard.setData( + ClipboardData(text: swapResModel.depositAddress!.replaceRange(6, swapResModel.depositAddress!.length - 6, ".......")), + ); + /* Copy Text */ + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text("From Address is Copied to Clipboard"), + ), + ); + }, + ) + ], + ), + + const Divider(), + + Row( + children: [ + MyTextConstant( + text: "To Address", + fontWeight: FontWeight.w600, + color2: hexaCodeToColor(AppColors.darkGrey), + ), + + const Spacer(), + + MyTextConstant( + text: swapResModel.depositAddress!.replaceRange(6, swapResModel.depositAddress!.length - 6, "......."), + fontWeight: FontWeight.w600, + ), + + IconButton( + icon: Icon(Iconsax.copy, color: hexaCodeToColor(AppColors.primary), size: 20), + onPressed: () async { + Clipboard.setData( + ClipboardData(text: swapResModel.depositAddress!), + ); + /* Copy Text */ + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text("To Address is Copied to Clipboard"), + ), + ); + }, + ) + ], + ), + + const Divider(), + + Padding( + padding: const EdgeInsets.symmetric(vertical: 8.0), + child: Row( + children: [ + MyTextConstant( + text: "Provider", + fontWeight: FontWeight.w600, + color2: hexaCodeToColor(AppColors.darkGrey), + ), + + const Spacer(), + + const MyTextConstant( + text: "Exolix.com", + fontWeight: FontWeight.w600, + ), + + const SizedBox(width: 10), + + ], + ), + ), + + ], + ), + ), + + const SizedBox(height: 10), + + InkWell( + onTap: () { + Clipboard.setData( + ClipboardData(text: swapResModel.id!), + ); + /* Copy Text */ + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text("Exchange ID is Copied to Clipboard"), + ), + ); + }, + child: Container( + padding: const EdgeInsets.all(paddingSize), + decoration: BoxDecoration( + color: hexaCodeToColor(AppColors.cardColor), + borderRadius: const BorderRadius.all(Radius.circular(18), + ), + ), + child: Column( + children: [ + + Row( + children: [ + + Flexible( + flex: 0, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + + MyTextConstant( + text: "Exchange ID", + fontWeight: FontWeight.w600, + color2: hexaCodeToColor(AppColors.darkGrey), + ), + + const SizedBox(height: 2.5,), + + MyTextConstant( + text: "${swapResModel.id}", + color2: hexaCodeToColor(AppColors.primary), + textAlign: TextAlign.start, + fontWeight: FontWeight.bold, + ), + + ], + ), + ), + + const Spacer(), + + Flexible( + flex: 0, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + + MyTextConstant( + text: "Status", + fontWeight: FontWeight.w600, + color2: hexaCodeToColor(AppColors.darkGrey), + ), + + const SizedBox(height: 2.5,), + + MyTextConstant( + text: "${swapResModel.status}", + color2: hexaCodeToColor(AppColors.primary), + textAlign: TextAlign.start, + fontWeight: FontWeight.bold, + ), + + ], + ), + ), + + const Spacer(), + + IconButton( + icon: Icon(Iconsax.refresh_circle, color: hexaCodeToColor(AppColors.orangeColor)), + onPressed: () { + getStatus(); + }, + ) + + ], + ), + + ], + ), + ), + ), + + ], + ), + ); + } + + +} \ No newline at end of file diff --git a/lib/presentation/screen/swap_exolix_ex/select_swap_token_screen.dart b/lib/presentation/screen/swap_exolix_ex/select_swap_token_screen.dart new file mode 100644 index 000000000..d54f29438 --- /dev/null +++ b/lib/presentation/screen/swap_exolix_ex/select_swap_token_screen.dart @@ -0,0 +1,98 @@ +import 'package:bitriel_wallet/domain/model/exolix_ex_coin_m.dart'; +import 'package:bitriel_wallet/index.dart'; + +class SelectSwapToken extends StatelessWidget { + + final List itemLE; + + const SelectSwapToken({super.key, required this.itemLE}); + + @override + Widget build(BuildContext context) { + + // final TextEditingController searchController = TextEditingController(); + + return Scaffold( + appBar: appBar(context, title: "Select Token"), + body: Column( + children: [ + + Expanded( + child: Stack( + children: [ + ListView.builder( + itemCount: itemLE.length, + itemBuilder: (context, index) { + + return _listTokenItem(context, index); + + }, + ), + + + ], + ), + ), + ], + ), + ); + } + + Widget _searchBar(TextEditingController searchController, List itemLE) { + return Padding( + padding: const EdgeInsets.only(top: 15 / 2, left: 15, right: 15, bottom: 15 / 2), + child: TextField( + controller: searchController, + decoration: InputDecoration( + contentPadding: EdgeInsets.zero, + hintText: 'Search among ${itemLE.length} tokens by name', + // Add a clear button to the search bar + suffixIcon: IconButton( + icon: const Icon(Iconsax.close_circle), + onPressed: () => searchController.clear(), + ), + // Add a search icon or button to the search bar + prefixIcon: IconButton( + icon: const Icon(Iconsax.search_normal_1), + onPressed: () { + // Perform the search here + }, + ), + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(50.0), + ), + ), + ), + ); + } + + Widget _buildImageItem(int index) { + return const CircleAvatar(); + } + + Widget _listTokenItem(BuildContext context, int index) { + return ListTile( + contentPadding: const EdgeInsets.symmetric(horizontal: 20.0), + leading: SizedBox( + height: 40, + width: 40, + child: _buildImageItem(index), + ), + title: MyTextConstant( + text: itemLE[index].title ?? '', + fontWeight: FontWeight.w600, + fontSize: 17, + textAlign: TextAlign.start, + ), + subtitle: MyTextConstant( + text: itemLE[index].network, + color2: hexaCodeToColor(AppColors.grey), + fontSize: 13, + textAlign: TextAlign.start, + ), + onTap: () { + Navigator.pop(context, index); + }, + ); + } +} \ No newline at end of file diff --git a/lib/presentation/screen/swap_exolix_ex/status_exchange.dart b/lib/presentation/screen/swap_exolix_ex/status_exchange.dart new file mode 100644 index 000000000..768a97a0b --- /dev/null +++ b/lib/presentation/screen/swap_exolix_ex/status_exchange.dart @@ -0,0 +1,150 @@ +import 'package:bitriel_wallet/domain/usecases/swap_uc/exolix_uc/exolix_ex_uc_impl.dart'; +import 'package:bitriel_wallet/index.dart'; + +class StatusExolixExchange extends StatelessWidget { + + final ExolixExchangeUCImpl? exolixExchangeUCImpl; + + const StatusExolixExchange({super.key, required this.exolixExchangeUCImpl}); + + @override + Widget build(BuildContext context) { + + return Scaffold( + appBar: appBar(context, title: "Exchange Status"), + body: Column( + children: [ + + ValueListenableBuilder( + valueListenable: exolixExchangeUCImpl!.lstTx, + builder: (context, lst, wg) { + + if (lst.isEmpty){ + return Center( + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + + Padding( + padding: const EdgeInsets.only(top: 150), + child: Lottie.asset( + "assets/animation/search_empty.json", + repeat: false, + height: 200, + width: 200 + ), + ), + + const MyTextConstant( + text: "No request exchange activity.", + fontSize: 20, + fontWeight: FontWeight.bold, + ) + + ], + ), + ); + } + + // ignore: curly_braces_in_flow_control_structures, unnecessary_null_comparison + else if (lst[0] == null) return Expanded( + child: Shimmer.fromColors( + baseColor: Colors.grey[300]!, + highlightColor: Colors.grey[100]!, + child: ListView.builder( + itemCount: 6, + itemBuilder: (context, index) { + return Card( + elevation: 1.0, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(16), + ), + child: const SizedBox(height: 80), + ); + }, + ), + ) + ); + + return ListView( + shrinkWrap: true, + children: lst.map((e) { + return _statusSwapRes(exolixExchangeUCImpl: exolixExchangeUCImpl!, index: lst.indexOf(e)); + }).toList(), + ); + } + ), + ], + ), + ); + } + + Widget _statusSwapRes({required ExolixExchangeUCImpl exolixExchangeUCImpl, int? index}) { + + return Card( + margin: const EdgeInsets.symmetric(horizontal: 14, vertical: 4), + child: ListTile( + onTap: () { + exolixExchangeUCImpl.exolixConfirmSwap(index); + }, + title: MyTextConstant( + text: "Exchange ID: ${exolixExchangeUCImpl.lstTx.value[index!]!.id}", + fontWeight: FontWeight.bold, + textAlign: TextAlign.start, + ), + subtitle: MyTextConstant( + text: "Status: ${exolixExchangeUCImpl.lstTx.value[index]!.createdAt}", + color2: hexaCodeToColor(AppColors.iconGreyColor), + textAlign: TextAlign.start, + ), + trailing: MyTextConstant( + text: "Status: ${exolixExchangeUCImpl.lstTx.value[index]!.status}", + color2: hexaCodeToColor(AppColors.primary), + textAlign: TextAlign.end, + ), + ), + ); + } + + Widget _inputExchangeID() { + return Container( + margin: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 16.0), + child: const Card( + color: Colors.white, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(15.0)) + ), + child: Padding( + padding: EdgeInsets.symmetric(horizontal: 4.0, vertical: 8.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: + EdgeInsets.only(left: 16.0, right: 16.0, top: 8.0), + child: Text( + 'Enter Exchange ID', + style: TextStyle(fontWeight: FontWeight.bold, fontSize: 14.0), + ), + ), + Padding( + padding: EdgeInsets.symmetric(horizontal: 16.0, vertical: 0.0), + child: TextField( + style: TextStyle( + fontSize: 20.0, + fontWeight: FontWeight.w700, + color: Colors.black), + decoration: InputDecoration( + hintText: 'Exchange ID', + labelStyle: TextStyle(fontWeight: FontWeight.bold, fontSize: 30.0)), + ), + ), + ], + ), + ), + ), + ); + } + +} \ No newline at end of file diff --git a/lib/presentation/screen/swap_exolix_ex/swap_ex_screen.dart b/lib/presentation/screen/swap_exolix_ex/swap_ex_screen.dart new file mode 100644 index 000000000..761d43679 --- /dev/null +++ b/lib/presentation/screen/swap_exolix_ex/swap_ex_screen.dart @@ -0,0 +1,433 @@ +import 'package:bitriel_wallet/domain/usecases/swap_uc/exolix_uc/exolix_ex_uc_impl.dart'; +import 'package:bitriel_wallet/index.dart'; +import 'package:bitriel_wallet/presentation/screen/swap_exolix_ex/status_exchange.dart'; + +class SwapExolicExchange extends StatelessWidget { + + SwapExolicExchange({super.key}); + + final ExolixExchangeUCImpl exolicUCImpl = ExolixExchangeUCImpl(); + + @override + Widget build(BuildContext context) { + + exolicUCImpl.setContext = context; + + exolicUCImpl.getExolixExchangeCoin(); + + return Scaffold( + appBar: AppBar( + elevation: 0, + centerTitle: true, + backgroundColor: hexaCodeToColor(AppColors.background), + title: MyTextConstant( + text: "Swap Exolix", + fontSize: 26, + color2: hexaCodeToColor(AppColors.midNightBlue), + fontWeight: FontWeight.w600, + ), + leading: IconButton( + onPressed: () => Navigator.pop(context), + icon: Icon( + Iconsax.arrow_left_2, + size: 30, + color: hexaCodeToColor(AppColors.midNightBlue), + ), + ), + actions: [ + TextButton( + onPressed: () { + Navigator.push( + context, + MaterialPageRoute(builder: (builder) => StatusExolixExchange(exolixExchangeUCImpl: exolicUCImpl,)) + ); + }, + child: MyTextConstant( + text: "Status", + color2: hexaCodeToColor(AppColors.primary), + ), + ) + ], + ), + body: SizedBox( + height: MediaQuery.of(context).size.height, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + + Padding( + padding: const EdgeInsets.only(bottom: 8.0, left: 8.0, right: 8.0), + child: Container( + decoration: const BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.all(Radius.circular(10)) + ), + child: ValueListenableBuilder( + valueListenable: exolicUCImpl.swapModel.amt!, + builder: (context, value, wg) { + return Column( + children: [ + + _payInput(context, exolicUCImpl), + + const SizedBox(height: 10), + + Align( + alignment: Alignment.centerRight, + child: IconButton( + onPressed: (){ + + }, + icon: Icon(Iconsax.refresh_circle, size: 35, color: hexaCodeToColor(AppColors.orangeColor),) + ), + ), + + _getDisplay(context, exolicUCImpl), + ], + ); + } + ), + ), + ), + + Expanded( + child: Container() + ), + + Center( + child: _buildNumberPad(context, exolicUCImpl.swapModel.amt!.value, exolicUCImpl.onDeleteTxt, exolicUCImpl.formatDouble) + ), + + // Swap Button + ValueListenableBuilder( + valueListenable: exolicUCImpl.isReady, + builder: (context, isReady, wg) { + return MyButton( + edgeMargin: const EdgeInsets.all(paddingSize), + textButton: "Swap", + buttonColor: isReady == false ? AppColors.greyCode : AppColors.primaryBtn, + action: isReady == false ? null : + () async { + await exolicUCImpl.exolixSwap(); + }, + ); + } + ), + + ], + ), + ), + ); + } + + Widget _payInput(BuildContext context, ExolixExchangeUCImpl leUCImpl) { + return Padding( + padding: const EdgeInsets.only(top: paddingSize, left: paddingSize, right: paddingSize), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + + Padding( + padding: const EdgeInsets.only(right: 5), + child: Row( + children: [ + + MyTextConstant( + text: 'You send', + color2: hexaCodeToColor(AppColors.midNightBlue), + fontSize: 18, + ), + + ], + ), + ), + + Row( + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + + SizedBox( + width: MediaQuery.of(context).size.width / 2.50, + child: Container( + width: MediaQuery.of(context).size.width / 2.50, + padding: const EdgeInsets.only(top: paddingSize, left: paddingSize / 2, bottom: paddingSize), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(50.0), + color: hexaCodeToColor(AppColors.background) + ), + child: MyTextConstant( + textAlign: TextAlign.start, + text: leUCImpl.swapModel.amt!.value.isEmpty ? "0.00" : leUCImpl.swapModel.amt!.value.toString(), + fontSize: 20, + color2: leUCImpl.swapModel.amt!.value.isEmpty ? hexaCodeToColor(AppColors.grey) : hexaCodeToColor(AppColors.midNightBlue), + ), + ), + ), + ], + ), + + Expanded(child: Container()), + + ValueListenableBuilder( + valueListenable: leUCImpl.isLstCoinReady, + builder: (context, isLstCoinReady, wg){ + return isLstCoinReady == false + ? Shimmer.fromColors( + baseColor: hexaCodeToColor(AppColors.background), + highlightColor: hexaCodeToColor(AppColors.orangeColor), + child: Container( + width: MediaQuery.of(context).size.width / 2.20, + padding: const EdgeInsets.only(top: paddingSize, left: paddingSize / 2, bottom: paddingSize), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(50.0), + color: hexaCodeToColor(AppColors.background) + ), + child: const MyTextConstant( + text: "Token Loading...", + fontWeight: FontWeight.bold, + ), + ) + ) + + : InkWell( + onTap: (){ + + if (kDebugMode) { + // ignore: unnecessary_null_comparison + print(isLstCoinReady == null); + } + if (isLstCoinReady == true) leUCImpl.setCoin(context, true); + }, + child: SizedBox( + width: MediaQuery.of(context).size.width / 2.20, + child: Container( + width: MediaQuery.of(context).size.width / 2.20, + padding: const EdgeInsets.only(top: paddingSize, left: paddingSize / 2, bottom: paddingSize), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(50.0), + color: hexaCodeToColor(AppColors.background) + ), + child: ValueListenableBuilder( + valueListenable: leUCImpl.coin1, + builder: (context, coin1, wg) { + return Row( + children: [ + + MyTextConstant( + text: coin1.title ?? 'Select Token', + color2: coin1.title == null ? hexaCodeToColor(AppColors.grey) : hexaCodeToColor(AppColors.midNightBlue), + fontWeight: coin1.title == null ? FontWeight.normal : FontWeight.bold, + ), + + coin1.networkCode != null ? MyTextConstant( + text: " (${coin1.networkCode})", + color2: coin1.networkCode == null ? hexaCodeToColor(AppColors.grey) : hexaCodeToColor(AppColors.midNightBlue), + overflow: TextOverflow.ellipsis, + ) : const SizedBox(), + + const Spacer(), + + Icon(Iconsax.arrow_down_1, color: hexaCodeToColor(AppColors.orangeColor),), + + const SizedBox(width: 10), + ], + ); + } + ), + ), + ), + ); + } + ), + + ], + ), + + ], + ), + ); + } + + Widget _getDisplay(BuildContext context, ExolixExchangeUCImpl leUCImpl){ + return Padding( + padding: const EdgeInsets.only(left: paddingSize, right: paddingSize, bottom: paddingSize), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + + Padding( + padding: const EdgeInsets.only(right: 5), + child: MyTextConstant( + text: 'You recieve', + color2: hexaCodeToColor(AppColors.midNightBlue), + fontSize: 18, + ), + ), + + Row( + mainAxisSize: MainAxisSize.min, + children: [ + + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // pro.balance2.isNotEmpty ? + SizedBox( + width: MediaQuery.of(context).size.width / 2.50, + child: Container( + width: MediaQuery.of(context).size.width / 2.50, + padding: const EdgeInsets.only(top: paddingSize, left: paddingSize / 2, bottom: paddingSize), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(50.0), + color: hexaCodeToColor(AppColors.background) + ), + child: ValueListenableBuilder( + valueListenable: leUCImpl.receiveAmt, + builder: (context, receiveAmt, wg) { + return MyTextConstant( + textAlign: TextAlign.start, + // text: pro.lstConvertCoin![pro.name2] != null ? "≈ ${pro.lstConvertCoin![pro.name2]}" : "≈ 0", + text: "≈ $receiveAmt", + fontSize: 20, + ); + } + ), + ), + ) + ], + ), + + Expanded(child: Container()), + + ValueListenableBuilder( + valueListenable: leUCImpl.isLstCoinReady, + builder: (context, isLstCoinReady, wg){ + return isLstCoinReady == false + ? Shimmer.fromColors( + baseColor: hexaCodeToColor(AppColors.background), + highlightColor: hexaCodeToColor(AppColors.orangeColor), + child: Stack( + children: [ + Container( + width: MediaQuery.of(context).size.width / 2.20, + padding: const EdgeInsets.only(top: paddingSize, left: paddingSize / 2, bottom: paddingSize), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(50.0), + color: hexaCodeToColor(AppColors.background) + ), + child: const MyTextConstant( + text: "Token Loading...", + fontWeight: FontWeight.bold, + ), + ), + ], + ) + ) + + : InkWell( + onTap: (){ + + if (isLstCoinReady == true){ + + leUCImpl.setCoin(context, false); + } + }, + child: SizedBox( + width: MediaQuery.of(context).size.width / 2.20, + child: Container( + width: MediaQuery.of(context).size.width / 2.20, + padding: const EdgeInsets.only(top: paddingSize, left: paddingSize / 2, bottom: paddingSize), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(50.0), + color: hexaCodeToColor(AppColors.background) + ), + child: ValueListenableBuilder( + valueListenable: leUCImpl.coin2, + builder: (context, coin2, wg) { + return Row( + children: [ + MyTextConstant( + text: coin2.title ?? 'Select Token', + color2: coin2.title == null ? hexaCodeToColor(AppColors.grey) : hexaCodeToColor(AppColors.midNightBlue), + fontWeight: coin2.title == null ? FontWeight.normal : FontWeight.bold, + ), + + coin2.networkCode != null ? MyTextConstant( + text: " (${coin2.networkCode})", + color2: coin2.networkCode == null ? hexaCodeToColor(AppColors.grey) : hexaCodeToColor(AppColors.midNightBlue), + overflow: TextOverflow.ellipsis, + ) : const SizedBox(), + + const Spacer(), + + Icon(Iconsax.arrow_down_1, color: hexaCodeToColor(AppColors.orangeColor),), + + const SizedBox(width: 10), + ], + ); + } + ), + ), + ), + ); + } + ), + + ], + ), + ], + ), + ); + } + + /// dd stand for dropdown + Widget _ddTokenButton({Function()? onPressed, required int? i, required ExolixExchangeUCImpl exolixExchangeRepoImpl}){ + + return GestureDetector( + onTap: onPressed!, + child: Row( + mainAxisAlignment: MainAxisAlignment.end, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + + SizedBox( + height: 30, + width: 30, + child: ClipRRect( + borderRadius: BorderRadius.circular(50), + child: exolixExchangeRepoImpl.lstLECoin.value[0].image! + ), + ), + + const SizedBox(width: 5), + + MyTextConstant( + textAlign: TextAlign.start, + text: i == 0 ? exolixExchangeRepoImpl.lstLECoin.value[0].title : exolixExchangeRepoImpl.lstLECoin.value[1].title, + fontSize: 18, + color2: hexaCodeToColor("#949393"), + ), + + const Icon( + Iconsax.arrow_down_1, + size: 20 + ), + ], + ), + ); + } + + Widget _buildNumberPad(context, String valInput, Function onDeleteTxt, Function formatCurrency) { + return SwapNumPad( + buttonSize: 10, + valInput: valInput, + buttonColor: hexaCodeToColor("#FEFEFE"), + delete: onDeleteTxt, + formatCurrency: formatCurrency, + ); + } + +} \ No newline at end of file diff --git a/lib/presentation/screen/swap_lets_ex/status_exchange.dart b/lib/presentation/screen/swap_lets_ex/status_exchange.dart index 24e71c9e8..dd4e4db2d 100644 --- a/lib/presentation/screen/swap_lets_ex/status_exchange.dart +++ b/lib/presentation/screen/swap_lets_ex/status_exchange.dart @@ -28,7 +28,6 @@ class StatusExchange extends StatelessWidget { valueListenable: letsExchangeUCImpl!.lstTx, builder: (context, lst, wg) { - print(lst.length); if (lst.isEmpty){ return Center( child: Column( diff --git a/lib/presentation/screen/swap_lets_ex/swap_ex_screen.dart b/lib/presentation/screen/swap_lets_ex/swap_ex_screen.dart index f92ed10f3..8f77c776f 100644 --- a/lib/presentation/screen/swap_lets_ex/swap_ex_screen.dart +++ b/lib/presentation/screen/swap_lets_ex/swap_ex_screen.dart @@ -2,13 +2,13 @@ import 'package:bitriel_wallet/index.dart'; class SwapExchange extends StatelessWidget { - const SwapExchange({super.key}); + SwapExchange({super.key}); + + final LetsExchangeUCImpl letsExchangeUCImpl = LetsExchangeUCImpl(); @override Widget build(BuildContext context) { - final LetsExchangeUCImpl letsExchangeUCImpl = LetsExchangeUCImpl(); - letsExchangeUCImpl.setContext = context; letsExchangeUCImpl.getLetsExchangeCoin(); diff --git a/lib/presentation/widget/appbar_widget.dart b/lib/presentation/widget/appbar_widget.dart index 6b6244808..ee0086d9a 100644 --- a/lib/presentation/widget/appbar_widget.dart +++ b/lib/presentation/widget/appbar_widget.dart @@ -74,13 +74,14 @@ PreferredSizeWidget defaultAppBar({ child: Consumer( builder: (context, pro, wg) { if (pro.isConnected == false) return const SizedBox(); - return pro.getSdkImpl.getKeyring.current.icon == null ? - const CircleAvatar() : - RandomAvatar( - pro.getSdkImpl.getKeyring.current.icon!, - height: 40, - width: 40 - ); + + return pro.getSdkImpl.getKeyring.current.icon == null + ? const CircleAvatar() + : RandomAvatar( + pro.getSdkImpl.getKeyring.current.address!, + height: 40, + width: 40 + ); } ), ) diff --git a/lib/standalone/utils/routes/router.dart b/lib/standalone/utils/routes/router.dart index ad1285043..723988721 100644 --- a/lib/standalone/utils/routes/router.dart +++ b/lib/standalone/utils/routes/router.dart @@ -32,7 +32,7 @@ class AppRouter { "/${BitrielRouter.createWalletRoute}": (context) => const CreateWalletScreen(), "/${BitrielRouter.importWalletRoute}": (context) => const ImportWalletScreen(), "/${BitrielRouter.walletRoute}": (context) => const WalletScreen(), - "/${BitrielRouter.homeRoute}": (context) => const MainScreen(), + "/${BitrielRouter.homeRoute}": (context) => MainScreen(), }; } \ No newline at end of file diff --git a/pubspec.yaml b/pubspec.yaml index 6ebf65d81..2301be26e 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -75,7 +75,7 @@ dependencies: # ref: main easy_debounce: ^2.0.3 dropdown_button2: ^2.3.7 - flutter_inappwebview: ^5.7.2+3 + flutter_inappwebview: ^5.8.0 url_launcher: ^6.1.12 share_plus: ^7.1.0 icons_launcher: ^2.1.3