mirror of
https://github.com/KRTirtho/spotube.git
synced 2025-09-12 23:45:18 +00:00
feat(translations): make state page's hard coded strings translatable (#1719)
This commit is contained in:
parent
95b68687d5
commit
7408a87860
@ -83,7 +83,7 @@ abstract class LanguageLocals {
|
||||
// ),
|
||||
"eu": const ISOLanguageName(
|
||||
name: "Basque",
|
||||
nativeName: "euskara",
|
||||
nativeName: "Euskara",
|
||||
),
|
||||
// "be": const ISOLanguageName(
|
||||
// name: "Belarusian",
|
||||
|
@ -15,15 +15,12 @@ class SelectDeviceDialog extends HookConsumerWidget {
|
||||
final remoteService = connectClients.asData!.value.resolvedService!;
|
||||
|
||||
return AlertDialog(
|
||||
title: const Text("Choose the device:"),
|
||||
title: Text(context.l10n.choose_the_device),
|
||||
insetPadding: const EdgeInsets.all(16),
|
||||
content: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const Text(
|
||||
"There are multiple device connected.\n"
|
||||
"Choose the device you want this action to take place",
|
||||
),
|
||||
Text(context.l10n.multiple_device_connected),
|
||||
RadioListTile.adaptive(
|
||||
title: Text(remoteService.name),
|
||||
value: true,
|
||||
@ -33,7 +30,7 @@ class SelectDeviceDialog extends HookConsumerWidget {
|
||||
},
|
||||
),
|
||||
RadioListTile.adaptive(
|
||||
title: const Text("This Device"),
|
||||
title: Text(context.l10n.this_device),
|
||||
value: false,
|
||||
groupValue: isRemoteService.value,
|
||||
onChanged: (value) {
|
||||
|
@ -1,5 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:spotube/collections/assets.gen.dart';
|
||||
import 'package:spotube/extensions/context.dart';
|
||||
|
||||
class NotFound extends StatelessWidget {
|
||||
final bool vertical;
|
||||
@ -18,9 +19,9 @@ class NotFound extends StatelessWidget {
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Text("Nothing found", style: theme.textTheme.titleLarge),
|
||||
Text(context.l10n.nothing_found, style: theme.textTheme.titleLarge),
|
||||
Text(
|
||||
"The box is empty",
|
||||
context.l10n.the_box_is_empty,
|
||||
style: theme.textTheme.titleMedium,
|
||||
),
|
||||
],
|
||||
|
@ -3,11 +3,11 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:gap/gap.dart';
|
||||
import 'package:skeletonizer/skeletonizer.dart';
|
||||
|
||||
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/context.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';
|
||||
@ -128,7 +128,7 @@ class PlaybuttonCard extends HookWidget {
|
||||
),
|
||||
if (isHovered)
|
||||
Text(
|
||||
"Owned by you",
|
||||
context.l10n.owned_by_you,
|
||||
style: theme.textTheme.bodySmall?.copyWith(
|
||||
color: Colors.white,
|
||||
),
|
||||
|
@ -32,6 +32,9 @@ class TrackViewHeaderActions extends HookConsumerWidget {
|
||||
|
||||
final auth = ref.watch(authenticationProvider);
|
||||
|
||||
final copiedText =
|
||||
context.l10n.copied_shareurl_to_clipboard(props.shareUrl);
|
||||
|
||||
return Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
@ -48,7 +51,7 @@ class TrackViewHeaderActions extends HookConsumerWidget {
|
||||
width: 300,
|
||||
behavior: SnackBarBehavior.floating,
|
||||
content: Text(
|
||||
"Copied ${props.shareUrl} to clipboard",
|
||||
copiedText,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
|
@ -326,5 +326,64 @@
|
||||
"this_device": "This Device",
|
||||
"remote": "Remote",
|
||||
"stats": "Stats",
|
||||
"and_n_more": "and {count} more"
|
||||
"and_n_more": "and {count} more",
|
||||
"recently_played": "Recently Played",
|
||||
"browse_more": "Browse More",
|
||||
"no_title": "No Title",
|
||||
"not_playing": "Not playing",
|
||||
"epic_failure": "Epic failure!",
|
||||
"added_num_tracks_to_queue": "Added {tracks_length} tracks to queue",
|
||||
"spotube_has_an_update": "Spotube has an update",
|
||||
"download_now": "Download Now",
|
||||
"nightly_version": "Spotube Nightly {nightlyBuildNum} has been released",
|
||||
"release_version": "Spotube v{version} has been released",
|
||||
"read_the_latest": "Read the latest ",
|
||||
"release_notes": "release notes",
|
||||
"pick_color_scheme": "Pick color scheme",
|
||||
"save": "Save",
|
||||
"choose_the_device": "Choose the device:",
|
||||
"multiple_device_connected": "There are multiple device connected.\nChoose the device you want this action to take place",
|
||||
"nothing_found": "Nothing found",
|
||||
"the_box_is_empty": "The box is empty",
|
||||
"top_tracks": "Top Tracks",
|
||||
"top_artists": "Top Artists",
|
||||
"top_albums": "Top Albums",
|
||||
"this_week": "This week",
|
||||
"this_month": "This month",
|
||||
"last_6_months": "Last 6 months",
|
||||
"this_year": "This year",
|
||||
"last_2_years": "Last 2 years",
|
||||
"all_time": "All time",
|
||||
"powered_by_provider": "Powered by {providerName}",
|
||||
"email": "Email",
|
||||
"profile_followers": "Followers",
|
||||
"birthday": "Birthday",
|
||||
"country": "Country",
|
||||
"subscription": "Subscription",
|
||||
"not_born": "Not born",
|
||||
"hacker": "Hacker",
|
||||
"profile": "Profile",
|
||||
"no_name": "No Name",
|
||||
"edit": "Edit",
|
||||
"user_profile": "User Profile",
|
||||
"count_plays": "{count} plays",
|
||||
"streaming_fees_hypothetical": "Streaming fees (hypothetical)",
|
||||
"minutes_listened": "Minutes listened",
|
||||
"streamed_songs": "Streamed songs",
|
||||
"count_streams": "{count} streams",
|
||||
"owned_by_you": "Owned by you",
|
||||
"copied_shareurl_to_clipboard": "Copied {shareUrl} to clipboard",
|
||||
"spotify_hipotetical_calculation": "*This is calculated based on Spotify's per stream\npayout of $0.003 to $0.005. This is a hypothetical\ncalculation to give user insight about how much they\nwould have paid to the artists if they were to listen\ntheir song in Spotify.",
|
||||
"count_mins": "{minutes} mins",
|
||||
"summary_minutes": "minutes",
|
||||
"summary_listened_to_music": "Listened to music",
|
||||
"summary_songs": "songs",
|
||||
"summary_streamed_overall": "Streamed overall",
|
||||
"summary_owed_to_artists": "Owed to artists\nthis month",
|
||||
"summary_artists": "artist's",
|
||||
"summary_music_reached_you": "Music reached you",
|
||||
"summary_full_albums": "full albums",
|
||||
"summary_got_your_love": "Got your love",
|
||||
"summary_playlists": "playlists",
|
||||
"summary_were_on_repeat": "Were on repeat"
|
||||
}
|
@ -107,6 +107,9 @@
|
||||
"always_on_top": "Beti ikusgai",
|
||||
"exit_mini_player": "Irten mini erreproduzitzailetik",
|
||||
"download_location": "Deskargen kokapena",
|
||||
"local_library": "Liburutegi lokala",
|
||||
"add_library_location": "Gehitu liburutegira",
|
||||
"remove_library_location": "Kendu liburutegitik",
|
||||
"account": "Kontua",
|
||||
"login_with_spotify": "Hasi saioa zure Spotify kontuarekin",
|
||||
"connect_with_spotify": "Spotify-rekin konektatu",
|
||||
@ -118,8 +121,8 @@
|
||||
"market_place_region": "Dendaren herrialdea",
|
||||
"recommendation_country": "Gomendio herrialdea",
|
||||
"appearance": "Itxura",
|
||||
"layout_mode": "Diseinu modua",
|
||||
"override_layout_settings": "Responsive diseinu moduaren ezarpenak ezeztatu",
|
||||
"layout_mode": "Diseinua",
|
||||
"override_layout_settings": "Responsive diseinuaren ezarpenak ezeztatu",
|
||||
"adaptive": "Moldagarria",
|
||||
"compact": "Trinkoa",
|
||||
"extended": "Hedatua",
|
||||
@ -287,7 +290,7 @@
|
||||
"genres": "Generoak",
|
||||
"explore_genres": "Esploratu generoak",
|
||||
"friends": "Lagunak",
|
||||
"no_lyrics_available": "Sentitzen dut, ezin dira kanta honen hitzak aurkitu",
|
||||
"no_lyrics_available": "Sentitzen dugu, ezin dira kanta honen hitzak aurkitu",
|
||||
"start_a_radio": "Hasi Irrati bat",
|
||||
"how_to_start_radio": "Nola hasi nahi duzu irratia?",
|
||||
"replace_queue_question": "Uneko zerrenda ordezkatu nahi duzu edo bertan gehitu?",
|
||||
@ -295,6 +298,7 @@
|
||||
"delete_playlist": "Ezabatu zerrenda",
|
||||
"delete_playlist_confirmation": "Ziur zaude zerrenda ezabatu nahi duzula?",
|
||||
"local_tracks": "Kanta lokalak",
|
||||
"local_tab": "Lokalean",
|
||||
"song_link": "Kantaren lotura",
|
||||
"skip_this_nonsense": "Utzi txorakeria hau",
|
||||
"freedom_of_music": "“Musika Askatasuna”",
|
||||
@ -321,9 +325,65 @@
|
||||
"connect_client_alert": "{client} gailuak kontrolatzen zaitu",
|
||||
"this_device": "Gailu hau",
|
||||
"remote": "Urrunekoa",
|
||||
"local_library": "Liburutegi lokala",
|
||||
"add_library_location": "Gehitu liburutegira",
|
||||
"remove_library_location": "Kendu liburutegitik",
|
||||
"local_tab": "Tokiko",
|
||||
"stats": "Estatistikak"
|
||||
"stats": "Estatistikak",
|
||||
"and_n_more": "eta {count} gehiago",
|
||||
"recently_played": "Berriki entzunak",
|
||||
"browse_more": "Gehiago Bilatu",
|
||||
"no_title": "Titulurik ez",
|
||||
"not_playing": "Erreprodukziorik ez",
|
||||
"epic_failure": "Sekulako errorea!",
|
||||
"added_num_tracks_to_queue": "{tracks_length} kanta gehitu dira zerrendara",
|
||||
"spotube_has_an_update": "Spotube-ren eguneraketa bat dago",
|
||||
"download_now": "Orain deskargatu",
|
||||
"nightly_version": "Spotube {nightlyBuildNum} Nightly-a argitaratu da",
|
||||
"release_version": "Spotube v{version} argitaratu da",
|
||||
"read_the_latest": "Irakurri azken ",
|
||||
"release_notes": "argitatratze oharrak",
|
||||
"pick_color_scheme": "Aukeratu kolore eskema",
|
||||
"save": "Gorde",
|
||||
"choose_the_device": "Aukeratu gailua:",
|
||||
"multiple_device_connected": "Hainbat gailu daude konektatuta.\nAukeratu zein gailutan aplikatu nahi duzun ekintza hau",
|
||||
"nothing_found": "Ezer ez da aurkitu",
|
||||
"the_box_is_empty": "Kaxa hutsik dago",
|
||||
"top_tracks": "Top Kantak",
|
||||
"top_artists": "Top Artistak",
|
||||
"top_albums": "Top Albumak",
|
||||
"this_week": "Aste honetan",
|
||||
"this_month": "Hilabete honetan",
|
||||
"last_6_months": "Azken 6 hilabeteetan",
|
||||
"this_year": "Aurten",
|
||||
"last_2_years": "Azken 2 urtetan",
|
||||
"all_time": "Betidanik",
|
||||
"powered_by_provider": "{providerName}-ren eskutik",
|
||||
"email": "Email",
|
||||
"profile_followers": "Jarraitzaileak",
|
||||
"birthday": "Jaiotze-data",
|
||||
"country": "Herrialdea",
|
||||
"subscription": "Harpidetzak",
|
||||
"not_born": "Jaio gabe",
|
||||
"hacker": "Hacker",
|
||||
"profile": "Profila",
|
||||
"no_name": "Izenik Ez",
|
||||
"edit": "Editatu",
|
||||
"user_profile": "Erabiltzaile Profila",
|
||||
"count_plays": "{count} erreprodukzio",
|
||||
"streaming_fees_hypothetical": "Streaming ordainketa (hipotetikoa)",
|
||||
"minutes_listened": "Entzundako minutuak",
|
||||
"streamed_songs": "Stream-eatutako kantak",
|
||||
"count_streams": "{count} stream",
|
||||
"owned_by_you": "Zure jabetzakoa",
|
||||
"copied_shareurl_to_clipboard": "{shareUrl} arbelera kopiatua",
|
||||
"spotify_hipotetical_calculation": "*Sportify-k stream bakoitzeko duen $0.003 eta $0.005\nordainsarian oinarritua da. Kalkulu hipotetiko bat,\nkanta hauek Spotify-n entzun bazenitu,\nberaiek artistari zenbat ordaiduko lioketen jakin dezazun.",
|
||||
"count_mins": "{minutes} minutu",
|
||||
"summary_minutes": "minutu",
|
||||
"summary_listened_to_music": "Musika entzuten",
|
||||
"summary_songs": "kanta",
|
||||
"summary_streamed_overall": "Stream-eatuta oro har",
|
||||
"summary_owed_to_artists": "Hilabete honetan\nartistei zor zaiena",
|
||||
"summary_artists": "artisten",
|
||||
"summary_music_reached_you": "Musika ailegatu zaizu",
|
||||
"summary_full_albums": "album osok",
|
||||
"summary_got_your_love": "Izan dute zure maitasuna",
|
||||
"summary_playlists": "zerrenda",
|
||||
"summary_were_on_repeat": "Dituzu errepikatze moduan"
|
||||
}
|
@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:spotube/collections/spotube_icons.dart';
|
||||
import 'package:spotube/components/horizontal_playbutton_card_view/horizontal_playbutton_card_view.dart';
|
||||
import 'package:spotube/extensions/context.dart';
|
||||
import 'package:spotube/pages/home/feed/feed_section.dart';
|
||||
import 'package:spotube/provider/spotify/views/home.dart';
|
||||
import 'package:spotube/utils/service_utils.dart';
|
||||
@ -33,14 +34,14 @@ class HomePageFeedSection extends HookConsumerWidget {
|
||||
else if (item.playlist != null)
|
||||
item.playlist!.asPlaylist
|
||||
],
|
||||
title: Text(section.title ?? "No Titel"),
|
||||
title: Text(section.title ?? context.l10n.no_title),
|
||||
hasNextPage: false,
|
||||
isLoadingNextPage: false,
|
||||
onFetchMore: () {},
|
||||
titleTrailing: Directionality(
|
||||
textDirection: TextDirection.rtl,
|
||||
child: TextButton.icon(
|
||||
label: const Text("Browse More"),
|
||||
label: Text(context.l10n.browse_more),
|
||||
icon: const Icon(SpotubeIcons.angleRight),
|
||||
onPressed: () => ServiceUtils.pushNamed(
|
||||
context,
|
||||
|
@ -6,6 +6,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:skeletonizer/skeletonizer.dart';
|
||||
import 'package:spotube/collections/fake.dart';
|
||||
import 'package:spotube/modules/home/sections/friends/friend_item.dart';
|
||||
import 'package:spotube/extensions/context.dart';
|
||||
import 'package:spotube/hooks/utils/use_breakpoint_value.dart';
|
||||
import 'package:spotube/models/spotify_friends.dart';
|
||||
import 'package:spotube/provider/authentication/authentication.dart';
|
||||
@ -73,7 +74,7 @@ class HomePageFriendsSection extends HookConsumerWidget {
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Text(
|
||||
'Friends',
|
||||
context.l10n.friends,
|
||||
style: Theme.of(context).textTheme.titleMedium,
|
||||
),
|
||||
),
|
||||
|
@ -3,6 +3,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:skeletonizer/skeletonizer.dart';
|
||||
import 'package:spotube/collections/fake.dart';
|
||||
import 'package:spotube/components/horizontal_playbutton_card_view/horizontal_playbutton_card_view.dart';
|
||||
import 'package:spotube/extensions/context.dart';
|
||||
import 'package:spotube/models/database/database.dart';
|
||||
import 'package:spotube/provider/history/recent.dart';
|
||||
|
||||
@ -22,7 +23,7 @@ class HomeRecentlyPlayedSection extends HookConsumerWidget {
|
||||
return Skeletonizer(
|
||||
enabled: history.isLoading,
|
||||
child: HorizontalPlaybuttonCardView(
|
||||
title: const Text('Recently Played'),
|
||||
title: Text(context.l10n.recently_played),
|
||||
items: [
|
||||
for (final item in historyData)
|
||||
if (item.playlist != null)
|
||||
|
@ -187,7 +187,7 @@ class _MultiSelectDialog<T> extends HookWidget {
|
||||
|
||||
return AlertDialog(
|
||||
scrollable: true,
|
||||
title: dialogTitle ?? const Text('Select'),
|
||||
title: dialogTitle ?? Text(context.l10n.select),
|
||||
contentPadding: mediaQuery.mdAndUp ? null : const EdgeInsets.all(16),
|
||||
insetPadding: const EdgeInsets.all(16),
|
||||
actions: [
|
||||
|
@ -233,7 +233,8 @@ class PlayerView extends HookConsumerWidget {
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
AutoSizeText(
|
||||
currentTrack?.name ?? "Not playing",
|
||||
currentTrack?.name ??
|
||||
context.l10n.not_playing,
|
||||
style: TextStyle(
|
||||
color: titleTextColor,
|
||||
fontSize: 22,
|
||||
|
@ -4,6 +4,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:spotify/spotify.dart';
|
||||
import 'package:spotube/components/dialogs/select_device_dialog.dart';
|
||||
import 'package:spotube/components/playbutton_card.dart';
|
||||
import 'package:spotube/extensions/context.dart';
|
||||
import 'package:spotube/extensions/image.dart';
|
||||
import 'package:spotube/models/connect/connect.dart';
|
||||
import 'package:spotube/pages/playlist/playlist.dart';
|
||||
@ -133,8 +134,8 @@ class PlaylistCard extends HookConsumerWidget {
|
||||
historyNotifier.addPlaylists([playlist]);
|
||||
if (context.mounted) {
|
||||
final snackbar = SnackBar(
|
||||
content:
|
||||
Text("Added ${fetchedInitialTracks.length} tracks to queue"),
|
||||
content: Text(context.l10n
|
||||
.added_num_tracks_to_queue(fetchedInitialTracks.length)),
|
||||
action: SnackBarAction(
|
||||
label: "Undo",
|
||||
onPressed: () {
|
||||
|
@ -76,7 +76,7 @@ class PlaylistCreateDialog extends HookConsumerWidget {
|
||||
scaffold.showSnackBar(
|
||||
SnackBar(
|
||||
content: Text(
|
||||
l10n.error(error.message ?? "Epic failure!"),
|
||||
l10n.error(error.message ?? context.l10n.epic_failure),
|
||||
style: theme.textTheme.bodyMedium!.copyWith(
|
||||
color: theme.colorScheme.onError,
|
||||
),
|
||||
|
@ -1,6 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:spotube/components/links/anchor_button.dart';
|
||||
import 'package:url_launcher/url_launcher_string.dart';
|
||||
import 'package:spotube/extensions/context.dart';
|
||||
import 'package:version/version.dart';
|
||||
|
||||
class RootAppUpdateDialog extends StatelessWidget {
|
||||
@ -16,10 +17,10 @@ class RootAppUpdateDialog extends StatelessWidget {
|
||||
const url = "https://spotube.krtirtho.dev/downloads";
|
||||
const nightlyUrl = "https://spotube.krtirtho.dev/downloads/nightly";
|
||||
return AlertDialog(
|
||||
title: const Text("Spotube has an update"),
|
||||
title: Text(context.l10n.spotube_has_an_update),
|
||||
actions: [
|
||||
FilledButton(
|
||||
child: const Text("Download Now"),
|
||||
child: Text(context.l10n.download_now),
|
||||
onPressed: () => launchUrlString(
|
||||
nightlyBuildNum != null ? nightlyUrl : url,
|
||||
mode: LaunchMode.externalApplication,
|
||||
@ -31,16 +32,16 @@ class RootAppUpdateDialog extends StatelessWidget {
|
||||
children: [
|
||||
Text(
|
||||
nightlyBuildNum != null
|
||||
? "Spotube Nightly $nightlyBuildNum has been released"
|
||||
: "Spotube v$version has been released",
|
||||
? context.l10n.nightly_version(nightlyBuildNum!)
|
||||
: context.l10n.release_version(version!),
|
||||
),
|
||||
if (nightlyBuildNum == null)
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
const Text("Read the latest "),
|
||||
Text(context.l10n.read_the_latest),
|
||||
AnchorButton(
|
||||
"release notes",
|
||||
context.l10n.release_notes,
|
||||
style: const TextStyle(color: Colors.blue),
|
||||
onTap: () => launchUrlString(
|
||||
url,
|
||||
|
@ -1,6 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:spotube/extensions/context.dart';
|
||||
|
||||
import 'package:spotube/provider/user_preferences/user_preferences_provider.dart';
|
||||
import 'package:system_theme/system_theme.dart';
|
||||
@ -69,17 +70,17 @@ class ColorSchemePickerDialog extends HookConsumerWidget {
|
||||
}
|
||||
|
||||
return AlertDialog(
|
||||
title: const Text("Pick color scheme"),
|
||||
title: Text(context.l10n.pick_color_scheme),
|
||||
actions: [
|
||||
OutlinedButton(
|
||||
child: const Text("Cancel"),
|
||||
child: Text(context.l10n.cancel),
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
),
|
||||
FilledButton(
|
||||
onPressed: onOk,
|
||||
child: const Text("Save"),
|
||||
child: Text(context.l10n.save),
|
||||
),
|
||||
],
|
||||
content: SizedBox(
|
||||
|
@ -5,6 +5,7 @@ import 'package:spotube/collections/fake.dart';
|
||||
import 'package:spotube/collections/formatters.dart';
|
||||
import 'package:spotube/modules/stats/summary/summary_card.dart';
|
||||
import 'package:spotube/extensions/constrains.dart';
|
||||
import 'package:spotube/extensions/context.dart';
|
||||
import 'package:spotube/pages/stats/albums/albums.dart';
|
||||
import 'package:spotube/pages/stats/artists/artists.dart';
|
||||
import 'package:spotube/pages/stats/fees/fees.dart';
|
||||
@ -45,8 +46,8 @@ class StatsPageSummarySection extends HookConsumerWidget {
|
||||
delegate: SliverChildListDelegate([
|
||||
SummaryCard(
|
||||
title: summaryData.duration.inMinutes.toDouble(),
|
||||
unit: "minutes",
|
||||
description: 'Listened to music',
|
||||
unit: context.l10n.summary_minutes,
|
||||
description: context.l10n.summary_listened_to_music,
|
||||
color: Colors.purple,
|
||||
onTap: () {
|
||||
ServiceUtils.pushNamed(context, StatsMinutesPage.name);
|
||||
@ -54,8 +55,8 @@ class StatsPageSummarySection extends HookConsumerWidget {
|
||||
),
|
||||
SummaryCard(
|
||||
title: summaryData.tracks.toDouble(),
|
||||
unit: "songs",
|
||||
description: 'Streamed overall',
|
||||
unit: context.l10n.summary_songs,
|
||||
description: context.l10n.summary_streamed_overall,
|
||||
color: Colors.lightBlue,
|
||||
onTap: () {
|
||||
ServiceUtils.pushNamed(context, StatsStreamsPage.name);
|
||||
@ -64,7 +65,7 @@ class StatsPageSummarySection extends HookConsumerWidget {
|
||||
SummaryCard.unformatted(
|
||||
title: usdFormatter.format(summaryData.fees.toDouble()),
|
||||
unit: "",
|
||||
description: 'Owed to artists\nthis month',
|
||||
description: context.l10n.summary_owed_to_artists,
|
||||
color: Colors.green,
|
||||
onTap: () {
|
||||
ServiceUtils.pushNamed(context, StatsStreamFeesPage.name);
|
||||
@ -72,8 +73,8 @@ class StatsPageSummarySection extends HookConsumerWidget {
|
||||
),
|
||||
SummaryCard(
|
||||
title: summaryData.artists.toDouble(),
|
||||
unit: "artist's",
|
||||
description: 'Music reached you',
|
||||
unit: context.l10n.summary_artists,
|
||||
description: context.l10n.summary_music_reached_you,
|
||||
color: Colors.yellow,
|
||||
onTap: () {
|
||||
ServiceUtils.pushNamed(context, StatsArtistsPage.name);
|
||||
@ -81,8 +82,8 @@ class StatsPageSummarySection extends HookConsumerWidget {
|
||||
),
|
||||
SummaryCard(
|
||||
title: summaryData.albums.toDouble(),
|
||||
unit: "full albums",
|
||||
description: 'Got your love',
|
||||
unit: context.l10n.summary_full_albums,
|
||||
description: context.l10n.summary_got_your_love,
|
||||
color: Colors.pink,
|
||||
onTap: () {
|
||||
ServiceUtils.pushNamed(context, StatsAlbumsPage.name);
|
||||
@ -90,8 +91,8 @@ class StatsPageSummarySection extends HookConsumerWidget {
|
||||
),
|
||||
SummaryCard(
|
||||
title: summaryData.playlists.toDouble(),
|
||||
unit: "playlists",
|
||||
description: 'Were on repeat',
|
||||
unit: context.l10n.summary_playlists,
|
||||
description: context.l10n.summary_were_on_repeat,
|
||||
color: Colors.teal,
|
||||
onTap: () {
|
||||
ServiceUtils.pushNamed(context, StatsPlaylistsPage.name);
|
||||
|
@ -3,6 +3,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:skeletonizer/skeletonizer.dart';
|
||||
import 'package:spotube/collections/formatters.dart';
|
||||
import 'package:spotube/modules/stats/common/album_item.dart';
|
||||
import 'package:spotube/extensions/context.dart';
|
||||
import 'package:spotube/provider/history/top.dart';
|
||||
import 'package:spotube/provider/history/top/albums.dart';
|
||||
import 'package:spotube/provider/spotify/spotify.dart';
|
||||
@ -35,7 +36,8 @@ class TopAlbums extends HookConsumerWidget {
|
||||
return StatsAlbumItem(
|
||||
album: album.album,
|
||||
info: Text(
|
||||
"${compactNumberFormatter.format(album.count)} plays",
|
||||
context.l10n
|
||||
.count_plays(compactNumberFormatter.format(album.count)),
|
||||
),
|
||||
);
|
||||
},
|
||||
|
@ -4,6 +4,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:skeletonizer/skeletonizer.dart';
|
||||
import 'package:spotube/collections/formatters.dart';
|
||||
import 'package:spotube/modules/stats/common/artist_item.dart';
|
||||
import 'package:spotube/extensions/context.dart';
|
||||
import 'package:spotube/provider/history/top.dart';
|
||||
import 'package:spotube/provider/history/top/tracks.dart';
|
||||
import 'package:spotube/provider/spotify/spotify.dart';
|
||||
@ -38,7 +39,10 @@ class TopArtists extends HookConsumerWidget {
|
||||
final artist = artistsData[index];
|
||||
return StatsArtistItem(
|
||||
artist: artist.artist,
|
||||
info: Text("${compactNumberFormatter.format(artist.count)} plays"),
|
||||
info: Text(
|
||||
context.l10n
|
||||
.count_plays(compactNumberFormatter.format(artist.count)),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
|
@ -5,6 +5,7 @@ import 'package:spotube/components/themed_button_tab_bar.dart';
|
||||
import 'package:spotube/modules/stats/top/albums.dart';
|
||||
import 'package:spotube/modules/stats/top/artists.dart';
|
||||
import 'package:spotube/modules/stats/top/tracks.dart';
|
||||
import 'package:spotube/extensions/context.dart';
|
||||
|
||||
import 'package:spotube/provider/history/top.dart';
|
||||
|
||||
@ -24,23 +25,23 @@ class StatsPageTopSection extends HookConsumerWidget {
|
||||
floating: true,
|
||||
flexibleSpace: ThemedButtonsTabBar(
|
||||
controller: tabController,
|
||||
tabs: const [
|
||||
tabs: [
|
||||
Tab(
|
||||
child: Padding(
|
||||
padding: EdgeInsets.all(5),
|
||||
child: Text("Top Tracks"),
|
||||
padding: const EdgeInsets.all(5),
|
||||
child: Text(context.l10n.top_tracks),
|
||||
),
|
||||
),
|
||||
Tab(
|
||||
child: Padding(
|
||||
padding: EdgeInsets.all(5),
|
||||
child: Text("Top Artists"),
|
||||
padding: const EdgeInsets.all(5),
|
||||
child: Text(context.l10n.top_artists),
|
||||
),
|
||||
),
|
||||
Tab(
|
||||
child: Padding(
|
||||
padding: EdgeInsets.all(5),
|
||||
child: Text("Top Albums"),
|
||||
padding: const EdgeInsets.all(5),
|
||||
child: Text(context.l10n.top_albums),
|
||||
),
|
||||
),
|
||||
],
|
||||
@ -61,30 +62,30 @@ class StatsPageTopSection extends HookConsumerWidget {
|
||||
historyDurationNotifier.update((_) => value);
|
||||
},
|
||||
icon: const Icon(Icons.arrow_drop_down),
|
||||
items: const [
|
||||
items: [
|
||||
DropdownMenuItem(
|
||||
value: HistoryDuration.days7,
|
||||
child: Text("This week"),
|
||||
child: Text(context.l10n.this_week),
|
||||
),
|
||||
DropdownMenuItem(
|
||||
value: HistoryDuration.days30,
|
||||
child: Text("This month"),
|
||||
child: Text(context.l10n.this_month),
|
||||
),
|
||||
DropdownMenuItem(
|
||||
value: HistoryDuration.months6,
|
||||
child: Text("Last 6 months"),
|
||||
child: Text(context.l10n.last_6_months),
|
||||
),
|
||||
DropdownMenuItem(
|
||||
value: HistoryDuration.year,
|
||||
child: Text("This year"),
|
||||
child: Text(context.l10n.this_year),
|
||||
),
|
||||
DropdownMenuItem(
|
||||
value: HistoryDuration.years2,
|
||||
child: Text("Last 2 years"),
|
||||
child: Text(context.l10n.last_2_years),
|
||||
),
|
||||
DropdownMenuItem(
|
||||
value: HistoryDuration.allTime,
|
||||
child: Text("All time"),
|
||||
child: Text(context.l10n.all_time),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
@ -3,6 +3,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:skeletonizer/skeletonizer.dart';
|
||||
import 'package:spotube/collections/formatters.dart';
|
||||
import 'package:spotube/modules/stats/common/track_item.dart';
|
||||
import 'package:spotube/extensions/context.dart';
|
||||
import 'package:spotube/provider/history/top.dart';
|
||||
import 'package:spotube/provider/history/top/tracks.dart';
|
||||
import 'package:spotube/provider/spotify/spotify.dart';
|
||||
@ -37,7 +38,8 @@ class TopTracks extends HookConsumerWidget {
|
||||
return StatsTrackItem(
|
||||
track: track.track,
|
||||
info: Text(
|
||||
"${compactNumberFormatter.format(track.count)} plays",
|
||||
context.l10n
|
||||
.count_plays(compactNumberFormatter.format(track.count)),
|
||||
),
|
||||
);
|
||||
},
|
||||
|
@ -73,7 +73,7 @@ class LyricsPage extends HookConsumerWidget {
|
||||
|
||||
return Align(
|
||||
alignment: Alignment.bottomRight,
|
||||
child: Text("Powered by $providerName"),
|
||||
child: Text(context.l10n.powered_by_provider(providerName)),
|
||||
);
|
||||
},
|
||||
),
|
||||
|
@ -103,7 +103,7 @@ class SyncedLyrics extends HookConsumerWidget {
|
||||
backgroundColor: Colors.transparent,
|
||||
centerTitle: true,
|
||||
title: Text(
|
||||
playlist.activeTrack?.name ?? "Not Playing",
|
||||
playlist.activeTrack?.name ?? context.l10n.not_playing,
|
||||
style: headlineTextStyle,
|
||||
),
|
||||
bottom: PreferredSize(
|
||||
|
@ -9,6 +9,7 @@ import 'package:spotube/collections/spotify_markets.dart';
|
||||
import 'package:spotube/collections/spotube_icons.dart';
|
||||
import 'package:spotube/components/image/universal_image.dart';
|
||||
import 'package:spotube/components/titlebar/titlebar.dart';
|
||||
import 'package:spotube/extensions/context.dart';
|
||||
import 'package:spotube/extensions/image.dart';
|
||||
import 'package:spotube/provider/spotify/spotify.dart';
|
||||
import 'package:url_launcher/url_launcher_string.dart';
|
||||
@ -27,21 +28,22 @@ class ProfilePage extends HookConsumerWidget {
|
||||
|
||||
final userProperties = useMemoized(
|
||||
() => {
|
||||
"Email": meData.email ?? "N/A",
|
||||
"Followers": meData.followers?.total.toString() ?? "N/A",
|
||||
"Birthday": meData.birthdate ?? "Not born",
|
||||
"Country": spotifyMarkets
|
||||
context.l10n.email: meData.email ?? "N/A",
|
||||
context.l10n.profile_followers:
|
||||
meData.followers?.total.toString() ?? "N/A",
|
||||
context.l10n.birthday: meData.birthdate ?? context.l10n.not_born,
|
||||
context.l10n.country: spotifyMarkets
|
||||
.firstWhere((market) => market.$1 == meData.country)
|
||||
.$2,
|
||||
"Subscription": meData.product ?? "Hacker",
|
||||
context.l10n.subscription: meData.product ?? context.l10n.hacker,
|
||||
},
|
||||
[meData],
|
||||
);
|
||||
|
||||
return SafeArea(
|
||||
child: Scaffold(
|
||||
appBar: const PageWindowTitleBar(
|
||||
title: Text("Profile"),
|
||||
appBar: PageWindowTitleBar(
|
||||
title: Text(context.l10n.profile),
|
||||
titleSpacing: 0,
|
||||
automaticallyImplyLeading: true,
|
||||
centerTitle: false,
|
||||
@ -72,7 +74,7 @@ class ProfilePage extends HookConsumerWidget {
|
||||
const SliverGap(10),
|
||||
SliverToBoxAdapter(
|
||||
child: Text(
|
||||
meData.displayName ?? "No Name",
|
||||
meData.displayName ?? context.l10n.no_name,
|
||||
style: textTheme.titleLarge,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
@ -85,7 +87,7 @@ class ProfilePage extends HookConsumerWidget {
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
TextButton.icon(
|
||||
label: const Text("Edit"),
|
||||
label: Text(context.l10n.edit),
|
||||
icon: const Icon(SpotubeIcons.edit),
|
||||
onPressed: () {
|
||||
launchUrlString(
|
||||
@ -118,7 +120,7 @@ class ProfilePage extends HookConsumerWidget {
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(6),
|
||||
child: Text(
|
||||
key,
|
||||
'$key',
|
||||
style: textTheme.titleSmall,
|
||||
),
|
||||
),
|
||||
|
@ -92,7 +92,7 @@ class SettingsAccountSection extends HookConsumerWidget {
|
||||
if (auth.asData?.value != null)
|
||||
ListTile(
|
||||
leading: const Icon(SpotubeIcons.user),
|
||||
title: const Text("User Profile"),
|
||||
title: Text(context.l10n.user_profile),
|
||||
trailing: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: CircleAvatar(
|
||||
|
@ -4,6 +4,7 @@ import 'package:skeletonizer/skeletonizer.dart';
|
||||
import 'package:spotube/collections/formatters.dart';
|
||||
import 'package:spotube/components/titlebar/titlebar.dart';
|
||||
import 'package:spotube/modules/stats/common/album_item.dart';
|
||||
import 'package:spotube/extensions/context.dart';
|
||||
|
||||
import 'package:spotube/provider/history/top.dart';
|
||||
import 'package:spotube/provider/history/top/albums.dart';
|
||||
@ -24,10 +25,10 @@ class StatsAlbumsPage extends HookConsumerWidget {
|
||||
final albumsData = topAlbums.asData?.value.items ?? [];
|
||||
|
||||
return Scaffold(
|
||||
appBar: const PageWindowTitleBar(
|
||||
appBar: PageWindowTitleBar(
|
||||
automaticallyImplyLeading: true,
|
||||
centerTitle: false,
|
||||
title: Text("Albums"),
|
||||
title: Text(context.l10n.albums),
|
||||
),
|
||||
body: Skeletonizer(
|
||||
enabled: topAlbums.isLoading && !topAlbums.isLoadingNextPage,
|
||||
@ -43,9 +44,8 @@ class StatsAlbumsPage extends HookConsumerWidget {
|
||||
final album = albumsData[index];
|
||||
return StatsAlbumItem(
|
||||
album: album.album,
|
||||
info: Text(
|
||||
"${compactNumberFormatter.format(album.count)} plays",
|
||||
),
|
||||
info: Text(context.l10n
|
||||
.count_plays(compactNumberFormatter.format(album.count))),
|
||||
);
|
||||
},
|
||||
),
|
||||
|
@ -5,6 +5,7 @@ import 'package:skeletonizer/skeletonizer.dart';
|
||||
import 'package:spotube/collections/formatters.dart';
|
||||
import 'package:spotube/components/titlebar/titlebar.dart';
|
||||
import 'package:spotube/modules/stats/common/artist_item.dart';
|
||||
import 'package:spotube/extensions/context.dart';
|
||||
|
||||
import 'package:spotube/provider/history/top.dart';
|
||||
import 'package:spotube/provider/history/top/tracks.dart';
|
||||
@ -27,10 +28,10 @@ class StatsArtistsPage extends HookConsumerWidget {
|
||||
() => topTracks.asData?.value.artists ?? [], [topTracks.asData?.value]);
|
||||
|
||||
return Scaffold(
|
||||
appBar: const PageWindowTitleBar(
|
||||
appBar: PageWindowTitleBar(
|
||||
automaticallyImplyLeading: true,
|
||||
centerTitle: false,
|
||||
title: Text("Artists"),
|
||||
title: Text(context.l10n.artists),
|
||||
),
|
||||
body: Skeletonizer(
|
||||
enabled: topTracks.isLoading && !topTracks.isLoadingNextPage,
|
||||
@ -46,8 +47,8 @@ class StatsArtistsPage extends HookConsumerWidget {
|
||||
final artist = artistsData[index];
|
||||
return StatsArtistItem(
|
||||
artist: artist.artist,
|
||||
info:
|
||||
Text("${compactNumberFormatter.format(artist.count)} plays"),
|
||||
info: Text(context.l10n
|
||||
.count_plays(compactNumberFormatter.format(artist.count))),
|
||||
);
|
||||
},
|
||||
),
|
||||
|
@ -6,6 +6,7 @@ import 'package:sliver_tools/sliver_tools.dart';
|
||||
import 'package:spotube/collections/formatters.dart';
|
||||
import 'package:spotube/components/titlebar/titlebar.dart';
|
||||
import 'package:spotube/modules/stats/common/artist_item.dart';
|
||||
import 'package:spotube/extensions/context.dart';
|
||||
|
||||
import 'package:spotube/provider/history/top.dart';
|
||||
import 'package:spotube/provider/history/top/tracks.dart';
|
||||
@ -40,10 +41,10 @@ class StatsStreamFeesPage extends HookConsumerWidget {
|
||||
);
|
||||
|
||||
return Scaffold(
|
||||
appBar: const PageWindowTitleBar(
|
||||
appBar: PageWindowTitleBar(
|
||||
automaticallyImplyLeading: true,
|
||||
centerTitle: false,
|
||||
title: Text("Streaming fees (hypothetical)"),
|
||||
title: Text(context.l10n.streaming_fees_hypothetical),
|
||||
),
|
||||
body: CustomScrollView(
|
||||
slivers: [
|
||||
@ -54,11 +55,7 @@ class StatsStreamFeesPage extends HookConsumerWidget {
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
sliver: SliverToBoxAdapter(
|
||||
child: Text(
|
||||
"*This is calculated based on Spotify's per stream "
|
||||
"payout of \$0.003 to \$0.005. This is a hypothetical "
|
||||
"calculation to give user insight about how much they "
|
||||
"would have paid to the artists if they were to listen "
|
||||
"their song in Spotify.",
|
||||
context.l10n.spotify_hipotetical_calculation,
|
||||
style: textTheme.bodySmall?.copyWith(
|
||||
color: hintColor,
|
||||
),
|
||||
|
@ -5,6 +5,7 @@ import 'package:skeletonizer/skeletonizer.dart';
|
||||
import 'package:spotube/collections/formatters.dart';
|
||||
import 'package:spotube/components/titlebar/titlebar.dart';
|
||||
import 'package:spotube/modules/stats/common/track_item.dart';
|
||||
import 'package:spotube/extensions/context.dart';
|
||||
|
||||
import 'package:spotube/provider/history/top.dart';
|
||||
import 'package:spotube/provider/history/top/tracks.dart';
|
||||
@ -27,8 +28,8 @@ class StatsMinutesPage extends HookConsumerWidget {
|
||||
final tracksData = topTracks.asData?.value.items ?? [];
|
||||
|
||||
return Scaffold(
|
||||
appBar: const PageWindowTitleBar(
|
||||
title: Text("Minutes listened"),
|
||||
appBar: PageWindowTitleBar(
|
||||
title: Text(context.l10n.minutes_listened),
|
||||
centerTitle: false,
|
||||
automaticallyImplyLeading: true,
|
||||
),
|
||||
@ -48,7 +49,8 @@ class StatsMinutesPage extends HookConsumerWidget {
|
||||
return StatsTrackItem(
|
||||
track: track.track,
|
||||
info: Text(
|
||||
"${compactNumberFormatter.format(track.count)} plays",
|
||||
context.l10n
|
||||
.count_plays(compactNumberFormatter.format(track.count)),
|
||||
),
|
||||
);
|
||||
},
|
||||
|
@ -4,6 +4,7 @@ import 'package:skeletonizer/skeletonizer.dart';
|
||||
import 'package:spotube/collections/formatters.dart';
|
||||
import 'package:spotube/components/titlebar/titlebar.dart';
|
||||
import 'package:spotube/modules/stats/common/playlist_item.dart';
|
||||
import 'package:spotube/extensions/context.dart';
|
||||
|
||||
import 'package:spotube/provider/history/top.dart';
|
||||
import 'package:spotube/provider/history/top/playlists.dart';
|
||||
@ -25,10 +26,10 @@ class StatsPlaylistsPage extends HookConsumerWidget {
|
||||
final playlistsData = topPlaylists.asData?.value.items ?? [];
|
||||
|
||||
return Scaffold(
|
||||
appBar: const PageWindowTitleBar(
|
||||
appBar: PageWindowTitleBar(
|
||||
automaticallyImplyLeading: true,
|
||||
centerTitle: false,
|
||||
title: Text("Playlists"),
|
||||
title: Text(context.l10n.playlists),
|
||||
),
|
||||
body: Skeletonizer(
|
||||
enabled: topPlaylists.isLoading && !topPlaylists.isLoadingNextPage,
|
||||
@ -45,7 +46,9 @@ class StatsPlaylistsPage extends HookConsumerWidget {
|
||||
return StatsPlaylistItem(
|
||||
playlist: playlist.playlist,
|
||||
info: Text(
|
||||
"${compactNumberFormatter.format(playlist.count)} plays"),
|
||||
context.l10n
|
||||
.count_plays(compactNumberFormatter.format(playlist.count)),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
|
@ -5,6 +5,7 @@ import 'package:skeletonizer/skeletonizer.dart';
|
||||
import 'package:spotube/collections/formatters.dart';
|
||||
import 'package:spotube/components/titlebar/titlebar.dart';
|
||||
import 'package:spotube/modules/stats/common/track_item.dart';
|
||||
import 'package:spotube/extensions/context.dart';
|
||||
|
||||
import 'package:spotube/provider/history/top.dart';
|
||||
import 'package:spotube/provider/history/top/tracks.dart';
|
||||
@ -27,8 +28,8 @@ class StatsStreamsPage extends HookConsumerWidget {
|
||||
final tracksData = topTracks.asData?.value.items ?? [];
|
||||
|
||||
return Scaffold(
|
||||
appBar: const PageWindowTitleBar(
|
||||
title: Text("Streamed songs"),
|
||||
appBar: PageWindowTitleBar(
|
||||
title: Text(context.l10n.streamed_songs),
|
||||
centerTitle: false,
|
||||
automaticallyImplyLeading: true,
|
||||
),
|
||||
@ -48,7 +49,8 @@ class StatsStreamsPage extends HookConsumerWidget {
|
||||
return StatsTrackItem(
|
||||
track: track.track,
|
||||
info: Text(
|
||||
"${compactNumberFormatter.format(track.count * track.track.duration!.inMinutes)} mins",
|
||||
context.l10n.count_mins(compactNumberFormatter
|
||||
.format(track.count * track.track.duration!.inMinutes)),
|
||||
),
|
||||
);
|
||||
},
|
||||
|
Loading…
Reference in New Issue
Block a user