Compare commits

...

6 Commits

Author SHA1 Message Date
Guanciottaman
0edb33fd20
Merge ff252d6b14 into d3edf07ac9 2025-04-07 19:20:20 +06:00
Kingkor Roy Tirtho
d3edf07ac9 fix: default accent color in orange but it shows blue in settings 2025-04-07 16:16:43 +06:00
Kingkor Roy Tirtho
8fc319d980 fix(mobile): dialogs in bottom sheet are not opening 2025-04-07 14:53:05 +06:00
Guanciottaman
ff252d6b14
Merge branch 'dev' into patch-1 2024-06-03 16:26:24 +02:00
Guanciottaman
195cad8f39
Update app_it.arb fixing translations 2024-03-27 20:54:18 +01:00
Guanciottaman
19f525fa3c
Update app_it.arb
Made the translations more friendly
2024-03-12 21:44:24 +01:00
16 changed files with 3783 additions and 77 deletions

View File

@ -3,4 +3,17 @@
to allow setting breakpoints, to provide hot reload, etc. to allow setting breakpoints, to provide hot reload, etc.
--> -->
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.INTERNET" />
<application
android:name="${applicationName}"
android:allowBackup="false"
android:fullBackupContent="false"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name_en"
android:requestLegacyExternalStorage="true"
android:usesCleartextTraffic="true">
<!-- Disable Impeller -->
<meta-data
android:name="io.flutter.embedding.android.EnableImpeller"
android:value="false" />
</application>
</manifest> </manifest>

File diff suppressed because one or more lines are too long

View File

