From c0ace9468586e546ba803e4e8749b7003d1cfe85 Mon Sep 17 00:00:00 2001 From: MSOB7YY Date: Sat, 31 Aug 2024 23:03:03 +0300 Subject: [PATCH] feat: left & right swipe actions for track tile ref: #333 --- lib/controller/settings_controller.dart | 10 ++ lib/core/enums.dart | 8 ++ lib/core/namida_converter_ext.dart | 11 ++ lib/core/translations/keys.dart | 1 + lib/packages/miniplayer.dart | 1 + lib/ui/dialogs/common_dialogs.dart | 2 +- .../subpages/playlist_tracks_subpage.dart | 1 + lib/ui/widgets/custom_widgets.dart | 44 ++++-- lib/ui/widgets/library/queue_tile.dart | 2 +- lib/ui/widgets/library/track_tile.dart | 136 ++++++++++++------ lib/ui/widgets/selected_tracks_preview.dart | 1 + .../settings/customization_settings.dart | 51 +++++++ .../widgets/yt_description_widget.dart | 2 +- pubspec.yaml | 2 +- 14 files changed, 218 insertions(+), 54 deletions(-) diff --git a/lib/controller/settings_controller.dart b/lib/controller/settings_controller.dart index 205609fb..0bde4464 100644 --- a/lib/controller/settings_controller.dart +++ b/lib/controller/settings_controller.dart @@ -198,6 +198,8 @@ class _SettingsController with SettingsFileWriter { final ytMostPlayedCustomisStartOfDay = true.obs; /// Track Items + final onTrackSwipeLeft = OnTrackTileSwapActions.none.obs; + final onTrackSwipeRight = OnTrackTileSwapActions.none.obs; final displayThirdRow = true.obs; final displayThirdItemInEachRow = false.obs; final trackTileSeparator = '•'.obs; @@ -439,6 +441,8 @@ class _SettingsController with SettingsFileWriter { ytMostPlayedCustomisStartOfDay.value = json['ytMostPlayedCustomisStartOfDay'] ?? ytMostPlayedCustomisStartOfDay.value; /// Track Items + onTrackSwipeLeft.value = OnTrackTileSwapActions.values.getEnum(json['onTrackSwipeLeft']) ?? onTrackSwipeLeft.value; + onTrackSwipeRight.value = OnTrackTileSwapActions.values.getEnum(json['onTrackSwipeRight']) ?? onTrackSwipeRight.value; displayThirdRow.value = json['displayThirdRow'] ?? displayThirdRow.value; displayThirdItemInEachRow.value = json['displayThirdItemInEachRow'] ?? displayThirdItemInEachRow.value; trackTileSeparator.value = json['trackTileSeparator'] ?? trackTileSeparator.value; @@ -610,6 +614,8 @@ class _SettingsController with SettingsFileWriter { 'ytMostPlayedCustomisStartOfDay': ytMostPlayedCustomisStartOfDay.value, /// Track Items + 'onTrackSwipeLeft': onTrackSwipeLeft.value.name, + 'onTrackSwipeRight': onTrackSwipeRight.value.name, 'displayThirdRow': displayThirdRow.value, 'displayThirdItemInEachRow': displayThirdItemInEachRow.value, 'trackTileSeparator': trackTileSeparator.value, @@ -689,6 +695,8 @@ class _SettingsController with SettingsFileWriter { bool? playlistSortReversed, GroupSortType? ytPlaylistSort, bool? ytPlaylistSortReversed, + OnTrackTileSwapActions? onTrackSwipeLeft, + OnTrackTileSwapActions? onTrackSwipeRight, bool? displayThirdRow, bool? displayThirdItemInEachRow, String? trackTileSeparator, @@ -859,6 +867,8 @@ class _SettingsController with SettingsFileWriter { if (playlistSortReversed != null) this.playlistSortReversed.value = playlistSortReversed; if (ytPlaylistSort != null) this.ytPlaylistSort.value = ytPlaylistSort; if (ytPlaylistSortReversed != null) this.ytPlaylistSortReversed.value = ytPlaylistSortReversed; + if (onTrackSwipeLeft != null) this.onTrackSwipeLeft.value = onTrackSwipeLeft; + if (onTrackSwipeRight != null) this.onTrackSwipeRight.value = onTrackSwipeRight; if (displayThirdRow != null) this.displayThirdRow.value = displayThirdRow; if (displayThirdItemInEachRow != null) this.displayThirdItemInEachRow.value = displayThirdItemInEachRow; if (trackTileSeparator != null) this.trackTileSeparator.value = trackTileSeparator; diff --git a/lib/core/enums.dart b/lib/core/enums.dart index bf5b0af4..f7e45aa9 100644 --- a/lib/core/enums.dart +++ b/lib/core/enums.dart @@ -410,3 +410,11 @@ enum YTVisibleMixesPlaces { search, relatedVideos, } + +enum OnTrackTileSwapActions { + none, + playnext, + playlast, + playafter, + addtoplaylist, +} diff --git a/lib/core/namida_converter_ext.dart b/lib/core/namida_converter_ext.dart index b1f5a37c..2003f36e 100644 --- a/lib/core/namida_converter_ext.dart +++ b/lib/core/namida_converter_ext.dart @@ -374,6 +374,10 @@ extension LocalVideoMatchingTypeText on LocalVideoMatchingType { String toText() => _NamidaConverters.inst.getTitle(this); } +extension OnTrackTileSwapActionsUtils on OnTrackTileSwapActions { + String toText() => _NamidaConverters.inst.getTitle(this); +} + extension TRACKPLAYMODE on TrackPlayMode { String toText() => _NamidaConverters.inst.getTitle(this); } @@ -1177,6 +1181,13 @@ class _NamidaConverters { TrackPlayMode.trackArtist: lang.TRACK_PLAY_MODE_TRACK_ARTIST, TrackPlayMode.trackGenre: lang.TRACK_PLAY_MODE_TRACK_GENRE, }, + OnTrackTileSwapActions: { + OnTrackTileSwapActions.none: lang.NONE, + OnTrackTileSwapActions.playnext: lang.PLAY_NEXT, + OnTrackTileSwapActions.playlast: lang.PLAY_LAST, + OnTrackTileSwapActions.playafter: lang.PLAY_AFTER, + OnTrackTileSwapActions.addtoplaylist: lang.ADD_TO_PLAYLIST, + }, InsertionSortingType: { InsertionSortingType.listenCount: lang.TOTAL_LISTENS, InsertionSortingType.random: lang.RANDOM, diff --git a/lib/core/translations/keys.dart b/lib/core/translations/keys.dart index cd26dd0a..a3cfb1bd 100644 --- a/lib/core/translations/keys.dart +++ b/lib/core/translations/keys.dart @@ -444,6 +444,7 @@ abstract class LanguageKeys { String get ON_INTERRUPTION => _getKey('ON_INTERRUPTION'); String get ON_NOTIFICATION_TAP => _getKey('ON_NOTIFICATION_TAP'); String get ON_OPENING_YOUTUBE_LINK => _getKey('ON_OPENING_YOUTUBE_LINK'); + String get ON_SWIPING => _getKey('ON_SWIPING'); String get ON_VOLUME_ZERO => _getKey('ON_VOLUME_ZERO'); String get OPEN => _getKey('OPEN'); String get OPEN_APP => _getKey('OPEN_APP'); diff --git a/lib/packages/miniplayer.dart b/lib/packages/miniplayer.dart index af29f970..96c9d86c 100644 --- a/lib/packages/miniplayer.dart +++ b/lib/packages/miniplayer.dart @@ -158,6 +158,7 @@ class NamidaMiniPlayerTrack extends StatelessWidget { trackTileConfigs: const TrackTilePropertiesConfigs( displayRightDragHandler: true, draggableThumbnail: true, + horizontalGestures: false, queueSource: QueueSource.playerQueue, ), itemBuilder: (context, i, currentIndex, queue, properties) { diff --git a/lib/ui/dialogs/common_dialogs.dart b/lib/ui/dialogs/common_dialogs.dart index e2ab74a8..ebb5f03a 100644 --- a/lib/ui/dialogs/common_dialogs.dart +++ b/lib/ui/dialogs/common_dialogs.dart @@ -198,7 +198,7 @@ class NamidaDialogs { required Folder folder, required bool recursiveTracks, }) async { - if (recursiveTracks) Vibration.vibrate(duration: 20, amplitude: 50); + if (recursiveTracks) Vibration.vibrate(duration: 20, amplitude: 40); final tracks = recursiveTracks ? folder.tracksRecusive().toList() : folder.tracks(); await showGeneralPopupDialog( tracks, diff --git a/lib/ui/pages/subpages/playlist_tracks_subpage.dart b/lib/ui/pages/subpages/playlist_tracks_subpage.dart index 20abb5b5..e2f38b72 100644 --- a/lib/ui/pages/subpages/playlist_tracks_subpage.dart +++ b/lib/ui/pages/subpages/playlist_tracks_subpage.dart @@ -430,6 +430,7 @@ class _NormalPlaylistTracksPageState extends State wit queueSource: playlist.toQueueSource(), playlistName: playlist.name, draggableThumbnail: reorderable, + horizontalGestures: !reorderable, selectable: () => !PlaylistController.inst.canReorderTracks.value, ), builder: (properties) => NamidaListViewRaw( diff --git a/lib/ui/widgets/custom_widgets.dart b/lib/ui/widgets/custom_widgets.dart index ac1849d1..ad8c8412 100644 --- a/lib/ui/widgets/custom_widgets.dart +++ b/lib/ui/widgets/custom_widgets.dart @@ -2150,7 +2150,7 @@ class NamidaContainerDivider extends StatelessWidget { class FadeDismissible extends StatefulWidget { final Widget child; - final void Function(DismissDirection onDismissed) onDismissed; + final void Function(DismissDirection direction) onDismissed; final void Function(DragStartDetails details)? onDismissStart; final void Function(DragEndDetails details)? onDismissEnd; final void Function(DragEndDetails details)? onDismissCancel; @@ -2165,6 +2165,7 @@ class FadeDismissible extends StatefulWidget { final bool Function()? draggable; final RxBase? draggableRx; final Widget? onTopWidget; + final bool removeOnDismiss; const FadeDismissible({ required Key key, @@ -2184,6 +2185,7 @@ class FadeDismissible extends StatefulWidget { this.draggable, this.draggableRx, this.onTopWidget, + this.removeOnDismiss = true, }) : super(key: key); @override @@ -2210,6 +2212,7 @@ class _FadeDismissibleState extends State with SingleTickerProv bool _draggable = true; bool _inDismissRange = true; + bool? _canSwipeInternal; // calculate for direction once to allow swiping back. void calculateInDismissRange(double positionDx, double maxWidth) { final percentage = positionDx / maxWidth; @@ -2221,17 +2224,27 @@ class _FadeDismissibleState extends State with SingleTickerProv } Future _dismissToRight(DragEndDetails d, {bool faster = false}) async { - await _animateDismiss(1, faster: faster); - widget.onDismissed(DismissDirection.horizontal); - if (widget.onDismissEnd != null) widget.onDismissEnd!(d); - _animation.animateTo(0, duration: Duration.zero); // fixes rendering issue + if (widget.removeOnDismiss) { + await _animateDismiss(1, faster: faster); + widget.onDismissed(DismissDirection.startToEnd); + if (widget.onDismissEnd != null) widget.onDismissEnd!(d); + _animation.animateTo(0, duration: Duration.zero); // fixes rendering issue + } else { + widget.onDismissed(DismissDirection.startToEnd); + await _resetToMiddle(d); + } } Future _dismissToLeft(DragEndDetails d, {bool faster = false}) async { - await _animateDismiss(-1, faster: faster); - widget.onDismissed(DismissDirection.horizontal); - if (widget.onDismissEnd != null) widget.onDismissEnd!(d); - _animation.animateTo(0, duration: Duration.zero); // fixes rendering issue + if (widget.removeOnDismiss) { + await _animateDismiss(-1, faster: faster); + widget.onDismissed(DismissDirection.endToStart); + if (widget.onDismissEnd != null) widget.onDismissEnd!(d); + _animation.animateTo(0, duration: Duration.zero); // fixes rendering issue + } else { + widget.onDismissed(DismissDirection.endToStart); + await _resetToMiddle(d); + } } Future _resetToMiddle(DragEndDetails d) async { @@ -2253,12 +2266,25 @@ class _FadeDismissibleState extends State with SingleTickerProv : (d) { if (!_draggable) return; if (!_inDismissRange) return; + if (_canSwipeInternal == null) { + bool canSwipe = true; + if (d.delta.dx.isNegative) { + if (widget.direction == DismissDirection.startToEnd) canSwipe = false; + } else { + if (widget.direction == DismissDirection.endToStart) canSwipe = false; + } + if (canSwipe != _canSwipeInternal) _canSwipeInternal = canSwipe; + } + if (_canSwipeInternal == false) return; + _dragged += d.delta.dx; _animation.animateTo(_dragged / maxWidth, duration: Duration.zero); }, onEnd: !draggable ? null : (d) { + _canSwipeInternal = null; + final velocity = d.velocity.pixelsPerSecond.dx; if (velocity > 800) { _dismissToRight(d, faster: true); diff --git a/lib/ui/widgets/library/queue_tile.dart b/lib/ui/widgets/library/queue_tile.dart index 6eb7e385..701f011b 100644 --- a/lib/ui/widgets/library/queue_tile.dart +++ b/lib/ui/widgets/library/queue_tile.dart @@ -45,7 +45,7 @@ class QueueTile extends StatelessWidget { FadeDismissible( direction: DismissDirection.endToStart, key: Key("${queue.date}"), - onDismissed: (onDismissed) { + onDismissed: (direction) { final oldQueue = queue; QueueController.inst.removeQueue(oldQueue); snackyy( diff --git a/lib/ui/widgets/library/track_tile.dart b/lib/ui/widgets/library/track_tile.dart index ff8743c5..ab6f9483 100644 --- a/lib/ui/widgets/library/track_tile.dart +++ b/lib/ui/widgets/library/track_tile.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:jiffy/jiffy.dart'; +import 'package:vibration/vibration.dart'; import 'package:namida/class/track.dart'; import 'package:namida/class/video.dart'; @@ -16,6 +17,7 @@ import 'package:namida/core/extensions.dart'; import 'package:namida/core/icon_fonts/broken_icons.dart'; import 'package:namida/core/namida_converter_ext.dart'; import 'package:namida/core/utils.dart'; +import 'package:namida/ui/dialogs/add_to_playlist_dialog.dart'; import 'package:namida/ui/dialogs/common_dialogs.dart'; import 'package:namida/ui/dialogs/track_info_dialog.dart'; import 'package:namida/ui/widgets/artwork.dart'; @@ -55,45 +57,53 @@ class TrackTilePropertiesProvider extends StatelessWidget { builder: (context, displayFavouriteIconInListTile) => ObxO( rx: settings.trackThumbnailSizeinList, builder: (context, thumbnailSize) => ObxO( - rx: settings.trackListTileHeight, - builder: (context, trackTileHeight) => ObxO( - rx: SelectedTracksController.inst.existingTracksMap, - builder: (context, selectedTracksMap) => _ObxPrefer( - rx: HistoryController.inst.topTracksMapListens, - enabled: listenToTopHistoryItems, - builder: (context, _) => ObxO( - rx: CurrentColor.inst.currentPlayingTrack, - builder: (context, currentPlayingTrack) => ObxO( - rx: CurrentColor.inst.currentPlayingIndex, - builder: (context, currentPlayingIndex) => Obx( - (context) { - int? sleepingIndex; - if (queueSource == QueueSource.playerQueue) { - final sleepconfig = Player.inst.sleepTimerConfig.valueR; - if (sleepconfig.enableSleepAfterItems) sleepingIndex = Player.inst.sleepingItemIndex(sleepconfig.sleepAfterItems, Player.inst.currentIndex.valueR); - } - - final backgroundColorPlaying = comingFromQueue ? CurrentColor.inst.miniplayerColor : CurrentColor.inst.currentColorScheme; - - final properties = TrackTileProperties( - backgroundColorPlaying: backgroundColorPlaying, - backgroundColorNotPlaying: backgroundColorNotPlaying, - selectionColorLayer: selectionColorLayer, - thumbnailSize: thumbnailSize, - trackTileHeight: trackTileHeight, - forceSquaredThumbnails: forceSquaredThumbnails, - sleepingIndex: sleepingIndex, - displayThirdRow: displayThirdRow, - displayFavouriteIconInListTile: displayFavouriteIconInListTile, - comingFromQueue: comingFromQueue, - configs: configs, - canHaveDuplicates: canHaveDuplicates, - currentPlayingTrack: currentPlayingTrack, - currentPlayingIndex: currentPlayingIndex, - isTrackSelected: (trOrTwd) => selectedTracksMap[trOrTwd.track] != null, - ); - return builder(properties); - }, + rx: settings.onTrackSwipeLeft, + builder: (context, onTrackSwipeLeft) => ObxO( + rx: settings.onTrackSwipeRight, + builder: (context, onTrackSwipeRight) => ObxO( + rx: settings.trackListTileHeight, + builder: (context, trackTileHeight) => ObxO( + rx: SelectedTracksController.inst.existingTracksMap, + builder: (context, selectedTracksMap) => _ObxPrefer( + rx: HistoryController.inst.topTracksMapListens, + enabled: listenToTopHistoryItems, + builder: (context, _) => ObxO( + rx: CurrentColor.inst.currentPlayingTrack, + builder: (context, currentPlayingTrack) => ObxO( + rx: CurrentColor.inst.currentPlayingIndex, + builder: (context, currentPlayingIndex) => Obx( + (context) { + int? sleepingIndex; + if (comingFromQueue) { + final sleepconfig = Player.inst.sleepTimerConfig.valueR; + if (sleepconfig.enableSleepAfterItems) sleepingIndex = Player.inst.sleepingItemIndex(sleepconfig.sleepAfterItems, Player.inst.currentIndex.valueR); + } + + final backgroundColorPlaying = comingFromQueue ? CurrentColor.inst.miniplayerColor : CurrentColor.inst.currentColorScheme; + + final properties = TrackTileProperties( + backgroundColorPlaying: backgroundColorPlaying, + backgroundColorNotPlaying: backgroundColorNotPlaying, + selectionColorLayer: selectionColorLayer, + thumbnailSize: thumbnailSize, + trackTileHeight: trackTileHeight, + forceSquaredThumbnails: forceSquaredThumbnails, + sleepingIndex: sleepingIndex, + displayThirdRow: displayThirdRow, + displayFavouriteIconInListTile: displayFavouriteIconInListTile, + comingFromQueue: comingFromQueue, + configs: configs, + canHaveDuplicates: canHaveDuplicates, + currentPlayingTrack: currentPlayingTrack, + currentPlayingIndex: currentPlayingIndex, + isTrackSelected: (trOrTwd) => selectedTracksMap[trOrTwd.track] != null, + allowSwipeLeft: !comingFromQueue && onTrackSwipeLeft != OnTrackTileSwapActions.none, + allowSwipeRight: !comingFromQueue && onTrackSwipeRight != OnTrackTileSwapActions.none, + ); + return builder(properties); + }, + ), + ), ), ), ), @@ -127,6 +137,7 @@ class TrackTilePropertiesConfigs { final bool draggableThumbnail; final bool displayRightDragHandler; final bool displayTrackNumber; + final bool horizontalGestures; final String? playlistName; const TrackTilePropertiesConfigs({ @@ -135,6 +146,7 @@ class TrackTilePropertiesConfigs { this.draggableThumbnail = true, this.displayRightDragHandler = false, this.displayTrackNumber = false, + this.horizontalGestures = true, this.playlistName, }); } @@ -157,6 +169,9 @@ class TrackTileProperties { final int? currentPlayingIndex; final Function(Selectable trOrTwd) isTrackSelected; + final bool allowSwipeLeft; + final bool allowSwipeRight; + const TrackTileProperties({ required this.configs, required this.backgroundColorPlaying, @@ -173,6 +188,8 @@ class TrackTileProperties { required this.currentPlayingTrack, required this.currentPlayingIndex, required this.isTrackSelected, + required this.allowSwipeLeft, + required this.allowSwipeRight, }); } @@ -323,7 +340,9 @@ class TrackTile extends StatelessWidget { final rightItem1Text = TrackTileManager._joinTrackItems(_TrackTileRowOrder.right1, track); final rightItem2Text = TrackTileManager._joinTrackItems(_TrackTileRowOrder.right2, track); - return Stack( + final heroTag = '${properties.comingFromQueue}${index}_sussydialogs_${track.path}$additionalHero'; + + Widget finalChild = Stack( alignment: Alignment.centerRight, children: [ Padding( @@ -386,7 +405,7 @@ class TrackTile extends StatelessWidget { width: properties.thumbnailSize, height: properties.thumbnailSize, child: NamidaHero( - tag: '${properties.comingFromQueue}${index}_sussydialogs_${track.path}$additionalHero', + tag: heroTag, child: ArtworkWidget( key: Key("$willSleepAfterThis${trackOrTwd.hashCode}"), track: track, @@ -539,6 +558,41 @@ class TrackTile extends StatelessWidget { ), ], ); + + if (properties.configs.horizontalGestures && (properties.allowSwipeLeft || properties.allowSwipeRight)) { + finalChild = FadeDismissible( + key: ValueKey(heroTag), + direction: properties.allowSwipeLeft && properties.allowSwipeRight + ? DismissDirection.horizontal + : properties.allowSwipeLeft + ? DismissDirection.endToStart + : properties.allowSwipeRight + ? DismissDirection.startToEnd + : DismissDirection.none, + removeOnDismiss: false, + dismissThreshold: 0.1, + onDismissed: (direction) { + final swipedLeft = direction == DismissDirection.endToStart; + final action = swipedLeft ? settings.onTrackSwipeLeft.value : settings.onTrackSwipeRight.value; + if (action == OnTrackTileSwapActions.none) return; + + switch (action) { + case OnTrackTileSwapActions.playnext: + Player.inst.addToQueue([trackOrTwd], insertNext: true); + case OnTrackTileSwapActions.playlast: + Player.inst.addToQueue([trackOrTwd], insertNext: false); + case OnTrackTileSwapActions.playafter: + Player.inst.addToQueue([trackOrTwd], insertAfterLatest: true); + case OnTrackTileSwapActions.addtoplaylist: + showAddToPlaylistDialog([trackOrTwd.track]); + case OnTrackTileSwapActions.none: + } + Vibration.vibrate(duration: 10, amplitude: 10); + }, + child: finalChild, + ); + } + return finalChild; } } diff --git a/lib/ui/widgets/selected_tracks_preview.dart b/lib/ui/widgets/selected_tracks_preview.dart index da82c4ef..5b39b2ff 100644 --- a/lib/ui/widgets/selected_tracks_preview.dart +++ b/lib/ui/widgets/selected_tracks_preview.dart @@ -29,6 +29,7 @@ class SelectedTracksPreviewContainer extends StatelessWidget { child: TrackTilePropertiesProvider( configs: const TrackTilePropertiesConfigs( displayRightDragHandler: true, + horizontalGestures: false, queueSource: QueueSource.selectedTracks, ), builder: (properties) => Obx( diff --git a/lib/ui/widgets/settings/customization_settings.dart b/lib/ui/widgets/settings/customization_settings.dart index 3ebb8f04..021ffd18 100644 --- a/lib/ui/widgets/settings/customization_settings.dart +++ b/lib/ui/widgets/settings/customization_settings.dart @@ -44,6 +44,7 @@ enum _CustomizationSettingsKeys { forceSquaredTrackThumb, sizeOfTrackThumb, heightOfTrackTile, + onSwiping, displayThirdRow, displayThirdItemInRow, displayFavButtonInTrackTile, @@ -90,6 +91,7 @@ class CustomizationSettings extends SettingSubpageProvider { _CustomizationSettingsKeys.forceSquaredTrackThumb: [lang.FORCE_SQUARED_TRACK_THUMBNAIL], _CustomizationSettingsKeys.sizeOfTrackThumb: [lang.TRACK_THUMBNAIL_SIZE_IN_LIST], _CustomizationSettingsKeys.heightOfTrackTile: [lang.HEIGHT_OF_TRACK_TILE], + _CustomizationSettingsKeys.onSwiping: [lang.ON_SWIPING], _CustomizationSettingsKeys.displayThirdRow: [lang.DISPLAY_THIRD_ROW_IN_TRACK_TILE], _CustomizationSettingsKeys.displayThirdItemInRow: [lang.DISPLAY_THIRD_ITEM_IN_ROW_IN_TRACK_TILE], _CustomizationSettingsKeys.displayFavButtonInTrackTile: [lang.DISPLAY_FAVOURITE_ICON_IN_TRACK_TILE], @@ -307,6 +309,46 @@ class CustomizationSettings extends SettingSubpageProvider { ); } + void _onSwipingTap() { + NamidaNavigator.inst.navigateDialog( + dialog: CustomBlurryDialog( + title: lang.ON_SWIPING, + actions: [ + NamidaButton( + onPressed: NamidaNavigator.inst.closeDialog, + text: lang.DONE, + ), + ], + child: Column( + children: [ + ObxO( + rx: settings.onTrackSwipeLeft, + builder: (context, onTrackSwipeLeft) => CustomListTile( + icon: Broken.arrow_left_1, + title: onTrackSwipeLeft.toText(), + onTap: () { + final next = settings.onTrackSwipeLeft.value.nextElement(OnTrackTileSwapActions.values); + settings.save(onTrackSwipeLeft: next); + }, + ), + ), + ObxO( + rx: settings.onTrackSwipeRight, + builder: (context, onTrackSwipeRight) => CustomListTile( + icon: Broken.arrow_right, + title: onTrackSwipeRight.toText(), + onTap: () { + final next = settings.onTrackSwipeRight.value.nextElement(OnTrackTileSwapActions.values); + settings.save(onTrackSwipeRight: next); + }, + ), + ), + ], + ), + ), + ); + } + Widget _getAlbumCustomizationsTile() { return getItemWrapper( key: _CustomizationSettingsKeys.ALBUMTILECUSTOMIZATION, @@ -559,6 +601,15 @@ class CustomizationSettings extends SettingSubpageProvider { ), ), ), + getItemWrapper( + key: _CustomizationSettingsKeys.onSwiping, + child: CustomListTile( + bgColor: getBgColor(_CustomizationSettingsKeys.onSwiping), + icon: Broken.arrow_swap_horizontal, + title: lang.ON_SWIPING, + onTap: _onSwipingTap, + ), + ), getItemWrapper( key: _CustomizationSettingsKeys.displayThirdRow, child: Obx( diff --git a/lib/youtube/widgets/yt_description_widget.dart b/lib/youtube/widgets/yt_description_widget.dart index 5037a33a..cefcbe77 100644 --- a/lib/youtube/widgets/yt_description_widget.dart +++ b/lib/youtube/widgets/yt_description_widget.dart @@ -111,7 +111,7 @@ class YoutubeDescriptionWidgetManager { onTap = () { if (sw.videoId == videoId && sw.videoStartSeconds != null) { Player.inst.seek(Duration(seconds: sw.videoStartSeconds!)); - Vibration.vibrate(duration: 10, amplitude: 10); + Vibration.vibrate(duration: 10, amplitude: 20); } else { Player.inst.playOrPause(0, [YoutubeID(id: sw.videoId!, playlistID: null)], QueueSource.others); // TODO: seek after playing? diff --git a/pubspec.yaml b/pubspec.yaml index ea8678b3..c52dc421 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: namida description: A Beautiful and Feature-rich Music Player, With YouTube & Video Support Built in Flutter publish_to: "none" -version: 4.0.75-beta+240831199 +version: 4.0.8-beta+240831200 environment: sdk: ">=3.4.0 <4.0.0"