mirror of
https://github.com/GitJournal/GitJournal.git
synced 2025-06-29 10:17:16 +08:00
Experiment with advertising a ZeroConf Service
This commit is contained in:
@ -5,6 +5,7 @@ Future<void> main() async {
|
||||
|
||||
var name = '_dartobservatory._tcp.local';
|
||||
name = '_gitjournal._tcp';
|
||||
name = '_bonsoirdemo._tcp';
|
||||
final MDnsClient client = MDnsClient();
|
||||
// Start the client with default options.
|
||||
await client.start();
|
||||
@ -39,5 +40,9 @@ Future<void> main() async {
|
||||
// Use connectivity plugin to get ssid info when connected to the wifi network
|
||||
// https://stackoverflow.com/questions/55716751/flutter-ios-reading-wifi-name-using-the-connectivity-or-wifi-plugin/55732656#55732656
|
||||
|
||||
// For Registering on Mobiles -
|
||||
// https://pub.dev/packages/bonsoir
|
||||
// Use the WorkManager in Android to do the syncing in the background
|
||||
// -> This should be configurable if we want to be able to sync in the background
|
||||
|
||||
// TODO:
|
||||
// * I don't know if/how I can run an HTTP Server in the Background
|
||||
// Is that still possible with current Android Versions?
|
||||
|
258
lib/main_zeroconf.dart
Normal file
258
lib/main_zeroconf.dart
Normal file
@ -0,0 +1,258 @@
|
||||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:bonsoir/bonsoir.dart';
|
||||
import 'package:device_info/device_info.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
/// Plugin's main method.
|
||||
void main() => runApp(BonsoirExampleMainWidget());
|
||||
|
||||
/// Allows to get the Bonsoir service corresponding to the current device.
|
||||
class AppService {
|
||||
/// The service type.
|
||||
static const String type = '_bonsoirdemo._tcp';
|
||||
|
||||
/// The service port (in this example we're not doing anything on that port but you should).
|
||||
static const int port = 4000;
|
||||
|
||||
/// The cached service.
|
||||
static BonsoirService _service;
|
||||
|
||||
/// Returns (and create if needed) the app Bonsoir service.
|
||||
static Future<BonsoirService> getService() async {
|
||||
if (_service != null) {
|
||||
return _service;
|
||||
}
|
||||
|
||||
String name;
|
||||
if (Platform.isAndroid) {
|
||||
name = (await DeviceInfoPlugin().androidInfo).model;
|
||||
} else if (Platform.isIOS) {
|
||||
name = (await DeviceInfoPlugin().iosInfo).localizedModel;
|
||||
} else {
|
||||
name = 'Flutter';
|
||||
}
|
||||
name += ' Bonsoir Demo';
|
||||
|
||||
_service = BonsoirService(name: name, type: type, port: port);
|
||||
return _service;
|
||||
}
|
||||
}
|
||||
|
||||
/// Provider model that allows to handle Bonsoir broadcasts.
|
||||
class BonsoirBroadcastModel extends ChangeNotifier {
|
||||
/// The current Bonsoir broadcast object instance.
|
||||
BonsoirBroadcast _bonsoirBroadcast;
|
||||
|
||||
/// Whether Bonsoir is currently broadcasting the app's service.
|
||||
bool _isBroadcasting = false;
|
||||
|
||||
/// Returns wether Bonsoir is currently broadcasting the app's service.
|
||||
bool get isBroadcasting => _isBroadcasting;
|
||||
|
||||
/// Starts the Bonsoir broadcast.
|
||||
Future<void> start({bool notify = true}) async {
|
||||
if (_bonsoirBroadcast == null || _bonsoirBroadcast.isStopped) {
|
||||
_bonsoirBroadcast =
|
||||
BonsoirBroadcast(service: await AppService.getService());
|
||||
await _bonsoirBroadcast.ready;
|
||||
}
|
||||
|
||||
await _bonsoirBroadcast.start();
|
||||
_isBroadcasting = true;
|
||||
if (notify) {
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
|
||||
/// Stops the Bonsoir broadcast.
|
||||
void stop({bool notify = true}) {
|
||||
_bonsoirBroadcast?.stop();
|
||||
_isBroadcasting = false;
|
||||
if (notify) {
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
stop(notify: false);
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// Provider model that allows to handle Bonsoir discoveries.
|
||||
class BonsoirDiscoveryModel extends ChangeNotifier {
|
||||
/// The current Bonsoir discovery object instance.
|
||||
BonsoirDiscovery _bonsoirDiscovery;
|
||||
|
||||
/// Contains all discovered (and resolved) services.
|
||||
final List<ResolvedBonsoirService> _resolvedServices = [];
|
||||
|
||||
/// The subscription object.
|
||||
StreamSubscription<BonsoirDiscoveryEvent> _subscription;
|
||||
|
||||
/// Creates a new Bonsoir discovery model instance.
|
||||
BonsoirDiscoveryModel() {
|
||||
start();
|
||||
}
|
||||
|
||||
/// Returns all discovered (and resolved) services.
|
||||
List<ResolvedBonsoirService> get discoveredServices =>
|
||||
List.of(_resolvedServices);
|
||||
|
||||
/// Starts the Bonsoir discovery.
|
||||
Future<void> start() async {
|
||||
if (_bonsoirDiscovery == null || _bonsoirDiscovery.isStopped) {
|
||||
_bonsoirDiscovery =
|
||||
BonsoirDiscovery(type: (await AppService.getService()).type);
|
||||
await _bonsoirDiscovery.ready;
|
||||
}
|
||||
|
||||
await _bonsoirDiscovery.start();
|
||||
_subscription = _bonsoirDiscovery.eventStream.listen(_onEventOccurred);
|
||||
}
|
||||
|
||||
/// Stops the Bonsoir discovery.
|
||||
void stop() {
|
||||
_subscription?.cancel();
|
||||
_subscription = null;
|
||||
_bonsoirDiscovery?.stop();
|
||||
}
|
||||
|
||||
/// Triggered when a Bonsoir discovery event occurred.
|
||||
void _onEventOccurred(BonsoirDiscoveryEvent event) {
|
||||
if (event.service == null || !event.isServiceResolved) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.type == BonsoirDiscoveryEventType.DISCOVERY_SERVICE_RESOLVED) {
|
||||
_resolvedServices.add(event.service);
|
||||
notifyListeners();
|
||||
} else if (event.type == BonsoirDiscoveryEventType.DISCOVERY_SERVICE_LOST) {
|
||||
_resolvedServices.remove(event.service);
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
stop();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// Allows to switch the app broadcast state.
|
||||
class BroadcastSwitch extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
BonsoirBroadcastModel model = context.watch<BonsoirBroadcastModel>();
|
||||
return InkWell(
|
||||
onTap: () => _onTap(model),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text('Broadcast'.toUpperCase()),
|
||||
Switch(
|
||||
value: model.isBroadcasting,
|
||||
onChanged: (value) => _onTap(model),
|
||||
activeColor: Colors.white,
|
||||
activeTrackColor: Colors.white54,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// Triggered when the widget has been tapped on.
|
||||
void _onTap(BonsoirBroadcastModel model) {
|
||||
if (model.isBroadcasting) {
|
||||
model.stop();
|
||||
} else {
|
||||
model.start();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Allows to display all discovered services.
|
||||
class ServiceList extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
BonsoirDiscoveryModel model = context.watch<BonsoirDiscoveryModel>();
|
||||
List<ResolvedBonsoirService> discoveredServices = model.discoveredServices;
|
||||
if (discoveredServices.isEmpty) {
|
||||
return const Padding(
|
||||
padding: EdgeInsets.all(20),
|
||||
child: Center(
|
||||
child: Text(
|
||||
'Found no service of type "${AppService.type}".',
|
||||
style: TextStyle(
|
||||
color: Colors.black54,
|
||||
fontStyle: FontStyle.italic,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return ListView.builder(
|
||||
itemCount: discoveredServices.length,
|
||||
itemBuilder: (context, index) =>
|
||||
_ServiceWidget(service: discoveredServices[index]),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Allows to display a discovered service.
|
||||
class _ServiceWidget extends StatelessWidget {
|
||||
/// The discovered service.
|
||||
final ResolvedBonsoirService service;
|
||||
|
||||
/// Creates a new service widget.
|
||||
const _ServiceWidget({
|
||||
@required this.service,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => ListTile(
|
||||
title: Text(service.name),
|
||||
subtitle: Text(
|
||||
'Type : ${service.type}, ip : ${service.ip}, port : ${service.port}'),
|
||||
);
|
||||
}
|
||||
|
||||
/// Allows to display the app title based on how many services have been discovered.
|
||||
class TitleWidget extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
int count =
|
||||
context.watch<BonsoirDiscoveryModel>().discoveredServices.length;
|
||||
return Text(count == 0 ? 'Bonsoir app demo' : 'Found $count service(s)');
|
||||
}
|
||||
}
|
||||
|
||||
/// The main widget.
|
||||
class BonsoirExampleMainWidget extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) => MultiProvider(
|
||||
providers: [
|
||||
ChangeNotifierProvider<BonsoirBroadcastModel>(
|
||||
create: (context) => BonsoirBroadcastModel()),
|
||||
ChangeNotifierProvider<BonsoirDiscoveryModel>(
|
||||
create: (context) => BonsoirDiscoveryModel()),
|
||||
],
|
||||
builder: (context, child) => MaterialApp(
|
||||
home: Scaffold(
|
||||
appBar: AppBar(
|
||||
title: TitleWidget(),
|
||||
actions: [BroadcastSwitch()],
|
||||
centerTitle: false,
|
||||
),
|
||||
body: ServiceList(),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
16
pubspec.lock
16
pubspec.lock
@ -64,6 +64,13 @@ packages:
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.0.5"
|
||||
bonsoir:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: bonsoir
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.1.2+2"
|
||||
boolean_selector:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -588,6 +595,13 @@ packages:
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.0.3"
|
||||
nested:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: nested
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.0.4"
|
||||
node_interop:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -713,7 +727,7 @@ packages:
|
||||
name: provider
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.2.0"
|
||||
version: "4.3.2+2"
|
||||
pub_cache:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -28,7 +28,7 @@ dependencies:
|
||||
fimber: ^0.3.0
|
||||
dynamic_theme: ^1.0.0
|
||||
flutter_staggered_grid_view: ^0.3.0
|
||||
provider: ^3.2.0
|
||||
provider: ^4.3.2+2
|
||||
git_bindings: ^0.0.15
|
||||
dart_git:
|
||||
git: https://github.com/GitJournal/dart_git.git
|
||||
@ -57,6 +57,7 @@ dependencies:
|
||||
flutter_plugin_android_lifecycle: ^1.0.8 # for fixing the build
|
||||
timeago: ^2.0.27
|
||||
multicast_dns: ^0.2.2
|
||||
bonsoir: ^0.1.2+2
|
||||
|
||||
dev_dependencies:
|
||||
flutter_launcher_icons: "^0.7.2"
|
||||
|
Reference in New Issue
Block a user