diff --git a/lib/pages/discover_page.dart b/lib/pages/discover_page.dart new file mode 100644 index 0000000..da2994d --- /dev/null +++ b/lib/pages/discover_page.dart @@ -0,0 +1,83 @@ +import 'dart:async'; + +import 'package:bonsoir/bonsoir.dart'; +import 'package:flutter/material.dart'; +import 'package:rutorrentflutter/api/api_conf.dart'; + +class DiscoverPage extends StatefulWidget { + @override + _DiscoverPageState createState() => _DiscoverPageState(); +} + +class _DiscoverPageState extends State { + final BonsoirDiscovery zeroconfService = + BonsoirDiscovery(type: "_rutorrent_mobile._tcp"); + final List urls = []; + StreamSubscription zeroconfSub; + + @override + void dispose() { + zeroconfSub?.cancel(); + if (zeroconfService.isReady && !zeroconfService.isStopped) { + zeroconfService.stop(); + } + super.dispose(); + } + + static buildURL(ResolvedBonsoirService resolved) { + // TODO: Enable password authentication + var protocol = resolved.attributes["protocol"]; + var port = resolved.port; + if (port == 80) { + return "http://${resolved.ip}/"; + } else if (port == 443) { + return "https://${resolved.ip}/"; + } else { + if (protocol != null) { + return "$protocol://${resolved.ip}:${resolved.port}/"; + } else { + return "http://${resolved.ip}:${resolved.port}"; + } + } + } + + void setupListener() { + zeroconfSub = zeroconfService.eventStream.listen((event) { + if (event.isServiceResolved && + event.type == BonsoirDiscoveryEventType.DISCOVERY_SERVICE_RESOLVED) { + var resolved = event.service as ResolvedBonsoirService; + setState(() { + urls.add(resolved); + }); + } + }); + zeroconfService.start(); + } + + @override + void initState() { + zeroconfService.ready.then((_) => setupListener()); + super.initState(); + } + + @override + Widget build(BuildContext context) { + return Dialog( + child: Container( + child: ListView.builder( + itemBuilder: (context, index) => ListTile( + title: Text(urls[index].name), + subtitle: Text("IP address: ${urls[index].ip}"), + onTap: () { + var api = Api(); + api.setUrl(buildURL(urls[index])); + api.setUsername(""); + api.setPassword(""); + Navigator.of(context).pop(api); + }, + ), + itemCount: urls.length, + )), + ); + } +} diff --git a/lib/screens/configurations_screen.dart b/lib/screens/configurations_screen.dart index a150189..28321b4 100644 --- a/lib/screens/configurations_screen.dart +++ b/lib/screens/configurations_screen.dart @@ -7,6 +7,7 @@ import 'package:provider/provider.dart'; import 'package:rutorrentflutter/components/data_input.dart'; import 'package:rutorrentflutter/components/password_input.dart'; import 'package:rutorrentflutter/models/mode.dart'; +import 'package:rutorrentflutter/pages/discover_page.dart'; import 'package:rutorrentflutter/screens/main_screen.dart'; import 'package:modal_progress_hud/modal_progress_hud.dart'; import 'package:rutorrentflutter/utilities/preferences.dart'; @@ -222,6 +223,47 @@ class _ConfigurationsScreenState extends State { passwordFocus: passwordFocus, ), ), + Padding( + padding: + const EdgeInsets.symmetric(vertical: 16, horizontal: 32), + child: Container( + width: double.infinity, + child: ElevatedButton( + style: ElevatedButton.styleFrom( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(5.0), + side: + BorderSide(color: Theme.of(context).primaryColor), + ), + primary: Provider.of(context).isLightMode + ? Colors.white + : Colors.black, + ), + child: Padding( + padding: const EdgeInsets.symmetric( + horizontal: 28, vertical: 16), + child: Text( + 'Discover ruTorrent servers in LAN', + style: TextStyle( + color: Theme.of(context).primaryColor, + fontSize: 18), + ), + ), + onPressed: () async { + var received = await showDialog( + context: context, builder: (ctx) => DiscoverPage()); + if (received != null) { + Api api = Provider.of(context, + listen: false); // One call to provider + api.setUrl(api.url); + api.setUsername(api.username); + api.setPassword(api.password); + _validateConfigurationDetails(api); + } + }, + ), + ), + ), Padding( padding: const EdgeInsets.symmetric(vertical: 16, horizontal: 32), diff --git a/pubspec.lock b/pubspec.lock index 2011954..cd91b32 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -8,6 +8,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.5.0" + bonsoir: + dependency: "direct main" + description: + name: bonsoir + url: "https://pub.dartlang.org" + source: hosted + version: "0.1.3+2" boolean_selector: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index fed66a9..7d63b47 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -34,6 +34,7 @@ dependencies: wakelock: ^0.5.0+2 flutter_slidable: ^0.6.0-nullsafety.0 flutter_svg: ^0.21.0-nullsafety.0 + bonsoir: ^0.1.3+2 dev_dependencies: flutter_test: