snapshot of https://github.com/flutter/samples.git (main, 2026-09-16; blobs > 131072B omitted)
Some checks failed
Main Branch CI / Test Flutter beta on ubuntu-latest (push) Has been skipped
Main Branch CI / Test Flutter stable on ubuntu-latest (push) Has been skipped
Main Branch CI / Test Flutter beta on macos-latest (push) Has been cancelled
Main Branch CI / Test Flutter stable on macos-latest (push) Has been cancelled
Some checks failed
Main Branch CI / Test Flutter beta on ubuntu-latest (push) Has been skipped
Main Branch CI / Test Flutter stable on ubuntu-latest (push) Has been skipped
Main Branch CI / Test Flutter beta on macos-latest (push) Has been cancelled
Main Branch CI / Test Flutter stable on macos-latest (push) Has been cancelled
This commit is contained in:
113
platform_channels/lib/main.dart
Normal file
113
platform_channels/lib/main.dart
Normal file
@@ -0,0 +1,113 @@
|
||||
// Copyright 2020 The Flutter team. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:platform_channels/src/add_pet_details.dart';
|
||||
import 'package:platform_channels/src/event_channel_demo.dart';
|
||||
import 'package:platform_channels/src/method_channel_demo.dart';
|
||||
import 'package:platform_channels/src/pet_list_screen.dart';
|
||||
import 'package:platform_channels/src/platform_image_demo.dart';
|
||||
|
||||
void main() {
|
||||
runApp(const PlatformChannelSample());
|
||||
}
|
||||
|
||||
class PlatformChannelSample extends StatelessWidget {
|
||||
const PlatformChannelSample({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MaterialApp.router(
|
||||
title: 'Platform Channel Sample',
|
||||
theme: ThemeData(
|
||||
snackBarTheme: SnackBarThemeData(
|
||||
backgroundColor: Colors.blue[500],
|
||||
),
|
||||
),
|
||||
routerConfig: router(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
GoRouter router([String? initialLocation]) {
|
||||
return GoRouter(
|
||||
initialLocation: initialLocation ?? '/',
|
||||
routes: [
|
||||
GoRoute(
|
||||
path: '/',
|
||||
builder: (context, state) => const HomePage(),
|
||||
routes: [
|
||||
GoRoute(
|
||||
path: 'methodChannelDemo',
|
||||
builder: (context, state) => const MethodChannelDemo(),
|
||||
),
|
||||
GoRoute(
|
||||
path: 'eventChannelDemo',
|
||||
builder: (context, state) => const EventChannelDemo(),
|
||||
),
|
||||
GoRoute(
|
||||
path: 'platformImageDemo',
|
||||
builder: (context, state) => const PlatformImageDemo(),
|
||||
),
|
||||
GoRoute(
|
||||
path: 'petListScreen',
|
||||
builder: (context, state) => const PetListScreen(),
|
||||
routes: [
|
||||
GoRoute(
|
||||
path: 'addPetDetails',
|
||||
builder: (context, state) => const AddPetDetails(),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
class DemoInfo {
|
||||
final String demoTitle;
|
||||
final String demoRoute;
|
||||
|
||||
DemoInfo(this.demoTitle, this.demoRoute);
|
||||
}
|
||||
|
||||
List<DemoInfo> demoList = [
|
||||
DemoInfo('MethodChannel Demo', '/methodChannelDemo'),
|
||||
DemoInfo('EventChannel Demo', '/eventChannelDemo'),
|
||||
DemoInfo('Platform Image Demo', '/platformImageDemo'),
|
||||
DemoInfo('BasicMessageChannel Demo', '/petListScreen'),
|
||||
];
|
||||
|
||||
class HomePage extends StatelessWidget {
|
||||
const HomePage({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(title: const Text('Platform Channel Sample')),
|
||||
body: ListView(
|
||||
children: demoList.map((demoInfo) => DemoTile(demoInfo)).toList(),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// This widget is responsible for displaying the [ListTile] on [HomePage].
|
||||
class DemoTile extends StatelessWidget {
|
||||
final DemoInfo demoInfo;
|
||||
|
||||
const DemoTile(this.demoInfo, {super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ListTile(
|
||||
title: Text(demoInfo.demoTitle),
|
||||
onTap: () {
|
||||
context.go(demoInfo.demoRoute);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
37
platform_channels/lib/src/accelerometer_event_channel.dart
Normal file
37
platform_channels/lib/src/accelerometer_event_channel.dart
Normal file
@@ -0,0 +1,37 @@
|
||||
// Copyright 2020 The Flutter team. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
/// This class includes the implementation for [EventChannel] to listen to value
|
||||
/// changes from the Accelerometer sensor from native side. It has a [readings]
|
||||
/// getter to provide a stream of [AccelerometerReadings].
|
||||
class Accelerometer {
|
||||
static const _eventChannel = EventChannel('eventChannelDemo');
|
||||
|
||||
/// Method responsible for providing a stream of [AccelerometerReadings] to listen
|
||||
/// to value changes from the Accelerometer sensor.
|
||||
static Stream<AccelerometerReadings> get readings {
|
||||
return _eventChannel.receiveBroadcastStream().map(
|
||||
(dynamic event) => AccelerometerReadings(
|
||||
event[0] as double,
|
||||
event[1] as double,
|
||||
event[2] as double,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class AccelerometerReadings {
|
||||
/// Acceleration force along the x-axis.
|
||||
final double x;
|
||||
|
||||
/// Acceleration force along the y-axis.
|
||||
final double y;
|
||||
|
||||
/// Acceleration force along the z-axis.
|
||||
final double z;
|
||||
|
||||
AccelerometerReadings(this.x, this.y, this.z);
|
||||
}
|
||||
81
platform_channels/lib/src/add_pet_details.dart
Normal file
81
platform_channels/lib/src/add_pet_details.dart
Normal file
@@ -0,0 +1,81 @@
|
||||
// Copyright 2020 The Flutter team. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:platform_channels/src/pet_list_message_channel.dart';
|
||||
|
||||
/// Demonstrates how to use [BasicMessageChannel] to send a message to platform.
|
||||
///
|
||||
/// The widget uses [TextField] and [RadioListTile] to take the [PetDetails.breed] and
|
||||
/// [PetDetails.petType] from the user respectively.
|
||||
class AddPetDetails extends StatefulWidget {
|
||||
const AddPetDetails({super.key});
|
||||
|
||||
@override
|
||||
State<AddPetDetails> createState() => _AddPetDetailsState();
|
||||
}
|
||||
|
||||
class _AddPetDetailsState extends State<AddPetDetails> {
|
||||
final breedTextController = TextEditingController();
|
||||
String petType = 'Dog';
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text('Add Pet Details'),
|
||||
actions: [
|
||||
IconButton(
|
||||
icon: const Icon(Icons.add),
|
||||
onPressed: () {
|
||||
PetListMessageChannel.addPetDetails(
|
||||
PetDetails(
|
||||
petType: petType,
|
||||
breed: breedTextController.text,
|
||||
),
|
||||
);
|
||||
|
||||
context.pop();
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
body: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: RadioGroup(
|
||||
groupValue: petType,
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
petType = value!;
|
||||
});
|
||||
},
|
||||
child: Column(
|
||||
children: [
|
||||
const SizedBox(height: 8),
|
||||
TextField(
|
||||
controller: breedTextController,
|
||||
decoration: const InputDecoration(
|
||||
border: OutlineInputBorder(),
|
||||
filled: true,
|
||||
hintText: 'Breed of pet',
|
||||
labelText: 'Breed',
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
RadioListTile<String>(
|
||||
title: const Text('Dog'),
|
||||
value: 'Dog',
|
||||
),
|
||||
RadioListTile<String>(
|
||||
title: const Text('Cat'),
|
||||
value: 'Cat',
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
33
platform_channels/lib/src/counter_method_channel.dart
Normal file
33
platform_channels/lib/src/counter_method_channel.dart
Normal file
@@ -0,0 +1,33 @@
|
||||
// Copyright 2020 The Flutter team. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
/// This class includes implementation of two platform methods [increment],
|
||||
/// and [decrement] which are used to increment and decrement value
|
||||
/// of count respectively.
|
||||
class Counter {
|
||||
/// Creates a [MethodChannel] with the specified name to invoke platform method.
|
||||
/// In order to communicate across platforms, the name of MethodChannel
|
||||
/// should be same on native and dart side.
|
||||
static MethodChannel methodChannel = const MethodChannel(
|
||||
'methodChannelDemo',
|
||||
);
|
||||
|
||||
/// This method is responsible to increment and return the value of count.
|
||||
static Future<int> increment({required int counterValue}) async {
|
||||
final result = await methodChannel.invokeMethod<int>('increment', {
|
||||
'count': counterValue,
|
||||
});
|
||||
return result!;
|
||||
}
|
||||
|
||||
/// This method is responsible to decrement and return the value of count.
|
||||
static Future<int> decrement({required int counterValue}) async {
|
||||
final result = await methodChannel.invokeMethod<int>('decrement', {
|
||||
'count': counterValue,
|
||||
});
|
||||
return result!;
|
||||
}
|
||||
}
|
||||
56
platform_channels/lib/src/event_channel_demo.dart
Normal file
56
platform_channels/lib/src/event_channel_demo.dart
Normal file
@@ -0,0 +1,56 @@
|
||||
// Copyright 2020 The Flutter team. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:platform_channels/src/accelerometer_event_channel.dart';
|
||||
|
||||
/// Demonstrates how to use [EventChannel] to listen continuous values
|
||||
/// of Accelerometer Sensor from platform.
|
||||
///
|
||||
/// The widget uses a [StreamBuilder] to rebuild it's descendant whenever it
|
||||
/// listens a new value from the [Accelerometer.readings] stream. It has three
|
||||
/// [Text] widgets to display the value of [AccelerometerReadings.x],
|
||||
/// [AccelerometerReadings.y], and [AccelerometerReadings.z] respectively.
|
||||
class EventChannelDemo extends StatelessWidget {
|
||||
const EventChannelDemo({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final textStyle = Theme.of(context).textTheme.headlineSmall;
|
||||
return Scaffold(
|
||||
appBar: AppBar(title: const Text('EventChannel Demo')),
|
||||
body: Center(
|
||||
child: StreamBuilder<AccelerometerReadings>(
|
||||
stream: Accelerometer.readings,
|
||||
builder: (context, snapshot) {
|
||||
return switch (snapshot) {
|
||||
AsyncSnapshot(hasError: true) => Text(
|
||||
(snapshot.error as PlatformException).message!,
|
||||
),
|
||||
AsyncSnapshot(hasData: true) => Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Text(
|
||||
'x axis: ${snapshot.data!.x.toStringAsFixed(3)}',
|
||||
style: textStyle,
|
||||
),
|
||||
Text(
|
||||
'y axis: ${snapshot.data!.y.toStringAsFixed(3)}',
|
||||
style: textStyle,
|
||||
),
|
||||
Text(
|
||||
'z axis: ${snapshot.data!.z.toStringAsFixed(3)}',
|
||||
style: textStyle,
|
||||
),
|
||||
],
|
||||
),
|
||||
_ => Text('No Data Available', style: textStyle),
|
||||
};
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
28
platform_channels/lib/src/image_basic_message_channel.dart
Normal file
28
platform_channels/lib/src/image_basic_message_channel.dart
Normal file
@@ -0,0 +1,28 @@
|
||||
// Copyright 2020 The Flutter team. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
/// This class manages a [BasicMessageChannel] that can return an image loaded
|
||||
/// from a native asset. The [BasicMessageChannel] uses [StandardMessageCodec]
|
||||
/// since it supports [Uint8List], which is used to transport the image data.
|
||||
class PlatformImageFetcher {
|
||||
static const _basicMessageChannel = BasicMessageChannel<dynamic>(
|
||||
'platformImageDemo',
|
||||
StandardMessageCodec(),
|
||||
);
|
||||
|
||||
/// Method responsible for providing the platform image.
|
||||
static Future<Uint8List> getImage() async {
|
||||
final reply = await _basicMessageChannel.send('getImage') as Uint8List?;
|
||||
if (reply == null) {
|
||||
throw PlatformException(
|
||||
code: 'Error',
|
||||
message: 'Failed to load Platform Image',
|
||||
details: null,
|
||||
);
|
||||
}
|
||||
return reply;
|
||||
}
|
||||
}
|
||||
90
platform_channels/lib/src/method_channel_demo.dart
Normal file
90
platform_channels/lib/src/method_channel_demo.dart
Normal file
@@ -0,0 +1,90 @@
|
||||
// Copyright 2020 The Flutter team. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:platform_channels/src/counter_method_channel.dart';
|
||||
|
||||
/// The widget demonstrates how to use [MethodChannel] to invoke platform methods.
|
||||
/// It has two [FilledButton]s to increment and decrement the value of
|
||||
/// [count], and a [Text] widget to display its value.
|
||||
class MethodChannelDemo extends StatefulWidget {
|
||||
const MethodChannelDemo({super.key});
|
||||
|
||||
@override
|
||||
State<MethodChannelDemo> createState() => _MethodChannelDemoState();
|
||||
}
|
||||
|
||||
class _MethodChannelDemoState extends State<MethodChannelDemo> {
|
||||
int count = 0;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(title: const Text('MethodChannel Demo')),
|
||||
body: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Text(
|
||||
'Value of count is $count',
|
||||
style: Theme.of(context).textTheme.headlineSmall,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: [
|
||||
// Whenever users press the FilledButton, it invokes
|
||||
// Counter.increment method to increment the value of count.
|
||||
FilledButton.icon(
|
||||
onPressed: () async {
|
||||
try {
|
||||
final value = await Counter.increment(
|
||||
counterValue: count,
|
||||
);
|
||||
setState(() => count = value);
|
||||
} catch (error) {
|
||||
if (!context.mounted) return;
|
||||
showErrorMessage(
|
||||
context,
|
||||
(error as PlatformException).message!,
|
||||
);
|
||||
}
|
||||
},
|
||||
icon: const Icon(Icons.add),
|
||||
label: const Text('Increment'),
|
||||
),
|
||||
|
||||
// Whenever users press the FilledButton, it invokes
|
||||
// Counter.decrement method to decrement the value of count.
|
||||
FilledButton.icon(
|
||||
onPressed: () async {
|
||||
try {
|
||||
final value = await Counter.decrement(
|
||||
counterValue: count,
|
||||
);
|
||||
setState(() => count = value);
|
||||
} catch (error) {
|
||||
if (!context.mounted) return;
|
||||
showErrorMessage(
|
||||
context,
|
||||
(error as PlatformException).message!,
|
||||
);
|
||||
}
|
||||
},
|
||||
icon: const Icon(Icons.remove),
|
||||
label: const Text('Decrement'),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void showErrorMessage(BuildContext context, String errorMessage) {
|
||||
ScaffoldMessenger.of(
|
||||
context,
|
||||
).showSnackBar(SnackBar(content: Text(errorMessage)));
|
||||
}
|
||||
}
|
||||
86
platform_channels/lib/src/pet_list_message_channel.dart
Normal file
86
platform_channels/lib/src/pet_list_message_channel.dart
Normal file
@@ -0,0 +1,86 @@
|
||||
// Copyright 2020 The Flutter team. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
/// This class includes two methods [addPetDetails] and [removePet] which are used
|
||||
/// to add a new pet and remove a pet from the the list respectively.
|
||||
class PetListMessageChannel {
|
||||
static const _jsonMessageCodecChannel = BasicMessageChannel<dynamic>(
|
||||
'jsonMessageCodecDemo',
|
||||
JSONMessageCodec(),
|
||||
);
|
||||
|
||||
static const _binaryCodecChannel = BasicMessageChannel(
|
||||
'binaryCodecDemo',
|
||||
BinaryCodec(),
|
||||
);
|
||||
|
||||
/// Method to add a new pet to the list.
|
||||
///
|
||||
/// Demonstrates how to use [BasicMessageChannel] and [JSONMessageCodec] to
|
||||
/// send more structured data to platform like a [Map] in this case.
|
||||
static void addPetDetails(PetDetails petDetails) {
|
||||
_jsonMessageCodecChannel.send(petDetails.toJson());
|
||||
}
|
||||
|
||||
/// Method to remove a pet from the list.
|
||||
///
|
||||
/// Demonstrates how to use [BasicMessageChannel] and [BinaryCodec] to
|
||||
/// send [ByteData] to platform. If the reply received is null, then
|
||||
/// we will throw a [PlatformException].
|
||||
static Future<void> removePet(int index) async {
|
||||
final uInt8List = utf8.encoder.convert(index.toString());
|
||||
final reply = await _binaryCodecChannel.send(
|
||||
uInt8List.buffer.asByteData(),
|
||||
);
|
||||
if (reply == null) {
|
||||
throw PlatformException(
|
||||
code: 'INVALID INDEX',
|
||||
message: 'Failed to delete pet details',
|
||||
details: null,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A model class that provides [petList] which is received from platform.
|
||||
class PetListModel {
|
||||
PetListModel({required this.petList});
|
||||
|
||||
final List<PetDetails> petList;
|
||||
|
||||
/// Method that maps the incoming string of json object to List of [PetDetails].
|
||||
factory PetListModel.fromJson(String jsonString) {
|
||||
final jsonData = json.decode(jsonString) as Map<String, dynamic>;
|
||||
return PetListModel(
|
||||
petList: List.from(
|
||||
(jsonData['petList'] as List).map<PetDetails>(
|
||||
(dynamic petDetailsMap) =>
|
||||
PetDetails.fromMap(petDetailsMap as Map<String, dynamic>),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// A simple model that provides pet details like [petType] and [breed] of pet.
|
||||
class PetDetails {
|
||||
PetDetails({required this.petType, required this.breed});
|
||||
|
||||
final String petType;
|
||||
final String breed;
|
||||
|
||||
factory PetDetails.fromMap(Map<String, dynamic> map) => PetDetails(
|
||||
petType: map['petType'] as String,
|
||||
breed: map['breed'] as String,
|
||||
);
|
||||
|
||||
Map<String, String> toJson() => <String, String>{
|
||||
'petType': petType,
|
||||
'breed': breed,
|
||||
};
|
||||
}
|
||||
103
platform_channels/lib/src/pet_list_screen.dart
Normal file
103
platform_channels/lib/src/pet_list_screen.dart
Normal file
@@ -0,0 +1,103 @@
|
||||
// Copyright 2020 The Flutter team. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:platform_channels/src/pet_list_message_channel.dart';
|
||||
|
||||
/// Demonstrates how to use [BasicMessageChannel] to send & receive the platform
|
||||
/// Message.
|
||||
class PetListScreen extends StatefulWidget {
|
||||
const PetListScreen({super.key});
|
||||
|
||||
@override
|
||||
State<PetListScreen> createState() => _PetListScreenState();
|
||||
}
|
||||
|
||||
class _PetListScreenState extends State<PetListScreen> {
|
||||
PetListModel petListModel = PetListModel(petList: []);
|
||||
final scaffoldKey = GlobalKey<ScaffoldState>();
|
||||
|
||||
@override
|
||||
void didChangeDependencies() {
|
||||
super.didChangeDependencies();
|
||||
// Receives a string of json object from the platform and converts it
|
||||
// to PetModel.
|
||||
final scaffoldMessenger = ScaffoldMessenger.of(context);
|
||||
const BasicMessageChannel<String?>(
|
||||
'stringCodecDemo',
|
||||
StringCodec(),
|
||||
).setMessageHandler((message) async {
|
||||
if (message == null) {
|
||||
scaffoldMessenger.showSnackBar(
|
||||
const SnackBar(
|
||||
content: Text('An error occurred while adding pet details.'),
|
||||
),
|
||||
);
|
||||
} else {
|
||||
setState(() {
|
||||
petListModel = PetListModel.fromJson(message);
|
||||
});
|
||||
}
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
key: scaffoldKey,
|
||||
appBar: AppBar(title: const Text('Pet List')),
|
||||
floatingActionButton: FloatingActionButton(
|
||||
child: const Icon(Icons.add),
|
||||
onPressed: () {
|
||||
context.go('/petListScreen/addPetDetails');
|
||||
},
|
||||
),
|
||||
body: petListModel.petList.isEmpty
|
||||
? const Center(child: Text('Enter Pet Details'))
|
||||
: BuildPetList(petListModel.petList),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Shows list of [PetDetails].
|
||||
class BuildPetList extends StatelessWidget {
|
||||
final List<PetDetails> petList;
|
||||
|
||||
const BuildPetList(this.petList, {super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ListView.builder(
|
||||
padding: const EdgeInsets.all(8),
|
||||
itemCount: petList.length,
|
||||
itemBuilder: (context, index) {
|
||||
return ListTile(
|
||||
title: Text('Pet breed: ${petList[index].breed}'),
|
||||
subtitle: Text('Pet type: ${petList[index].petType}'),
|
||||
trailing: IconButton(
|
||||
icon: const Icon(Icons.delete),
|
||||
onPressed: () async {
|
||||
final scaffoldMessenger = ScaffoldMessenger.of(context);
|
||||
try {
|
||||
await PetListMessageChannel.removePet(index);
|
||||
scaffoldMessenger.showSnackBar(
|
||||
const SnackBar(content: Text('Removed successfully!')),
|
||||
);
|
||||
} catch (error) {
|
||||
scaffoldMessenger.showSnackBar(
|
||||
SnackBar(
|
||||
content: Text((error as PlatformException).message!),
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
74
platform_channels/lib/src/platform_image_demo.dart
Normal file
74
platform_channels/lib/src/platform_image_demo.dart
Normal file
@@ -0,0 +1,74 @@
|
||||
// Copyright 2020 The Flutter team. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:platform_channels/src/image_basic_message_channel.dart';
|
||||
|
||||
/// Demonstrates how to use [BasicMessageChannel] to get an image from platform.
|
||||
///
|
||||
/// The widget uses [Image.memory] to display the image obtained from the
|
||||
/// platform.
|
||||
class PlatformImageDemo extends StatefulWidget {
|
||||
const PlatformImageDemo({super.key});
|
||||
|
||||
@override
|
||||
State<PlatformImageDemo> createState() => _PlatformImageDemoState();
|
||||
}
|
||||
|
||||
class _PlatformImageDemoState extends State<PlatformImageDemo> {
|
||||
Future<Uint8List>? imageData;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(title: const Text('Platform Image Demo')),
|
||||
body: Center(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Flexible(
|
||||
child: FractionallySizedBox(
|
||||
widthFactor: 1,
|
||||
heightFactor: 0.6,
|
||||
child: FutureBuilder<Uint8List>(
|
||||
future: imageData,
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.connectionState == ConnectionState.none) {
|
||||
return const Placeholder();
|
||||
} else if (snapshot.hasError) {
|
||||
return Center(
|
||||
child: Text(
|
||||
(snapshot.error as PlatformException).message!,
|
||||
),
|
||||
);
|
||||
} else if (snapshot.connectionState ==
|
||||
ConnectionState.done) {
|
||||
return Image.memory(
|
||||
snapshot.data!,
|
||||
fit: BoxFit.fill,
|
||||
);
|
||||
}
|
||||
return const CircularProgressIndicator();
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
FilledButton(
|
||||
onPressed: imageData != null
|
||||
? null
|
||||
: () {
|
||||
setState(() {
|
||||
imageData = PlatformImageFetcher.getImage();
|
||||
});
|
||||
},
|
||||
child: const Text('Get Image'),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user