feat(example): clean up for android
This commit is contained in:
@@ -0,0 +1,34 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:nearby_service/nearby_service.dart';
|
||||||
|
|
||||||
|
class ConnectedDeviceView extends StatelessWidget {
|
||||||
|
const ConnectedDeviceView({
|
||||||
|
super.key,
|
||||||
|
required this.device,
|
||||||
|
required this.onDisconnect,
|
||||||
|
});
|
||||||
|
|
||||||
|
final NearbyDevice device;
|
||||||
|
final VoidCallback onDisconnect;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Container(
|
||||||
|
decoration: const BoxDecoration(color: Colors.blueAccent),
|
||||||
|
padding: const EdgeInsets.all(20.0),
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
device.info.displayName,
|
||||||
|
style: const TextStyle(color: Colors.white),
|
||||||
|
),
|
||||||
|
ElevatedButton(
|
||||||
|
onPressed:onDisconnect,
|
||||||
|
child: const Text('Disconnect'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
import 'package:file_picker/file_picker.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:nearby_service/nearby_service.dart';
|
||||||
|
|
||||||
|
class FilesMessagingView extends StatefulWidget {
|
||||||
|
const FilesMessagingView({super.key, required this.onSend});
|
||||||
|
|
||||||
|
final ValueChanged<List<NearbyFileInfo>> onSend;
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<FilesMessagingView> createState() => _FilesMessagingViewState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _FilesMessagingViewState extends State<FilesMessagingView> {
|
||||||
|
List<PlatformFile> _pickedFiles = [];
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
|
children: [
|
||||||
|
ElevatedButton(
|
||||||
|
onPressed: () async {
|
||||||
|
final result = await FilePicker.platform.pickFiles(
|
||||||
|
allowMultiple: true,
|
||||||
|
);
|
||||||
|
if (result != null) {
|
||||||
|
setState(() => _pickedFiles = result.files);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
child: const Text('Pick the files'),
|
||||||
|
),
|
||||||
|
ElevatedButton(
|
||||||
|
onPressed: () => widget.onSend(
|
||||||
|
_pickedFiles.map((e) => NearbyFileInfo(path: e.path!)).toList(),
|
||||||
|
),
|
||||||
|
child: const Text('Send files'),
|
||||||
|
),
|
||||||
|
const Text('Picked files:', style: TextStyle(fontSize: 16)),
|
||||||
|
..._pickedFiles.map((e) => Text(e.name)),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class IOSRoleSelector extends StatelessWidget {
|
||||||
|
const IOSRoleSelector({
|
||||||
|
super.key,
|
||||||
|
required this.isIosBrowser,
|
||||||
|
required this.onSelect,
|
||||||
|
});
|
||||||
|
|
||||||
|
final bool isIosBrowser;
|
||||||
|
final ValueChanged<bool> onSelect;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Center(
|
||||||
|
child: Text(
|
||||||
|
'You are ${isIosBrowser ? 'Browser' : 'Advertiser'}',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Switch(
|
||||||
|
value: isIosBrowser,
|
||||||
|
onChanged: onSelect,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:nearby_service/nearby_service.dart';
|
||||||
|
|
||||||
|
class PeerWidget extends StatelessWidget {
|
||||||
|
const PeerWidget({
|
||||||
|
super.key,
|
||||||
|
required this.device,
|
||||||
|
required this.isIosBrowser,
|
||||||
|
required this.onConnect,
|
||||||
|
});
|
||||||
|
|
||||||
|
final NearbyDevice device;
|
||||||
|
final bool isIosBrowser;
|
||||||
|
final ValueChanged<NearbyDevice> onConnect;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final status =
|
||||||
|
device.status.isConnected ? 'Tap to chat' : device.status.name;
|
||||||
|
return ListTile(
|
||||||
|
title: Text(
|
||||||
|
'${isIosBrowser ? 'Found device' : 'Pending invitation'} | ${device.info.displayName} | $status',
|
||||||
|
),
|
||||||
|
onTap: () => onConnect(device),
|
||||||
|
tileColor: Colors.blueAccent,
|
||||||
|
textColor: Colors.white,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class TextMessagingView extends StatefulWidget {
|
||||||
|
const TextMessagingView({super.key, required this.onSend});
|
||||||
|
|
||||||
|
final ValueChanged<String> onSend;
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<TextMessagingView> createState() => _TextMessagingViewState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _TextMessagingViewState extends State<TextMessagingView> {
|
||||||
|
String _message = '';
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
|
children: [
|
||||||
|
TextField(
|
||||||
|
onChanged: (value) => setState(() => _message = value),
|
||||||
|
decoration: const InputDecoration(
|
||||||
|
hintText: 'Enter your message',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 10),
|
||||||
|
ElevatedButton(
|
||||||
|
onPressed: () => widget.onSend(_message),
|
||||||
|
child: const Text('Send message'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
+121
-215
@@ -1,16 +1,33 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:file_picker/file_picker.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:nearby_service/nearby_service.dart';
|
import 'package:nearby_service/nearby_service.dart';
|
||||||
import 'package:path_provider/path_provider.dart';
|
|
||||||
|
|
||||||
|
/// All UI components and utilities are moved out of main
|
||||||
|
/// to focus on the nearby_service plugin.
|
||||||
|
/// If you are interested to see them,
|
||||||
|
/// see https://github.com/ksenia312/nearby_service/blob/main/example/lib/.
|
||||||
|
import 'components/connected_device_view.dart';
|
||||||
|
import 'components/files_messaging_view.dart';
|
||||||
|
import 'components/ios_role_selector.dart';
|
||||||
|
import 'components/peer_widget.dart';
|
||||||
|
import 'components/text_messaging_view.dart';
|
||||||
|
import 'utils/app_snack_bar.dart';
|
||||||
|
import 'utils/file_saver.dart';
|
||||||
|
|
||||||
|
/// Short example variant for pub.dev
|
||||||
|
/// See the full example at
|
||||||
|
/// https://github.com/ksenia312/nearby_service/tree/main/example_full
|
||||||
Future<void> main() async {
|
Future<void> main() async {
|
||||||
runApp(const App());
|
runApp(const App());
|
||||||
}
|
}
|
||||||
|
|
||||||
enum AppState { idle, ready, discovering, connected }
|
/// Simplified application states, main 3:
|
||||||
|
/// - Preparatory
|
||||||
|
/// - Device search
|
||||||
|
/// - Communicating with the connected device
|
||||||
|
enum AppState { idle, discovering, connected }
|
||||||
|
|
||||||
class App extends StatelessWidget {
|
class App extends StatelessWidget {
|
||||||
const App({super.key});
|
const App({super.key});
|
||||||
@@ -39,19 +56,25 @@ class AppBody extends StatefulWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _AppBodyState extends State<AppBody> {
|
class _AppBodyState extends State<AppBody> {
|
||||||
|
/// Our service
|
||||||
final _nearbyService = NearbyService.getInstance(
|
final _nearbyService = NearbyService.getInstance(
|
||||||
|
/// Define log level here
|
||||||
logLevel: NearbyServiceLogLevel.debug,
|
logLevel: NearbyServiceLogLevel.debug,
|
||||||
);
|
);
|
||||||
AppState _state = AppState.idle;
|
AppState _state = AppState.idle;
|
||||||
|
|
||||||
|
/// Browser OR Advertiser for IOS
|
||||||
bool _isIosBrowser = true;
|
bool _isIosBrowser = true;
|
||||||
|
|
||||||
|
/// List of discovered devices
|
||||||
List<NearbyDevice> _peers = [];
|
List<NearbyDevice> _peers = [];
|
||||||
NearbyDevice? _connectedDevice;
|
|
||||||
StreamSubscription? _peersSubscription;
|
StreamSubscription? _peersSubscription;
|
||||||
|
|
||||||
List<PlatformFile> _pickedFiles = [];
|
/// Temporary solution to check the connection,
|
||||||
String _message = '';
|
/// use [NearbyService.getConnectedDeviceStream] for this purpose
|
||||||
|
/// in your application
|
||||||
Timer? _connectionCheckTimer;
|
Timer? _connectionCheckTimer;
|
||||||
|
NearbyDevice? _connectedDevice;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
@@ -73,46 +96,26 @@ class _AppBodyState extends State<AppBody> {
|
|||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
if (Platform.isIOS)
|
if (Platform.isIOS)
|
||||||
Row(
|
IOSRoleSelector(
|
||||||
mainAxisSize: MainAxisSize.min,
|
isIosBrowser: _isIosBrowser,
|
||||||
children: [
|
onSelect: (value) => setState(() => _isIosBrowser = value),
|
||||||
Center(
|
|
||||||
child: Text(
|
|
||||||
'You are ${_isIosBrowser ? 'Browser' : 'Advertiser'}',
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Switch(
|
|
||||||
value: _isIosBrowser,
|
|
||||||
onChanged: (value) => setState(() => _isIosBrowser = value),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
ElevatedButton(
|
ElevatedButton(
|
||||||
onPressed: _preparePlatforms,
|
onPressed: _startProcess,
|
||||||
child: const Text('Prepare Platforms'),
|
child: const Text('Start'),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
} else if (_state == AppState.ready) {
|
|
||||||
return ElevatedButton(
|
|
||||||
onPressed: _discovery,
|
|
||||||
child: const Text('Start discovery'),
|
|
||||||
);
|
|
||||||
} else if (_state == AppState.discovering) {
|
} else if (_state == AppState.discovering) {
|
||||||
return ListView(
|
return ListView(
|
||||||
children: [
|
children: [
|
||||||
if (Platform.isIOS)
|
if (Platform.isIOS)
|
||||||
Text(
|
Text('You are ${_isIosBrowser ? 'Browser' : 'Advertiser'}'),
|
||||||
'You are ${_isIosBrowser ? 'Browser' : 'Advertiser'}',
|
|
||||||
),
|
|
||||||
..._peers.map(
|
..._peers.map(
|
||||||
(e) => ListTile(
|
(e) => PeerWidget(
|
||||||
title: Text(
|
device: e,
|
||||||
'${_isIosBrowser ? 'Found device' : 'Pending invitation'} | ${e.info.displayName} | ${e.status.name}',
|
isIosBrowser: _isIosBrowser,
|
||||||
),
|
onConnect: _connect,
|
||||||
onTap: () => _connect(e),
|
|
||||||
tileColor: Colors.blueAccent,
|
|
||||||
textColor: Colors.white,
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@@ -123,81 +126,28 @@ class _AppBodyState extends State<AppBody> {
|
|||||||
mainAxisAlignment: MainAxisAlignment.start,
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
children: [
|
children: [
|
||||||
DecoratedBox(
|
// Preview of the connected device
|
||||||
decoration: const BoxDecoration(
|
ConnectedDeviceView(
|
||||||
color: Colors.blueAccent,
|
device: _connectedDevice!,
|
||||||
),
|
onDisconnect: _disconnect,
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.all(20.0),
|
|
||||||
child: Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
_connectedDevice!.info.displayName,
|
|
||||||
style: const TextStyle(color: Colors.white),
|
|
||||||
),
|
|
||||||
ElevatedButton(
|
|
||||||
onPressed: _disconnect,
|
|
||||||
child: const Text('Disconnect'),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
const SizedBox(height: 50),
|
const SizedBox(height: 50),
|
||||||
Column(
|
// Send messages section
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
TextMessagingView(
|
||||||
children: [
|
onSend: (message) => _send(
|
||||||
TextField(
|
NearbyMessageTextRequest.create(value: message),
|
||||||
onChanged: (value) => setState(() => _message = value),
|
),
|
||||||
decoration: const InputDecoration(
|
|
||||||
hintText: 'Enter your message',
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(height: 10),
|
|
||||||
ElevatedButton(
|
|
||||||
onPressed: () {
|
|
||||||
_send(NearbyMessageTextRequest.create(value: _message));
|
|
||||||
},
|
|
||||||
child: const Text('Send message'),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
|
|
||||||
const SizedBox(height: 50),
|
const SizedBox(height: 50),
|
||||||
Column(
|
// Send files section
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
FilesMessagingView(
|
||||||
children: [
|
onSend: (files) {
|
||||||
ElevatedButton(
|
_send(
|
||||||
onPressed: () async {
|
NearbyMessageFilesRequest.create(files: files),
|
||||||
final result = await FilePicker.platform.pickFiles(
|
);
|
||||||
allowMultiple: true,
|
},
|
||||||
);
|
),
|
||||||
if (result != null) {
|
|
||||||
setState(
|
|
||||||
() => _pickedFiles = result.files,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
child: const Text('Pick the files'),
|
|
||||||
),
|
|
||||||
ElevatedButton(
|
|
||||||
onPressed: () {
|
|
||||||
_send(
|
|
||||||
NearbyMessageFilesRequest.create(
|
|
||||||
files: [
|
|
||||||
..._pickedFiles.map(
|
|
||||||
(e) => NearbyFileInfo(path: e.path!),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
child: const Text('Send files'),
|
|
||||||
),
|
|
||||||
const Text('Picked files:', style: TextStyle(fontSize: 16)),
|
|
||||||
..._pickedFiles.map((e) => Text(e.name)),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@@ -209,27 +159,27 @@ class _AppBodyState extends State<AppBody> {
|
|||||||
await _nearbyService.initialize();
|
await _nearbyService.initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _preparePlatforms() async {
|
Future<void> _startProcess() async {
|
||||||
bool result;
|
final platformsReady = await _checkPlatforms();
|
||||||
|
if (platformsReady) {
|
||||||
if (Platform.isAndroid) {
|
await _discover();
|
||||||
final isGranted = await _nearbyService.android?.requestPermissions();
|
|
||||||
final wifiEnabled = await _nearbyService.android?.checkWifiService();
|
|
||||||
result = (isGranted ?? false) && (wifiEnabled ?? false);
|
|
||||||
} else if (Platform.isIOS) {
|
|
||||||
_nearbyService.ios?.setIsBrowser(value: _isIosBrowser);
|
|
||||||
result = true;
|
|
||||||
} else {
|
|
||||||
result = false;
|
|
||||||
}
|
|
||||||
if (result) {
|
|
||||||
setState(() {
|
|
||||||
_state = AppState.ready;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _discovery() async {
|
Future<bool> _checkPlatforms() async {
|
||||||
|
if (Platform.isAndroid) {
|
||||||
|
final isGranted = await _nearbyService.android?.requestPermissions();
|
||||||
|
final wifiEnabled = await _nearbyService.android?.checkWifiService();
|
||||||
|
return (isGranted ?? false) && (wifiEnabled ?? false);
|
||||||
|
} else if (Platform.isIOS) {
|
||||||
|
_nearbyService.ios?.setIsBrowser(value: _isIosBrowser);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _discover() async {
|
||||||
final result = await _nearbyService.discover();
|
final result = await _nearbyService.discover();
|
||||||
if (result) {
|
if (result) {
|
||||||
setState(() {
|
setState(() {
|
||||||
@@ -238,60 +188,70 @@ class _AppBodyState extends State<AppBody> {
|
|||||||
_peersSubscription = _nearbyService.getPeersStream().listen((event) {
|
_peersSubscription = _nearbyService.getPeersStream().listen((event) {
|
||||||
setState(() {
|
setState(() {
|
||||||
_peers = event;
|
_peers = event;
|
||||||
|
// Check and filter your peers here
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _connect(NearbyDevice device) async {
|
Future<void> _connect(NearbyDevice device) async {
|
||||||
|
// Be careful with already connected devices,
|
||||||
|
// double connection may be unnecessary
|
||||||
final result = await _nearbyService.connect(device);
|
final result = await _nearbyService.connect(device);
|
||||||
if (result) {
|
if (result || device.status.isConnected) {
|
||||||
_connectionCheckTimer = Timer.periodic(
|
_connectionCheckTimer = Timer.periodic(
|
||||||
const Duration(seconds: 3),
|
const Duration(seconds: 3),
|
||||||
(_) {
|
(_) {
|
||||||
|
NearbyDevice? selectedDevice;
|
||||||
try {
|
try {
|
||||||
final selectedDevice = _peers.firstWhere(
|
selectedDevice = _peers.firstWhere(
|
||||||
(element) => element.info.id == device.info.id,
|
(element) => element.info.id == device.info.id,
|
||||||
);
|
);
|
||||||
if (selectedDevice.status.isConnected) {
|
} finally {}
|
||||||
|
|
||||||
|
if (selectedDevice.status.isConnected) {
|
||||||
|
try {
|
||||||
|
_startCommunicationChannel(device);
|
||||||
|
} finally {
|
||||||
_connectionCheckTimer?.cancel();
|
_connectionCheckTimer?.cancel();
|
||||||
_connectionCheckTimer = null;
|
_connectionCheckTimer = null;
|
||||||
_nearbyService.startCommunicationChannel(
|
|
||||||
NearbyCommunicationChannelData(
|
|
||||||
device.info.id,
|
|
||||||
messagesListener: NearbyServiceMessagesListener(
|
|
||||||
onCreated: () {
|
|
||||||
setState(() {
|
|
||||||
_connectedDevice = device;
|
|
||||||
_state = AppState.connected;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
onData: _messagesListener,
|
|
||||||
onError: (e, [StackTrace? s]) {
|
|
||||||
setState(() {
|
|
||||||
_connectedDevice = null;
|
|
||||||
_state = AppState.discovering;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
onDone: () {
|
|
||||||
setState(() {
|
|
||||||
_connectedDevice = null;
|
|
||||||
_state = AppState.discovering;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
),
|
|
||||||
filesListener: NearbyServiceFilesListener(
|
|
||||||
onData: _filesListener,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
} finally {}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _startCommunicationChannel(NearbyDevice device) {
|
||||||
|
_nearbyService.startCommunicationChannel(
|
||||||
|
NearbyCommunicationChannelData(
|
||||||
|
device.info.id,
|
||||||
|
filesListener: NearbyServiceFilesListener(onData: _filesListener),
|
||||||
|
messagesListener: NearbyServiceMessagesListener(
|
||||||
|
onData: _messagesListener,
|
||||||
|
onCreated: () {
|
||||||
|
setState(() {
|
||||||
|
_connectedDevice = device;
|
||||||
|
_state = AppState.connected;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
onError: (e, [StackTrace? s]) {
|
||||||
|
setState(() {
|
||||||
|
_connectedDevice = null;
|
||||||
|
_state = AppState.idle;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
onDone: () {
|
||||||
|
setState(() {
|
||||||
|
_connectedDevice = null;
|
||||||
|
_state = AppState.idle;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> _disconnect() async {
|
Future<void> _disconnect() async {
|
||||||
try {
|
try {
|
||||||
await _nearbyService.disconnect(_connectedDevice!);
|
await _nearbyService.disconnect(_connectedDevice!);
|
||||||
@@ -307,6 +267,7 @@ class _AppBodyState extends State<AppBody> {
|
|||||||
|
|
||||||
void _messagesListener(ReceivedNearbyMessage<NearbyMessageContent> message) {
|
void _messagesListener(ReceivedNearbyMessage<NearbyMessageContent> message) {
|
||||||
if (_connectedDevice == null) return;
|
if (_connectedDevice == null) return;
|
||||||
|
// Very useful stuff! Process messages according to the type of content
|
||||||
message.content.byType(
|
message.content.byType(
|
||||||
onTextRequest: (request) {
|
onTextRequest: (request) {
|
||||||
AppSnackBar.show(
|
AppSnackBar.show(
|
||||||
@@ -356,66 +317,11 @@ class _AppBodyState extends State<AppBody> {
|
|||||||
|
|
||||||
Future<void> _send(NearbyMessageContent content) async {
|
Future<void> _send(NearbyMessageContent content) async {
|
||||||
if (_connectedDevice == null) return;
|
if (_connectedDevice == null) return;
|
||||||
|
|
||||||
await _nearbyService.send(
|
await _nearbyService.send(
|
||||||
OutgoingNearbyMessage(content: content, receiver: _connectedDevice!.info),
|
OutgoingNearbyMessage(
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class AppSnackBar {
|
|
||||||
AppSnackBar._();
|
|
||||||
|
|
||||||
static Future<void> show(
|
|
||||||
BuildContext context, {
|
|
||||||
required String title,
|
|
||||||
String? subtitle,
|
|
||||||
String? actionName,
|
|
||||||
VoidCallback? onAcceptAction,
|
|
||||||
}) async {
|
|
||||||
final content = Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: [
|
|
||||||
Text(title, style: const TextStyle(fontSize: 16)),
|
|
||||||
if (subtitle != null) Text(subtitle),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
final action = onAcceptAction != null && actionName != null
|
|
||||||
? SnackBarAction(
|
|
||||||
label: actionName,
|
|
||||||
onPressed: onAcceptAction,
|
|
||||||
)
|
|
||||||
: null;
|
|
||||||
final messenger = ScaffoldMessenger.of(context).showSnackBar(
|
|
||||||
SnackBar(
|
|
||||||
content: content,
|
content: content,
|
||||||
action: action,
|
receiver: _connectedDevice!.info,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
return messenger.closed.then((value) => null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class FilesSaver {
|
|
||||||
FilesSaver._();
|
|
||||||
|
|
||||||
static Future<List<NearbyFileInfo>> savePack(
|
|
||||||
ReceivedNearbyFilesPack pack,
|
|
||||||
) async {
|
|
||||||
final files = <NearbyFileInfo>[];
|
|
||||||
final directory = Platform.isAndroid
|
|
||||||
? Directory('storage/emulated/0/Download')
|
|
||||||
: await getApplicationDocumentsDirectory();
|
|
||||||
|
|
||||||
for (final nearbyFile in pack.files) {
|
|
||||||
final newFile = await File(nearbyFile.path).copy(
|
|
||||||
'${directory.path}/${DateTime.now().microsecondsSinceEpoch}.${nearbyFile.extension}',
|
|
||||||
);
|
|
||||||
if (!await newFile.exists()) {
|
|
||||||
await newFile.create();
|
|
||||||
}
|
|
||||||
files.add(NearbyFileInfo(path: newFile.path));
|
|
||||||
}
|
|
||||||
return files;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class AppSnackBar {
|
||||||
|
AppSnackBar._();
|
||||||
|
|
||||||
|
static Future<void> show(
|
||||||
|
BuildContext context, {
|
||||||
|
required String title,
|
||||||
|
String? subtitle,
|
||||||
|
String? actionName,
|
||||||
|
VoidCallback? onAcceptAction,
|
||||||
|
}) async {
|
||||||
|
final content = Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Text(title, style: const TextStyle(fontSize: 16)),
|
||||||
|
if (subtitle != null) Text(subtitle),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
final action = onAcceptAction != null && actionName != null
|
||||||
|
? SnackBarAction(label: actionName, onPressed: onAcceptAction)
|
||||||
|
: null;
|
||||||
|
final messenger = ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
SnackBar(
|
||||||
|
content: content,
|
||||||
|
action: action,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
return messenger.closed.then((value) => null);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:nearby_service/nearby_service.dart';
|
||||||
|
import 'package:path_provider/path_provider.dart';
|
||||||
|
|
||||||
|
class FilesSaver {
|
||||||
|
FilesSaver._();
|
||||||
|
|
||||||
|
static Future<bool> savePack(
|
||||||
|
ReceivedNearbyFilesPack pack,
|
||||||
|
) async {
|
||||||
|
final directory = Platform.isAndroid
|
||||||
|
? Directory('storage/emulated/0/Download')
|
||||||
|
: await getApplicationDocumentsDirectory();
|
||||||
|
|
||||||
|
for (final nearbyFile in pack.files) {
|
||||||
|
final newFile = await File(nearbyFile.path).copy(
|
||||||
|
'${directory.path}/${DateTime.now().microsecondsSinceEpoch}.${nearbyFile.extension}',
|
||||||
|
);
|
||||||
|
if (!await newFile.exists()) {
|
||||||
|
await newFile.create();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user