329 lines
12 KiB
Dart
329 lines
12 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:flutter/services.dart';
|
|
import 'package:provider/provider.dart';
|
|
import 'package:intl/intl.dart';
|
|
import '../providers/price_provider.dart';
|
|
|
|
class VendorTable extends StatefulWidget {
|
|
const VendorTable({super.key});
|
|
|
|
@override
|
|
State<VendorTable> createState() => _VendorTableState();
|
|
}
|
|
|
|
class _VendorTableState extends State<VendorTable> {
|
|
final _customAmountController = TextEditingController();
|
|
String _selectedPreset = '1T';
|
|
double _customAmount = 1000000000000; // 1 trillion AUEC
|
|
bool _showCustomInput = false;
|
|
|
|
// Preset AUEC amounts
|
|
static const Map<String, double> _presetAmounts = {
|
|
'10T': 10000000000000,
|
|
'5T': 5000000000000,
|
|
'1T': 1000000000000,
|
|
'750B': 750000000000,
|
|
'500B': 500000000000,
|
|
'250B': 250000000000,
|
|
'Other': 0, // Special case for custom input
|
|
};
|
|
|
|
@override
|
|
void dispose() {
|
|
_customAmountController.dispose();
|
|
super.dispose();
|
|
}
|
|
|
|
void _updateAmount(String preset) {
|
|
setState(() {
|
|
_selectedPreset = preset;
|
|
if (preset == 'Other') {
|
|
_showCustomInput = true;
|
|
_customAmountController.text = _customAmount.toStringAsFixed(0);
|
|
} else {
|
|
_showCustomInput = false;
|
|
_customAmount = _presetAmounts[preset]!;
|
|
}
|
|
});
|
|
}
|
|
|
|
void _setCustomAmount() {
|
|
final amount = double.tryParse(_customAmountController.text);
|
|
if (amount != null && amount > 0) {
|
|
setState(() {
|
|
_customAmount = amount;
|
|
});
|
|
}
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Container(
|
|
padding: const EdgeInsets.all(16),
|
|
decoration: BoxDecoration(
|
|
color: const Color(0xFF1A1F3A),
|
|
borderRadius: BorderRadius.circular(4),
|
|
border: Border.all(color: const Color(0xFF50E3C2), width: 1),
|
|
),
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Row(
|
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
children: [
|
|
Consumer<PriceProvider>(
|
|
builder: (context, provider, child) {
|
|
final count = provider.latestPrice?.allPrices.length ?? 0;
|
|
return Text(
|
|
'Current Listings ($count)',
|
|
style: const TextStyle(
|
|
color: Colors.white,
|
|
fontSize: 18,
|
|
fontWeight: FontWeight.bold,
|
|
fontFamily: 'monospace',
|
|
),
|
|
);
|
|
},
|
|
),
|
|
// AUEC amount selector
|
|
Row(
|
|
children: [
|
|
// Dropdown for preset amounts
|
|
Container(
|
|
height: 32,
|
|
padding: const EdgeInsets.symmetric(horizontal: 8),
|
|
decoration: BoxDecoration(
|
|
color: const Color(0xFF2A2F4A),
|
|
borderRadius: BorderRadius.circular(4),
|
|
border: Border.all(color: const Color(0xFF50E3C2), width: 1),
|
|
),
|
|
child: DropdownButtonHideUnderline(
|
|
child: DropdownButton<String>(
|
|
value: _selectedPreset,
|
|
dropdownColor: const Color(0xFF2A2F4A),
|
|
style: const TextStyle(
|
|
color: Colors.white,
|
|
fontSize: 12,
|
|
fontFamily: 'monospace',
|
|
),
|
|
alignment: AlignmentDirectional.center,
|
|
items: _presetAmounts.keys.map((String preset) {
|
|
return DropdownMenuItem<String>(
|
|
value: preset,
|
|
alignment: AlignmentDirectional.center,
|
|
child: Text(
|
|
preset,
|
|
style: const TextStyle(
|
|
color: Colors.white,
|
|
fontSize: 12,
|
|
fontFamily: 'monospace',
|
|
),
|
|
textAlign: TextAlign.center,
|
|
),
|
|
);
|
|
}).toList(),
|
|
onChanged: (String? newValue) {
|
|
if (newValue != null) {
|
|
_updateAmount(newValue);
|
|
}
|
|
},
|
|
),
|
|
),
|
|
),
|
|
if (_showCustomInput) ...[
|
|
const SizedBox(width: 8),
|
|
Container(
|
|
width: 120,
|
|
height: 32,
|
|
decoration: BoxDecoration(
|
|
color: const Color(0xFF2A2F4A),
|
|
borderRadius: BorderRadius.circular(4),
|
|
border: Border.all(color: const Color(0xFF50E3C2), width: 1),
|
|
),
|
|
child: TextField(
|
|
controller: _customAmountController,
|
|
style: const TextStyle(
|
|
color: Colors.white,
|
|
fontSize: 12,
|
|
fontFamily: 'monospace',
|
|
),
|
|
decoration: const InputDecoration(
|
|
border: InputBorder.none,
|
|
contentPadding: EdgeInsets.symmetric(horizontal: 8, vertical: 8),
|
|
hintText: 'Enter amount',
|
|
hintStyle: TextStyle(
|
|
color: Color(0xFF888888),
|
|
fontSize: 11,
|
|
),
|
|
),
|
|
textAlignVertical: TextAlignVertical.center,
|
|
textAlign: TextAlign.center,
|
|
keyboardType: TextInputType.number,
|
|
inputFormatters: [
|
|
FilteringTextInputFormatter.digitsOnly,
|
|
],
|
|
onSubmitted: (_) => _setCustomAmount(),
|
|
),
|
|
),
|
|
const SizedBox(width: 8),
|
|
ElevatedButton(
|
|
onPressed: _setCustomAmount,
|
|
style: ElevatedButton.styleFrom(
|
|
backgroundColor: const Color(0xFF50E3C2),
|
|
foregroundColor: const Color(0xFF0A0E27),
|
|
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 6),
|
|
minimumSize: const Size(0, 32),
|
|
),
|
|
child: const Text(
|
|
'Set',
|
|
style: TextStyle(
|
|
fontSize: 12,
|
|
fontWeight: FontWeight.bold,
|
|
),
|
|
),
|
|
),
|
|
],
|
|
],
|
|
),
|
|
],
|
|
),
|
|
const SizedBox(height: 16),
|
|
Consumer<PriceProvider>(
|
|
builder: (context, provider, child) {
|
|
if (provider.latestPrice == null) {
|
|
return const Center(
|
|
child: Padding(
|
|
padding: EdgeInsets.all(20),
|
|
child: Text(
|
|
'Loading vendor data...',
|
|
style: TextStyle(color: Color(0xFF888888)),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
final prices = provider.latestPrice!.allPrices;
|
|
final sortedPrices = List.from(prices)
|
|
..sort((a, b) => a.pricePerMillion.compareTo(b.pricePerMillion));
|
|
|
|
return SizedBox(
|
|
width: double.infinity, // Force full width
|
|
child: SingleChildScrollView(
|
|
scrollDirection: Axis.horizontal,
|
|
child: ConstrainedBox(
|
|
constraints: BoxConstraints(
|
|
minWidth: MediaQuery.of(context).size.width - 64, // Account for padding
|
|
),
|
|
child: DataTable(
|
|
headingRowColor: WidgetStateProperty.all(const Color(0xFF2A2F4A)),
|
|
dataRowColor: WidgetStateProperty.all(const Color(0xFF1A1F3A)),
|
|
headingRowHeight: 40,
|
|
dataRowMinHeight: 36,
|
|
dataRowMaxHeight: 36,
|
|
columnSpacing: 32,
|
|
columns: [
|
|
const DataColumn(
|
|
label: Text(
|
|
'Platform',
|
|
style: TextStyle(
|
|
color: Color(0xFF888888),
|
|
fontWeight: FontWeight.bold,
|
|
fontSize: 12,
|
|
fontFamily: 'monospace',
|
|
),
|
|
),
|
|
),
|
|
const DataColumn(
|
|
label: Text(
|
|
'Seller',
|
|
style: TextStyle(
|
|
color: Color(0xFF888888),
|
|
fontWeight: FontWeight.bold,
|
|
fontSize: 12,
|
|
fontFamily: 'monospace',
|
|
),
|
|
),
|
|
),
|
|
const DataColumn(
|
|
label: Text(
|
|
'Price/1M AUEC',
|
|
style: TextStyle(
|
|
color: Color(0xFF888888),
|
|
fontWeight: FontWeight.bold,
|
|
fontSize: 12,
|
|
fontFamily: 'monospace',
|
|
),
|
|
),
|
|
),
|
|
DataColumn(
|
|
label: Text(
|
|
'Price for ${NumberFormat('#,###').format(_customAmount)} AUEC',
|
|
style: const TextStyle(
|
|
color: Color(0xFF888888),
|
|
fontWeight: FontWeight.bold,
|
|
fontSize: 12,
|
|
fontFamily: 'monospace',
|
|
),
|
|
),
|
|
),
|
|
],
|
|
rows: sortedPrices.map((price) {
|
|
final totalPrice = (_customAmount / 1000000) * price.pricePerMillion;
|
|
return DataRow(
|
|
cells: [
|
|
DataCell(
|
|
Text(
|
|
price.platform,
|
|
style: const TextStyle(
|
|
color: Colors.white,
|
|
fontSize: 12,
|
|
fontFamily: 'monospace',
|
|
),
|
|
),
|
|
),
|
|
DataCell(
|
|
Text(
|
|
price.sellerName,
|
|
style: const TextStyle(
|
|
color: Colors.white,
|
|
fontSize: 12,
|
|
fontFamily: 'monospace',
|
|
),
|
|
),
|
|
),
|
|
DataCell(
|
|
Text(
|
|
'\$${price.pricePerMillion.toStringAsFixed(10)}',
|
|
style: const TextStyle(
|
|
color: Color(0xFF50E3C2),
|
|
fontWeight: FontWeight.bold,
|
|
fontSize: 12,
|
|
fontFamily: 'monospace',
|
|
),
|
|
),
|
|
),
|
|
DataCell(
|
|
Text(
|
|
'\$${totalPrice.toStringAsFixed(2)}',
|
|
style: const TextStyle(
|
|
color: Color(0xFF50E3C2),
|
|
fontWeight: FontWeight.bold,
|
|
fontSize: 12,
|
|
fontFamily: 'monospace',
|
|
),
|
|
),
|
|
),
|
|
],
|
|
);
|
|
}).toList(),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
},
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
} |