diff --git a/lib/app/(public)/splash_page.dart b/lib/app/(public)/splash_page.dart index 0f54b18..524a06c 100644 --- a/lib/app/(public)/splash_page.dart +++ b/lib/app/(public)/splash_page.dart @@ -11,6 +11,7 @@ import '../core/assets/sounds.dart' as sounds; import '../core/assets/svgs.dart' as svgs; import '../interactor/actions/apps_action.dart' as apps; import '../interactor/actions/apps_action.dart'; +import '../interactor/actions/config_action.dart'; import '../interactor/actions/platform_action.dart' as platform; class AppPage extends StatefulWidget { @@ -31,6 +32,8 @@ class _AppPageState extends State { svgs.precacheCache(context), images.precacheCache(context), sounds.precacheCache(), + registerBatteryListener(), + registerHourListener(), Future.delayed(const Duration(seconds: 2)), ]).whenComplete(() { sounds.introSound(); diff --git a/lib/app/core/widgets/command_bar.dart b/lib/app/core/widgets/command_bar.dart index de85be9..82c39f5 100644 --- a/lib/app/core/widgets/command_bar.dart +++ b/lib/app/core/widgets/command_bar.dart @@ -1,8 +1,15 @@ +import 'dart:math'; + +import 'package:asp/asp.dart'; +import 'package:based_battery_indicator/based_battery_indicator.dart'; +import 'package:battery_plus/battery_plus.dart'; import 'package:flutter/material.dart'; import 'package:gap/gap.dart'; import 'package:localization/localization.dart'; import 'package:yuno/app/core/widgets/animated_sync_button.dart'; +import '../../interactor/atoms/config_atom.dart'; + class NavigationCommand extends StatelessWidget { final VoidCallback? onApps; final VoidCallback? onPlay; @@ -60,6 +67,15 @@ class NavigationCommand extends StatelessWidget { Text('${'syncing'.i18n()}...'), ], ), + if (!isSyncing) + const Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + _BatteryIcon(), + _HourIcon(), + ], + ), const Spacer(), LabelButton( label: 'favorite'.i18n(), @@ -82,6 +98,58 @@ class NavigationCommand extends StatelessWidget { } } +class _HourIcon extends StatelessWidget { + const _HourIcon({super.key}); + + @override + Widget build(BuildContext context) { + return RxBuilder( + builder: (context) { + return Text( + hoursState.value, + style: const TextStyle( + fontSize: 14, + fontWeight: FontWeight.bold, + ), + ); + }, + ); + } +} + +class _BatteryIcon extends StatelessWidget { + const _BatteryIcon({super.key}); + + @override + Widget build(BuildContext context) { + return RxBuilder(builder: (_) { + final model = batteryState.value; + var type = BasedBatteryStatusType.normal; + if (model.batteryState == BatteryState.charging) { + type = BasedBatteryStatusType.charging; + } + + return Transform.translate( + offset: const Offset(0, -2), + child: Transform.rotate( + angle: -pi / 2, + alignment: Alignment.center, + child: BasedBatteryIndicator( + status: BasedBatteryStatus( + value: model.batteryLevel, + type: type, + ), + trackHeight: 8.0, + trackAspectRatio: 2.0, + curve: Curves.ease, + duration: const Duration(seconds: 1), + ), + ), + ); + }); + } +} + class LabelButton extends StatelessWidget { final String label; final String buttonText; diff --git a/lib/app/interactor/actions/config_action.dart b/lib/app/interactor/actions/config_action.dart index 10cee61..658ea25 100644 --- a/lib/app/interactor/actions/config_action.dart +++ b/lib/app/interactor/actions/config_action.dart @@ -1,3 +1,8 @@ +import 'dart:async'; + +import 'package:battery_plus/battery_plus.dart'; +import 'package:intl/intl.dart'; +import 'package:yuno/app/interactor/models/battery_model.dart'; import 'package:yuno/app/interactor/models/game_config.dart'; import 'package:yuno/injector.dart'; @@ -19,3 +24,26 @@ Future openUrl(Uri uri) async { final repository = injector.get(); await repository.openUrl(uri); } + +final _battery = Battery(); +StreamSubscription? _batterySubscription; + +Future registerBatteryListener() async { + _batterySubscription?.cancel(); + _batterySubscription = _battery.onBatteryStateChanged.listen( + (BatteryState state) async { + batteryState.value = BatteryModel( + batteryLevel: await _battery.batteryLevel, + batteryState: state, + ); + }, + ); +} + +Timer? timer; + +Future registerHourListener() async { + timer ??= Timer.periodic(const Duration(seconds: 1), (timer) { + hoursState.value = DateFormat('HH:mm').format(DateTime.now()); + }); +} diff --git a/lib/app/interactor/actions/platform_action.dart b/lib/app/interactor/actions/platform_action.dart index 9bc0418..1802d40 100644 --- a/lib/app/interactor/actions/platform_action.dart +++ b/lib/app/interactor/actions/platform_action.dart @@ -73,11 +73,12 @@ Future syncPlatform(PlatformModel platform) async { final repository = injector(); - final folderGames = await _getGames(platform); - final currentGames = platform.games; - final games = syncGames(currentGames, folderGames); - - platform = platform.copyWith(games: games); + if (platform.category.id != 'android') { + final folderGames = await _getGames(platform); + final currentGames = platform.games; + final games = syncGames(currentGames, folderGames); + platform = platform.copyWith(games: games); + } for (var i = 0; i < platform.games.length; i++) { if (platform.games[i].isSynced) continue; diff --git a/lib/app/interactor/atoms/config_atom.dart b/lib/app/interactor/atoms/config_atom.dart index 6a00e29..3e1acac 100644 --- a/lib/app/interactor/atoms/config_atom.dart +++ b/lib/app/interactor/atoms/config_atom.dart @@ -1,14 +1,22 @@ import 'dart:ui'; import 'package:asp/asp.dart'; +import 'package:battery_plus/battery_plus.dart'; import 'package:yuno/app/interactor/models/language_model.dart'; +import '../models/battery_model.dart'; import '../models/game_config.dart'; final gameConfigState = Atom(GameConfig()); final buildNumberState = Atom(''); +final batteryState = Atom(BatteryModel( + batteryLevel: 0, + batteryState: BatteryState.unknown, +)); +final hoursState = Atom('00:00'); + Locale? localeResolution(Locale? locale, Iterable supportedLocales) { if (supportedLocales.contains(locale)) { return locale; diff --git a/lib/app/interactor/models/battery_model.dart b/lib/app/interactor/models/battery_model.dart new file mode 100644 index 0000000..b962747 --- /dev/null +++ b/lib/app/interactor/models/battery_model.dart @@ -0,0 +1,11 @@ +import 'package:battery_plus/battery_plus.dart'; + +class BatteryModel { + final int batteryLevel; + final BatteryState batteryState; + + BatteryModel({ + required this.batteryLevel, + required this.batteryState, + }); +} diff --git a/pubspec.yaml b/pubspec.yaml index 4e1965a..e110803 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -16,7 +16,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html # In Windows, build-name is used as the major, minor, and patch parts # of the product and file versions while build-number is used as the build suffix. -version: 0.0.7+15 +version: 0.0.8+16 environment: sdk: '>=3.2.4 <4.0.0' @@ -66,6 +66,9 @@ dependencies: isar_flutter_libs: ^3.1.0+1 url_launcher: ^6.2.3 path: ^1.8.3 + battery_plus: ^5.0.2 + intl: ^0.18.1 + based_battery_indicator: ^1.0.3 install_or_uninstall_app_listener: path: plugins/install_or_uninstall_app_listener localization: ^2.1.1