feat(example_full): create example representing the whole plugin functional

This commit is contained in:
ksenia312
2024-02-06 19:41:56 +01:00
parent 258cdf0adc
commit f71121bd92
89 changed files with 3112 additions and 1164 deletions
@@ -0,0 +1,126 @@
import 'package:flutter/material.dart';
import 'package:nearby_service/nearby_service.dart';
import 'package:nearby_service_example_full/domain/app_service.dart';
import 'package:nearby_service_example_full/presentation/app.dart';
import 'package:provider/provider.dart';
class DevicePreview extends StatelessWidget {
const DevicePreview(
{super.key, required this.device, this.largeView = false});
final NearbyDevice device;
final bool largeView;
@override
Widget build(BuildContext context) {
final color = device.status.isConnected ? kGreenColor : kGreyColor;
final avatar = CircleAvatar(
backgroundColor: kBlueColor.withOpacity(0.7),
foregroundColor: kWhiteColor,
maxRadius: largeView ? 100 : 30,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
device.info.displayName.substring(0, 1).toUpperCase(),
style: TextStyle(fontSize: largeView ? 32 : 16),
),
),
);
final name = Text(
'${device.info.displayName} '
'${device.byPlatform(onAndroid: (d) => d.isGroupOwner ? " - group owner" : "") ?? ''}',
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
fontWeight: FontWeight.bold,
),
);
final id = Text(
'ID: ${device.info.id}',
style: Theme.of(context).textTheme.labelSmall?.copyWith(
fontSize: 10,
),
);
final status = Text(
device.byPlatform(
onAny: (d) => d.status.name,
onIOS: (d) =>
context.select<AppService, bool>((v) => v.isIOSBrowser)
? "Peer found | ${d.status.name}"
: "Pending invitation | ${d.status.name}",
) ??
'',
style: Theme.of(context).textTheme.labelSmall?.copyWith(
color: color,
),
);
final disconnectButton = device.status.isConnected
? TextButton(
onPressed: () => context.read<AppService>().disconnect(device),
style: TextButton.styleFrom(
foregroundColor: kPinkColor,
),
child: const Text('Disconnect'),
)
: null;
if (largeView) {
return Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
avatar,
const SizedBox(height: 10),
name,
const SizedBox(height: 5),
id,
if (disconnectButton != null)
Padding(
padding: const EdgeInsets.only(top: 10),
child: disconnectButton,
),
],
);
} else {
return InkWell(
borderRadius: BorderRadius.circular(12),
onTap: () {
if (!device.status.isConnected) {
context.read<AppService>().connect(device);
} else {
context.read<AppService>().startListeningConnectedDevice(device);
}
},
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Flexible(
flex: 3,
child: Row(
children: [
avatar,
const SizedBox(width: 10),
Flexible(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [name, id, status],
),
),
],
),
),
Flexible(
child: Text(
device.status.isConnected ? 'Tap to chat' : 'Tap to connect',
style: const TextStyle(color: kGreenColor, fontSize: 12),
textAlign: TextAlign.center,
),
)
],
),
),
);
}
}
}
@@ -0,0 +1,149 @@
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:nearby_service_example_full/domain/app_service.dart';
import 'package:nearby_service_example_full/presentation/app.dart';
import 'package:nearby_service_example_full/utils/extensions.dart';
import 'package:provider/provider.dart';
class InfoPanel extends StatelessWidget {
const InfoPanel({super.key});
static Future show(BuildContext context) {
return showModalBottomSheet(
context: context,
backgroundColor: kWhiteColor,
builder: (context) {
return const Padding(
padding: EdgeInsets.fromLTRB(16, 24, 16, 10),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Text(
'Informational panel',
style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
),
SizedBox(height: 32),
AdditionalInfoPanel(),
SizedBox(height: 8),
InfoPanel(),
],
),
);
},
);
}
@override
Widget build(BuildContext context) {
return Consumer<AppService>(
builder: (context, service, _) {
return Wrap(
alignment: WrapAlignment.start,
crossAxisAlignment: WrapCrossAlignment.center,
spacing: 4,
runSpacing: 8,
children: [
if (service.currentDeviceInfo != null)
_InfoChip(
label: 'Device P2P Name',
value: service.currentDeviceInfo!.displayName,
),
_InfoChip(
label: 'Communication channel state',
value: service.communicationChannelState.previewName,
),
if (Platform.isIOS)
_InfoChip(
label: 'Role',
value: service.isIOSBrowser
? 'You are going to find your friend'
: 'You are waiting for another user to connect',
),
if (Platform.isAndroid && service.isAndroidGroupOwner != null)
_InfoChip(
label: 'Role',
value: service.isAndroidGroupOwner!
? 'You are a group owner'
: 'You are not a group owner',
),
],
);
},
);
}
}
class AdditionalInfoPanel extends StatelessWidget {
const AdditionalInfoPanel({super.key});
@override
Widget build(BuildContext context) {
return Consumer<AppService>(builder: (context, service, _) {
return Wrap(
alignment: WrapAlignment.start,
crossAxisAlignment: WrapCrossAlignment.center,
spacing: 4,
runSpacing: 8,
children: [
_InfoChip(
label: 'Platform',
value: service.platformVersion,
),
_InfoChip(
label: 'Model',
value: service.platformModel,
),
if (service.currentDeviceInfo != null && Platform.isIOS)
_InfoChip(
label: 'Device P2P ID',
value: service.currentDeviceInfo!.id,
),
],
);
});
}
}
class _InfoChip extends StatelessWidget {
const _InfoChip({required this.label, required this.value});
final String label;
final String value;
@override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(16),
color: Theme.of(context).colorScheme.background,
boxShadow: [
BoxShadow(
blurRadius: 2,
color: Theme.of(context).shadowColor.withOpacity(0.4),
offset: const Offset(0, 1),
),
],
),
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 3),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Text(
'$label: ',
style: TextStyle(
fontWeight: FontWeight.bold,
color: Theme.of(context).colorScheme.onBackground,
),
),
Text(
value,
style: TextStyle(
color: Theme.of(context).colorScheme.onBackground,
),
),
],
),
);
}
}