Skip to content

Commit

Permalink
feat(battery_plus)!: Migrate to package:web (#2720)
Browse files Browse the repository at this point in the history
  • Loading branch information
koji-1009 committed Mar 19, 2024
1 parent e6853a0 commit 21ccfa4
Show file tree
Hide file tree
Showing 4 changed files with 171 additions and 97 deletions.
129 changes: 84 additions & 45 deletions packages/battery_plus/battery_plus/example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,24 @@ class _MyHomePageState extends State<MyHomePage> {
@override
void initState() {
super.initState();
_battery.batteryState.then(_updateBatteryState);
_batteryStateSubscription =
_battery.onBatteryStateChanged.listen(_updateBatteryState);
try {
_battery.batteryState.then(
_updateBatteryState,
onError: (e) {
_showError('onError: batteryState: $e');
_updateBatteryState(BatteryState.unknown);
},
);
_batteryStateSubscription = _battery.onBatteryStateChanged.listen(
_updateBatteryState,
onError: (e) {
_showError('onError: onBatteryStateChanged: $e');
_updateBatteryState(BatteryState.unknown);
},
);
} on Error catch (e) {
_showError('catch: batteryState: $e');
}
}

void _updateBatteryState(BatteryState state) {
Expand All @@ -54,6 +69,16 @@ class _MyHomePageState extends State<MyHomePage> {
});
}

void _showError(String message) {
// see https://github.com/fluttercommunity/plus_plugins/pull/2720
// The exception may not be caught in the package and an exception may occur in the caller, so use try-catch as needed.
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(message),
),
);
}

