mirror of
https://github.com/localsend/localsend.git
synced 2026-08-07 07:14:52 +00:00
feat: do not show hashtag
This commit is contained in:
@@ -9,7 +9,6 @@ import 'package:localsend_app/provider/animation_provider.dart';
|
||||
import 'package:localsend_app/provider/local_ip_provider.dart';
|
||||
import 'package:localsend_app/provider/network/server/server_provider.dart';
|
||||
import 'package:localsend_app/provider/settings_provider.dart';
|
||||
import 'package:localsend_app/util/ip_helper.dart';
|
||||
import 'package:localsend_app/widget/animations/initial_fade_transition.dart';
|
||||
import 'package:localsend_app/widget/column_list_view.dart';
|
||||
import 'package:localsend_app/widget/custom_icon_button.dart';
|
||||
@@ -94,7 +93,7 @@ class _ReceiveTabState extends State<ReceiveTab> {
|
||||
duration: const Duration(milliseconds: 300),
|
||||
delay: const Duration(milliseconds: 500),
|
||||
child: Text(
|
||||
serverState == null ? t.general.offline : localIps.map((ip) => '#${ip.visualId}').toSet().join(' '),
|
||||
serverState == null ? t.general.offline : t.general.online,
|
||||
style: const TextStyle(fontSize: 24),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
import 'package:collection/collection.dart';
|
||||
|
||||
extension StringIpExt on String {
|
||||
String get visualId => split('.').last;
|
||||
}
|
||||
|
||||
class IpHelper {
|
||||
/// Sorts Ip addresses with first being the most likely primary local address
|
||||
/// Currently,
|
||||
|
||||
@@ -17,20 +17,7 @@ import 'package:localsend_isolates/util/rust.dart';
|
||||
import 'package:refena_flutter/refena_flutter.dart';
|
||||
import 'package:routerino/routerino.dart';
|
||||
|
||||
enum _InputMode {
|
||||
hashtag,
|
||||
ip
|
||||
;
|
||||
|
||||
String get label {
|
||||
return switch (this) {
|
||||
_InputMode.hashtag => t.dialogs.addressInput.hashtag,
|
||||
_InputMode.ip => t.dialogs.addressInput.ip,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// A dialog to input an hash or address.
|
||||
/// A dialog to input an address.
|
||||
/// Pops the dialog with the device if found.
|
||||
class AddressInputDialog extends StatefulWidget {
|
||||
const AddressInputDialog();
|
||||
@@ -40,22 +27,12 @@ class AddressInputDialog extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _AddressInputDialogState extends State<AddressInputDialog> with Refena {
|
||||
final _selected = List.generate(_InputMode.values.length, (index) => index == 0);
|
||||
_InputMode _mode = _InputMode.hashtag;
|
||||
String _input = '';
|
||||
bool _fetching = false;
|
||||
String? _error;
|
||||
|
||||
Future<void> _submit(List<String> localIps, int port, [String? candidate]) async {
|
||||
final List<String> candidates;
|
||||
final String input = _input.trim();
|
||||
if (candidate != null) {
|
||||
candidates = [candidate];
|
||||
} else if (_mode == _InputMode.ip) {
|
||||
candidates = [input];
|
||||
} else {
|
||||
candidates = localIps.map((ip) => '${ip.ipPrefix}.$input').toList();
|
||||
}
|
||||
Future<void> _submit(int port, [String? candidate]) async {
|
||||
final candidates = [candidate ?? _input.trim()];
|
||||
|
||||
setState(() {
|
||||
_fetching = true;
|
||||
@@ -129,89 +106,43 @@ class _AddressInputDialogState extends State<AddressInputDialog> with Refena {
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
ToggleButtons(
|
||||
isSelected: _selected,
|
||||
onPressed: (int index) {
|
||||
setState(() {
|
||||
for (int i = 0; i < _selected.length; i++) {
|
||||
_selected[i] = i == index;
|
||||
}
|
||||
_mode = _InputMode.values[index];
|
||||
});
|
||||
},
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
||||
constraints: const BoxConstraints(minWidth: 0, minHeight: 0),
|
||||
children: _InputMode.values.map((mode) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 5),
|
||||
child: Text(mode.label),
|
||||
);
|
||||
}).toList(),
|
||||
),
|
||||
const SizedBox(height: 15),
|
||||
TextFormField(
|
||||
key: ValueKey('input-$_mode'),
|
||||
autofocus: true,
|
||||
enabled: !_fetching,
|
||||
keyboardType: _mode == _InputMode.hashtag ? TextInputType.number : TextInputType.text,
|
||||
decoration: InputDecoration(
|
||||
prefixText: _mode == _InputMode.hashtag ? '# ' : 'IP: ',
|
||||
prefixText: 'IP: ',
|
||||
),
|
||||
onChanged: (s) {
|
||||
setState(() => _input = s);
|
||||
},
|
||||
onFieldSubmitted: (s) async => _submit(localIps, settings.port),
|
||||
onFieldSubmitted: (s) async => _submit(settings.port),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
if (_mode == _InputMode.hashtag) ...[
|
||||
if (lastDevices.isEmpty)
|
||||
Text(
|
||||
'${t.general.example}: 123',
|
||||
'${t.general.example}: ${localIps.firstOrNull?.ipPrefix ?? '192.168.2'}.123',
|
||||
style: const TextStyle(color: Colors.grey),
|
||||
)
|
||||
else
|
||||
Text.rich(
|
||||
TextSpan(
|
||||
children: [
|
||||
TextSpan(text: t.dialogs.addressInput.recentlyUsed),
|
||||
...lastDevices
|
||||
.mapIndexed((index, device) {
|
||||
return [
|
||||
if (index != 0) const TextSpan(text: ', '),
|
||||
TextSpan(
|
||||
text: device.ip,
|
||||
style: TextStyle(color: Theme.of(context).colorScheme.primary),
|
||||
recognizer: TapGestureRecognizer()..onTap = () async => _submit(settings.port, device.ip),
|
||||
),
|
||||
];
|
||||
})
|
||||
.expand((e) => e),
|
||||
],
|
||||
),
|
||||
),
|
||||
if (localIps.length <= 1)
|
||||
Text(
|
||||
'${t.dialogs.addressInput.ip}: ${localIps.firstOrNull?.ipPrefix ?? '192.168.2'}.$_input',
|
||||
style: const TextStyle(color: Colors.grey),
|
||||
)
|
||||
else ...[
|
||||
Text(
|
||||
'${t.dialogs.addressInput.ip}:',
|
||||
style: const TextStyle(color: Colors.grey),
|
||||
),
|
||||
for (final ip in localIps)
|
||||
Text(
|
||||
'- ${ip.ipPrefix}.$_input',
|
||||
style: const TextStyle(color: Colors.grey),
|
||||
),
|
||||
],
|
||||
] else ...[
|
||||
if (lastDevices.isEmpty)
|
||||
Text(
|
||||
'${t.general.example}: ${localIps.firstOrNull?.ipPrefix ?? '192.168.2'}.123',
|
||||
style: const TextStyle(color: Colors.grey),
|
||||
)
|
||||
else
|
||||
Text.rich(
|
||||
TextSpan(
|
||||
children: [
|
||||
TextSpan(text: t.dialogs.addressInput.recentlyUsed),
|
||||
...lastDevices
|
||||
.mapIndexed((index, device) {
|
||||
return [
|
||||
if (index != 0) const TextSpan(text: ', '),
|
||||
TextSpan(
|
||||
text: device.ip,
|
||||
style: TextStyle(color: Theme.of(context).colorScheme.primary),
|
||||
recognizer: TapGestureRecognizer()..onTap = () async => _submit(localIps, settings.port, device.ip),
|
||||
),
|
||||
];
|
||||
})
|
||||
.expand((e) => e),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
if (_error != null)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 10),
|
||||
@@ -244,7 +175,7 @@ class _AddressInputDialogState extends State<AddressInputDialog> with Refena {
|
||||
child: Text(t.general.cancel),
|
||||
),
|
||||
FilledButton(
|
||||
onPressed: _fetching ? null : () async => _submit(localIps, settings.port),
|
||||
onPressed: _fetching ? null : () async => _submit(settings.port),
|
||||
child: Text(t.general.confirm),
|
||||
),
|
||||
],
|
||||
|
||||
Reference in New Issue
Block a user