Skip to content

Commit

Permalink
fix: track tile playCount & latestListenDate not refreshing properly
Browse files Browse the repository at this point in the history
ref #323
  • Loading branch information
MSOB7YY committed Aug 16, 2024
1 parent 0222ad4 commit 6ca25fd
Show file tree
Hide file tree
Showing 4 changed files with 142 additions and 85 deletions.
6 changes: 5 additions & 1 deletion lib/controller/history_controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,15 @@ import 'package:namida/core/constants.dart';
import 'package:namida/core/dimensions.dart';
import 'package:namida/core/enums.dart';
import 'package:namida/core/extensions.dart';
import 'package:namida/ui/widgets/library/track_tile.dart';

class HistoryController with HistoryManager<TrackWithDate, Track> {
static HistoryController get inst => _instance;
static final HistoryController _instance = HistoryController._internal();
HistoryController._internal();
HistoryController._internal() {
onTopItemsMapModified = TrackTileManager.onTrackItemPropChange;
latestUpdatedMostPlayedItem.addListener(() => TrackTileManager.rebuildTrackInfo(latestUpdatedMostPlayedItem.value! /* not null bet */));
}

@override
double daysToSectionExtent(List<int> days) {
Expand Down
5 changes: 4 additions & 1 deletion lib/controller/indexer_controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -940,6 +940,10 @@ class Indexer {
List<String>? moods,
int? lastPositionInMs,
}) async {
if (rating != null || tags != null || moods != null) {
TrackTileManager.onTrackItemPropChange();
}

rating ??= track.stats.rating;
tags ??= track.stats.tags;
moods ??= track.stats.moods;
Expand All @@ -952,7 +956,6 @@ class Indexer {
}

Future<void> _saveTrackStatsFileToStorage() async {
TrackTileManager.onTrackItemPropChange();
await File(AppPaths.TRACKS_STATS).writeAsJson(trackStatsMap.values.map((e) => e.toJson()).toList());
}

Expand Down
214 changes: 132 additions & 82 deletions lib/ui/widgets/library/track_tile.dart
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ class TrackTilePropertiesProvider extends StatelessWidget {
final backgroundColorNotPlaying = context.theme.cardTheme.color ?? Colors.transparent;
final selectionColorLayer = context.theme.focusColor;

final listenToTopHistoryItems = settings.trackItem.values.any((element) => element == TrackTileItem.listenCount || element == TrackTileItem.latestListenDate);

return ObxO(
rx: settings.forceSquaredTrackThumbnail,
builder: (forceSquaredThumbnails) => ObxO(
Expand All @@ -55,39 +57,43 @@ class TrackTilePropertiesProvider extends StatelessWidget {
rx: settings.trackListTileHeight,
builder: (trackTileHeight) => ObxO(
rx: SelectedTracksController.inst.existingTracksMap,
builder: (selectedTracksMap) => ObxO(
rx: CurrentColor.inst.currentPlayingTrack,
builder: (currentPlayingTrack) => ObxO(
rx: CurrentColor.inst.currentPlayingIndex,
builder: (currentPlayingIndex) => Obx(
() {
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);
},
builder: (selectedTracksMap) => _ObxPrefer(
rx: HistoryController.inst.topTracksMapListens,
enabled: listenToTopHistoryItems,
builder: (_) => ObxO(
rx: CurrentColor.inst.currentPlayingTrack,
builder: (currentPlayingTrack) => ObxO(
rx: CurrentColor.inst.currentPlayingIndex,
builder: (currentPlayingIndex) => Obx(
() {
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);
},
),
),
),
),
Expand All @@ -100,6 +106,18 @@ class TrackTilePropertiesProvider extends StatelessWidget {
}
}

class _ObxPrefer<T> extends StatelessWidget {
final RxBaseCore<T> rx;
final Widget Function(T? value) builder;
final bool enabled;
const _ObxPrefer({required this.rx, required this.builder, required this.enabled, super.key});

@override
Widget build(BuildContext context) {
return enabled ? builder(null) : ObxO(rx: rx, builder: builder);
}
}

class TrackTilePropertiesConfigs {
final QueueSource queueSource;

Expand Down Expand Up @@ -221,15 +239,15 @@ class TrackTile extends StatelessWidget {
final isInSelectedTracksPreview = queueSource == QueueSource.selectedTracks;
final additionalHero = this.additionalHero;
final thirdLineText = this.thirdLineText;
final row1Text = TrackTileManager.joinTrackItems(TrackTilePosition.row1Item1, TrackTilePosition.row1Item2, TrackTilePosition.row1Item3, track);
final row2Text = TrackTileManager.joinTrackItems(TrackTilePosition.row2Item1, TrackTilePosition.row2Item2, TrackTilePosition.row2Item3, track);
final row1Text = TrackTileManager._joinTrackItems(_TrackTileRowOrder.first, track);
final row2Text = TrackTileManager._joinTrackItems(_TrackTileRowOrder.second, track);
final row3Text = thirdLineText != null && thirdLineText.isNotEmpty
? thirdLineText
: properties.displayThirdRow
? TrackTileManager.joinTrackItems(TrackTilePosition.row3Item1, TrackTilePosition.row3Item2, TrackTilePosition.row3Item3, track)
? TrackTileManager._joinTrackItems(_TrackTileRowOrder.third, track)
: null;
final rightItem1Text = TrackTileManager.getChoosenTrackTileItem(TrackTilePosition.rightItem1, track);
final rightItem2Text = TrackTileManager.getChoosenTrackTileItem(TrackTilePosition.rightItem2, track);
final rightItem1Text = TrackTileManager._joinTrackItems(_TrackTileRowOrder.right1, track);
final rightItem2Text = TrackTileManager._joinTrackItems(_TrackTileRowOrder.right2, track);

final willSleepAfterThis = properties.sleepingIndex == index;

Expand Down Expand Up @@ -507,69 +525,101 @@ class TrackTile extends StatelessWidget {
}
}

enum _TrackTileRowOrder {
first,
second,
third,

right1,
right2,
}

class TrackTileManager {
static final _infoMap = <Track, Map<TrackTilePosition, String>>{};
const TrackTileManager._();

static const _rowOrderToPosition = <_TrackTileRowOrder, List<TrackTilePosition>>{
_TrackTileRowOrder.first: [TrackTilePosition.row1Item1, TrackTilePosition.row1Item2, TrackTilePosition.row1Item3],
_TrackTileRowOrder.second: [TrackTilePosition.row2Item1, TrackTilePosition.row2Item2, TrackTilePosition.row2Item3],
_TrackTileRowOrder.third: [TrackTilePosition.row3Item1, TrackTilePosition.row3Item2, TrackTilePosition.row3Item3],
_TrackTileRowOrder.right1: [TrackTilePosition.rightItem1],
_TrackTileRowOrder.right2: [TrackTilePosition.rightItem2],
};
static const _rowOrderToPositionWithoutThird = <_TrackTileRowOrder, List<TrackTilePosition>>{
_TrackTileRowOrder.first: [TrackTilePosition.row1Item1, TrackTilePosition.row1Item2],
_TrackTileRowOrder.second: [TrackTilePosition.row2Item1, TrackTilePosition.row2Item2],
_TrackTileRowOrder.third: [TrackTilePosition.row3Item1, TrackTilePosition.row3Item2],
_TrackTileRowOrder.right1: [TrackTilePosition.rightItem1],
_TrackTileRowOrder.right2: [TrackTilePosition.rightItem2],
};

static final _infoFullMap = <Track, Map<_TrackTileRowOrder, String>?>{};

static void onTrackItemPropChange() {
_infoMap.clear();
_infoFullMap.clear();
_separator = _buildSeparator();
}

static void rebuildTrackInfo(Track track) {
_infoFullMap[track] = null;
}

static String _separator = _buildSeparator();
static String _buildSeparator() => ' ${settings.trackTileSeparator.value} ';
static final _buffer = StringBuffer(); // clearing and reusing is more performant

static String _joinTrackItems(
_TrackTileRowOrder rowOrder,
Track track,
) {
final row = _infoFullMap[track]?[rowOrder];
if (row != null) return row;

final positions = settings.displayThirdItemInEachRow.value ? _rowOrderToPosition[rowOrder] : _rowOrderToPositionWithoutThird[rowOrder];
final newRowDetails = _joinTrackItemsInternal(positions!, track);
final newRow = newRowDetails.text;

if (newRowDetails.shouldNotCache) return newRow;

final innerMap = _infoFullMap[track] ??= {};
innerMap[rowOrder] = newRow;

return newRow;
}

static ({String text, bool shouldNotCache}) _joinTrackItemsInternal(List<TrackTilePosition> positions, Track track) {
_buffer.clear();

static String joinTrackItems(TrackTilePosition? p1, TrackTilePosition? p2, TrackTilePosition? p3, Track track) {
var buffer = StringBuffer();
bool needsSeparator = false;
if (p1 != null) {
var info = getChoosenTrackTileItem(p1, track);
if (info.isNotEmpty) {
buffer.write(info);
needsSeparator = true;
}
}
if (p2 != null) {
var info = getChoosenTrackTileItem(p2, track);
if (info.isNotEmpty) {
if (needsSeparator) buffer.write(_separator);
buffer.write(info);
needsSeparator = true;
}
}
if (p3 != null && settings.displayThirdItemInEachRow.value) {
var info = getChoosenTrackTileItem(p3, track);
bool shouldNotCache = false;

final length = positions.length;
for (int i = 0; i < length; i++) {
final itemPosition = positions[i];
final trackItem = settings.trackItem.value[itemPosition];
if (trackItem == TrackTileItem.latestListenDate) shouldNotCache = true;

var info = _buildChoosenTrackTileItem(trackItem, track);

if (info.isNotEmpty) {
if (needsSeparator) buffer.write(_separator);
buffer.write(info);
if (needsSeparator) _buffer.write(_separator);
_buffer.write(info);
needsSeparator = true;
}
}
return buffer.toString();
}

static String getChoosenTrackTileItem(TrackTilePosition itemPosition, Track trackPre) {
final inf = _infoMap[trackPre]?[itemPosition];
if (inf != null) return inf;
return (text: _buffer.toString(), shouldNotCache: shouldNotCache);
}

String val;
static String _buildChoosenTrackTileItem(TrackTileItem? trackItem, Track trackPre) {
if (trackItem == null || trackItem == TrackTileItem.none) return '';

final trackItem = settings.trackItem.value[itemPosition];
if (trackItem == null || trackItem == TrackTileItem.none) {
val = '';
} else {
final fn = _lookup[trackItem];
if (fn != null) {
final track = trackPre.toTrackExt();
val = fn(track);
} else {
val = '';
}
final fn = _lookup[trackItem];
if (fn != null) {
final track = trackPre.toTrackExt();
return fn(track);
}

_infoMap[trackPre] ??= {};
_infoMap[trackPre]![itemPosition] = val;

return val;
return '';
}

static final _lookup = <TrackTileItem, String Function(TrackExtended track)>{
Expand Down
2 changes: 1 addition & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
@@ -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: 3.9.2-beta+240815234
version: 3.9.22-beta+240816204

environment:
sdk: ">=3.4.0 <4.0.0"
Expand Down

0 comments on commit 6ca25fd

Please sign in to comment.