@ -1,4 +1,3 @@
import 'package:flutter/material.dart' show showModalBottomSheet;
import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart';
import 'package:shadcn_flutter/shadcn_flutter_extension.dart'; import 'package:shadcn_flutter/shadcn_flutter_extension.dart';
import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/collections/spotube_icons.dart';
@ -26,7 +25,7 @@ class AdaptiveMenuButton<T> extends MenuButton {
/// An adaptive widget that shows a [PopupMenuButton] when screen size is above /// An adaptive widget that shows a [PopupMenuButton] when screen size is above
/// or equal to 640px /// or equal to 640px
/// In smaller screen, a [IconButton] with a [showModalBottomSheet] is shown /// In smaller screen, a [IconButton] with a [openDrawer] is shown
class AdaptivePopSheetList<T> extends StatelessWidget { class AdaptivePopSheetList<T> extends StatelessWidget {
final List<AdaptiveMenuButton<T>> Function(BuildContext context) items; final List<AdaptiveMenuButton<T>> Function(BuildContext context) items;
final Widget? icon; final Widget? icon;
@ -102,15 +101,13 @@ class AdaptivePopSheetList<T> extends StatelessWidget {
return; return;
} }
showModalBottomSheet( await openDrawer(
context: context, context: context,
enableDrag: true, draggable: true,
showDragHandle: true, showDragHandle: true,
useRootNavigator: true, position: OverlayPosition.bottom,
shape: RoundedRectangleBorder( borderRadius: context.theme.borderRadiusMd,
borderRadius: context.theme.borderRadiusMd, transformBackdrop: false,
),
backgroundColor: context.theme.colorScheme.card,
builder: (context) { builder: (context) {
final children = childrenModified(context); final children = childrenModified(context);
return ListView.builder( return ListView.builder(
@ -127,7 +124,7 @@ class AdaptivePopSheetList<T> extends StatelessWidget {
onPressed: () { onPressed: () {
data.onPressed?.call(context); data.onPressed?.call(context);
if (data.autoClose) { if (data.autoClose) {
Navigator.of(context).pop(); closeDrawer(context);
} }
}, },
leading: data.leading, leading: data.leading,

View File

@ -74,6 +74,26 @@ class TrackPresentationActionsSection extends HookConsumerWidget {
ref.watch(presentationStateProvider(options.collection).notifier); ref.watch(presentationStateProvider(options.collection).notifier);
final selectedTracks = state.selectedTracks; final selectedTracks = state.selectedTracks;
Future<void> actionDownloadTracks({
required BuildContext context,
required List<Track> tracks,
required String action,
}) async {
final confirmed = audioSource == AudioSource.piped ||
(await showDialog<bool>(
context: context,
builder: (context) {
return const ConfirmDownloadDialog();
},
) ??
false);
if (confirmed != true) return;
downloader.batchAddToQueue(tracks);
notifier.deselectAllTracks();
if (!context.mounted) return;
showToastForAction(context, action, tracks.length);
}
return AdaptivePopSheetList( return AdaptivePopSheetList(
tooltip: context.l10n.more_actions, tooltip: context.l10n.more_actions,
headings: [ headings: [
@ -95,22 +115,12 @@ class TrackPresentationActionsSection extends HookConsumerWidget {
switch (action) { switch (action) {
case "download": case "download":
{ await actionDownloadTracks(
final confirmed = audioSource == AudioSource.piped || context: context,
(await showDialog<bool?>( tracks: tracks,
context: context, action: action,
builder: (context) { );
return const ConfirmDownloadDialog(); break;
},
) ??
false);
if (confirmed != true) return;
downloader.batchAddToQueue(tracks);
notifier.deselectAllTracks();
if (!context.mounted) return;
showToastForAction(context, action, tracks.length);
break;
}
case "add-to-playlist": case "add-to-playlist":
{ {
if (context.mounted) { if (context.mounted) {

View File

@ -57,7 +57,7 @@ class TrackPresentationTopSection extends HookConsumerWidget {
Tooltip( Tooltip(
tooltip: TooltipContainer( tooltip: TooltipContainer(
child: Text(context.l10n.shuffle_playlist), child: Text(context.l10n.shuffle_playlist),
), ).call,
child: IconButton.secondary( child: IconButton.secondary(
icon: isLoading icon: isLoading
? const Center( ? const Center(
@ -73,7 +73,7 @@ class TrackPresentationTopSection extends HookConsumerWidget {
Tooltip( Tooltip(
tooltip: TooltipContainer( tooltip: TooltipContainer(
child: Text(context.l10n.add_to_queue), child: Text(context.l10n.add_to_queue),
), ).call,
child: IconButton.secondary( child: IconButton.secondary(
icon: const Icon(SpotubeIcons.queueAdd), icon: const Icon(SpotubeIcons.queueAdd),
enabled: !isLoading && !isActive, enabled: !isLoading && !isActive,
@ -126,7 +126,7 @@ class TrackPresentationTopSection extends HookConsumerWidget {
Tooltip( Tooltip(
tooltip: TooltipContainer( tooltip: TooltipContainer(
child: Text(context.l10n.share), child: Text(context.l10n.share),
), ).call,
child: IconButton.outline( child: IconButton.outline(
icon: const Icon(SpotubeIcons.share), icon: const Icon(SpotubeIcons.share),
size: ButtonSize.small, size: ButtonSize.small,

View File

@ -91,24 +91,14 @@ class TrackOptions extends HookConsumerWidget {
) { ) {
/// showDialog doesn't work for some reason. So we have to /// showDialog doesn't work for some reason. So we have to
/// manually push a Dialog Route in the Navigator to get it working /// manually push a Dialog Route in the Navigator to get it working
Navigator.push( showDialog(
context, context: context,
DialogRoute( builder: (context) {
alignment: Alignment.bottomCenter, return PlaylistAddTrackDialog(
transitionBuilder: (context, animation, secondaryAnimation, child) { tracks: [track],
return FadeTransition(opacity: animation, child: child); openFromPlaylist: playlistId,
}, );
context: context, },
barrierColor: Colors.black.withValues(alpha: 0.5),
builder: (context) {
return Center(
child: PlaylistAddTrackDialog(
tracks: [track],
openFromPlaylist: playlistId,
),
);
},
),
); );
} }
@ -338,6 +328,7 @@ class TrackOptions extends HookConsumerWidget {
} }
}, },
icon: icon ?? const Icon(SpotubeIcons.moreHorizontal), icon: icon ?? const Icon(SpotubeIcons.moreHorizontal),
variance: ButtonVariance.outline,
headings: [ headings: [
Basic( Basic(
leading: AspectRatio( leading: AspectRatio(

View File

@ -137,16 +137,16 @@
"pre_download_play_description": "Anzi che effettuare lo stream dell'audio, scarica invece i byte e li riproduce (raccomandato per gli utenti con banda più alta)", "pre_download_play_description": "Anzi che effettuare lo stream dell'audio, scarica invece i byte e li riproduce (raccomandato per gli utenti con banda più alta)",
"skip_non_music": "Salta i segmenti non di musica (SponsorBlock)", "skip_non_music": "Salta i segmenti non di musica (SponsorBlock)",
"blacklist_description": "Tracce e artisti in blacklist", "blacklist_description": "Tracce e artisti in blacklist",
"wait_for_download_to_finish": "Prego attendere che lo scaricamento corrente finisca", "wait_for_download_to_finish": "Prego attendere che il download corrente finisca",
"desktop": "Desktop", "desktop": "Desktop",
"close_behavior": "Comportamento Chiusura", "close_behavior": "Comportamento Chiusura",
"close": "Chiudi", "close": "Chiudi",
"minimize_to_tray": "Minimizza in tray", "minimize_to_tray": "Minimizza in tray",
"show_tray_icon": "Mostra icona in tray di sistema", "show_tray_icon": "Mostra icona in tray di sistema",
"about": "A proposito di", "about": "Informazioni su",
"u_love_spotube": "Sappiamo che ami Spotube", "u_love_spotube": "Sappiamo che ami Spotube",
"check_for_updates": "Controlla aggiornamenti", "check_for_updates": "Controlla aggiornamenti",
"about_spotube": "A proposito di Spotube", "about_spotube": "Informazioni su Spotube",
"blacklist": "Blacklist", "blacklist": "Blacklist",
"please_sponsor": "Per favore sponsorizza/dona", "please_sponsor": "Per favore sponsorizza/dona",
"spotube_description": "Spotube, un client spotify gratis per tutti, multipiattaforma e leggero", "spotube_description": "Spotube, un client spotify gratis per tutti, multipiattaforma e leggero",
@ -187,7 +187,7 @@
"generate_playlist": "Genera Playlist", "generate_playlist": "Genera Playlist",
"track_exists": "La traccia {track} esiste già", "track_exists": "La traccia {track} esiste già",
"replace_downloaded_tracks": "Sostituisci tutte le tracce scaricate", "replace_downloaded_tracks": "Sostituisci tutte le tracce scaricate",
"skip_download_tracks": "Salta lo scaricamento di tutte le tracce scaricate", "skip_download_tracks": "Salta il download di tutte le tracce scaricate",
"do_you_want_to_replace": "Vuoi sovrascrivere la traccia esistente??", "do_you_want_to_replace": "Vuoi sovrascrivere la traccia esistente??",
"replace": "Sovrascrivi", "replace": "Sovrascrivi",
"skip": "Salta", "skip": "Salta",
@ -256,7 +256,7 @@
"querying_info": "Richiesta informazioni...", "querying_info": "Richiesta informazioni...",
"piped_api_down": "Le Piped API non funzionano", "piped_api_down": "Le Piped API non funzionano",
"piped_down_error_instructions": "L'istanza di Piped {pipedInstance} è correntemente offline\n\nCambia istanza o cambia 'Tipo API' alle API ufficiali YouTube\n\nAssicurati di riavviare l'app dopo il cambio", "piped_down_error_instructions": "L'istanza di Piped {pipedInstance} è correntemente offline\n\nCambia istanza o cambia 'Tipo API' alle API ufficiali YouTube\n\nAssicurati di riavviare l'app dopo il cambio",
"you_are_offline": "Sei correntemente offline", "you_are_offline": "Al momento sei offline",
"connection_restored": "Connessione ad internet ripristinata", "connection_restored": "Connessione ad internet ripristinata",
"use_system_title_bar": "Usa la barra del titolo di sistema", "use_system_title_bar": "Usa la barra del titolo di sistema",
"crunching_results": "Elaborazione risultati...", "crunching_results": "Elaborazione risultati...",
@ -267,15 +267,15 @@
"change_cover": "Cambia copertina", "change_cover": "Cambia copertina",
"add_cover": "Aggiungi copertina", "add_cover": "Aggiungi copertina",
"restore_defaults": "Ripristina default", "restore_defaults": "Ripristina default",
"download_music_codec": "Codec musicale scaricamento", "download_music_codec": "Codec download musica",
"streaming_music_codec": "Codec musicale streaming", "streaming_music_codec": "Codec streaming musica",
"login_with_lastfm": "Accesso a Last.fm", "login_with_lastfm": "Accedi con Last.fm",
"connect": "Connetti", "connect": "Connettiti",
"disconnect_lastfm": "Disconnetti Last.fm", "disconnect_lastfm": "Disconnettiti da Last.fm",
"disconnect": "Disconnetti", "disconnect": "Disconnetti",
"username": "Nome utente", "username": "Nome utente",
"password": "Password", "password": "Password",
"login": "Accesso", "login": "Accedi",
"login_with_your_lastfm": "Accedi con il tuo account Last.fm", "login_with_your_lastfm": "Accedi con il tuo account Last.fm",
"scrobble_to_lastfm": "Invia a Last.fm", "scrobble_to_lastfm": "Invia a Last.fm",
"audio_source": "Fonte audio", "audio_source": "Fonte audio",
@ -299,7 +299,7 @@
"song_link": "Link della Canzone", "song_link": "Link della Canzone",
"skip_this_nonsense": "Salta questa sciocchezza", "skip_this_nonsense": "Salta questa sciocchezza",
"freedom_of_music": "“Libertà della Musica”", "freedom_of_music": "“Libertà della Musica”",
"freedom_of_music_palm": "“Libertà della Musica nel palmo della tua mano”", "freedom_of_music_palm": "“Libertà della Musica nelle tue mani”",
"get_started": "Cominciamo", "get_started": "Cominciamo",
"youtube_source_description": "Consigliato e funziona meglio.", "youtube_source_description": "Consigliato e funziona meglio.",
"piped_source_description": "Ti senti libero? Come YouTube ma molto più gratuito.", "piped_source_description": "Ti senti libero? Come YouTube ma molto più gratuito.",

View File

@ -62,7 +62,7 @@ class AppDatabase extends _$AppDatabase {
AppDatabase() : super(_openConnection()); AppDatabase() : super(_openConnection());
@override @override
int get schemaVersion => 4; int get schemaVersion => 5;
@override @override
MigrationStrategy get migration { MigrationStrategy get migration {
@ -87,6 +87,33 @@ class AppDatabase extends _$AppDatabase {
schema.preferencesTable.youtubeClientEngine, schema.preferencesTable.youtubeClientEngine,
); );
}, },
from4To5: (m, schema) async {
final columnName = schema.preferencesTable.accentColorScheme
.escapedNameFor(SqlDialect.sqlite);
final columnNameOld =
'"${schema.preferencesTable.accentColorScheme.name}_old"';
final tableName = schema.preferencesTable.actualTableName;
await customStatement(
"ALTER TABLE $tableName "
"RENAME COLUMN $columnName to $columnNameOld",
);
await customStatement(
"ALTER TABLE $tableName "
"ADD COLUMN $columnName TEXT NOT NULL DEFAULT 'Orange:0xFFf97315'",
);
await customStatement(
"UPDATE $tableName "
"SET $columnName = $columnNameOld",
);
await customStatement(
"ALTER TABLE $tableName "
"DROP COLUMN $columnNameOld",
);
await customStatement(
"UPDATE $tableName "
"SET $columnName = 'Orange:0xFFf97315' WHERE $columnName = 'Blue:0xFF2196F3'",
);
},
), ),
); );
} }

View File

@ -666,7 +666,7 @@ class $PreferencesTableTable extends PreferencesTable
'accent_color_scheme', aliasedName, false, 'accent_color_scheme', aliasedName, false,
type: DriftSqlType.string, type: DriftSqlType.string,
requiredDuringInsert: false, requiredDuringInsert: false,
defaultValue: const Constant("Blue:0xFF2196F3")) defaultValue: const Constant("Orange:0xFFf97315"))
.withConverter<SpotubeColor>( .withConverter<SpotubeColor>(
$PreferencesTableTable.$converteraccentColorScheme); $PreferencesTableTable.$converteraccentColorScheme);
static const VerificationMeta _layoutModeMeta = static const VerificationMeta _layoutModeMeta =

View File

@ -2,7 +2,7 @@
import 'package:drift/internal/versioned_schema.dart' as i0; import 'package:drift/internal/versioned_schema.dart' as i0;
import 'package:drift/drift.dart' as i1; import 'package:drift/drift.dart' as i1;
import 'package:drift/drift.dart'; import 'package:drift/drift.dart';
import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:flutter/material.dart';
import 'package:spotify/spotify.dart'; import 'package:spotify/spotify.dart';
import 'package:spotube/models/database/database.dart'; import 'package:spotube/models/database/database.dart';
import 'package:spotube/services/sourced_track/enums.dart'; // ignore_for_file: type=lint,unused_import import 'package:spotube/services/sourced_track/enums.dart'; // ignore_for_file: type=lint,unused_import
@ -1188,10 +1188,232 @@ i1.GeneratedColumn<String> _column_54(String aliasedName) =>
i1.GeneratedColumn<String>('youtube_client_engine', aliasedName, false, i1.GeneratedColumn<String>('youtube_client_engine', aliasedName, false,
type: i1.DriftSqlType.string, type: i1.DriftSqlType.string,
defaultValue: Constant(YoutubeClientEngine.youtubeExplode.name)); defaultValue: Constant(YoutubeClientEngine.youtubeExplode.name));
final class Schema5 extends i0.VersionedSchema {
Schema5({required super.database}) : super(version: 5);
@override
late final List<i1.DatabaseSchemaEntity> entities = [
authenticationTable,
blacklistTable,
preferencesTable,
scrobblerTable,
skipSegmentTable,
sourceMatchTable,
audioPlayerStateTable,
playlistTable,
playlistMediaTable,
historyTable,
lyricsTable,
uniqueBlacklist,
uniqTrackMatch,
];
late final Shape0 authenticationTable = Shape0(
source: i0.VersionedTable(
entityName: 'authentication_table',
withoutRowId: false,
isStrict: false,
tableConstraints: [],
columns: [
_column_0,
_column_1,
_column_2,
_column_3,
],
attachedDatabase: database,
),
alias: null);
late final Shape1 blacklistTable = Shape1(
source: i0.VersionedTable(
entityName: 'blacklist_table',
withoutRowId: false,
isStrict: false,
tableConstraints: [],
columns: [
_column_0,
_column_4,
_column_5,
_column_6,
],
attachedDatabase: database,
),
alias: null);
late final Shape12 preferencesTable = Shape12(
source: i0.VersionedTable(
entityName: 'preferences_table',
withoutRowId: false,
isStrict: false,
tableConstraints: [],
columns: [
_column_0,
_column_7,
_column_8,
_column_9,
_column_10,
_column_11,
_column_12,
_column_13,
_column_14,
_column_15,
_column_55,
_column_17,
_column_18,
_column_19,
_column_20,
_column_21,
_column_22,
_column_23,
_column_24,
_column_25,
_column_26,
_column_54,
_column_27,
_column_28,
_column_29,
_column_30,
_column_31,
_column_53,
],
attachedDatabase: database,
),
alias: null);
late final Shape3 scrobblerTable = Shape3(
source: i0.VersionedTable(
entityName: 'scrobbler_table',
withoutRowId: false,
isStrict: false,
tableConstraints: [],
columns: [
_column_0,
_column_32,
_column_33,
_column_34,
],
attachedDatabase: database,
),
alias: null);
late final Shape4 skipSegmentTable = Shape4(
source: i0.VersionedTable(
entityName: 'skip_segment_table',
withoutRowId: false,
isStrict: false,
tableConstraints: [],
columns: [
_column_0,
_column_35,
_column_36,
_column_37,
_column_32,
],
attachedDatabase: database,
),
alias: null);
late final Shape5 sourceMatchTable = Shape5(
source: i0.VersionedTable(
entityName: 'source_match_table',
withoutRowId: false,
isStrict: false,
tableConstraints: [],
columns: [
_column_0,
_column_37,
_column_38,
_column_39,
_column_32,
],
attachedDatabase: database,
),
alias: null);
late final Shape6 audioPlayerStateTable = Shape6(
source: i0.VersionedTable(
entityName: 'audio_player_state_table',
withoutRowId: false,
isStrict: false,
tableConstraints: [],
columns: [
_column_0,
_column_40,
_column_41,
_column_42,
_column_43,
],
attachedDatabase: database,
),
alias: null);
late final Shape7 playlistTable = Shape7(
source: i0.VersionedTable(
entityName: 'playlist_table',
withoutRowId: false,
isStrict: false,
tableConstraints: [],
columns: [
_column_0,
_column_44,
_column_45,
],
attachedDatabase: database,
),
alias: null);
late final Shape8 playlistMediaTable = Shape8(
source: i0.VersionedTable(
entityName: 'playlist_media_table',
withoutRowId: false,
isStrict: false,
tableConstraints: [],
columns: [
_column_0,
_column_46,
_column_47,
_column_48,
_column_49,
],
attachedDatabase: database,
),
alias: null);
late final Shape9 historyTable = Shape9(
source: i0.VersionedTable(
entityName: 'history_table',
withoutRowId: false,
isStrict: false,
tableConstraints: [],
columns: [
_column_0,
_column_32,
_column_50,
_column_51,
_column_52,
],
attachedDatabase: database,
),
alias: null);
late final Shape10 lyricsTable = Shape10(
source: i0.VersionedTable(
entityName: 'lyrics_table',
withoutRowId: false,
isStrict: false,
tableConstraints: [],
columns: [
_column_0,
_column_37,
_column_52,
],
attachedDatabase: database,
),
alias: null);
final i1.Index uniqueBlacklist = i1.Index('unique_blacklist',
'CREATE UNIQUE INDEX unique_blacklist ON blacklist_table (element_type, element_id)');
final i1.Index uniqTrackMatch = i1.Index('uniq_track_match',
'CREATE UNIQUE INDEX uniq_track_match ON source_match_table (track_id, source_id, source_type)');
}
i1.GeneratedColumn<String> _column_55(String aliasedName) =>
i1.GeneratedColumn<String>('accent_color_scheme', aliasedName, false,
type: i1.DriftSqlType.string,
defaultValue: const Constant("Orange:0xFFf97315"));
i0.MigrationStepWithVersion migrationSteps({ i0.MigrationStepWithVersion migrationSteps({
required Future<void> Function(i1.Migrator m, Schema2 schema) from1To2, required Future<void> Function(i1.Migrator m, Schema2 schema) from1To2,
required Future<void> Function(i1.Migrator m, Schema3 schema) from2To3, required Future<void> Function(i1.Migrator m, Schema3 schema) from2To3,
required Future<void> Function(i1.Migrator m, Schema4 schema) from3To4, required Future<void> Function(i1.Migrator m, Schema4 schema) from3To4,
required Future<void> Function(i1.Migrator m, Schema5 schema) from4To5,
}) { }) {
return (currentVersion, database) async { return (currentVersion, database) async {
switch (currentVersion) { switch (currentVersion) {
@ -1210,6 +1432,11 @@ i0.MigrationStepWithVersion migrationSteps({
final migrator = i1.Migrator(database, schema); final migrator = i1.Migrator(database, schema);
await from3To4(migrator, schema); await from3To4(migrator, schema);
return 4; return 4;
case 4:
final schema = Schema5(database: database);
final migrator = i1.Migrator(database, schema);
await from4To5(migrator, schema);
return 5;
default: default:
throw ArgumentError.value('Unknown migration from $currentVersion'); throw ArgumentError.value('Unknown migration from $currentVersion');
} }
@ -1220,10 +1447,12 @@ i1.OnUpgrade stepByStep({
required Future<void> Function(i1.Migrator m, Schema2 schema) from1To2, required Future<void> Function(i1.Migrator m, Schema2 schema) from1To2,
required Future<void> Function(i1.Migrator m, Schema3 schema) from2To3, required Future<void> Function(i1.Migrator m, Schema3 schema) from2To3,
required Future<void> Function(i1.Migrator m, Schema4 schema) from3To4, required Future<void> Function(i1.Migrator m, Schema4 schema) from3To4,
required Future<void> Function(i1.Migrator m, Schema5 schema) from4To5,
}) => }) =>
i0.VersionedSchema.stepByStepHelper( i0.VersionedSchema.stepByStepHelper(
step: migrationSteps( step: migrationSteps(
from1To2: from1To2, from1To2: from1To2,
from2To3: from2To3, from2To3: from2To3,
from3To4: from3To4, from3To4: from3To4,
from4To5: from4To5,
)); ));

View File

@ -79,7 +79,7 @@ class PreferencesTable extends Table {
TextColumn get closeBehavior => textEnum<CloseBehavior>() TextColumn get closeBehavior => textEnum<CloseBehavior>()
.withDefault(Constant(CloseBehavior.close.name))(); .withDefault(Constant(CloseBehavior.close.name))();
TextColumn get accentColorScheme => text() TextColumn get accentColorScheme => text()
.withDefault(const Constant("Blue:0xFF2196F3")) .withDefault(const Constant("Orange:0xFFf97315"))
.map(const SpotubeColorConverter())(); .map(const SpotubeColorConverter())();
TextColumn get layoutMode => TextColumn get layoutMode =>
textEnum<LayoutMode>().withDefault(Constant(LayoutMode.adaptive.name))(); textEnum<LayoutMode>().withDefault(Constant(LayoutMode.adaptive.name))();
@ -130,7 +130,7 @@ class PreferencesTable extends Table {
systemTitleBar: false, systemTitleBar: false,
skipNonMusic: false, skipNonMusic: false,
closeBehavior: CloseBehavior.close, closeBehavior: CloseBehavior.close,
accentColorScheme: SpotubeColor(Colors.blue.value, name: "Blue"), accentColorScheme: SpotubeColor(Colors.orange.value, name: "Orange"),
layoutMode: LayoutMode.adaptive, layoutMode: LayoutMode.adaptive,
locale: const Locale("system", "system"), locale: const Locale("system", "system"),
market: Market.US, market: Market.US,

View File

@ -132,7 +132,7 @@ class PlayerView extends HookConsumerWidget {
Tooltip( Tooltip(
tooltip: TooltipContainer( tooltip: TooltipContainer(
child: Text(context.l10n.details), child: Text(context.l10n.details),
), ).call,
child: IconButton.ghost( child: IconButton.ghost(
icon: const Icon(SpotubeIcons.info, size: 18), icon: const Icon(SpotubeIcons.info, size: 18),
onPressed: currentTrack == null onPressed: currentTrack == null

View File

@ -82,7 +82,7 @@ class PlayerActions extends HookConsumerWidget {
children: [ children: [
if (showQueue) if (showQueue)
Tooltip( Tooltip(
tooltip: TooltipContainer(child: Text(context.l10n.queue)), tooltip: TooltipContainer(child: Text(context.l10n.queue)).call,
child: IconButton.ghost( child: IconButton.ghost(
icon: const Icon(SpotubeIcons.queue), icon: const Icon(SpotubeIcons.queue),
enabled: playlist.activeTrack != null, enabled: playlist.activeTrack != null,
@ -119,7 +119,8 @@ class PlayerActions extends HookConsumerWidget {
if (!isLocalTrack) if (!isLocalTrack)
Tooltip( Tooltip(
tooltip: TooltipContainer( tooltip: TooltipContainer(
child: Text(context.l10n.alternative_track_sources)), child: Text(context.l10n.alternative_track_sources),
).call,
child: IconButton.ghost( child: IconButton.ghost(
enabled: playlist.activeTrack != null, enabled: playlist.activeTrack != null,
icon: const Icon(SpotubeIcons.alternativeRoute), icon: const Icon(SpotubeIcons.alternativeRoute),
@ -160,7 +161,8 @@ class PlayerActions extends HookConsumerWidget {
else else
Tooltip( Tooltip(
tooltip: tooltip:
TooltipContainer(child: Text(context.l10n.download_track)), TooltipContainer(child: Text(context.l10n.download_track))
.call,
child: IconButton.ghost( child: IconButton.ghost(
icon: Icon( icon: Icon(
isDownloaded ? SpotubeIcons.done : SpotubeIcons.download, isDownloaded ? SpotubeIcons.done : SpotubeIcons.download,

View File

@ -90,9 +90,9 @@ class UserPreferencesNotifier extends Notifier<PreferencesTableData> {
Future<void> reset() async { Future<void> reset() async {
final db = ref.read(databaseProvider); final db = ref.read(databaseProvider);
final query = db.update(db.preferencesTable)..where((t) => t.id.equals(0)); final query = db.update(db.preferencesTable);
await query.replace(PreferencesTableCompanion.insert()); await query.replace(PreferencesTableCompanion.insert(id: const Value(0)));
} }
static Future<String> getMusicCacheDir() async { static Future<String> getMusicCacheDir() async {

View File

@ -3,27 +3,30 @@
// ignore_for_file: type=lint // ignore_for_file: type=lint
import 'package:drift/drift.dart'; import 'package:drift/drift.dart';
import 'package:drift/internal/migrations.dart'; import 'package:drift/internal/migrations.dart';
import 'schema_v4.dart' as v4;
import 'schema_v3.dart' as v3; import 'schema_v3.dart' as v3;
import 'schema_v2.dart' as v2; import 'schema_v5.dart' as v5;
import 'schema_v1.dart' as v1; import 'schema_v1.dart' as v1;
import 'schema_v2.dart' as v2;
import 'schema_v4.dart' as v4;
class GeneratedHelper implements SchemaInstantiationHelper { class GeneratedHelper implements SchemaInstantiationHelper {
@override @override
GeneratedDatabase databaseForVersion(QueryExecutor db, int version) { GeneratedDatabase databaseForVersion(QueryExecutor db, int version) {
switch (version) { switch (version) {
case 4:
return v4.DatabaseAtV4(db);
case 3: case 3:
return v3.DatabaseAtV3(db); return v3.DatabaseAtV3(db);
case 2: case 5:
return v2.DatabaseAtV2(db); return v5.DatabaseAtV5(db);
case 1: case 1:
return v1.DatabaseAtV1(db); return v1.DatabaseAtV1(db);
case 2:
return v2.DatabaseAtV2(db);
case 4:
return v4.DatabaseAtV4(db);
default: default:
throw MissingSchemaException(version, versions); throw MissingSchemaException(version, versions);
} }
} }
static const versions = const [1, 2, 3, 4]; static const versions = const [1, 2, 3, 4, 5];
} }

File diff suppressed because it is too large Load Diff