mirror of
https://github.com/KRTirtho/spotube.git
synced 2025-09-12 23:45:18 +00:00
fix: unescape html escape values #1300
This commit is contained in:
parent
c7d8ed567a
commit
44861a9f5c
@ -8,18 +8,10 @@ import 'package:spotube/collections/spotube_icons.dart';
|
||||
import 'package:spotube/components/hover_builder.dart';
|
||||
import 'package:spotube/components/image/universal_image.dart';
|
||||
import 'package:spotube/extensions/constrains.dart';
|
||||
import 'package:spotube/extensions/string.dart';
|
||||
import 'package:spotube/hooks/utils/use_breakpoint_value.dart';
|
||||
import 'package:spotube/hooks/utils/use_brightness_value.dart';
|
||||
|
||||
final htmlTagRegexp = RegExp(r"<[^>]*>", caseSensitive: true);
|
||||
|
||||
String? useDescription(String? description) {
|
||||
return useMemoized(() {
|
||||
if (description == null) return null;
|
||||
return description.replaceAll(htmlTagRegexp, '');
|
||||
}, [description]);
|
||||
}
|
||||
|
||||
class PlaybuttonCard extends HookWidget {
|
||||
final void Function()? onTap;
|
||||
final void Function()? onPlaybuttonPressed;
|
||||
@ -66,8 +58,7 @@ class PlaybuttonCard extends HookWidget {
|
||||
others: 15,
|
||||
);
|
||||
|
||||
final cleanDescription = useDescription(description);
|
||||
|
||||
var unescapeHtml = description?.unescapeHtml();
|
||||
return Container(
|
||||
constraints: BoxConstraints(maxWidth: size),
|
||||
margin: margin,
|
||||
@ -205,11 +196,11 @@ class PlaybuttonCard extends HookWidget {
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
if (cleanDescription != null)
|
||||
if (description != null)
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12.0),
|
||||
child: AutoSizeText(
|
||||
cleanDescription,
|
||||
unescapeHtml!,
|
||||
maxLines: 2,
|
||||
style: theme.textTheme.bodySmall?.copyWith(
|
||||
color: theme.colorScheme.onSurface.withOpacity(.5),
|
||||
|
@ -5,12 +5,12 @@ import 'package:flutter/material.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:spotube/collections/assets.gen.dart';
|
||||
import 'package:spotube/components/image/universal_image.dart';
|
||||
import 'package:spotube/components/playbutton_card.dart';
|
||||
import 'package:spotube/components/tracks_view/sections/header/header_actions.dart';
|
||||
import 'package:spotube/components/tracks_view/sections/header/header_buttons.dart';
|
||||
import 'package:spotube/components/tracks_view/track_view_props.dart';
|
||||
import 'package:gap/gap.dart';
|
||||
import 'package:spotube/extensions/constrains.dart';
|
||||
import 'package:spotube/extensions/string.dart';
|
||||
import 'package:spotube/hooks/utils/use_palette_color.dart';
|
||||
import 'package:spotube/utils/platform.dart';
|
||||
|
||||
@ -24,8 +24,6 @@ class TrackViewFlexHeader extends HookConsumerWidget {
|
||||
final defaultTextStyle = DefaultTextStyle.of(context);
|
||||
final mediaQuery = MediaQuery.of(context);
|
||||
|
||||
final description = useDescription(props.description);
|
||||
|
||||
final palette = usePaletteColor(props.image, ref);
|
||||
|
||||
return IconTheme(
|
||||
@ -127,10 +125,10 @@ class TrackViewFlexHeader extends HookConsumerWidget {
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
if (description != null &&
|
||||
description.isNotEmpty)
|
||||
if (props.description != null &&
|
||||
props.description!.isNotEmpty)
|
||||
Text(
|
||||
description,
|
||||
props.description!.unescapeHtml(),
|
||||
style:
|
||||
defaultTextStyle.style.copyWith(
|
||||
color: palette.bodyTextColor,
|
||||
|
@ -7,7 +7,7 @@ extension UnescapeHtml on String {
|
||||
}
|
||||
|
||||
extension NullableUnescapeHtml on String? {
|
||||
String? unescapeHtml() => this == null ? null : htmlEscape.convert(this!);
|
||||
String? unescapeHtml() => this?.unescapeHtml();
|
||||
}
|
||||
|
||||
extension StringExtension on String {
|
||||
|
@ -15,6 +15,7 @@ import 'package:spotube/components/image/universal_image.dart';
|
||||
import 'package:spotube/extensions/constrains.dart';
|
||||
import 'package:spotube/extensions/context.dart';
|
||||
import 'package:spotube/extensions/image.dart';
|
||||
import 'package:spotube/extensions/string.dart';
|
||||
import 'package:spotube/provider/spotify/spotify.dart';
|
||||
import 'package:spotube/provider/spotify_provider.dart';
|
||||
|
||||
@ -54,7 +55,7 @@ class PlaylistCreateDialog extends HookConsumerWidget {
|
||||
text: updatingPlaylist?.name,
|
||||
);
|
||||
final description = useTextEditingController(
|
||||
text: updatingPlaylist?.description,
|
||||
text: updatingPlaylist?.description?.unescapeHtml(),
|
||||
);
|
||||
final public = useState(
|
||||
updatingPlaylist?.public ?? false,
|
||||
|
@ -1,8 +1,8 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:spotify/spotify.dart';
|
||||
import 'package:spotube/components/image/universal_image.dart';
|
||||
import 'package:spotube/components/playbutton_card.dart';
|
||||
import 'package:spotube/extensions/image.dart';
|
||||
import 'package:spotube/extensions/string.dart';
|
||||
import 'package:spotube/pages/playlist/playlist.dart';
|
||||
import 'package:spotube/utils/service_utils.dart';
|
||||
|
||||
@ -28,7 +28,7 @@ class StatsPlaylistItem extends StatelessWidget {
|
||||
),
|
||||
title: Text(playlist.name!),
|
||||
subtitle: Text(
|
||||
playlist.description!.replaceAll(htmlTagRegexp, ''),
|
||||
playlist.description?.unescapeHtml() ?? '',
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
|
@ -1,3 +1,4 @@
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:flutter/material.dart' hide Page;
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:spotify/spotify.dart';
|
||||
@ -12,19 +13,33 @@ import 'package:spotube/provider/spotify/spotify.dart';
|
||||
class PlaylistPage extends HookConsumerWidget {
|
||||
static const name = "playlist";
|
||||
|
||||
final PlaylistSimple playlist;
|
||||
final PlaylistSimple _playlist;
|
||||
const PlaylistPage({
|
||||
super.key,
|
||||
required this.playlist,
|
||||
});
|
||||
required PlaylistSimple playlist,
|
||||
}) : _playlist = playlist;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, ref) {
|
||||
final playlist = ref
|
||||
.watch(
|
||||
favoritePlaylistsProvider.select(
|
||||
(value) => value.whenData(
|
||||
(value) =>
|
||||
value.items.firstWhereOrNull((s) => s.id == _playlist.id),
|
||||
),
|
||||
),
|
||||
)
|
||||
.asData
|
||||
?.value ??
|
||||
_playlist;
|
||||
|
||||
final tracks = ref.watch(playlistTracksProvider(playlist.id!));
|
||||
final tracksNotifier =
|
||||
ref.watch(playlistTracksProvider(playlist.id!).notifier);
|
||||
final isFavoritePlaylist =
|
||||
ref.watch(isFavoritePlaylistProvider(playlist.id!));
|
||||
|
||||
final favoritePlaylistsNotifier =
|
||||
ref.watch(favoritePlaylistsProvider.notifier);
|
||||
|
||||
|
@ -51,6 +51,20 @@ class FavoritePlaylistsNotifier
|
||||
);
|
||||
}
|
||||
|
||||
void updatePlaylist(PlaylistSimple playlist) {
|
||||
if (state.value == null) return;
|
||||
|
||||
if (state.value!.items.none((e) => e.id == playlist.id)) return;
|
||||
|
||||
state = AsyncData(
|
||||
state.value!.copyWith(
|
||||
items: state.value!.items
|
||||
.map((element) => element.id == playlist.id ? playlist : element)
|
||||
.toList(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> addFavorite(PlaylistSimple playlist) async {
|
||||
await update((state) async {
|
||||
await spotify.playlists.followPlaylist(playlist.id!);
|
||||
|
@ -71,16 +71,32 @@ class PlaylistNotifier extends FamilyAsyncNotifier<Playlist, String> {
|
||||
state.id!,
|
||||
input.base64Image!,
|
||||
);
|
||||
|
||||
final playlist = await spotify.playlists.get(state.id!);
|
||||
|
||||
ref.read(favoritePlaylistsProvider.notifier).updatePlaylist(playlist);
|
||||
return playlist;
|
||||
}
|
||||
|
||||
return spotify.playlists.get(state.id!);
|
||||
} catch (e) {
|
||||
final playlist = Playlist.fromJson(
|
||||
{
|
||||
...state.toJson(),
|
||||
'name': input.playlistName,
|
||||
'collaborative': input.collaborative,
|
||||
'description': input.description,
|
||||
'public': input.public,
|
||||
},
|
||||
);
|
||||
|
||||
ref.read(favoritePlaylistsProvider.notifier).updatePlaylist(playlist);
|
||||
|
||||
return playlist;
|
||||
} catch (e, stack) {
|
||||
onError?.call(e);
|
||||
AppLogger.reportError(e, stack);
|
||||
rethrow;
|
||||
}
|
||||
});
|
||||
|
||||
ref.invalidate(favoritePlaylistsProvider);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user