@override
Widget build(BuildContext context) {
return Scaffold(
Expand All @@ -77,55 +102,69 @@ class _MyHomePageState extends State<MyHomePage> {
const SizedBox(height: 24),
ElevatedButton(
onPressed: () {
_battery.batteryLevel.then(
(batteryLevel) {
showDialog<void>(
context: context,
builder: (_) => AlertDialog(
content: Text('Battery: $batteryLevel%'),
actions: <Widget>[
TextButton(
onPressed: () {
Navigator.pop(context);
},
child: const Text('OK'),
)
],
),
);
},
);
try {
_battery.batteryLevel.then(
(batteryLevel) {
showDialog<void>(
context: context,
builder: (_) => AlertDialog(
content: Text('Battery: $batteryLevel%'),
actions: <Widget>[
TextButton(
onPressed: () {
Navigator.pop(context);
},
child: const Text('OK'),
)
],
),
);
},
onError: (e) {
_showError('onError: batteryLevel: $e');
},
);
} on Error catch (e) {
_showError('catch: batteryLevel: $e');
}
},
child: const Text('Get battery level'),
),
const SizedBox(height: 24),
ElevatedButton(
onPressed: () {
_battery.isInBatterySaveMode.then(
(isInPowerSaveMode) {
showDialog<void>(
context: context,
builder: (_) => AlertDialog(
title: const Text(
'Is in Battery Save mode?',
style: TextStyle(fontSize: 20),
),
content: Text(
"$isInPowerSaveMode",
style: const TextStyle(fontSize: 18),
try {
_battery.isInBatterySaveMode.then(
(isInPowerSaveMode) {
showDialog<void>(
context: context,
builder: (_) => AlertDialog(
title: const Text(
'Is in Battery Save mode?',
style: TextStyle(fontSize: 20),
),
content: Text(
"$isInPowerSaveMode",
style: const TextStyle(fontSize: 18),
),
actions: <Widget>[
TextButton(
onPressed: () {
Navigator.pop(context);
},
child: const Text('Close'),
)
],
),
actions: <Widget>[
TextButton(
onPressed: () {
Navigator.pop(context);
},
child: const Text('Close'),
)
],
),
);
},
);
);
},
onError: (e) {
_showError('onError: isInBatterySaveMode: $e');
},
);
} on Error catch (e) {
_showError('catch: isInBatterySaveMode: $e');
}
},
child: const Text('Is in Battery Save mode?'),
)
Expand Down
3 changes: 2 additions & 1 deletion packages/battery_plus/battery_plus/example/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ name: battery_plus_example
description: Demonstrates how to use the battery_plus plugin.

environment:
sdk: '>=2.18.0 <4.0.0'
sdk: '>=3.3.0 <4.0.0'
flutter: '>=3.19.0'

dependencies:
flutter:
Expand Down
131 changes: 82 additions & 49 deletions packages/battery_plus/battery_plus/lib/src/battery_plus_web.dart
Original file line number Diff line number Diff line change
@@ -1,85 +1,100 @@
import 'dart:async';
import 'dart:html' as html show window, BatteryManager, Navigator;
import 'dart:js_util';
import 'dart:js_interop';

import 'package:battery_plus_platform_interface/battery_plus_platform_interface.dart';
import 'package:flutter_web_plugins/flutter_web_plugins.dart';
import 'package:web/web.dart' as web;

/// The web implementation of the BatteryPlatform of the Battery plugin.
///
/// The Battery Status API is not supported by Firefox and Safari.
/// Therefore, when using this plugin, recommend that test not only in Chrome but also in Firefox and Safari.
/// In some environments, accessing this plugin from Firefox or Safari will cause unexpected exception.
/// If an unexpected Exception occurs, try-catch at the point where the method is being called.
class BatteryPlusWebPlugin extends BatteryPlatform {
/// Constructs a BatteryPlusPlugin.
BatteryPlusWebPlugin(html.Navigator navigator)
: _getBattery = navigator.getBattery;

/// A check to determine if this version of the plugin can be used.
// ignore: unnecessary_null_comparison
bool get isSupported => html.window.navigator.getBattery != null;
BatteryPlusWebPlugin();

late final Future<dynamic> Function() _getBattery;
/// Return [BatteryManager] if the BatteryManager API is supported by the User Agent.
Future<BatteryManager?> _getBatteryManager() async {
try {
return await web.window.navigator.getBattery().toDart;
} on NoSuchMethodError catch (_) {
// BatteryManager API is not supported this User Agent.
return null;
} on Object catch (_) {
// Unexpected exception occurred.
return null;
}
}

/// Factory method that initializes the Battery plugin platform with an instance
/// of the plugin for the web.
static void registerWith(Registrar registrar) {
BatteryPlatform.instance = BatteryPlusWebPlugin(html.window.navigator);
BatteryPlatform.instance = BatteryPlusWebPlugin();
}

/// Returns the current battery level in percent.
@override
Future<int> get batteryLevel async {
if (isSupported) {
// level is a number representing the system's battery charge level scaled to a value between 0.0 and 1.0
final batteryManager = await _getBattery() as html.BatteryManager;
final level = batteryManager.level ?? 0;
return level * 100 as int;
final batteryManager = await _getBatteryManager();
if (batteryManager == null) {
return 0;
}
return 0;

// level is a number representing the system's battery charge level scaled to a value between 0.0 and 1.0
final level = batteryManager.level;
return level * 100 as int;
}

/// Returns the current battery state.
@override
Future<BatteryState> get batteryState async {
if (isSupported) {
final battery = await _getBattery() as html.BatteryManager;
if (battery.charging != null) {
return _checkBatteryChargingState(battery.charging!);
}
final batteryManager = await _getBatteryManager();
if (batteryManager == null) {
return BatteryState.unknown;
}
return BatteryState.unknown;

return _checkBatteryChargingState(batteryManager.charging);
}

StreamController<BatteryState>? _batteryChangeStreamController;
late Stream<BatteryState> _batteryChange;
Stream<BatteryState>? _batteryChange;

/// Returns a Stream of BatteryState changes.
@override
Stream<BatteryState> get onBatteryStateChanged {
if (_batteryChangeStreamController == null && isSupported) {
_batteryChangeStreamController = StreamController<BatteryState>();

_getBattery().then(
(battery) {
_batteryChangeStreamController!
.add(_checkBatteryChargingState(battery.charging));
setProperty(
battery,
'onchargingchange',
allowInterop(
(event) {
_batteryChangeStreamController!
.add(_checkBatteryChargingState(battery.charging));
},
),
);
},
Stream<BatteryState> get onBatteryStateChanged async* {
final batteryManager = await _getBatteryManager();
if (batteryManager == null) {
yield BatteryState.unknown;
return;
}

if (_batteryChange != null) {
yield* _batteryChange!;
return;
}

_batteryChangeStreamController = StreamController<BatteryState>();
_batteryChangeStreamController?.add(
_checkBatteryChargingState(batteryManager.charging),
);

batteryManager.onchargingchange = (web.Event _) {
_batteryChangeStreamController?.add(
_checkBatteryChargingState(batteryManager.charging),
);
}.toJS;

_batteryChange =
_batteryChangeStreamController!.stream.asBroadcastStream();
_batteryChangeStreamController?.onCancel = () {
_batteryChangeStreamController?.close();

_batteryChangeStreamController?.onCancel = () {
_batteryChangeStreamController?.close();
};
}
return _batteryChange;
_batteryChangeStreamController = null;
_batteryChange = null;
};

_batteryChange = _batteryChangeStreamController!.stream.asBroadcastStream();
yield* _batteryChange!;
}

BatteryState _checkBatteryChargingState(bool charging) {
Expand All @@ -90,3 +105,21 @@ class BatteryPlusWebPlugin extends BatteryPlatform {
}
}
}

extension on web.Navigator {
/// https://developer.mozilla.org/en-US/docs/Web/API/Navigator/getBattery
external JSPromise<BatteryManager> getBattery();
}

/// BatteryManager API
/// https://developer.mozilla.org/en-US/docs/Web/API/BatteryManager
extension type BatteryManager(JSObject _) implements JSObject {
/// https://developer.mozilla.org/en-US/docs/Web/API/BatteryManager/level
external double get level;

/// https://developer.mozilla.org/en-US/docs/Web/API/BatteryManager/charging
external bool get charging;

/// https://developer.mozilla.org/en-US/docs/Web/API/BatteryManager/chargingchange_event
external set onchargingchange(JSFunction fn);
}
5 changes: 3 additions & 2 deletions packages/battery_plus/battery_plus/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ dependencies:
battery_plus_platform_interface: ^2.0.0
meta: ^1.8.0
upower: ^0.7.0
web: ^0.5.0

dev_dependencies:
flutter_test:
Expand All @@ -41,5 +42,5 @@ dev_dependencies:
plugin_platform_interface: ^2.1.4

environment:
sdk: ">=2.18.0 <4.0.0"
flutter: ">=3.3.0"
sdk: ">=3.3.0 <4.0.0"
flutter: ">=3.19.0"

0 comments on commit 21ccfa4

Please sign in to comment.