Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion app/lib/screens/farm_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ class _FarmScreenState extends State<FarmScreen> {
);
} else {
mainWidget = ListView(
children: [for (final farm in farms) FarmItemWidget(farm: farm)]);
children: [for (final farm in farms) FarmItemWidget(farm: farm, wallets: wallets,)]);
}
return LayoutDrawer(
titleText: 'Farming',
Expand Down
20 changes: 20 additions & 0 deletions app/lib/services/tfchain_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,26 @@ Future<Farm?> createFarm(
}
}

Future<void> addStellarAddress(
String tfchainSeed, int farmId, String stellarAddress) async {
final chainUrl = Globals().chainUrl;
final client = TFChain.Client(chainUrl, tfchainSeed, 'sr25519');

try {
final twinId = await getTwinIdByClient(client);
if (twinId == 0) {
await activateAccount(tfchainSeed);
}
await client.connect();
await client.farms
.addStellarAddress(farmId: farmId, stellarAddress: stellarAddress);
} catch (e) {
throw Exception('Failed to add stellar address to farm due to $e');
} finally {
await client.disconnect();
}
}

Future<void> transfer(String secret, String dest, String amount) async {
final chainUrl = Globals().chainUrl;
final client = TFChain.Client(chainUrl, secret, 'sr25519');
Expand Down
218 changes: 203 additions & 15 deletions app/lib/widgets/farm_item.dart
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:threebotlogin/helpers/logger.dart';
import 'package:threebotlogin/models/farm.dart';
import 'package:threebotlogin/models/wallet.dart';
import 'package:threebotlogin/screens/wallets/contacts.dart';
import 'package:threebotlogin/services/stellar_service.dart';
import 'package:threebotlogin/services/tfchain_service.dart';
import 'package:threebotlogin/widgets/farm_node_item.dart';

class FarmItemWidget extends StatefulWidget {
const FarmItemWidget({super.key, required this.farm});
const FarmItemWidget({super.key, required this.farm, required this.wallets});
final Farm farm;
final List<Wallet> wallets;

@override
State<FarmItemWidget> createState() => _FarmItemWidgetState();
Expand All @@ -18,6 +25,19 @@ class _FarmItemWidgetState extends State<FarmItemWidget> {
final twinIdController = TextEditingController();
final farmIdController = TextEditingController();
bool showTfchainSecret = false;
bool edit = false;
bool isSaving = false;
final walletFocus = FocusNode();
ChainType chainType = ChainType.Stellar;
String? addressError;
String? currentAddress;

@override
void initState() {
super.initState();
currentAddress = widget.farm.walletAddress;
walletAddressController.text = currentAddress!;
}

@override
void dispose() {
Expand All @@ -29,9 +49,102 @@ class _FarmItemWidgetState extends State<FarmItemWidget> {
super.dispose();
}

_editStellarPayoutAddress() async {
setState(() {
isSaving = true;
});

final String newAddress = walletAddressController.text.trim();
if (newAddress == currentAddress) {
FocusScope.of(context).requestFocus(walletFocus);
setState(() {
isSaving = false;
edit = false;
});
return;
}

try {
await addStellarAddress(
widget.farm.tfchainWalletSecret,
widget.farm.farmId,
newAddress,
);
final savingAddressSuccess = SnackBar(
content: Text(
'Address is saved Successfully.',
style: Theme.of(context).textTheme.bodyMedium!.copyWith(
color: Theme.of(context).colorScheme.surface,
),
),
duration: const Duration(seconds: 3),
);
setState(() {
currentAddress = newAddress;
});
ScaffoldMessenger.of(context).clearSnackBars();
ScaffoldMessenger.of(context).showSnackBar(savingAddressSuccess);
} catch (e) {
logger.e('Failed to add stellar address due to $e');
if (context.mounted) {
final savingAddressFailure = SnackBar(
content: Text(
'Failed to Add Stellar address',
style: Theme.of(context).textTheme.bodyMedium!.copyWith(
color: Theme.of(context).colorScheme.errorContainer,
),
),
duration: const Duration(seconds: 3),
);
ScaffoldMessenger.of(context).clearSnackBars();
ScaffoldMessenger.of(context).showSnackBar(savingAddressFailure);
}
} finally {
setState(() {
edit = false;
isSaving = false;
});
}
}

void validateStellarAddress(String address) async {
setState(() {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please trim the address before start validating

addressError =
Comment thread
AlaaElattar marked this conversation as resolved.
isValidStellarAddress(address) ? null : 'Invalid Stellar address';
});

if (addressError == null) {
try {
final balance = await getBalanceByAccountId(address);
if (balance == '-1') {
setState(() {
addressError = 'Wallet not activated on stellar';
});
}
} catch (e) {
setState(() {
addressError = 'Error fetching account balance';
});
}
}
}

void _selectAddress(String address) {
setState(() {
walletAddressController.text = address;
});
}

void _cancelEdit() {
setState(() {
edit = false;
walletAddressController.text = currentAddress!;
addressError = null;
});
}

@override
Widget build(BuildContext context) {
walletAddressController.text = widget.farm.walletAddress;
tfchainWalletSecretController.text = widget.farm.tfchainWalletSecret;
walletNameController.text = widget.farm.walletName;
farmIdController.text = widget.farm.farmId.toString();
Expand All @@ -48,24 +161,99 @@ class _FarmItemWidgetState extends State<FarmItemWidget> {
children: [
ListTile(
title: TextField(
readOnly: true,
focusNode: walletFocus,
autofocus: edit,
readOnly: !edit,
style: Theme.of(context).textTheme.bodyMedium!.copyWith(
color: Theme.of(context).colorScheme.onSurface,
),
controller: walletAddressController,
decoration: const InputDecoration(
labelText: 'Stellar Payout Address',
)),
subtitle: const Text('This address will be used for payout.'),
trailing: IconButton(
onPressed: () {
Clipboard.setData(
ClipboardData(text: walletAddressController.text));
ScaffoldMessenger.of(context).clearSnackBars();
ScaffoldMessenger.of(context)
.showSnackBar(const SnackBar(content: Text('Copied!')));
onChanged: (value) {
validateStellarAddress(value.trim());
},
icon: const Icon(Icons.copy)),
decoration: InputDecoration(
errorText: addressError,
labelText: 'Stellar Payout Address',
suffixIcon: edit
? IconButton(
onPressed: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => ContractsScreen(
chainType: chainType,
currentWalletAddress: currentAddress!,
wallets: widget.wallets
.where((w) =>
double.parse(w.stellarBalance) >= 0)
.toList(),
onSelectToAddress: _selectAddress),
));
},
icon: const Icon(Icons.person))
: null)),
subtitle: const Text('This address will be used for payout.'),
trailing: isSaving
? Transform.scale(
scale: 0.5, child: const CircularProgressIndicator())
: edit
? SizedBox(
width: 100,
child: Row(
children: [
IconButton(
onPressed: addressError == null
? () {
_editStellarPayoutAddress();
}
: null,
icon: Icon(
Icons.save,
color: addressError == null
? Theme.of(context).colorScheme.onSurface
: Theme.of(context)
.colorScheme
.onSurfaceVariant,
),
),
IconButton(
onPressed: _cancelEdit,
icon: const Icon(
Icons.cancel_outlined,
),
)
],
),
)
: SizedBox(
width: 100,
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
IconButton(
onPressed: () {
setState(() {
edit = !edit;
});
if (edit) {
FocusScope.of(context)
.requestFocus(walletFocus);
}
},
icon: edit
? const Icon(Icons.save)
: const Icon(Icons.edit)),
IconButton(
onPressed: () {
Clipboard.setData(ClipboardData(
text: walletAddressController.text));
ScaffoldMessenger.of(context).clearSnackBars();
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Copied!')));
},
icon: const Icon(Icons.copy),
),
],
),
),
),
ListTile(
title: TextField(
Expand Down