From 913daf33208249ec68c55f6c38ef920eded00fc0 Mon Sep 17 00:00:00 2001 From: sakofchit Date: Mon, 28 Nov 2022 18:15:39 -0500 Subject: [PATCH] skeumorphic menu --- lib/alt_menu/alt_menu_design.dart | 64 +++++ lib/alt_menu/alt_menu_item.dart | 14 + lib/alt_menu/alt_menu_page_widget.dart | 262 ++++++++++++++++++ lib/alt_menu/alt_menu_widget.dart | 97 +++++++ lib/alt_menu/alt_sub_menu.dart | 31 +++ lib/clickwheel/pan_handlers.dart | 16 +- lib/clickwheel/wheel.dart | 61 ---- lib/clickwheel/wheel_content.dart | 44 +-- lib/{ipod.dart => core.dart} | 167 +++++++++-- lib/games/breakout/breakout.dart | 5 + lib/ipod_menu_widget/ipod_menu_widget.dart | 13 +- lib/main.dart | 11 +- .../music_player_screen.dart | 180 ++++++++---- pubspec.lock | 146 +++++----- pubspec.yaml | 1 + 15 files changed, 856 insertions(+), 256 deletions(-) create mode 100644 lib/alt_menu/alt_menu_design.dart create mode 100644 lib/alt_menu/alt_menu_item.dart create mode 100644 lib/alt_menu/alt_menu_page_widget.dart create mode 100644 lib/alt_menu/alt_menu_widget.dart create mode 100644 lib/alt_menu/alt_sub_menu.dart delete mode 100644 lib/clickwheel/wheel.dart rename lib/{ipod.dart => core.dart} (72%) diff --git a/lib/alt_menu/alt_menu_design.dart b/lib/alt_menu/alt_menu_design.dart new file mode 100644 index 0000000..c726358 --- /dev/null +++ b/lib/alt_menu/alt_menu_design.dart @@ -0,0 +1,64 @@ +/* + + Menu appearance + +*/ +import 'package:flutter/material.dart'; +import 'package:retro/alt_menu/alt_menu_widget.dart'; +import 'package:retro/main.dart'; + +Widget buildAltMenu() { + return AltMenuWidget( + subMenu: altMenu, + key: altMenuKey, + decoration: BoxDecoration( + gradient: LinearGradient( + begin: Alignment.bottomCenter, + end: Alignment.topCenter, + stops: [0.7, 1.0], + colors: [Color(0xff5e616d), Color(0xffb0b3b6)], + ), + boxShadow: [ + BoxShadow( + color: Color.fromARGB(255, 36, 36, 36).withOpacity(0.5), + spreadRadius: 1, + blurRadius: 3, + offset: Offset(0, -2), // changes position of shadow + ), + ], + ), + ); +} + +Widget signIn(context) { + return AnimatedPositioned( + bottom: 5, + left: 5.5, + right: 5.5, + height: popUp ? MediaQuery.of(context).size.width * 0.55 : 0, + duration: Duration(milliseconds: 200), + curve: Curves.easeInOut, + child: Container( + width: 400, + decoration: BoxDecoration( + gradient: LinearGradient( + begin: Alignment.bottomCenter, + end: Alignment.topCenter, + stops: [0.2, 0.7, 1.0], + colors: [Color(0xff3c3c43), Color(0xff5e616d), Color(0xffb0b3b6)], + ), + boxShadow: [ + BoxShadow( + color: Color.fromARGB(255, 36, 36, 36).withOpacity(0.5), + spreadRadius: 1, + blurRadius: 3, + offset: Offset(0, -2), // changes position of shadow + ), + ], + ), + child: Center( + child: buildAltMenu(), + ), + ) + ); + } \ No newline at end of file diff --git a/lib/alt_menu/alt_menu_item.dart b/lib/alt_menu/alt_menu_item.dart new file mode 100644 index 0000000..b96b0be --- /dev/null +++ b/lib/alt_menu/alt_menu_item.dart @@ -0,0 +1,14 @@ +import 'package:flutter/material.dart'; +import 'package:retro/alt_menu/alt_sub_menu.dart'; +import 'package:retro/ipod_menu_widget/ipod_sub_menu.dart'; + +class AltMenuItem { + final String text; + final String subText; + final VoidCallback onTap; + final AltSubMenu subMenu; + + AltMenuItem({@required String text, this.subText, this.onTap, this.subMenu}) + : assert(text != null), + this.text = text; +} diff --git a/lib/alt_menu/alt_menu_page_widget.dart b/lib/alt_menu/alt_menu_page_widget.dart new file mode 100644 index 0000000..adc1f21 --- /dev/null +++ b/lib/alt_menu/alt_menu_page_widget.dart @@ -0,0 +1,262 @@ +/* + + Controls how the menu list looks and handles basic menu animations. + +*/ + +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:retro/alt_menu/alt_menu_item.dart'; +import 'package:retro/alt_menu/alt_sub_menu.dart'; +import 'package:scrollable_positioned_list/scrollable_positioned_list.dart'; + +class AltMenuPageWidget extends StatefulWidget { + final AltSubMenu subMenu; + final LinearGradient selectionColor; + final Decoration decoration; + final TextStyle itemTextStyle; + final TextStyle selectedItemTextStyle; + final TextStyle cancelButtonTextStyle; + + AltMenuPageWidget({ + Key key, + @required AltSubMenu subMenu, + LinearGradient selectionColor, + this.decoration, + TextStyle itemTextStyle, + TextStyle selectedItemTextStyle, + TextStyle cancelButtonTextStyle, + }) : assert(subMenu != null), + this.subMenu = subMenu, + this.selectionColor = selectionColor ?? + LinearGradient( + colors: [ + Color(0xFF1F7BC4), + Color(0xFF3BB3EF), + ], + begin: Alignment.bottomCenter, + end: Alignment.topCenter, + ), + this.itemTextStyle = itemTextStyle ?? + TextStyle(color: Colors.black, fontWeight: FontWeight.w800, fontSize: 17), + this.selectedItemTextStyle = selectedItemTextStyle ?? + TextStyle(color: Colors.white, fontWeight: FontWeight.w800, fontSize: 17), + this.cancelButtonTextStyle = cancelButtonTextStyle ?? TextStyle(color: Colors.white, fontWeight: FontWeight.w800, fontSize: 17), + super(key: key); + + @override + AltMenuPageWidgetState createState() => AltMenuPageWidgetState(); +} + +class AltMenuPageWidgetState extends State + with SingleTickerProviderStateMixin { + int _selectedIndex = 0; + int _startVisibleIndex; + int _endVisibleIndex; + int _visibleItemsCount; + final ItemScrollController _scrollController = ItemScrollController(); + final ItemPositionsListener _itemPositionsListener = + ItemPositionsListener.create(); + + List _menuItems; + Widget _captionItem; + + @override + void initState() { + super.initState(); + _initValues(); + _menuItems = widget.subMenu.itemsBuilder != null + ? widget.subMenu.itemsBuilder() + : widget.subMenu.items; + _captionItem = widget.subMenu.caption; + _itemPositionsListener.itemPositions.addListener(_positionListener); + } + + void refresh() { + if (widget.subMenu.itemsBuilder != null) { + _startVisibleIndex = 0; + _endVisibleIndex = 0; + _selectedIndex = 0; + _visibleItemsCount = widget.subMenu.visibleItemsCount; + _menuItems = widget.subMenu.itemsBuilder(); + if (mounted) setState(() {}); + } + } + + void _positionListener() { + final positions = _itemPositionsListener.itemPositions.value; + if (positions.isNotEmpty) { + if (positions.first.itemLeadingEdge >= 0 || positions.length == 1) { + _startVisibleIndex = positions.first.index; + } else { + _startVisibleIndex = positions.toList()[1].index; + } + + if (positions.last.itemTrailingEdge <= 1 || positions.length == 1) { + _endVisibleIndex = positions.last.index; + } else { + _endVisibleIndex = positions.toList()[positions.length - 2].index; + } + } else { + _startVisibleIndex = 0; + _endVisibleIndex = 0; + } + } + + void _initValues() { + _startVisibleIndex = 0; + _endVisibleIndex = 0; + _visibleItemsCount = widget.subMenu.visibleItemsCount; + _menuItems = widget.subMenu.items; + _captionItem = widget.subMenu.caption; + } + + @override + void dispose() { + _itemPositionsListener.itemPositions.removeListener(_positionListener); + super.dispose(); + } + + // panning to the right on the wheel + + void increaseSelectedIndex(bool haptics) { + if (_selectedIndex < _menuItems.length - 1) { + _selectedIndex++; + if (_endVisibleIndex < _selectedIndex) { + final int jumpIndex = + _selectedIndex - (_endVisibleIndex - _startVisibleIndex); + _scrollController.jumpTo(index: jumpIndex); + } + setState(() {}); + if (haptics) { + HapticFeedback.lightImpact(); + SystemSound.play(SystemSoundType.click); + } + + } + } + + // panning to the left + void decreaseSelectedIndex(bool haptics) { + if (_selectedIndex > 0) { + _selectedIndex--; + + if (_startVisibleIndex > _selectedIndex) { + _scrollController.jumpTo(index: _selectedIndex); + } + setState(() {}); + if (haptics) { + HapticFeedback.lightImpact(); + SystemSound.play(SystemSoundType.click); + } + } + } + + AltSubMenu tap() { + HapticFeedback.mediumImpact(); + SystemSound.play(SystemSoundType.click); + final AltMenuItem item = _menuItems[_selectedIndex]; + final VoidCallback tap = item.onTap; + if (tap != null) tap(); + return item.subMenu; + } + + + @override + Widget build(BuildContext ctx) { + return _buildBody(); + } + + Container _buildBody() { + return Container( + decoration: widget.decoration, + child: Column( + children: [ + _captionItem, + Expanded( + child: LayoutBuilder( + builder: (BuildContext context, BoxConstraints constraints) { + final double normalHeight = + constraints.maxHeight / _visibleItemsCount; + + return ScrollablePositionedList.builder( + physics: NeverScrollableScrollPhysics(), + itemScrollController: _scrollController, + itemPositionsListener: _itemPositionsListener, + itemCount: _menuItems.length, + itemBuilder: (BuildContext context, int index) => + Padding( + padding: EdgeInsets.fromLTRB(20, 15, 20, 0), + child: _buildItem( + index: index, + height: normalHeight, + isSelected: index == _selectedIndex, + ), + ) + ); + }), + ), + ], + ), + ); + } + + Widget _buildItem({ + @required int index, + @required double height, + @required bool isSelected, + bool isCancelButton = false, + }) { + assert(index != null); + assert(height != null); + assert(isSelected != null); + assert(isCancelButton != null); + + final AltMenuItem item = _menuItems[index]; + + if(item == _menuItems.last) { + isCancelButton = true; + } + + return Container( + height: 250 / _visibleItemsCount, + decoration: + isSelected ? BoxDecoration( + gradient: widget.selectionColor, + border: Border.all(color: Colors.white, width: 3), + borderRadius: BorderRadius.all(Radius.circular(15)), + ) + : BoxDecoration( + gradient: LinearGradient( + begin: Alignment.bottomCenter, + end: Alignment.topCenter, + colors: isCancelButton ? [Color(0xff383c44), Color(0xff666b73)] : [Color(0xffdddddd), Color(0xfff0f1f3)], + ), + border: Border.all(color: Color(0xff3e434b), width: 3), + borderRadius: BorderRadius.all(Radius.circular(15)), + ), + child: ListTile( + title: Transform( + transform: Matrix4.translationValues(0, 0.0, 0.0), + child: Padding( + padding: EdgeInsets.fromLTRB(0, 0, 0, 5), + child: Text(item.text, textAlign: TextAlign.center, + maxLines: 1, + style: isSelected + ? widget.selectedItemTextStyle + : (isCancelButton ? widget.cancelButtonTextStyle : widget.itemTextStyle)))), + subtitle: item.subText != null + ? Transform( + transform: Matrix4.translationValues(-10, -5.0, 0.0), + child: Text(item.subText, + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: isSelected + ? widget.selectedItemTextStyle + : widget.itemTextStyle)) + : null, + dense: true, + ), + ); + } +} diff --git a/lib/alt_menu/alt_menu_widget.dart b/lib/alt_menu/alt_menu_widget.dart new file mode 100644 index 0000000..87a7906 --- /dev/null +++ b/lib/alt_menu/alt_menu_widget.dart @@ -0,0 +1,97 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:retro/blocs/player/player_bloc.dart'; +import 'package:retro/blocs/player/player_event.dart'; +import 'package:retro/alt_menu/alt_menu_page_widget.dart'; +import 'package:retro/main.dart'; + +import 'alt_sub_menu.dart'; + +class AltMenuWidget extends StatefulWidget { + final AltSubMenu subMenu; + final LinearGradient selectionColor; + final Decoration decoration; + final TextStyle itemTextStyle; + final TextStyle selectedItemTextStyle; + final Widget subMenuIcon; + final Widget selectedSubMenuIcon; + + AltMenuWidget({ + Key key, + @required AltSubMenu subMenu, + Color selectionColor, + this.decoration, + this.itemTextStyle, + this.selectedItemTextStyle, + this.subMenuIcon, + this.selectedSubMenuIcon, + }) : assert(subMenu != null), + this.subMenu = subMenu, + this.selectionColor = selectionColor ?? + LinearGradient( + colors: [ + Color(0xFF1F7BC4), + Color(0xFF3BB3EF), + ], + begin: Alignment.bottomCenter, + end: Alignment.topCenter, + ), + super(key: key); + + @override + AltMenuWidgetState createState() => AltMenuWidgetState(); +} + +class AltMenuWidgetState extends State { + final List _pages = []; + final List> _keys = []; + + @override + void initState() { + _keys.add(GlobalKey()); + _pages.add(AltMenuPageWidget( + key: _keys.last, + subMenu: widget.subMenu, + decoration: widget.decoration, + selectionColor: widget.selectionColor, + itemTextStyle: widget.itemTextStyle, + selectedItemTextStyle: widget.selectedItemTextStyle, + )); + super.initState(); + } + + @override + Widget build(BuildContext context) { + return Stack(children: _pages); + } + + void up(bool haptics) { + _keys.last?.currentState?.decreaseSelectedIndex(haptics); + } + + void down(bool haptics) { + _keys.last?.currentState?.increaseSelectedIndex(haptics); + } + + void select() { + final AltSubMenu newMenu = _keys.last?.currentState?.tap(); + if (newMenu != null) { + setState(() { + _keys.add(GlobalKey()); + _pages.add( + AltMenuPageWidget( + key: _keys.last, + subMenu: newMenu, + decoration: widget.decoration, + selectionColor: widget.selectionColor, + itemTextStyle: widget.itemTextStyle, + selectedItemTextStyle: widget.selectedItemTextStyle, + ), + ); + }); + } + } + +} + diff --git a/lib/alt_menu/alt_sub_menu.dart b/lib/alt_menu/alt_sub_menu.dart new file mode 100644 index 0000000..618e67f --- /dev/null +++ b/lib/alt_menu/alt_sub_menu.dart @@ -0,0 +1,31 @@ +/* + + submenu constructor + +*/ + +import 'package:flutter/material.dart'; +import 'package:retro/alt_menu/alt_menu_item.dart'; +import 'package:retro/ipod_menu_widget/ipod_menu_item.dart'; + +typedef AltMenuItemBuilder = List Function(); + +class AltSubMenu { + final List items; + final AltMenuItemBuilder itemsBuilder; + final Widget caption; + final int visibleItemsCount; + + AltSubMenu( + {List items, + Widget caption, + AltMenuItemBuilder itemsBuilder, + int visibleItemsCount}) + : this.items = items ?? [], + this.itemsBuilder = itemsBuilder, + this.caption = caption ?? FittedBox(), + this.visibleItemsCount = + visibleItemsCount != null && visibleItemsCount > 0 + ? visibleItemsCount + : 5; +} diff --git a/lib/clickwheel/pan_handlers.dart b/lib/clickwheel/pan_handlers.dart index 3ff0c55..9d8275d 100644 --- a/lib/clickwheel/pan_handlers.dart +++ b/lib/clickwheel/pan_handlers.dart @@ -87,11 +87,19 @@ bool testExtraRadius(double radius) { void scroll (bool up, int micros) { int count = pow(2, (micros/1000000).floor()) - 1; - if (up) menuKey?.currentState?.up(true); //play sound and haptics - else menuKey?.currentState?.down(true); + if(up) { + popUp ? altMenuKey?.currentState?.up(true) : menuKey?.currentState?.up(true); + } + else { + popUp ? altMenuKey?.currentState?.down(true) : menuKey?.currentState?.down(true); + } for (int i = 0; i < count; i++) { - if (up) menuKey?.currentState?.up(false); //don't play them - else menuKey?.currentState?.down(false); + if(up) { + popUp ? altMenuKey?.currentState?.up(false) : menuKey?.currentState?.up(false); + } + else { + popUp ? altMenuKey?.currentState?.down(false) : menuKey?.currentState?.down(false); + } } } diff --git a/lib/clickwheel/wheel.dart b/lib/clickwheel/wheel.dart deleted file mode 100644 index b508404..0000000 --- a/lib/clickwheel/wheel.dart +++ /dev/null @@ -1,61 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; -import 'package:retro/blocs/theme/theme_state.dart'; -import 'package:retro/clickwheel/pan_handlers.dart'; -import 'package:retro/clickwheel/wheel_content.dart'; -import 'package:retro/games/breakout/breakout.dart'; -import 'package:retro/main.dart'; - -Color wheelColor; -Color controlsColor; - -Widget clickWheel(BuildContext context, ThemeState state) { - wheelColor = state.wheelColor == WheelColor.black - ? const Color(0xff151516) - : Colors.white; - - - controlsColor = state.wheelColor == WheelColor.white - ? Color.fromARGB(255, 185, 185, 190) - : Color.fromARGB(255, 222, 222, 222); - return Center( - child: Stack( - alignment: Alignment.center, - children: [ - GestureDetector( - onPanUpdate: panUpdateHandler, - onPanStart: panStartHandler, - child: Container( - height: widgetSize, - width: widgetSize, - decoration: BoxDecoration( - shape: BoxShape.circle, - color: wheelColor, - ), - child: Stack(children: [ - menuButton(), - fastForward(), - fastRewind(), - playButton() - ]), - ), - ), - GestureDetector( - onTap: () { - if(mainViewMode == MainViewMode.breakoutGame){ - if(breakoutGame.currentState?.isBreakoutGameOver == true && breakoutGame.currentState?.gameState == Game.fail){ - breakoutGame.currentState?.restart(); - } - } - else { - menuKey?.currentState?.select(); - } - HapticFeedback.mediumImpact(); - SystemSound.play(SystemSoundType.click); - }, - child: selectButton() - ), - ], - ), - ); - } \ No newline at end of file diff --git a/lib/clickwheel/wheel_content.dart b/lib/clickwheel/wheel_content.dart index c2a5069..bd3e2e2 100644 --- a/lib/clickwheel/wheel_content.dart +++ b/lib/clickwheel/wheel_content.dart @@ -8,41 +8,16 @@ import 'package:retro/blocs/player/player_bloc.dart'; import 'package:retro/blocs/player/player_event.dart'; import 'package:retro/blocs/theme/theme_bloc.dart'; import 'package:retro/blocs/theme/theme_state.dart'; -import 'package:retro/clickwheel/wheel.dart'; +import 'package:retro/core.dart'; import 'package:retro/ipod_menu_widget/ipod_menu_widget.dart'; import 'package:retro/main.dart'; import 'package:retro/helpers/size_helpers.dart'; import 'package:shared_preferences/shared_preferences.dart'; -final IPodMenuWidgetState controls = new IPodMenuWidgetState(); - -Widget menuButton() { - return InkWell( - onTap: () { - if(mainViewMode == MainViewMode.player) { - menuKey.currentState?.homePressed(); - } - if(mainViewMode == MainViewMode.breakoutGame) { - menuKey.currentState?.homePressed(); - } - HapticFeedback.lightImpact(); - }, - child: Container( - child: Text( - 'MENU', - style: TextStyle( - fontSize: 20, - fontWeight: FontWeight.bold, - color: controlsColor, - ), - ), - alignment: Alignment.topCenter, - margin: EdgeInsets.only(top: 15), - ), - ); -} +final IPodMenuWidgetState musicControls = new IPodMenuWidgetState(); +final IPodState home = new IPodState(); -Widget fastForward() { +Widget fastForward(context) { return Container( child: IconButton( icon: Icon( @@ -52,10 +27,7 @@ Widget fastForward() { iconSize: 25, onPressed: () async { HapticFeedback.mediumImpact(); - if (mainViewMode == MainViewMode.menu || - mainViewMode == MainViewMode.player) { - controls.playNextSong(); - } + musicControls.playNextSong(context); }), alignment: Alignment.centerRight, @@ -63,7 +35,7 @@ Widget fastForward() { ); } -Widget fastRewind() { +Widget fastRewind(context) { return Container( child: IconButton( icon: Icon( @@ -73,14 +45,14 @@ Widget fastRewind() { iconSize: 25, onPressed: () async { HapticFeedback.mediumImpact(); - controls.playPrevSong(); + musicControls.playPrevSong(context); }), alignment: Alignment.centerLeft, //margin: EdgeInsets.only(left: 30), ); } -Widget playButton() { +Widget playButton(context) { return Container( child: IconButton( diff --git a/lib/ipod.dart b/lib/core.dart similarity index 72% rename from lib/ipod.dart rename to lib/core.dart index ad77eb8..71b33e5 100644 --- a/lib/ipod.dart +++ b/lib/core.dart @@ -9,15 +9,16 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:playify/playify.dart'; +import 'package:retro/alt_menu/alt_menu_item.dart'; +import 'package:retro/alt_menu/alt_sub_menu.dart'; +import 'package:retro/alt_menu/alt_menu_design.dart'; import 'package:retro/blocs/player/player_bloc.dart'; import 'package:retro/blocs/player/player_event.dart'; import 'package:retro/blocs/songs/song_list.dart'; import 'package:retro/blocs/theme/theme_bloc.dart'; import 'package:retro/blocs/theme/theme_event.dart'; import 'package:retro/blocs/theme/theme_state.dart'; -import 'package:retro/clickwheel/wheel.dart'; import 'package:retro/ipod_menu_widget/ipod_menu_item.dart'; -import 'package:retro/ipod_menu_widget/ipod_menu_widget.dart'; import 'package:retro/ipod_menu_widget/ipod_sub_menu.dart'; import 'package:retro/main.dart'; import 'package:retro/menu.dart'; @@ -26,6 +27,8 @@ import 'package:retro/music_models/apple_music/song/song_model.dart'; import 'package:retro/music_models/playlist/playlist_model.dart'; import 'package:retro/music_player_widget/music_player_screen.dart'; +import 'clickwheel/pan_handlers.dart'; +import 'clickwheel/wheel_content.dart'; import 'games/breakout/breakout.dart'; import 'ipod_menu_widget/menu_design.dart'; @@ -64,6 +67,7 @@ class IPodState extends State { void initState() { mainViewMode = MainViewMode.menu; menu = getIPodMenu(); + altMenu = getAltMenu(); widgetSize = 300.0; halfSize = widgetSize / 2; cartesianStartX = 1; @@ -83,7 +87,9 @@ class IPodState extends State { }); }); super.initState(); - // updateInfo(); + WidgetsBinding.instance.addPostFrameCallback((_) { + homePressed(context); + }); } Widget buildMainView() { @@ -98,19 +104,27 @@ class IPodState extends State { } return FittedBox(); } + + + + // sends the user back to the menu + void homePressed(context) { + setState(() => mainViewMode = MainViewMode.menu); + } + // sends the user to the player void showPlayer() { BlocProvider.of(context).add(NowPlayingFetched()); setState(() => mainViewMode = MainViewMode.player); } + // sends the user to Breakout void showBreakoutGame() { setState(() { mainViewMode = MainViewMode.breakoutGame; }); } - List _songListBuilder() { if (_songs == null || _songs.isEmpty) { return [IPodMenuItem(text: 'No songs fetched')]; @@ -127,6 +141,7 @@ class IPodState extends State { .toList(); } + // list the songs in a playlist List _songListBuilderPlaylist() { final List items = _songs @@ -153,6 +168,7 @@ class IPodState extends State { return items; } + // makes playlists accessible List _playListBuilder() { if (_playlists == null || _playlists.isEmpty) { return [IPodMenuItem(text: 'No playlist fetched')]; @@ -208,8 +224,19 @@ class IPodState extends State { child: Stack( children: [ + Padding( padding: EdgeInsets.all(5.8), child: buildMainView()), + Padding( + padding: EdgeInsets.all(5.5), + child: AnimatedOpacity( + opacity: popUp ? 1.0 : 0.0, + duration: Duration(milliseconds: 200), + child: Container(color: Colors.black.withOpacity(0.5)), + ), + ), + signIn(context), + ],) ), /*Container( @@ -256,6 +283,111 @@ class IPodState extends State { )); } + /* technically this should be in wheel_content.dart but for some reason it doesn't work when its there lol */ + Widget menuButton(context) { + return InkWell( + onTap: () { + if(mainViewMode != MainViewMode.menu) { + homePressed(context); + } + else if(popUp == true) { + setState(() { + popUp = false; + }); + } + else { + + menuKey.currentState?.back(); + } + HapticFeedback.mediumImpact(); + + }, + child: Container( + child: Text( + 'MENU', + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.bold, + color: controlsColor, + ), + ), + alignment: Alignment.topCenter, + margin: EdgeInsets.only(top: 15), + ), + ); + } + + Widget clickWheel(BuildContext context, ThemeState state) { + wheelColor = state.wheelColor == WheelColor.black + ? const Color(0xff151516) + : Colors.white; + + + controlsColor = state.wheelColor == WheelColor.white + ? Color.fromARGB(255, 185, 185, 190) + : Color.fromARGB(255, 222, 222, 222); + return Center( + child: Stack( + alignment: Alignment.center, + children: [ + GestureDetector( + onPanUpdate: panUpdateHandler, + onPanStart: panStartHandler, + child: Container( + height: widgetSize, + width: widgetSize, + decoration: BoxDecoration( + shape: BoxShape.circle, + border: Border.all(color: Color.fromARGB(255, 139, 139, 139)), + color: wheelColor, + ), + child: Stack(children: [ + menuButton(context), + fastForward(context), + fastRewind(context), + playButton(context) + ]), + ), + ), + GestureDetector( + onTap: () { + if(mainViewMode == MainViewMode.breakoutGame){ + if(breakoutGame.currentState?.isBreakoutGameOver == true && breakoutGame.currentState?.gameState == Game.fail){ + breakoutGame.currentState?.restart(); + } + } + else { + menuKey?.currentState?.select(); + altMenuKey?.currentState?.select(); + } + HapticFeedback.mediumImpact(); + SystemSound.play(SystemSoundType.click); + }, + child: selectButton() + ), + ], + ), + ); + } + + AltSubMenu getAltMenu() { + return AltSubMenu( + items: [ + AltMenuItem( + text: 'Spotify', + onTap: () { + //BlocProvider.of(context).add(SpotifyConnected()); + } + ), + AltMenuItem( + text: 'Apple Music', + ), + AltMenuItem( + text: 'Cancel', + ), + ], + ); + } IPodSubMenu getIPodMenu() { final IPodSubMenu wheelMenu = IPodSubMenu( @@ -273,12 +405,6 @@ class IPodState extends State { WheelColorChanged(WheelColor.black), ), ), - /* IPodMenuItem( - text: "Red", - onTap: () => BlocProvider.of(context).add( - WheelColorChanged(WheelColor.red), - ), - ),*/ ], ); @@ -308,22 +434,6 @@ class IPodState extends State { ], ); - final IPodSubMenu linkAccountMenu = IPodSubMenu( - caption: MenuCaption(text: "Link Account"), - items: [ - IPodMenuItem( - text: "Spotify", - onTap: () { - BlocProvider.of(context).add(SpotifyConnected()); - } - ), - /*IPodMenuItem( - text: - "Apple Music", - ),*/ - ], - ); - final IPodSubMenu songs = IPodSubMenu( caption: MenuCaption(text: "Songs"), items: [], @@ -337,7 +447,10 @@ class IPodState extends State { final IPodSubMenu musicMenu = IPodSubMenu( caption: MenuCaption(text: "Music"), items: [ - IPodMenuItem(text: "Music Service", subMenu: linkAccountMenu), + IPodMenuItem(text: "Sign In", + onTap:() => setState(() { + popUp = true; + }),), IPodMenuItem(text: "Songs", subMenu: songs), ], ); diff --git a/lib/games/breakout/breakout.dart b/lib/games/breakout/breakout.dart index 9fc722c..f6d84d4 100644 --- a/lib/games/breakout/breakout.dart +++ b/lib/games/breakout/breakout.dart @@ -13,6 +13,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:retro/blocs/theme/theme_bloc.dart'; import 'package:retro/blocs/theme/theme_state.dart'; +import 'package:retro/main.dart'; enum Game{running, fail} @@ -574,6 +575,10 @@ class BreakoutGameState extends State } } + void homePressed(context) async { + setState(() => mainViewMode = MainViewMode.menu); + } + void moveRight(){ int currTimeMS = DateTime.now().millisecondsSinceEpoch; int deltaMS = currTimeMS - prevTimeMS; diff --git a/lib/ipod_menu_widget/ipod_menu_widget.dart b/lib/ipod_menu_widget/ipod_menu_widget.dart index 9a8377c..3db5d30 100644 --- a/lib/ipod_menu_widget/ipod_menu_widget.dart +++ b/lib/ipod_menu_widget/ipod_menu_widget.dart @@ -49,7 +49,6 @@ class IPodMenuWidgetState extends State { @override void initState() { - homePressed(); _keys.add(GlobalKey()); _pages.add(IPodMenuPageWidget( key: _keys.last, @@ -113,19 +112,11 @@ class IPodMenuWidgetState extends State { } } - void homePressed() { - if (mainViewMode == MainViewMode.player || mainViewMode == MainViewMode.breakoutGame) { - setState(() => mainViewMode = MainViewMode.menu); - } else { - menuKey?.currentState?.back(); - } - } - - void playNextSong() { + void playNextSong(context) { BlocProvider.of(context).add(NextCalled(songIDs)); } - void playPrevSong() { + void playPrevSong(context) { BlocProvider.of(context).add(PrevCalled(songIDs)); } diff --git a/lib/main.dart b/lib/main.dart index b0cb188..94ae9a7 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -4,13 +4,15 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:playify/playify.dart'; +import 'package:retro/alt_menu/alt_sub_menu.dart'; import 'package:retro/blocs/player/player_bloc.dart'; import 'package:retro/blocs/songs/song_list.dart'; import 'package:retro/blocs/theme/theme.dart'; -import 'package:retro/ipod.dart'; +import 'package:retro/core.dart'; import 'package:retro/ipod_menu_widget/ipod_menu_widget.dart'; import 'package:retro/resources/main_player_repository.dart'; +import 'alt_menu/alt_menu_widget.dart'; import 'games/breakout/breakout.dart'; import 'ipod_menu_widget/ipod_sub_menu.dart'; @@ -36,10 +38,15 @@ double cartesianStartRadius; int ticksPerCircle; double tickAngel; bool wasExtraRadius; +Color wheelColor; +Color controlsColor; GlobalKey menuKey = new GlobalKey(); +GlobalKey altMenuKey = new GlobalKey(); GlobalKey breakoutGame = GlobalKey(); - +bool popUp = false; +bool showPlayerScreen = false; IPodSubMenu menu; +AltSubMenu altMenu; List songIDs; MainViewMode mainViewMode; diff --git a/lib/music_player_widget/music_player_screen.dart b/lib/music_player_widget/music_player_screen.dart index 229725b..e960c1b 100644 --- a/lib/music_player_widget/music_player_screen.dart +++ b/lib/music_player_widget/music_player_screen.dart @@ -1,4 +1,5 @@ import 'dart:async'; +import 'dart:math'; import 'package:battery_indicator/battery_indicator.dart'; import 'package:battery_plus/battery_plus.dart'; @@ -6,12 +7,15 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter/widgets.dart'; +import 'package:marquee/marquee.dart'; import 'package:retro/blocs/player/player_bloc.dart'; import 'package:retro/blocs/player/player_event.dart'; import 'package:retro/blocs/player/player_state.dart'; import 'package:intl/intl.dart'; +import 'package:retro/helpers/marquee.dart'; import 'package:retro/helpers/size_helpers.dart'; import 'package:retro/resources/resources.dart'; +import 'package:percent_indicator/percent_indicator.dart'; class NowPlayingScreen extends StatefulWidget { @@ -57,6 +61,7 @@ class _NowPlayingScreenState extends State { super.dispose(); } + // display the current time void _getTime() { DateTime _now = DateTime.now(); final String formattedDateTime = _formatDateTime(_now); @@ -80,14 +85,18 @@ class _NowPlayingScreenState extends State { children: [ _statusBar(), Padding( - padding: const EdgeInsets.symmetric(horizontal: 16.0), - child: Column( + padding: const EdgeInsets.symmetric(horizontal: 15.0), + child: Stack( children: [ - SizedBox(height: 33.0), - _albumArt(mediaQuery), - SizedBox(height: 35.0), - _linearProgressIndicator(), - ],)) + _albumArt(mediaQuery), + /* Positioned( + top: 100, + left: 0, + right: 0, + child: _linearProgressIndicator() + ),*/ + ], + ),) ], ), ); @@ -98,7 +107,7 @@ class _NowPlayingScreenState extends State { height: 25, width: double.infinity, child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 12.0), + padding: const EdgeInsets.symmetric(horizontal: 10.0), child: Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ @@ -179,7 +188,7 @@ class _NowPlayingScreenState extends State { mainAxisAlignment: MainAxisAlignment.center, children: [ Padding( - padding: EdgeInsets.fromLTRB(0, 0, 3, 0), + padding: EdgeInsets.fromLTRB(0, 0, 0, 10), child: Text( getHumanTime(state.playBackTime), style: TextStyle( @@ -189,19 +198,53 @@ class _NowPlayingScreenState extends State { fontSize: 12.0), ) ), - SizedBox( - height: 15, - width: displayWidth(context) * 0.6, - child: LinearProgressIndicator( - value: value, - valueColor: AlwaysStoppedAnimation( - Color(0xFF63beff), - ), - backgroundColor: Colors.grey[300], + Column(children: [ + SizedBox( + height: 15, + width: displayWidth(context) * 0.65, + child: LinearPercentIndicator( + clipLinearGradient: true, + lineHeight: 24, + backgroundColor: Colors.grey[100], + percent: value, + linearGradient: LinearGradient( + stops: [0.0, 0.4, 1.0], + colors: [ + Color(0xFF91B7F1), + Color(0xff7DB1F8), + Color(0xFF96DFFC), + ], + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + ), + ) ), - ), + Opacity( + opacity: 0.1, + child: SizedBox( + height: 10, + width: displayWidth(context) * 0.65, + child: LinearPercentIndicator( + clipLinearGradient: true, + lineHeight: 10, + backgroundColor: Colors.grey[100], + percent: value, + linearGradient: LinearGradient( + stops: [0.0, 0.4, 1.0], + colors: [ + Color(0xFF91B7F1), + Color(0xff7DB1F8), + Color(0xFF96DFFC), + ], + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + ), + ) + ), + ) + ],), Padding( - padding: EdgeInsets.fromLTRB(3, 0, 0, 0), + padding: EdgeInsets.fromLTRB(0, 0, 0, 10), child: Text( getHumanTime(state.songInfo.duration), style: TextStyle( @@ -233,20 +276,44 @@ class _NowPlayingScreenState extends State { child: Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ - Expanded( - flex: 2, - child: Container( - width: mediaQuery.size.width / 2.5, - height: mediaQuery.size.width / 2.5, - child: state.songInfo.coverArt ?? FittedBox(), - decoration: BoxDecoration( - shape: BoxShape.rectangle, - borderRadius: BorderRadius.all( - Radius.circular(24.0), + Column(children: [ + Transform( + transform: Matrix4.identity() + ..setEntry(3, 2, 0.005) + ..rotateY(-0.3), + alignment: FractionalOffset.center, + child: Expanded( + flex: 2, + child: Container( + width: mediaQuery.size.width / 3, + height: mediaQuery.size.width / 3, + child: state.songInfo.coverArt ?? FittedBox(), + ), ), ), - ), + // reflect the album art accross the x axis + Opacity( + opacity: 0.1, + child: Transform( + transform: Matrix4.identity() + ..setEntry(3, 2, 0.005) + ..rotateY(-0.3) + ..rotateX(pi), + alignment: FractionalOffset.center, + child: Container( + + width: mediaQuery.size.width / 3, + height: mediaQuery.size.width / 3, + child: state.songInfo.coverArt ?? FittedBox(), + + + ), + ), + ) + + ],), + Expanded( flex: 3, child: Container( @@ -258,37 +325,52 @@ class _NowPlayingScreenState extends State { children: [ Align( alignment: Alignment.centerLeft, - child: Text( - state.songInfo.title, - style: TextStyle( - color: Colors.black, - fontWeight: FontWeight.bold, - fontSize: 20.0, + child: MarqueeWidget( + direction: Axis.horizontal, + child: Text( + state.songInfo.title, + textAlign: TextAlign.center, + maxLines: 1, + style: TextStyle( + color: Colors.black, + fontSize: 18, + fontWeight: FontWeight.bold, + fontFamily: "Calibre-Semibold", + + ) + ) ), - maxLines: 2, - overflow: TextOverflow.ellipsis, - ), ), - SizedBox(height: 4.0), + SizedBox(height: 5.0), Align( alignment: Alignment.centerLeft, child: Text( state.songInfo.artistName, style: TextStyle( - color: Color.fromARGB(255, 33, 33, 33), - fontWeight: FontWeight.w600, + color: Color.fromARGB(255, 106, 106, 106), + fontWeight: FontWeight.bold, + fontSize: 15 ), ), ), + SizedBox(height: 5.0), Align( alignment: Alignment.centerLeft, - child: Text( - state.songInfo.albumTitle, - style: TextStyle( - color: Color.fromARGB(255, 33, 33, 33), - fontWeight: FontWeight.w600, + child: MarqueeWidget( + direction: Axis.horizontal, + child: Text( + state.songInfo.albumTitle, + textAlign: TextAlign.center, + maxLines: 1, + style: TextStyle( + color: Color.fromARGB(255, 106, 106, 106), + fontSize: 15, + fontWeight: FontWeight.bold, + fontFamily: "Calibre-Semibold", + + ) + ) ), - ), ) ], ), diff --git a/pubspec.lock b/pubspec.lock index b15e3b7..1ad80f8 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -7,21 +7,21 @@ packages: name: _fe_analyzer_shared url: "https://pub.dartlang.org" source: hosted - version: "39.0.0" + version: "50.0.0" analyzer: dependency: transitive description: name: analyzer url: "https://pub.dartlang.org" source: hosted - version: "4.0.0" + version: "5.2.0" archive: dependency: transitive description: name: archive url: "https://pub.dartlang.org" source: hosted - version: "3.3.0" + version: "3.3.5" args: dependency: transitive description: @@ -49,14 +49,14 @@ packages: name: battery_plus url: "https://pub.dartlang.org" source: hosted - version: "2.1.4" + version: "2.2.2" battery_plus_linux: dependency: transitive description: name: battery_plus_linux url: "https://pub.dartlang.org" source: hosted - version: "1.1.1" + version: "1.2.0" battery_plus_macos: dependency: transitive description: @@ -70,7 +70,7 @@ packages: name: battery_plus_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "1.2.1" + version: "1.2.2" battery_plus_web: dependency: transitive description: @@ -84,7 +84,7 @@ packages: name: battery_plus_windows url: "https://pub.dartlang.org" source: hosted - version: "1.1.2" + version: "1.1.3" bloc: dependency: transitive description: @@ -105,14 +105,14 @@ packages: name: build url: "https://pub.dartlang.org" source: hosted - version: "2.3.0" + version: "2.3.1" build_config: dependency: transitive description: name: build_config url: "https://pub.dartlang.org" source: hosted - version: "1.0.0" + version: "1.1.1" build_daemon: dependency: transitive description: @@ -126,21 +126,21 @@ packages: name: build_resolvers url: "https://pub.dartlang.org" source: hosted - version: "2.0.8" + version: "2.1.0" build_runner: dependency: "direct dev" description: name: build_runner url: "https://pub.dartlang.org" source: hosted - version: "2.1.10" + version: "2.3.2" build_runner_core: dependency: transitive description: name: build_runner_core url: "https://pub.dartlang.org" source: hosted - version: "7.2.3" + version: "7.2.7" built_collection: dependency: transitive description: @@ -154,7 +154,7 @@ packages: name: built_value url: "https://pub.dartlang.org" source: hosted - version: "8.3.0" + version: "8.4.2" characters: dependency: transitive description: @@ -162,13 +162,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.2.1" - charcode: - dependency: transitive - description: - name: charcode - url: "https://pub.dartlang.org" - source: hosted - version: "1.3.1" checked_yaml: dependency: transitive description: @@ -189,7 +182,7 @@ packages: name: code_builder url: "https://pub.dartlang.org" source: hosted - version: "4.1.0" + version: "4.3.0" collection: dependency: transitive description: @@ -203,7 +196,7 @@ packages: name: convert url: "https://pub.dartlang.org" source: hosted - version: "3.0.1" + version: "3.1.1" crypto: dependency: transitive description: @@ -217,21 +210,21 @@ packages: name: cupertino_icons url: "https://pub.dartlang.org" source: hosted - version: "1.0.4" + version: "1.0.5" dart_style: dependency: transitive description: name: dart_style url: "https://pub.dartlang.org" source: hosted - version: "2.2.3" + version: "2.2.4" dbus: dependency: transitive description: name: dbus url: "https://pub.dartlang.org" source: hosted - version: "0.7.3" + version: "0.7.8" dio: dependency: transitive description: @@ -245,7 +238,7 @@ packages: name: equatable url: "https://pub.dartlang.org" source: hosted - version: "2.0.3" + version: "2.0.5" fading_edge_scrollview: dependency: transitive description: @@ -266,14 +259,14 @@ packages: name: ffi url: "https://pub.dartlang.org" source: hosted - version: "1.2.1" + version: "2.0.1" file: dependency: transitive description: name: file url: "https://pub.dartlang.org" source: hosted - version: "6.1.2" + version: "6.1.4" fixnum: dependency: transitive description: @@ -299,7 +292,7 @@ packages: name: flutter_launcher_icons url: "https://pub.dartlang.org" source: hosted - version: "0.9.2" + version: "0.9.3" flutter_sfsymbols: dependency: "direct main" description: @@ -323,49 +316,49 @@ packages: name: frontend_server_client url: "https://pub.dartlang.org" source: hosted - version: "2.1.2" + version: "3.1.0" glob: dependency: transitive description: name: glob url: "https://pub.dartlang.org" source: hosted - version: "2.0.2" + version: "2.1.1" graphs: dependency: transitive description: name: graphs url: "https://pub.dartlang.org" source: hosted - version: "2.1.0" + version: "2.2.0" http: dependency: "direct main" description: name: http url: "https://pub.dartlang.org" source: hosted - version: "0.13.4" + version: "0.13.5" http_multi_server: dependency: transitive description: name: http_multi_server url: "https://pub.dartlang.org" source: hosted - version: "3.2.0" + version: "3.2.1" http_parser: dependency: transitive description: name: http_parser url: "https://pub.dartlang.org" source: hosted - version: "4.0.0" + version: "4.0.2" image: dependency: transitive description: name: image url: "https://pub.dartlang.org" source: hosted - version: "3.1.3" + version: "3.2.2" intl: dependency: "direct main" description: @@ -393,14 +386,14 @@ packages: name: json_annotation url: "https://pub.dartlang.org" source: hosted - version: "4.5.0" + version: "4.7.0" json_serializable: dependency: "direct main" description: name: json_serializable url: "https://pub.dartlang.org" source: hosted - version: "6.2.0" + version: "6.5.4" logger: dependency: transitive description: @@ -414,7 +407,7 @@ packages: name: logging url: "https://pub.dartlang.org" source: hosted - version: "1.0.2" + version: "1.1.0" marquee: dependency: "direct main" description: @@ -463,7 +456,7 @@ packages: name: package_config url: "https://pub.dartlang.org" source: hosted - version: "2.0.2" + version: "2.1.0" path: dependency: transitive description: @@ -477,21 +470,28 @@ packages: name: path_provider_linux url: "https://pub.dartlang.org" source: hosted - version: "2.1.6" + version: "2.1.7" path_provider_platform_interface: dependency: transitive description: name: path_provider_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "2.0.4" + version: "2.0.5" path_provider_windows: dependency: transitive description: name: path_provider_windows url: "https://pub.dartlang.org" source: hosted - version: "2.0.6" + version: "2.1.3" + percent_indicator: + dependency: "direct main" + description: + name: percent_indicator + url: "https://pub.dartlang.org" + source: hosted + version: "4.2.2" permission_handler: dependency: "direct main" description: @@ -512,28 +512,28 @@ packages: name: permission_handler_apple url: "https://pub.dartlang.org" source: hosted - version: "9.0.4" + version: "9.0.7" permission_handler_platform_interface: dependency: transitive description: name: permission_handler_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "3.7.0" + version: "3.9.0" permission_handler_windows: dependency: transitive description: name: permission_handler_windows url: "https://pub.dartlang.org" source: hosted - version: "0.1.0" + version: "0.1.2" petitparser: dependency: transitive description: name: petitparser url: "https://pub.dartlang.org" source: hosted - version: "4.4.0" + version: "5.1.0" platform: dependency: transitive description: @@ -554,14 +554,21 @@ packages: name: plugin_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "2.1.2" + version: "2.1.3" + pointycastle: + dependency: transitive + description: + name: pointycastle + url: "https://pub.dartlang.org" + source: hosted + version: "3.6.2" pool: dependency: transitive description: name: pool url: "https://pub.dartlang.org" source: hosted - version: "1.5.0" + version: "1.5.1" process: dependency: transitive description: @@ -575,21 +582,21 @@ packages: name: provider url: "https://pub.dartlang.org" source: hosted - version: "6.0.2" + version: "6.0.4" pub_semver: dependency: transitive description: name: pub_semver url: "https://pub.dartlang.org" source: hosted - version: "2.1.1" + version: "2.1.3" pubspec_parse: dependency: transitive description: name: pubspec_parse url: "https://pub.dartlang.org" source: hosted - version: "1.2.0" + version: "1.2.1" scrollable_positioned_list: dependency: "direct main" description: @@ -610,7 +617,7 @@ packages: name: shared_preferences_android url: "https://pub.dartlang.org" source: hosted - version: "2.0.12" + version: "2.0.14" shared_preferences_ios: dependency: transitive description: @@ -638,7 +645,7 @@ packages: name: shared_preferences_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "2.0.0" + version: "2.1.0" shared_preferences_web: dependency: transitive description: @@ -659,14 +666,14 @@ packages: name: shelf url: "https://pub.dartlang.org" source: hosted - version: "1.3.0" + version: "1.4.0" shelf_web_socket: dependency: transitive description: name: shelf_web_socket url: "https://pub.dartlang.org" source: hosted - version: "1.0.1" + version: "1.0.3" sky_engine: dependency: transitive description: flutter @@ -678,14 +685,14 @@ packages: name: source_gen url: "https://pub.dartlang.org" source: hosted - version: "1.2.2" + version: "1.2.6" source_helper: dependency: transitive description: name: source_helper url: "https://pub.dartlang.org" source: hosted - version: "1.3.2" + version: "1.3.3" source_span: dependency: transitive description: @@ -727,7 +734,7 @@ packages: name: stream_transform url: "https://pub.dartlang.org" source: hosted - version: "2.0.0" + version: "2.1.0" string_scanner: dependency: transitive description: @@ -741,7 +748,7 @@ packages: name: synchronized url: "https://pub.dartlang.org" source: hosted - version: "3.0.0+2" + version: "3.0.0+3" term_glyph: dependency: transitive description: @@ -769,7 +776,14 @@ packages: name: typed_data url: "https://pub.dartlang.org" source: hosted - version: "1.3.0" + version: "1.3.1" + upower: + dependency: transitive + description: + name: upower + url: "https://pub.dartlang.org" + source: hosted + version: "0.7.0" vector_math: dependency: transitive description: @@ -783,7 +797,7 @@ packages: name: watcher url: "https://pub.dartlang.org" source: hosted - version: "1.0.1" + version: "1.0.2" web_socket_channel: dependency: transitive description: @@ -797,21 +811,21 @@ packages: name: win32 url: "https://pub.dartlang.org" source: hosted - version: "2.5.2" + version: "3.1.1" xdg_directories: dependency: transitive description: name: xdg_directories url: "https://pub.dartlang.org" source: hosted - version: "0.2.0+1" + version: "0.2.0+2" xml: dependency: transitive description: name: xml url: "https://pub.dartlang.org" source: hosted - version: "5.3.1" + version: "6.1.0" yaml: dependency: transitive description: @@ -820,5 +834,5 @@ packages: source: hosted version: "3.1.1" sdks: - dart: ">=2.17.0 <3.0.0" + dart: ">=2.18.0 <3.0.0" flutter: ">=3.0.0" diff --git a/pubspec.yaml b/pubspec.yaml index 8e17dd5..1f928ec 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -42,6 +42,7 @@ dependencies: battery_plus: ^2.1.4 intl: ^0.17.0 marquee: ^2.2.3 + percent_indicator: ^4.0.1 # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons.