Refine peyawallet mining tab layout
This commit is contained in:
@@ -355,6 +355,7 @@
|
||||
"miningSoloHint": "Solo mode will target the local daemon bundled with the wallet.",
|
||||
"miningSoloNeedsLocalNode": "Solo mode expects the wallet to use the local node.",
|
||||
"miningPoolHint": "Default pool is preconfigured for Peya and can be adjusted here.",
|
||||
"miningPoolFixedHint": "Pool mode is fixed to the default Peya pool in this release. The endpoint is shown for visibility only.",
|
||||
"miningApiPortLabel": "XMRig API port",
|
||||
"miningResetDraftAction": "Reset draft",
|
||||
"miningConfigInvalid": "Enter a valid pool host and ports.",
|
||||
|
||||
@@ -1754,6 +1754,12 @@ abstract class AppLocalizations {
|
||||
/// **'Default pool is preconfigured for Peya and can be adjusted here.'**
|
||||
String get miningPoolHint;
|
||||
|
||||
/// No description provided for @miningPoolFixedHint.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Pool mode is fixed to the default Peya pool in this release. The endpoint is shown for visibility only.'**
|
||||
String get miningPoolFixedHint;
|
||||
|
||||
/// No description provided for @miningApiPortLabel.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
|
||||
@@ -884,6 +884,10 @@ class AppLocalizationsEn extends AppLocalizations {
|
||||
String get miningPoolHint =>
|
||||
'Default pool is preconfigured for Peya and can be adjusted here.';
|
||||
|
||||
@override
|
||||
String get miningPoolFixedHint =>
|
||||
'Pool mode is fixed to the default Peya pool in this release. The endpoint is shown for visibility only.';
|
||||
|
||||
@override
|
||||
String get miningApiPortLabel => 'XMRig API port';
|
||||
|
||||
|
||||
@@ -888,6 +888,10 @@ class AppLocalizationsPl extends AppLocalizations {
|
||||
String get miningPoolHint =>
|
||||
'Domyślny pool dla Peya jest już wpisany i można go tu zmienić.';
|
||||
|
||||
@override
|
||||
String get miningPoolFixedHint =>
|
||||
'Tryb pool jest w tym wydaniu na stałe spięty z domyślnym poolem Peya. Endpoint pokazujemy tylko informacyjnie.';
|
||||
|
||||
@override
|
||||
String get miningApiPortLabel => 'Port API XMRig';
|
||||
|
||||
|
||||
@@ -355,6 +355,7 @@
|
||||
"miningSoloHint": "Tryb solo będzie kierował kopanie do lokalnego daemona bundlowanego z walletem.",
|
||||
"miningSoloNeedsLocalNode": "Tryb solo zakłada, że portfel korzysta z lokalnego noda.",
|
||||
"miningPoolHint": "Domyślny pool dla Peya jest już wpisany i można go tu zmienić.",
|
||||
"miningPoolFixedHint": "Tryb pool jest w tym wydaniu na stałe spięty z domyślnym poolem Peya. Endpoint pokazujemy tylko informacyjnie.",
|
||||
"miningApiPortLabel": "Port API XMRig",
|
||||
"miningResetDraftAction": "Przywróć szkic",
|
||||
"miningConfigInvalid": "Podaj poprawny host poola i porty.",
|
||||
|
||||
+278
-308
@@ -5,7 +5,6 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:material_symbols_icons/material_symbols_icons.dart';
|
||||
|
||||
import '../../app_features.dart';
|
||||
import '../../domain/models.dart';
|
||||
import '../../state/providers.dart';
|
||||
import '../l10n/app_localizations_ext.dart';
|
||||
@@ -20,8 +19,6 @@ class MiningScreen extends ConsumerStatefulWidget {
|
||||
class _MiningScreenState extends ConsumerState<MiningScreen> {
|
||||
late MiningMode _mode;
|
||||
late int _cpuThreads;
|
||||
late final TextEditingController _poolHostController;
|
||||
late final TextEditingController _poolPortController;
|
||||
late final TextEditingController _apiPortController;
|
||||
bool _dirty = false;
|
||||
|
||||
@@ -31,15 +28,11 @@ class _MiningScreenState extends ConsumerState<MiningScreen> {
|
||||
final config = ref.read(appConfigControllerProvider).miningConfig;
|
||||
_mode = config.mode;
|
||||
_cpuThreads = config.cpuThreads;
|
||||
_poolHostController = TextEditingController(text: config.poolHost);
|
||||
_poolPortController = TextEditingController(text: config.poolPort.toString());
|
||||
_apiPortController = TextEditingController(text: config.apiPort.toString());
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_poolHostController.dispose();
|
||||
_poolPortController.dispose();
|
||||
_apiPortController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
@@ -51,14 +44,6 @@ class _MiningScreenState extends ConsumerState<MiningScreen> {
|
||||
final config = ref.watch(appConfigControllerProvider);
|
||||
final walletState = ref.watch(walletControllerProvider);
|
||||
final maxThreads = math.max(1, math.min(Platform.numberOfProcessors, 64));
|
||||
final poolHost = _poolHostController.text.trim();
|
||||
final poolPort = int.tryParse(_poolPortController.text.trim());
|
||||
final apiPort = int.tryParse(_apiPortController.text.trim());
|
||||
final canSave = poolHost.isNotEmpty &&
|
||||
poolPort != null &&
|
||||
poolPort > 0 &&
|
||||
apiPort != null &&
|
||||
apiPort > 0;
|
||||
|
||||
return SingleChildScrollView(
|
||||
padding: const EdgeInsets.all(24),
|
||||
@@ -82,295 +67,138 @@ class _MiningScreenState extends ConsumerState<MiningScreen> {
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
LayoutBuilder(
|
||||
builder: (context, constraints) {
|
||||
final wide = constraints.maxWidth >= 920;
|
||||
return Flex(
|
||||
direction: wide ? Axis.horizontal : Axis.vertical,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Expanded(
|
||||
flex: wide ? 3 : 0,
|
||||
child: Column(
|
||||
Column(
|
||||
children: [
|
||||
_SectionCard(
|
||||
title: l10n.miningControlsTitle,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Wrap(
|
||||
spacing: 12,
|
||||
runSpacing: 12,
|
||||
children: [
|
||||
_SectionCard(
|
||||
title: l10n.miningSourceTitle,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
DropdownButtonFormField<MiningMode>(
|
||||
value: _mode,
|
||||
decoration: InputDecoration(
|
||||
labelText: l10n.miningModeLabel,
|
||||
),
|
||||
items: [
|
||||
DropdownMenuItem(
|
||||
value: MiningMode.solo,
|
||||
child: Text(l10n.miningModeSolo),
|
||||
),
|
||||
DropdownMenuItem(
|
||||
value: MiningMode.pool,
|
||||
child: Text(l10n.miningModePool),
|
||||
),
|
||||
],
|
||||
onChanged: (value) {
|
||||
if (value == null) {
|
||||
return;
|
||||
}
|
||||
setState(() {
|
||||
_mode = value;
|
||||
_dirty = true;
|
||||
});
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
if (_mode == MiningMode.solo) ...[
|
||||
_InfoTile(
|
||||
label: l10n.miningTargetLabel,
|
||||
value: l10n.miningSoloTargetValue,
|
||||
icon: Symbols.lan,
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
Text(
|
||||
config.nodeConfig.mode == NodeMode.local
|
||||
? l10n.miningSoloHint
|
||||
: l10n.miningSoloNeedsLocalNode,
|
||||
style: theme.textTheme.bodyMedium?.copyWith(
|
||||
color: config.nodeConfig.mode == NodeMode.local
|
||||
? theme.colorScheme.onSurfaceVariant
|
||||
: theme.colorScheme.error,
|
||||
),
|
||||
),
|
||||
] else ...[
|
||||
TextFormField(
|
||||
controller: _poolHostController,
|
||||
decoration: InputDecoration(
|
||||
labelText: l10n.hostLabel,
|
||||
),
|
||||
onChanged: (_) => setState(() => _dirty = true),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
TextFormField(
|
||||
controller: _poolPortController,
|
||||
keyboardType: TextInputType.number,
|
||||
decoration: InputDecoration(
|
||||
labelText: l10n.portLabel,
|
||||
),
|
||||
onChanged: (_) => setState(() => _dirty = true),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
Text(
|
||||
l10n.miningPoolHint,
|
||||
style: theme.textTheme.bodyMedium?.copyWith(
|
||||
color: theme.colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
],
|
||||
const SizedBox(height: 20),
|
||||
DropdownButtonFormField<int>(
|
||||
value: _cpuThreads.clamp(1, maxThreads),
|
||||
decoration: InputDecoration(
|
||||
labelText: l10n.miningThreadsLabel,
|
||||
),
|
||||
items: [
|
||||
for (var value = 1; value <= maxThreads; value++)
|
||||
DropdownMenuItem(
|
||||
value: value,
|
||||
child: Text(value.toString()),
|
||||
),
|
||||
],
|
||||
onChanged: (value) {
|
||||
if (value == null) {
|
||||
return;
|
||||
}
|
||||
setState(() {
|
||||
_cpuThreads = value;
|
||||
_dirty = true;
|
||||
});
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
TextFormField(
|
||||
controller: _apiPortController,
|
||||
keyboardType: TextInputType.number,
|
||||
decoration: InputDecoration(
|
||||
labelText: l10n.miningApiPortLabel,
|
||||
),
|
||||
onChanged: (_) => setState(() => _dirty = true),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Row(
|
||||
children: [
|
||||
FilledButton.icon(
|
||||
onPressed: canSave ? _saveConfig : null,
|
||||
icon: const Icon(Symbols.save),
|
||||
label: Text(l10n.saveAction),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
OutlinedButton.icon(
|
||||
onPressed: _dirty ? _resetDraft : null,
|
||||
icon: const Icon(Symbols.undo),
|
||||
label: Text(l10n.miningResetDraftAction),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
FilledButton.icon(
|
||||
onPressed: null,
|
||||
icon: const Icon(Symbols.play_arrow),
|
||||
label: Text(l10n.miningStartAction),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
_SectionCard(
|
||||
title: l10n.miningControlsTitle,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Wrap(
|
||||
spacing: 12,
|
||||
runSpacing: 12,
|
||||
children: [
|
||||
FilledButton.icon(
|
||||
onPressed: null,
|
||||
icon: const Icon(Symbols.play_arrow),
|
||||
label: Text(l10n.miningStartAction),
|
||||
),
|
||||
OutlinedButton.icon(
|
||||
onPressed: null,
|
||||
icon: const Icon(Symbols.stop),
|
||||
label: Text(l10n.miningStopAction),
|
||||
),
|
||||
OutlinedButton.icon(
|
||||
onPressed: null,
|
||||
icon: const Icon(Symbols.refresh),
|
||||
label: Text(l10n.localNodeRestartAction),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
Text(
|
||||
l10n.miningBackendPending,
|
||||
style: theme.textTheme.bodyMedium?.copyWith(
|
||||
color: theme.colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
OutlinedButton.icon(
|
||||
onPressed: null,
|
||||
icon: const Icon(Symbols.stop),
|
||||
label: Text(l10n.miningStopAction),
|
||||
),
|
||||
OutlinedButton.icon(
|
||||
onPressed: null,
|
||||
icon: const Icon(Symbols.refresh),
|
||||
label: Text(l10n.localNodeRestartAction),
|
||||
),
|
||||
OutlinedButton.icon(
|
||||
onPressed: () => _showSettingsDialog(maxThreads),
|
||||
icon: const Icon(Symbols.settings),
|
||||
label: Text(l10n.miningSettingsAction),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
SizedBox(width: wide ? 16 : 0, height: wide ? 0 : 16),
|
||||
Expanded(
|
||||
flex: wide ? 2 : 0,
|
||||
child: Column(
|
||||
children: [
|
||||
_SectionCard(
|
||||
title: l10n.miningStatsTitle,
|
||||
child: Wrap(
|
||||
spacing: 12,
|
||||
runSpacing: 12,
|
||||
children: [
|
||||
_StatTile(
|
||||
label: l10n.transactionStatusLabel,
|
||||
value: l10n.comingSoon,
|
||||
),
|
||||
_StatTile(
|
||||
label: l10n.miningHashrate10sLabel,
|
||||
value: l10n.miningDataUnknownValue,
|
||||
),
|
||||
_StatTile(
|
||||
label: l10n.miningHashrate1mLabel,
|
||||
value: l10n.miningDataUnknownValue,
|
||||
),
|
||||
_StatTile(
|
||||
label: l10n.miningLabelHashrate15m,
|
||||
value: l10n.miningDataUnknownValue,
|
||||
),
|
||||
_StatTile(
|
||||
label: l10n.miningJobsLabel,
|
||||
value: l10n.miningDataUnknownValue,
|
||||
),
|
||||
_StatTile(
|
||||
label: l10n.miningAcceptedSharesLabel,
|
||||
value: l10n.miningDataUnknownValue,
|
||||
),
|
||||
_StatTile(
|
||||
label: l10n.miningRejectedSharesLabel,
|
||||
value: l10n.miningDataUnknownValue,
|
||||
),
|
||||
_StatTile(
|
||||
label: l10n.miningLabelUptime,
|
||||
value: l10n.miningDataUnknownValue,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
_SectionCard(
|
||||
title: l10n.miningCurrentConfigTitle,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
_InfoTile(
|
||||
label: l10n.miningWalletAddressLabel,
|
||||
value: walletState.walletInfo?.address.isNotEmpty == true
|
||||
? walletState.walletInfo!.address
|
||||
: l10n.miningNoWalletAddress,
|
||||
icon: Symbols.account_balance_wallet,
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
_InfoTile(
|
||||
label: l10n.miningModeLabel,
|
||||
value: config.miningConfig.mode == MiningMode.solo
|
||||
? l10n.miningModeSolo
|
||||
: '${config.miningConfig.poolHost}:${config.miningConfig.poolPort}',
|
||||
icon: config.miningConfig.mode == MiningMode.solo
|
||||
? Symbols.lan
|
||||
: Symbols.hub,
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
_InfoTile(
|
||||
label: l10n.miningThreadsLabel,
|
||||
value: config.miningConfig.cpuThreads.toString(),
|
||||
icon: Symbols.memory,
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
_InfoTile(
|
||||
label: l10n.miningApiPortLabel,
|
||||
value: config.miningConfig.apiPort.toString(),
|
||||
icon: Symbols.settings_ethernet,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
_SectionCard(
|
||||
title: l10n.miningBundledTitle,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
AppFeatures.isMiningFlavor
|
||||
? l10n.miningBundledEnabled
|
||||
: l10n.miningBundledDisabled,
|
||||
style: theme.textTheme.bodyMedium?.copyWith(
|
||||
color: theme.colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
Text(
|
||||
l10n.miningBundledBody,
|
||||
style: theme.textTheme.bodySmall?.copyWith(
|
||||
color: theme.colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
const SizedBox(height: 12),
|
||||
Text(
|
||||
l10n.miningBackendPending,
|
||||
style: theme.textTheme.bodyMedium?.copyWith(
|
||||
color: theme.colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
_SectionCard(
|
||||
title: l10n.miningCurrentConfigTitle,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
_InfoTile(
|
||||
label: l10n.miningWalletAddressLabel,
|
||||
value: walletState.walletInfo?.address.isNotEmpty == true
|
||||
? walletState.walletInfo!.address
|
||||
: l10n.miningNoWalletAddress,
|
||||
icon: Symbols.account_balance_wallet,
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
_InfoTile(
|
||||
label: l10n.miningModeLabel,
|
||||
value: config.miningConfig.mode == MiningMode.solo
|
||||
? l10n.miningModeSolo
|
||||
: '${config.miningConfig.poolHost}:${config.miningConfig.poolPort}',
|
||||
icon: config.miningConfig.mode == MiningMode.solo
|
||||
? Symbols.lan
|
||||
: Symbols.hub,
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
_InfoTile(
|
||||
label: l10n.miningTargetLabel,
|
||||
value: config.miningConfig.mode == MiningMode.solo
|
||||
? l10n.miningSoloTargetValue
|
||||
: '${config.miningConfig.poolHost}:${config.miningConfig.poolPort}',
|
||||
icon: Symbols.route,
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
_InfoTile(
|
||||
label: l10n.miningThreadsLabel,
|
||||
value: config.miningConfig.cpuThreads.toString(),
|
||||
icon: Symbols.memory,
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
_InfoTile(
|
||||
label: l10n.miningApiPortLabel,
|
||||
value: config.miningConfig.apiPort.toString(),
|
||||
icon: Symbols.settings_ethernet,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
_SectionCard(
|
||||
title: l10n.miningStatsTitle,
|
||||
child: Wrap(
|
||||
spacing: 12,
|
||||
runSpacing: 12,
|
||||
children: [
|
||||
_StatTile(
|
||||
label: l10n.transactionStatusLabel,
|
||||
value: l10n.comingSoon,
|
||||
),
|
||||
_StatTile(
|
||||
label: l10n.miningHashrate10sLabel,
|
||||
value: l10n.miningDataUnknownValue,
|
||||
),
|
||||
_StatTile(
|
||||
label: l10n.miningHashrate1mLabel,
|
||||
value: l10n.miningDataUnknownValue,
|
||||
),
|
||||
_StatTile(
|
||||
label: l10n.miningLabelHashrate15m,
|
||||
value: l10n.miningDataUnknownValue,
|
||||
),
|
||||
_StatTile(
|
||||
label: l10n.miningJobsLabel,
|
||||
value: l10n.miningDataUnknownValue,
|
||||
),
|
||||
_StatTile(
|
||||
label: l10n.miningAcceptedSharesLabel,
|
||||
value: l10n.miningDataUnknownValue,
|
||||
),
|
||||
_StatTile(
|
||||
label: l10n.miningRejectedSharesLabel,
|
||||
value: l10n.miningDataUnknownValue,
|
||||
),
|
||||
_StatTile(
|
||||
label: l10n.miningLabelUptime,
|
||||
value: l10n.miningDataUnknownValue,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -384,8 +212,6 @@ class _MiningScreenState extends ConsumerState<MiningScreen> {
|
||||
setState(() {
|
||||
_mode = config.mode;
|
||||
_cpuThreads = config.cpuThreads;
|
||||
_poolHostController.text = config.poolHost;
|
||||
_poolPortController.text = config.poolPort.toString();
|
||||
_apiPortController.text = config.apiPort.toString();
|
||||
_dirty = false;
|
||||
});
|
||||
@@ -393,13 +219,8 @@ class _MiningScreenState extends ConsumerState<MiningScreen> {
|
||||
|
||||
Future<void> _saveConfig() async {
|
||||
final l10n = context.l10n;
|
||||
final port = int.tryParse(_poolPortController.text.trim());
|
||||
final apiPort = int.tryParse(_apiPortController.text.trim());
|
||||
if (_poolHostController.text.trim().isEmpty ||
|
||||
port == null ||
|
||||
port <= 0 ||
|
||||
apiPort == null ||
|
||||
apiPort <= 0) {
|
||||
if (apiPort == null || apiPort <= 0) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(content: Text(l10n.miningConfigInvalid)),
|
||||
);
|
||||
@@ -409,8 +230,8 @@ class _MiningScreenState extends ConsumerState<MiningScreen> {
|
||||
final next = MiningConfig(
|
||||
mode: _mode,
|
||||
cpuThreads: _cpuThreads,
|
||||
poolHost: _poolHostController.text.trim(),
|
||||
poolPort: port,
|
||||
poolHost: 'peya.cryptohash.top',
|
||||
poolPort: 3333,
|
||||
apiPort: apiPort,
|
||||
);
|
||||
await ref.read(appConfigControllerProvider.notifier).setMiningConfig(next);
|
||||
@@ -422,6 +243,155 @@ class _MiningScreenState extends ConsumerState<MiningScreen> {
|
||||
SnackBar(content: Text(l10n.miningSettingsSaved)),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _showSettingsDialog(int maxThreads) async {
|
||||
final l10n = context.l10n;
|
||||
final theme = Theme.of(context);
|
||||
await showDialog<void>(
|
||||
context: context,
|
||||
builder: (dialogContext) {
|
||||
return AlertDialog(
|
||||
backgroundColor: theme.colorScheme.surface,
|
||||
title: Text(l10n.miningSettingsAction),
|
||||
content: SizedBox(
|
||||
width: 520,
|
||||
child: StatefulBuilder(
|
||||
builder: (context, setDialogState) {
|
||||
return Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
DropdownButtonFormField<MiningMode>(
|
||||
value: _mode,
|
||||
dropdownColor: theme.colorScheme.surface,
|
||||
decoration: InputDecoration(
|
||||
labelText: l10n.miningModeLabel,
|
||||
),
|
||||
items: [
|
||||
DropdownMenuItem(
|
||||
value: MiningMode.solo,
|
||||
child: Text(l10n.miningModeSolo),
|
||||
),
|
||||
DropdownMenuItem(
|
||||
value: MiningMode.pool,
|
||||
child: Text(l10n.miningModePool),
|
||||
),
|
||||
],
|
||||
onChanged: (value) {
|
||||
if (value == null) {
|
||||
return;
|
||||
}
|
||||
setState(() {
|
||||
_mode = value;
|
||||
_dirty = true;
|
||||
});
|
||||
setDialogState(() {});
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
if (_mode == MiningMode.solo) ...[
|
||||
_InfoTile(
|
||||
label: l10n.miningTargetLabel,
|
||||
value: l10n.miningSoloTargetValue,
|
||||
icon: Symbols.lan,
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
Text(
|
||||
ref.read(appConfigControllerProvider).nodeConfig.mode ==
|
||||
NodeMode.local
|
||||
? l10n.miningSoloHint
|
||||
: l10n.miningSoloNeedsLocalNode,
|
||||
style: theme.textTheme.bodyMedium?.copyWith(
|
||||
color: ref.read(appConfigControllerProvider).nodeConfig.mode ==
|
||||
NodeMode.local
|
||||
? theme.colorScheme.onSurfaceVariant
|
||||
: theme.colorScheme.error,
|
||||
),
|
||||
),
|
||||
] else ...[
|
||||
_InfoTile(
|
||||
label: l10n.miningTargetLabel,
|
||||
value: 'peya.cryptohash.top:3333',
|
||||
icon: Symbols.hub,
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
Text(
|
||||
l10n.miningPoolFixedHint,
|
||||
style: theme.textTheme.bodyMedium?.copyWith(
|
||||
color: theme.colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
],
|
||||
const SizedBox(height: 20),
|
||||
Text(
|
||||
'${l10n.miningThreadsLabel}: $_cpuThreads',
|
||||
style: theme.textTheme.titleSmall?.copyWith(
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
Slider(
|
||||
value: _cpuThreads.toDouble(),
|
||||
min: 1,
|
||||
max: maxThreads.toDouble(),
|
||||
divisions: math.max(0, maxThreads - 1),
|
||||
label: _cpuThreads.toString(),
|
||||
onChanged: (value) {
|
||||
final next = value.round();
|
||||
setState(() {
|
||||
_cpuThreads = next;
|
||||
_dirty = true;
|
||||
});
|
||||
setDialogState(() {});
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
TextFormField(
|
||||
controller: _apiPortController,
|
||||
keyboardType: TextInputType.number,
|
||||
decoration: InputDecoration(
|
||||
labelText: l10n.miningApiPortLabel,
|
||||
),
|
||||
onChanged: (_) {
|
||||
setState(() => _dirty = true);
|
||||
setDialogState(() {});
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
_resetDraft();
|
||||
Navigator.of(dialogContext).pop();
|
||||
},
|
||||
child: Text(l10n.miningResetDraftAction),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () => Navigator.of(dialogContext).pop(),
|
||||
child: Text(l10n.cancelAction),
|
||||
),
|
||||
FilledButton(
|
||||
onPressed: () {
|
||||
final apiPort = int.tryParse(_apiPortController.text.trim());
|
||||
return apiPort != null && apiPort > 0;
|
||||
}()
|
||||
? () async {
|
||||
await _saveConfig();
|
||||
if (mounted) {
|
||||
Navigator.of(dialogContext).pop();
|
||||
}
|
||||
}
|
||||
: null,
|
||||
child: Text(l10n.saveAction),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _SectionCard extends StatelessWidget {
|
||||
|
||||
Reference in New Issue
Block a user