feat(remote): remember manual host address

close #1074
This commit is contained in:
edde746
2026-05-18 17:22:10 +02:00
parent a679bae354
commit 68e27fdbb3
3 changed files with 65 additions and 14 deletions
+5
View File
@@ -357,6 +357,10 @@ class SettingsService extends BaseSharedPreferencesService {
static const customDownloadPath = NullableStringPref('custom_download_path');
static final customRelayUrl = NullableStringPref('custom_relay_url', transform: _trimEmptyAsNull);
static const recentRooms = NullableStringPref('watch_together_recent_rooms');
static final companionRemoteLastHostAddress = NullableStringPref(
'companion_remote_last_host_address',
transform: _trimEmptyAsNull,
);
static final maxVolume = IntPref('max_volume', defaultValue: 100, transform: (v) => v.clamp(100, 300));
static final subtitlePosition = IntPref('subtitle_position', defaultValue: 100, transform: (v) => v.clamp(0, 100));
@@ -736,6 +740,7 @@ class SettingsService extends BaseSharedPreferencesService {
selectedExternalPlayer,
customExternalPlayers,
customRelayUrl,
companionRemoteLastHostAddress,
];
Future<void> resetAllSettings() async {
@@ -16,6 +16,7 @@ import '../../profiles/active_profile_provider.dart';
import '../../profiles/plex_home_service.dart';
import '../../profiles/profile_connection_registry.dart';
import '../../providers/companion_remote_provider.dart';
import '../../services/settings_service.dart';
import '../../utils/app_logger.dart';
import '../loading_indicator_box.dart';
@@ -48,9 +49,20 @@ class _DiscoveryViewState extends State<DiscoveryView> with ControllerDisposerMi
void initState() {
super.initState();
_provider = context.read<CompanionRemoteProvider>();
unawaited(_loadSavedManualHostAddress());
_initCryptoAndDiscover();
}
Future<void> _loadSavedManualHostAddress() async {
final settings = SettingsService.instanceOrNull ?? await SettingsService.getInstance();
final hostAddress = settings.read(SettingsService.companionRemoteLastHostAddress);
if (!mounted || hostAddress == null || _hostAddressController.text.isNotEmpty) return;
setState(() {
_hostAddressController.text = hostAddress;
_showManualEntry = true;
});
}
Future<void> _initCryptoAndDiscover() async {
final connections = context.read<ConnectionRegistry>();
final activeProfile = context.read<ActiveProfileProvider>();
@@ -140,6 +152,26 @@ class _DiscoveryViewState extends State<DiscoveryView> with ControllerDisposerMi
}
}
Future<void> _saveManualHostAddress(String hostAddress) async {
try {
final settings = SettingsService.instanceOrNull ?? await SettingsService.getInstance();
await settings.write(SettingsService.companionRemoteLastHostAddress, hostAddress);
} catch (e) {
appLogger.w('Failed to save companion remote host address', error: e);
}
}
void _submitManualHost() {
if (!_formKey.currentState!.validate()) return;
final hostAddress = _hostAddressController.text.trim();
unawaited(
_connect(() async {
await _provider.connectToManualHost(hostAddress);
await _saveManualHostAddress(hostAddress);
}),
);
}
String _parseErrorMessage(String error) {
if (error.contains('timeout') || error.contains('Timed out')) {
return t.companionRemote.pairing.connectionTimedOut;
@@ -340,10 +372,11 @@ class _DiscoveryViewState extends State<DiscoveryView> with ControllerDisposerMi
prefixIcon: const Icon(Icons.computer),
),
validator: (value) {
if (value == null || value.isEmpty) {
final hostAddress = value?.trim() ?? '';
if (hostAddress.isEmpty) {
return t.companionRemote.pairing.validationHostRequired;
}
if (value.split(':').length != 2) {
if (hostAddress.split(':').length != 2) {
return t.companionRemote.pairing.validationHostFormat;
}
return null;
@@ -356,19 +389,9 @@ class _DiscoveryViewState extends State<DiscoveryView> with ControllerDisposerMi
FocusableButton(
focusNode: _connectFocusNode,
onNavigateUp: _hostAddressFocusNode.requestFocus,
onPressed: _isConnecting
? null
: () {
if (!_formKey.currentState!.validate()) return;
_connect(() => _provider.connectToManualHost(_hostAddressController.text.trim()));
},
onPressed: _isConnecting ? null : _submitManualHost,
child: FilledButton.icon(
onPressed: _isConnecting
? null
: () {
if (!_formKey.currentState!.validate()) return;
_connect(() => _provider.connectToManualHost(_hostAddressController.text.trim()));
},
onPressed: _isConnecting ? null : _submitManualHost,
icon: _isConnecting ? const LoadingIndicatorBox(size: 16) : const Icon(Icons.link),
label: Text(_isConnecting ? t.companionRemote.pairing.connecting : t.common.connect),
),