Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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"