diff options
Diffstat (limited to 'lib/presentation/screens/media')
-rw-r--r-- | lib/presentation/screens/media/media.dart | 55 | ||||
-rw-r--r-- | lib/presentation/screens/media/media_player.dart | 68 | ||||
-rw-r--r-- | lib/presentation/screens/media/media_player_controls.dart | 201 | ||||
-rw-r--r-- | lib/presentation/screens/media/play_list_table.dart | 244 | ||||
-rw-r--r-- | lib/presentation/screens/media/radio_player.dart | 4 | ||||
-rw-r--r-- | lib/presentation/screens/media/radio_player_controls.dart | 146 | ||||
-rw-r--r-- | lib/presentation/screens/media/radio_preset_table.dart | 172 |
7 files changed, 530 insertions, 360 deletions
diff --git a/lib/presentation/screens/media/media.dart b/lib/presentation/screens/media/media.dart index b7ce9e1..e2ba927 100644 --- a/lib/presentation/screens/media/media.dart +++ b/lib/presentation/screens/media/media.dart @@ -1,7 +1,7 @@ import 'package:flutter_ics_homescreen/export.dart'; import 'package:flutter_ics_homescreen/presentation/screens/media/media_player.dart'; import 'package:flutter_ics_homescreen/presentation/screens/media/radio_player.dart'; -import 'widgets/media_volume_bar.dart'; +import 'package:flutter_ics_homescreen/data/data_providers/play_controller.dart'; import 'media_nav_notifier.dart'; import 'player_navigation.dart'; @@ -50,6 +50,21 @@ class MediaPage extends StatelessWidget { } } +class MediaPlayingStateNotifier extends Notifier<bool> { + @override + bool build() { + return false; + } + + set(bool value) { + state = value; + } +} + +final mediaPlayingStateProvider = + NotifierProvider<MediaPlayingStateNotifier, bool>( + MediaPlayingStateNotifier.new); + class Media extends ConsumerStatefulWidget { const Media({super.key}); @@ -58,22 +73,44 @@ class Media extends ConsumerStatefulWidget { } class _MediaState extends ConsumerState<Media> { - //late MediaNavState selectedNav; - - //@override - //initState() { - // selectedNav = ref.read(mediaNavStateProvider); - // super.initState(); - //} + @override + void initState() { + // Set initial source so external control (like the volume bar button) + // will work from the start. + var navState = ref.read(mediaNavStateProvider); + switch (navState) { + case MediaNavState.fm: + ref.read(playControllerProvider).setSource(PlaySource.radio); + break; + case MediaNavState.media: + default: + ref.read(playControllerProvider).setSource(PlaySource.media); + break; + } + super.initState(); + } onPressed(MediaNavState type) { setState(() { if (type == MediaNavState.fm) { ref.read(mediaNavStateProvider.notifier).set(MediaNavState.fm); + ref.read(playControllerProvider).setSource(PlaySource.radio); + + bool mediaPlaying = false; + if (ref.read(mediaPlayerStateProvider).playState == PlayState.playing) { + ref.read(mpdClientProvider).pause(); + mediaPlaying = true; + } + ref.read(mediaPlayingStateProvider.notifier).set(mediaPlaying); ref.read(radioClientProvider).start(); } else if (type == MediaNavState.media) { ref.read(mediaNavStateProvider.notifier).set(MediaNavState.media); + ref.read(playControllerProvider).setSource(PlaySource.media); + ref.read(radioClientProvider).stop(); + if (ref.read(mediaPlayingStateProvider)) { + ref.read(mpdClientProvider).play(); + } } }); } @@ -103,11 +140,13 @@ class _MediaState extends ConsumerState<Media> { : Container(), ), ), + /* if (navState == MediaNavState.media || navState == MediaNavState.fm) const Padding( padding: EdgeInsets.symmetric(horizontal: 144, vertical: 23.5), child: CustomVolumeSlider(), ), + */ ], ), ); diff --git a/lib/presentation/screens/media/media_player.dart b/lib/presentation/screens/media/media_player.dart index d7486c7..0dab346 100644 --- a/lib/presentation/screens/media/media_player.dart +++ b/lib/presentation/screens/media/media_player.dart @@ -3,38 +3,31 @@ import 'media_player_controls.dart'; import 'play_list_table.dart'; import 'segmented_buttons.dart'; -class MediaPlayer extends StatefulWidget { +class MediaPlayer extends ConsumerStatefulWidget { const MediaPlayer({super.key}); @override - State<MediaPlayer> createState() => _MediaPlayerState(); + ConsumerState<MediaPlayer> createState() => _MediaPlayerState(); } -class _MediaPlayerState extends State<MediaPlayer> { - String selectedNav = "Bluetooth"; - List<String> navItems = ["Bluetooth", "SD", "USB"]; - - late String songName = "Feel Good Inc."; - - String tableName = "2000’s Dance Hits"; - List<PlayListModel> playList = [ - PlayListModel(songName: "Feel Good Inc.", albumName: "Gorillaz"), - PlayListModel( - songName: "Hips Don’t Lie", albumName: "Shakira, Wyclef Jean"), - PlayListModel(songName: "AG1", albumName: "Paid Advertisement"), - PlayListModel(songName: "Hey Ya!", albumName: "Outkast"), - PlayListModel(songName: "One, Two, Step", albumName: "Ciara, Missy Elliot"), - PlayListModel(songName: "Don’t Trust Me", albumName: "3OH!3"), - ]; - String selectedPlayListSongName = "Feel Good Inc."; +class _MediaPlayerState extends ConsumerState<MediaPlayer> { + String selectedNav = "USB"; + List<String> navItems = ["USB", "SD", "Bluetooth"]; @override Widget build(BuildContext context) { - double albumArtSize = 460; + double albumArtSize = 400; + final playlistPosition = ref.watch(mediaPlayerStateProvider + .select((mediaplayer) => mediaplayer.playlistPosition)); + final playlistArt = ref.watch(playlistArtProvider); + Uint8List art = Uint8List(0); + if (playlistArt.containsKey(playlistPosition)) { + art = playlistArt[playlistPosition]!; + } + return Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ - //const PlayerNavigation(), SegmentedButtons( navItems: navItems, selectedNav: selectedNav, @@ -45,11 +38,20 @@ class _MediaPlayerState extends State<MediaPlayer> { Row( mainAxisAlignment: MainAxisAlignment.center, children: [ - Image.asset( - "assets/AlbumArtMedia.png", - width: albumArtSize, - height: albumArtSize, - ) + art.isNotEmpty + ? Image.memory(art, + width: albumArtSize, + height: albumArtSize, + fit: BoxFit.contain) + : Container( + width: albumArtSize, + height: albumArtSize, + color: AGLDemoColors.jordyBlueColor.withOpacity(0.2), + child: Icon( + Icons.music_note, + size: albumArtSize, + color: AGLDemoColors.jordyBlueColor, + )) ], ), const SizedBox( @@ -58,19 +60,11 @@ class _MediaPlayerState extends State<MediaPlayer> { Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ - MediaPlayerControls( - songName: songName, - songLengthStart: "-1:23", - songLengthStop: "5:03"), + MediaPlayerControls(), const SizedBox( - height: 72, - ), - PlayListTable( - playList: playList, - selectedPlayListSongName: selectedPlayListSongName, - tableName: tableName, - type: "media", + height: 12, ), + PlayListTable(), ], ) ], diff --git a/lib/presentation/screens/media/media_player_controls.dart b/lib/presentation/screens/media/media_player_controls.dart index 518b669..26cdfce 100644 --- a/lib/presentation/screens/media/media_player_controls.dart +++ b/lib/presentation/screens/media/media_player_controls.dart @@ -1,40 +1,49 @@ import 'package:flutter_ics_homescreen/core/utils/helpers.dart'; import 'package:flutter_ics_homescreen/export.dart'; -import 'package:flutter_ics_homescreen/presentation/screens/media/widgets/gradient_progress_indicator.dart'; +import 'package:flutter_ics_homescreen/presentation/screens/settings/settings_screens/audio_settings/widget/slider_widgets.dart'; -class MediaPlayerControls extends StatefulWidget { - const MediaPlayerControls( - {super.key, - required this.songName, - required this.songLengthStart, - required this.songLengthStop}); +// Time to string helper, returns HH:MM:SS or MM:SS as appropriate +String timeToString(Duration time) { + String result = ""; + if (time > const Duration(minutes: 59, seconds: 59)) { + result = time.toString().split('.').first.padLeft(8, "0"); + } else { + result = time.toString().substring(2, 7); + } + return result; +} - final String songName; - final String songLengthStart; - final String songLengthStop; +class MediaPlayerControls extends ConsumerStatefulWidget { + const MediaPlayerControls({super.key}); @override - State<MediaPlayerControls> createState() => _MediaPlayerControlsState(); + ConsumerState<MediaPlayerControls> createState() => + _MediaPlayerControlsState(); } -class _MediaPlayerControlsState extends State<MediaPlayerControls> { - late String songName; - late String songLengthStart; - late String songLengthStop; - final String albumName = "Gorillaz"; - - int songProgress = 20; - - @override - void initState() { - songName = widget.songName; - songLengthStart = widget.songLengthStart; - songLengthStop = widget.songLengthStop; - super.initState(); - } +class _MediaPlayerControlsState extends ConsumerState<MediaPlayerControls> { + //@override + //void initState() { + // super.initState(); + //} @override Widget build(BuildContext context) { + var currentSong = ref.watch( + mediaPlayerStateProvider.select((mediaplayer) => mediaplayer.song)); + var songPosition = ref.watch(mediaPlayerPositionProvider); + + String songName = ""; + String songDetail = ""; + String songPositionString = "00:00"; + String songLengthString = "00:00"; + if (currentSong != null) { + songName = currentSong.title; + songDetail = currentSong.artist; + songLengthString = timeToString(currentSong.duration); + } + songPositionString = timeToString(songPosition); + return Material( color: Colors.transparent, child: Column(crossAxisAlignment: CrossAxisAlignment.stretch, children: [ @@ -46,42 +55,25 @@ class _MediaPlayerControlsState extends State<MediaPlayerControls> { shadows: [Helpers.dropShadowRegular], fontSize: 44), ), - MediaPlayerControlsubDetails( - albumName: albumName, + MediaPlayerControlsDetails( + songDetail: songDetail, ), Column(children: [ - GradientProgressIndicator( - percent: songProgress, - type: "media", - gradient: LinearGradient( - begin: Alignment.centerLeft, - end: Alignment.centerRight, - colors: [ - AGLDemoColors.jordyBlueColor, - AGLDemoColors.jordyBlueColor.withOpacity(0.8), - ]), - backgroundColor: AGLDemoColors.gradientBackgroundDarkColor, - ), - // const LinearProgressIndicator( - // backgroundColor: AGLDemoColors.gradientBackgroundDarkColor, - // color: Colors.white70, - // minHeight: 8, - // value: 0.7, - // ), + const MediaPlayerControlsSlider(), Padding( padding: const EdgeInsets.symmetric(vertical: 5), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( - songLengthStart, + songPositionString, style: TextStyle( color: Colors.white, fontSize: 26, shadows: [Helpers.dropShadowRegular]), ), Text( - songLengthStop, + songLengthString, style: TextStyle( color: Colors.white, fontSize: 26, @@ -91,23 +83,23 @@ class _MediaPlayerControlsState extends State<MediaPlayerControls> { ), ), ]), - const MediaPlayerActions(), + const MediaPlayerControlsActions(), ]), ); } } -class MediaPlayerControlsubDetails extends StatefulWidget { - const MediaPlayerControlsubDetails({super.key, required this.albumName}); - final String albumName; +class MediaPlayerControlsDetails extends StatefulWidget { + const MediaPlayerControlsDetails({super.key, required this.songDetail}); + final String songDetail; @override - State<MediaPlayerControlsubDetails> createState() => - _MediaPlayerControlsubDetailsState(); + State<MediaPlayerControlsDetails> createState() => + _MediaPlayerControlsDetailsState(); } -class _MediaPlayerControlsubDetailsState - extends State<MediaPlayerControlsubDetails> { +class _MediaPlayerControlsDetailsState + extends State<MediaPlayerControlsDetails> { bool isShuffleEnabled = false; bool isRepeatEnabled = false; @override @@ -116,7 +108,7 @@ class _MediaPlayerControlsubDetailsState mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( - widget.albumName, + widget.songDetail, style: TextStyle( color: Colors.white, fontWeight: FontWeight.w400, @@ -158,25 +150,98 @@ class _MediaPlayerControlsubDetailsState } } -class MediaPlayerActions extends StatefulWidget { - const MediaPlayerActions({super.key}); +class MediaPlayerControlsSlider extends ConsumerStatefulWidget { + const MediaPlayerControlsSlider({super.key}); + + @override + ConsumerState<MediaPlayerControlsSlider> createState() => + MediaPlayerControlsSliderState(); +} + +class MediaPlayerControlsSliderState + extends ConsumerState<MediaPlayerControlsSlider> { + //late Duration songPosition; + + //@override + //void initState() { + // songPosition = ref.read(mediaPlayerPositionProvider); + // super.initState(); + //} + + @override + Widget build(BuildContext context) { + var currentSong = ref.watch( + mediaPlayerStateProvider.select((mediaplayer) => mediaplayer.song)); + var songPosition = ref.watch(mediaPlayerPositionProvider); + + Duration songLength = Duration.zero; + if (currentSong != null) { + songLength = currentSong.duration; + } + + return Container( + height: 80, + child: SliderTheme( + data: SliderThemeData( + overlayShape: SliderComponentShape.noOverlay, + valueIndicatorShape: SliderComponentShape.noOverlay, + activeTickMarkColor: Colors.transparent, + inactiveTickMarkColor: Colors.transparent, + inactiveTrackColor: AGLDemoColors.periwinkleColor, + thumbShape: const PolygonSliderThumb(sliderValue: 3, thumbRadius: 23), + //trackHeight: 5, + ), + child: Slider( + max: songLength.inMilliseconds.toDouble(), + value: songPosition.inMilliseconds.toDouble(), + onChangeStart: (double value) { + // Disable timer so position will not change while control is + // being dragged. It will be re-enabled via the playback state + // update from MPD. + ref.read(mediaPlayerPositionProvider.notifier).pause(); + }, + onChanged: (double newValue) { + setState(() { + ref + .read(mediaPlayerPositionProvider.notifier) + .set(Duration(milliseconds: newValue.toInt())); + }); + }, + onChangeEnd: (double newValue) { + ref.read(mpdClientProvider).seek(newValue.toInt()); + }, + ), + ), + ); + } +} + +class MediaPlayerControlsActions extends ConsumerStatefulWidget { + const MediaPlayerControlsActions({super.key}); @override - State<MediaPlayerActions> createState() => _MediaPlayerActionsState(); + ConsumerState<MediaPlayerControlsActions> createState() => + _MediaPlayerControlsActionsState(); } -class _MediaPlayerActionsState extends State<MediaPlayerActions> { +class _MediaPlayerControlsActionsState + extends ConsumerState<MediaPlayerControlsActions> { bool isPressed = false; - bool isPlaying = true; @override Widget build(BuildContext context) { + bool isPlaying = ref.watch(mediaPlayerStateProvider + .select((mediaplayer) => mediaplayer.playState)) == + PlayState.playing; + return Row( mainAxisAlignment: MainAxisAlignment.center, children: [ InkWell( customBorder: const CircleBorder(), - onTap: () {}, + onTap: () { + ref.read(mpdClientProvider).previous(); + }, child: Padding( padding: const EdgeInsets.all(8.0), child: SvgPicture.asset( @@ -191,7 +256,11 @@ class _MediaPlayerActionsState extends State<MediaPlayerActions> { customBorder: const CircleBorder(), onTap: () { setState(() { - isPlaying = !isPlaying; + if (isPlaying) { + ref.read(mpdClientProvider).pause(); + } else { + ref.read(mpdClientProvider).play(); + } }); }, onTapDown: (details) { @@ -221,7 +290,9 @@ class _MediaPlayerActionsState extends State<MediaPlayerActions> { ), InkWell( customBorder: const CircleBorder(), - onTap: () {}, + onTap: () { + ref.read(mpdClientProvider).next(); + }, child: Padding( padding: const EdgeInsets.all(8.0), child: SvgPicture.asset( diff --git a/lib/presentation/screens/media/play_list_table.dart b/lib/presentation/screens/media/play_list_table.dart index 369bb9c..71d2fc9 100644 --- a/lib/presentation/screens/media/play_list_table.dart +++ b/lib/presentation/screens/media/play_list_table.dart @@ -2,38 +2,29 @@ import 'package:auto_size_text/auto_size_text.dart'; import 'package:flutter_ics_homescreen/core/utils/helpers.dart'; import 'package:flutter_ics_homescreen/export.dart'; -class PlayListTable extends StatefulWidget { - const PlayListTable( - {super.key, - required this.type, - required this.tableName, - required this.playList, - required this.selectedPlayListSongName}); - final String type; - final String tableName; - final List<PlayListModel> playList; - final String selectedPlayListSongName; +class PlayListTable extends ConsumerStatefulWidget { + PlayListTable({super.key}); @override - State<PlayListTable> createState() => _PlayListTableState(); + ConsumerState<PlayListTable> createState() => _PlayListTableState(); } -class _PlayListTableState extends State<PlayListTable> { +class _PlayListTableState extends ConsumerState<PlayListTable> { bool isAudioSettingsEnabled = false; - late String tableName; - late List<PlayListModel> playList; - late String selectedPlayListSongName; - @override - void initState() { - tableName = widget.tableName; - playList = widget.playList; - selectedPlayListSongName = widget.selectedPlayListSongName; - super.initState(); - } + //@override + //void initState() { + // super.initState(); + //} @override Widget build(BuildContext context) { + final controller = ScrollController(); + var playlist = ref.watch(playlistProvider); + var selectedPosition = ref.watch(mediaPlayerStateProvider + .select((mediaplayer) => mediaplayer.playlistPosition)); + late String tableName = "USB"; + return Material( color: Colors.transparent, child: Column( @@ -51,19 +42,18 @@ class _PlayListTableState extends State<PlayListTable> { fontWeight: FontWeight.w400, fontSize: 40), ), - if (widget.type == "media") - InkWell( - customBorder: const CircleBorder(), - onTap: () {}, - child: Opacity( - opacity: 0.5, - child: Padding( - padding: const EdgeInsets.all(8.0), - child: SvgPicture.asset( - "assets/AppleMusic.svg", - width: 32, - )), - )), + InkWell( + customBorder: const CircleBorder(), + onTap: () {}, + child: Opacity( + opacity: 0.5, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: SvgPicture.asset( + "assets/AppleMusic.svg", + width: 32, + )), + )), ], ), InkWell( @@ -81,77 +71,119 @@ class _PlayListTableState extends State<PlayListTable> { ))) ], ), - SizedBox( - height: 325, - child: SingleChildScrollView( - child: Column( - children: playList.map((index) { - return Container( - height: 100, - margin: const EdgeInsets.symmetric(vertical: 4), - decoration: BoxDecoration( - border: Border( - left: selectedPlayListSongName == index.songName - ? const BorderSide( - color: Colors.white, width: 4) - : BorderSide.none), - gradient: LinearGradient( - colors: selectedPlayListSongName == index.songName - ? [ - AGLDemoColors.neonBlueColor, - AGLDemoColors.neonBlueColor - .withOpacity(0.15) - ] - : [ - Colors.black, - Colors.black.withOpacity(0.20) - ])), - child: InkWell( - onTap: () { - setState(() { - selectedPlayListSongName = index.songName; - }); - }, - child: Padding( - padding: const EdgeInsets.symmetric( - vertical: 17, horizontal: 24), - child: Row( - children: [ - Expanded( - flex: 6, - child: AutoSizeText( - index.songName, - maxLines: 1, - style: TextStyle( - color: Colors.white, - fontSize: 40, - shadows: [Helpers.dropShadowRegular]), - )), - Expanded( - flex: 4, - child: Text( - index.albumName, - style: TextStyle( - color: Colors.white, - fontSize: 26, - shadows: [Helpers.dropShadowRegular]), - )) - ], - ), - ), - ), - ); - }).toList()), - ), - ), + Padding( + padding: const EdgeInsets.only(right: 12), + child: SizedBox( + height: 500, + child: RawScrollbar( + controller: controller, + thickness: 32, + thumbVisibility: true, + radius: const Radius.circular(10), + thumbColor: AGLDemoColors.periwinkleColor, + minThumbLength: 60, + interactive: true, + child: ScrollConfiguration( + behavior: ScrollConfiguration.of(context).copyWith( + scrollbars: false, + overscroll: false, + ), + child: CustomScrollView( + controller: controller, + physics: const ClampingScrollPhysics(), + slivers: <Widget>[ + SliverList.separated( + itemCount: playlist.length, + itemBuilder: (_, int index) { + return Container( + height: 92, + margin: + const EdgeInsets.only(right: 44), + decoration: BoxDecoration( + border: Border( + left: selectedPosition == + playlist[index].position + ? const BorderSide( + color: Colors.white, + width: 4) + : BorderSide.none), + gradient: LinearGradient( + colors: selectedPosition == + playlist[index].position + ? [ + AGLDemoColors + .neonBlueColor, + AGLDemoColors + .neonBlueColor + .withOpacity(0.15) + ] + : [ + Colors.black, + Colors.black + .withOpacity(0.20) + ])), + child: InkWell( + onTap: () { + setState(() { + selectedPosition = + playlist[index].position; + ref + .read(mpdClientProvider) + .pickTrack( + playlist[index].position); + }); + }, + child: Padding( + padding: const EdgeInsets.symmetric( + vertical: 17, horizontal: 24), + child: Column( + children: [ + Expanded( + flex: 6, + child: Align( + alignment: Alignment + .centerLeft, + child: AutoSizeText( + playlist[index].title, + maxLines: 1, + style: TextStyle( + color: + Colors.white, + fontSize: 40, + shadows: [ + Helpers + .dropShadowRegular + ]), + ))), + Expanded( + flex: 4, + child: Align( + alignment: Alignment + .centerLeft, + child: Text( + playlist[index] + .artist, + style: TextStyle( + color: + Colors.white, + fontSize: 22, + shadows: [ + Helpers + .dropShadowRegular + ]), + ))) + ], + ), + ), + ), + ); + }, + separatorBuilder: (_, __) { + return SizedBox(height: 8); + }, + ), + ]))))), ], )); } } - -class PlayListModel { - final String songName; - final String albumName; - - PlayListModel({required this.songName, required this.albumName}); -} diff --git a/lib/presentation/screens/media/radio_player.dart b/lib/presentation/screens/media/radio_player.dart index 4531c7b..f6695f1 100644 --- a/lib/presentation/screens/media/radio_player.dart +++ b/lib/presentation/screens/media/radio_player.dart @@ -34,8 +34,8 @@ class _RadioPlayerState extends ConsumerState<RadioPlayer> { @override Widget build(BuildContext context) { - double fmSignalHeight = 460; - double fmSignalWidth = 460; + double fmSignalHeight = 400; + double fmSignalWidth = 400; return Container( padding: const EdgeInsets.only(left: 7, right: 7), diff --git a/lib/presentation/screens/media/radio_player_controls.dart b/lib/presentation/screens/media/radio_player_controls.dart index bfa8da6..acc8291 100644 --- a/lib/presentation/screens/media/radio_player_controls.dart +++ b/lib/presentation/screens/media/radio_player_controls.dart @@ -10,6 +10,12 @@ class RadioPlayerControls extends ConsumerWidget { var freqCurrent = ref.watch(radioStateProvider.select((radio) => radio.freqCurrent)); String currentString = (freqCurrent / 1000000.0).toStringAsFixed(1); + var freqMin = + ref.watch(radioStateProvider.select((radio) => radio.freqMin)); + String freqMinString = (freqMin / 1000000.0).toStringAsFixed(1); + var freqMax = + ref.watch(radioStateProvider.select((radio) => radio.freqMax)); + String freqMaxString = (freqMax / 1000000.0).toStringAsFixed(1); return Material( color: Colors.transparent, @@ -24,16 +30,40 @@ class RadioPlayerControls extends ConsumerWidget { shadows: [Helpers.dropShadowRegular], fontSize: 44), ), - const RadioPlayerControlsSubDetails(), - const RadioPlayerControlsSlider(), + const RadioPlayerControlsActions(), + Column(children: [ + const RadioPlayerControlsSlider(), + Padding( + padding: const EdgeInsets.symmetric(vertical: 5), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + freqMinString, + style: TextStyle( + color: Colors.white, + fontSize: 26, + shadows: [Helpers.dropShadowRegular]), + ), + Text( + freqMaxString, + style: TextStyle( + color: Colors.white, + fontSize: 26, + shadows: [Helpers.dropShadowRegular]), + ) + ], + ), + ), + ]), ], ), ); } } -class RadioPlayerControlsSubDetails extends ConsumerWidget { - const RadioPlayerControlsSubDetails({super.key}); +class RadioPlayerControlsActions extends ConsumerWidget { + const RadioPlayerControlsActions({super.key}); onPressed({required WidgetRef ref, required String type}) { if (type == "tuneLeft") { @@ -174,78 +204,40 @@ class RadioPlayerControlsSliderState ref.watch(radioStateProvider.select((radio) => radio.freqCurrent)) / 1000000.0; - String minString = (freqMin / 1000000.0).toStringAsFixed(1); - String maxString = (freqMax / 1000000.0).toStringAsFixed(1); - - return Padding( - padding: const EdgeInsets.symmetric(horizontal: 64), - child: Container( - decoration: const ShapeDecoration( - color: AGLDemoColors.buttonFillEnabledColor, - shape: StadiumBorder( - side: BorderSide( - color: Color(0xFF5477D4), - width: 0.5, - )), - ), - height: 160, - child: Row( - children: [ - Padding( - padding: const EdgeInsets.symmetric(horizontal: 20), - child: Text( - minString, - style: TextStyle( - color: Colors.white, - fontSize: 32, - shadows: [Helpers.dropShadowRegular]), - )), - Expanded( - child: SliderTheme( - data: SliderThemeData( - overlayShape: SliderComponentShape.noOverlay, - valueIndicatorShape: SliderComponentShape.noOverlay, - activeTickMarkColor: Colors.transparent, - inactiveTickMarkColor: Colors.transparent, - inactiveTrackColor: AGLDemoColors.backgroundInsetColor, - thumbShape: const PolygonSliderThumb( - sliderValue: 3, thumbRadius: 23), - //trackHeight: 5, - ), - child: Slider( - divisions: (freqMax - freqMin) ~/ freqStep, - min: freqMin / 1000000.0, - max: freqMax / 1000000.0, - value: currentFreq, - onChangeStart: (double value) { - ref.read(radioClientProvider).scanStop(); - }, - onChanged: (double value) { - setState(() { - ref - .read(radioStateProvider.notifier) - .updateFrequency((value * 1000000.0).toInt()); - }); - }, - onChangeEnd: (double value) { - ref - .read(radioStateProvider.notifier) - .setFrequency((value * 1000000.0).toInt()); - }, - ), - ), - ), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 20), - child: Text( - maxString, - style: TextStyle( - color: Colors.white, - fontSize: 32, - shadows: [Helpers.dropShadowRegular]), - )), - ], - ), - )); + return Container( + height: 80, + child: SliderTheme( + data: SliderThemeData( + overlayShape: SliderComponentShape.noOverlay, + valueIndicatorShape: SliderComponentShape.noOverlay, + activeTickMarkColor: Colors.transparent, + inactiveTickMarkColor: Colors.transparent, + inactiveTrackColor: AGLDemoColors.periwinkleColor, + thumbShape: const PolygonSliderThumb(sliderValue: 3, thumbRadius: 23), + //trackHeight: 5, + ), + child: Slider( + divisions: (freqMax - freqMin) ~/ freqStep, + min: freqMin / 1000000.0, + max: freqMax / 1000000.0, + value: currentFreq, + onChangeStart: (double value) { + ref.read(radioClientProvider).scanStop(); + }, + onChanged: (double value) { + setState(() { + ref + .read(radioStateProvider.notifier) + .updateFrequency((value * 1000000.0).toInt()); + }); + }, + onChangeEnd: (double value) { + ref + .read(radioStateProvider.notifier) + .setFrequency((value * 1000000.0).toInt()); + }, + ), + ), + ); } } diff --git a/lib/presentation/screens/media/radio_preset_table.dart b/lib/presentation/screens/media/radio_preset_table.dart index 816bcb9..97affb8 100644 --- a/lib/presentation/screens/media/radio_preset_table.dart +++ b/lib/presentation/screens/media/radio_preset_table.dart @@ -38,6 +38,8 @@ class _RadioPresetTableState extends ConsumerState<RadioPresetTable> { @override Widget build(BuildContext context) { + final controller = ScrollController(); + return Material( color: Colors.transparent, child: Column( @@ -72,72 +74,112 @@ class _RadioPresetTableState extends ConsumerState<RadioPresetTable> { ))) ], ), - SizedBox( - height: 325, - child: SingleChildScrollView( - child: Column( - children: presets.map((index) { - return Container( - height: 100, - margin: const EdgeInsets.symmetric(vertical: 4), - decoration: BoxDecoration( - border: Border( - left: selectedPreset == index.name - ? const BorderSide( - color: Colors.white, width: 4) - : BorderSide.none), - gradient: LinearGradient( - colors: selectedPreset == index.name - ? [ - AGLDemoColors.neonBlueColor, - AGLDemoColors.neonBlueColor - .withOpacity(0.15) - ] - : [ - Colors.black, - Colors.black.withOpacity(0.20) - ])), - child: InkWell( - onTap: () { - ref - .read(radioClientProvider) - .setFrequency(index.frequency); - setState(() { - selectedPreset = index.name; - }); - }, - child: Padding( - padding: const EdgeInsets.symmetric( - vertical: 17, horizontal: 24), - child: Row( - children: [ - Expanded( - flex: 6, - child: AutoSizeText( - index.name, - maxLines: 1, - style: TextStyle( - color: Colors.white, - fontSize: 40, - shadows: [Helpers.dropShadowRegular]), - )), - Expanded( - flex: 4, - child: Text( - frequencyToString(index.frequency), - style: TextStyle( - color: Colors.white, - fontSize: 26, - shadows: [Helpers.dropShadowRegular]), - )) - ], + Padding( + padding: const EdgeInsets.only(right: 12), + child: SizedBox( + height: 500, + child: RawScrollbar( + controller: controller, + thickness: 32, + thumbVisibility: true, + radius: const Radius.circular(10), + thumbColor: AGLDemoColors.periwinkleColor, + minThumbLength: 60, + interactive: true, + child: ScrollConfiguration( + behavior: ScrollConfiguration.of(context).copyWith( + scrollbars: false, + overscroll: false, ), - ), - ), - ); - }).toList()), - ), - ), + child: CustomScrollView( + controller: controller, + physics: const ClampingScrollPhysics(), + slivers: <Widget>[ + SliverList.separated( + itemCount: presets.length, + itemBuilder: (_, int index) { + return Container( + height: 92, + margin: const EdgeInsets.only(right: 44), + decoration: BoxDecoration( + border: Border( + left: selectedPreset == + presets[index].name + ? const BorderSide( + color: Colors.white, + width: 4) + : BorderSide.none), + gradient: LinearGradient( + colors: selectedPreset == + presets[index].name + ? [ + AGLDemoColors.neonBlueColor, + AGLDemoColors.neonBlueColor + .withOpacity(0.15) + ] + : [ + Colors.black, + Colors.black + .withOpacity(0.20) + ])), + child: InkWell( + onTap: () { + ref + .read(radioClientProvider) + .setFrequency( + presets[index].frequency); + setState(() { + selectedPreset = presets[index].name; + }); + }, + child: Padding( + padding: const EdgeInsets.symmetric( + vertical: 17, horizontal: 24), + child: Row( + children: [ + Expanded( + flex: 6, + child: AutoSizeText( + presets[index].name, + maxLines: 1, + style: TextStyle( + color: Colors.white, + fontSize: 32, + shadows: [ + Helpers + .dropShadowRegular + ]), + )), + Expanded( + flex: 4, + child: Align( + alignment: + Alignment.centerRight, + child: Text( + frequencyToString( + presets[index] + .frequency), + style: TextStyle( + color: Colors.white, + fontSize: 24, + shadows: [ + Helpers + .dropShadowRegular + ]), + ))) + ], + ), + ), + ), + ); + }, + separatorBuilder: (_, __) { + return SizedBox(height: 8); + }, + ), + ])), + ), + )), ], )); } |