mirror of
https://github.com/zarzet/SpotiFLAC-Mobile.git
synced 2026-10-20 22:41:38 +02:00
perf(library): build DateFormat and RegExp once instead of per row
The month-year DateFormat was rebuilt for every loaded row and every fast-scroller drag label; it is now cached per locale tag. Constant-pattern RegExp objects built per call (or per word) are now static or top-level.
This commit is contained in:
1 parent
0810ee7847
commit
acbc614f42
5 files changed
+27
-14
No files matched your search
@@ -269,6 +269,7 @@ class _AlbumScreenState extends ConsumerState<AlbumScreen>
|
||||
}
|
||||
|
||||
static final _qualitySeparators = RegExp(r'[\s_-]+');
|
||||
static final _releaseYearPattern = RegExp(r'(\d{4})');
|
||||
|
||||
static (String, bool?) _qualitySignature(Track track) => (
|
||||
(track.audioQuality ?? '').trim().toLowerCase().replaceAll(
|
||||
@@ -360,7 +361,7 @@ class _AlbumScreenState extends ConsumerState<AlbumScreen>
|
||||
|
||||
String? _releaseYear(String? date) {
|
||||
if (date == null || date.isEmpty) return null;
|
||||
final match = RegExp(r'(\d{4})').firstMatch(date);
|
||||
final match = _releaseYearPattern.firstMatch(date);
|
||||
return match?.group(1);
|
||||
}
|
||||
|
||||
|
||||
@@ -13,6 +13,15 @@ class _LibrarySection {
|
||||
int get length => end - start;
|
||||
}
|
||||
|
||||
final _letterPattern = RegExp(r'[\p{L}]', unicode: true);
|
||||
|
||||
final _monthYearFormats = <String, DateFormat>{};
|
||||
|
||||
DateFormat _monthYearFormat(BuildContext context) {
|
||||
final locale = Localizations.localeOf(context).toLanguageTag();
|
||||
return _monthYearFormats.putIfAbsent(locale, () => DateFormat.yMMMM(locale));
|
||||
}
|
||||
|
||||
/// First letter of [text] for an alphabetical index; digits and symbols
|
||||
/// share `#`.
|
||||
String _sectionInitial(String text) {
|
||||
@@ -20,7 +29,7 @@ String _sectionInitial(String text) {
|
||||
for (final character in trimmed.characters) {
|
||||
final upper = character.toUpperCase();
|
||||
if (upper != character.toLowerCase()) return upper;
|
||||
if (RegExp(r'[\p{L}]', unicode: true).hasMatch(character)) return upper;
|
||||
if (_letterPattern.hasMatch(character)) return upper;
|
||||
return '#';
|
||||
}
|
||||
return '#';
|
||||
@@ -79,9 +88,7 @@ extension _QueueTabSections on _QueueTabState {
|
||||
return _sectionInitial(item.albumName);
|
||||
}
|
||||
if (_dateSorts.contains(_sortMode)) {
|
||||
return DateFormat.yMMMM(
|
||||
Localizations.localeOf(context).toLanguageTag(),
|
||||
).format(item.addedAt);
|
||||
return _monthYearFormat(context).format(item.addedAt);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -98,9 +105,7 @@ extension _QueueTabSections on _QueueTabState {
|
||||
}
|
||||
if (_artistSorts.contains(_sortMode)) return _sectionInitial(artist);
|
||||
if (_dateSorts.contains(_sortMode)) {
|
||||
return DateFormat.yMMMM(
|
||||
Localizations.localeOf(context).toLanguageTag(),
|
||||
).format(added);
|
||||
return _monthYearFormat(context).format(added);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -3,6 +3,8 @@ part of 'track_metadata_screen.dart';
|
||||
|
||||
// Display helpers: quality/bitrate labels, service track-id formatting,
|
||||
// snackbars, and path formatting.
|
||||
final _spotifyTrackIdPattern = RegExp(r'^[A-Za-z0-9]{22}$');
|
||||
|
||||
extension _TrackMetadataDisplay on _TrackMetadataScreenState {
|
||||
bool _isBitrateFormatValue(String? value) {
|
||||
return const {
|
||||
@@ -61,7 +63,7 @@ extension _TrackMetadataDisplay on _TrackMetadataScreenState {
|
||||
String _displayServiceTrackId(String value) {
|
||||
final raw = value.trim();
|
||||
if (raw.isEmpty) return raw;
|
||||
final spotifyTrackIdPattern = RegExp(r'^[A-Za-z0-9]{22}$');
|
||||
final spotifyTrackIdPattern = _spotifyTrackIdPattern;
|
||||
|
||||
if (raw.startsWith('deezer:')) return raw.substring('deezer:'.length);
|
||||
if (raw.startsWith('tidal:')) return raw.substring('tidal:'.length);
|
||||
@@ -91,7 +93,7 @@ extension _TrackMetadataDisplay on _TrackMetadataScreenState {
|
||||
String _serviceForTrackId(String value, {required String fallbackService}) {
|
||||
final raw = value.trim();
|
||||
if (raw.isEmpty) return fallbackService;
|
||||
final spotifyTrackIdPattern = RegExp(r'^[A-Za-z0-9]{22}$');
|
||||
final spotifyTrackIdPattern = _spotifyTrackIdPattern;
|
||||
|
||||
if (raw.startsWith('deezer:')) return MusicServices.deezer;
|
||||
if (raw.startsWith('tidal:')) return MusicServices.tidal;
|
||||
|
||||
@@ -15,6 +15,9 @@ class LyricPronunciationLayout {
|
||||
static const _phraseGap = 4.0;
|
||||
static const _pronunciationGap = 2.0;
|
||||
static const _rowGap = 6.0;
|
||||
static final _whitespaceRun = RegExp(r'\s+');
|
||||
static final _endsWithWhitespace = RegExp(r'\s$');
|
||||
static final _startsWithWhitespace = RegExp(r'^\s');
|
||||
|
||||
double get primaryHeight =>
|
||||
_rows.fold(0.0, (height, row) => height + row.primaryHeight) +
|
||||
@@ -42,7 +45,7 @@ class LyricPronunciationLayout {
|
||||
maxWidth <= 0) {
|
||||
return null;
|
||||
}
|
||||
String normalize(String text) => text.replaceAll(RegExp(r'\s+'), '');
|
||||
String normalize(String text) => text.replaceAll(_whitespaceRun, '');
|
||||
if (normalize(original.map((word) => word.text).join()) !=
|
||||
normalize(line.text) ||
|
||||
normalize(pronunciation.map((word) => word.text).join()) !=
|
||||
@@ -57,8 +60,8 @@ class LyricPronunciationLayout {
|
||||
for (var i = 1; i < pronunciation.length; i++) {
|
||||
// Preserve syllables inside a word. Providers may split a romanized
|
||||
// word into several timed spans without adding whitespace.
|
||||
if (!RegExp(r'\s$').hasMatch(pronunciation[i - 1].text) &&
|
||||
!RegExp(r'^\s').hasMatch(pronunciation[i].text)) {
|
||||
if (!_endsWithWhitespace.hasMatch(pronunciation[i - 1].text) &&
|
||||
!_startsWithWhitespace.hasMatch(pronunciation[i].text)) {
|
||||
continue;
|
||||
}
|
||||
final start = pronunciation[i].time.inMilliseconds;
|
||||
|
||||
@@ -671,9 +671,11 @@ String _peak(double value) {
|
||||
return '${value.toStringAsFixed(6)} · ${_db(dbfs).replaceFirst(' dB', ' dBFS')}';
|
||||
}
|
||||
|
||||
final _numberPattern = RegExp(r'[-+]?\d+(?:\.\d+)?');
|
||||
|
||||
/// Reads tag values such as "-6.52 dB" or "0.988831".
|
||||
double? _number(Object? raw) {
|
||||
if (raw is num) return raw.toDouble();
|
||||
final match = RegExp(r'[-+]?\d+(?:\.\d+)?').firstMatch(raw?.toString() ?? '');
|
||||
final match = _numberPattern.firstMatch(raw?.toString() ?? '');
|
||||
return match == null ? null : double.tryParse(match[0]!);
|
||||
}
|
||||
Reference in new issue
Block a user