fix: generate playlist page max width

This commit is contained in:
Kingkor Roy Tirtho 2023-08-15 13:13:07 +06:00
parent c69f81ec6f
commit 4adf6951d9
2 changed files with 276 additions and 255 deletions

View File

@ -1,12 +1,25 @@
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
// ignore: constant_identifier_names
const Breakpoints = (
xs: 480.0,
sm: 640.0,
md: 820.0,
lg: 1024.0,
xl: 1280.0,
);
extension ContainerBreakpoints on BoxConstraints { extension ContainerBreakpoints on BoxConstraints {
bool get isXs => biggest.width <= 480; bool get isXs => biggest.width <= Breakpoints.xs;
bool get isSm => biggest.width > 480 && biggest.width <= 640; bool get isSm =>
bool get isMd => biggest.width > 640 && biggest.width <= 820; biggest.width > Breakpoints.xs && biggest.width <= Breakpoints.sm;
bool get isLg => biggest.width > 820 && biggest.width <= 1024; bool get isMd =>
bool get isXl => biggest.width > 1024 && biggest.width <= 1280; biggest.width > Breakpoints.sm && biggest.width <= Breakpoints.md;
bool get is2Xl => biggest.width > 1280; bool get isLg =>
biggest.width > Breakpoints.md && biggest.width <= Breakpoints.lg;
bool get isXl =>
biggest.width > Breakpoints.lg && biggest.width <= Breakpoints.xl;
bool get is2Xl => biggest.width > Breakpoints.xl;
bool get smAndUp => isSm || isMd || isLg || isXl || is2Xl; bool get smAndUp => isSm || isMd || isLg || isXl || is2Xl;
bool get mdAndUp => isMd || isLg || isXl || is2Xl; bool get mdAndUp => isMd || isLg || isXl || is2Xl;
@ -20,12 +33,12 @@ extension ContainerBreakpoints on BoxConstraints {
} }
extension ScreenBreakpoints on MediaQueryData { extension ScreenBreakpoints on MediaQueryData {
bool get isXs => size.width <= 480; bool get isXs => size.width <= Breakpoints.xs;
bool get isSm => size.width > 480 && size.width <= 640; bool get isSm => size.width > Breakpoints.xs && size.width <= Breakpoints.sm;
bool get isMd => size.width > 640 && size.width <= 820; bool get isMd => size.width > Breakpoints.sm && size.width <= Breakpoints.md;
bool get isLg => size.width > 820 && size.width <= 1024; bool get isLg => size.width > Breakpoints.md && size.width <= Breakpoints.lg;
bool get isXl => size.width > 1024 && size.width <= 1280; bool get isXl => size.width > Breakpoints.lg && size.width <= Breakpoints.xl;
bool get is2Xl => size.width > 1280; bool get is2Xl => size.width > Breakpoints.xl;
bool get smAndUp => isSm || isMd || isLg || isXl || is2Xl; bool get smAndUp => isSm || isMd || isLg || isXl || is2Xl;
bool get mdAndUp => isMd || isLg || isXl || is2Xl; bool get mdAndUp => isMd || isLg || isXl || is2Xl;

View File

@ -248,255 +248,263 @@ class PlaylistGeneratorPage extends HookConsumerWidget {
title: Text(context.l10n.generate_playlist), title: Text(context.l10n.generate_playlist),
centerTitle: true, centerTitle: true,
), ),
body: SliderTheme( body: Center(
data: const SliderThemeData( child: ConstrainedBox(
overlayShape: RoundSliderOverlayShape(), constraints: BoxConstraints(maxWidth: Breakpoints.lg),
), child: SliderTheme(
child: SafeArea( data: const SliderThemeData(
child: LayoutBuilder(builder: (context, constrains) { overlayShape: RoundSliderOverlayShape(),
return ListView( ),
padding: const EdgeInsets.all(16), child: SafeArea(
children: [ child: LayoutBuilder(builder: (context, constrains) {
ValueListenableBuilder( return ListView(
valueListenable: limit, padding: const EdgeInsets.all(16),
builder: (context, value, child) { children: [
return Column( ValueListenableBuilder(
crossAxisAlignment: CrossAxisAlignment.start, valueListenable: limit,
children: [ builder: (context, value, child) {
Text( return Column(
context.l10n.number_of_tracks_generate, crossAxisAlignment: CrossAxisAlignment.start,
style: textTheme.titleMedium,
),
Row(
children: [ children: [
Container( Text(
width: 40, context.l10n.number_of_tracks_generate,
height: 40, style: textTheme.titleMedium,
alignment: Alignment.center,
decoration: BoxDecoration(
color: theme.colorScheme.primary,
shape: BoxShape.circle,
),
child: Text(
value.round().toString(),
style: textTheme.bodyLarge?.copyWith(
color: theme.colorScheme.primaryContainer,
),
),
), ),
Expanded( Row(
child: Slider( children: [
value: value.toDouble(), Container(
min: 10, width: 40,
max: 100, height: 40,
divisions: 9, alignment: Alignment.center,
label: value.round().toString(), decoration: BoxDecoration(
onChanged: (value) { color: theme.colorScheme.primary,
limit.value = value.round(); shape: BoxShape.circle,
}, ),
), child: Text(
value.round().toString(),
style: textTheme.bodyLarge?.copyWith(
color: theme.colorScheme.primaryContainer,
),
),
),
Expanded(
child: Slider(
value: value.toDouble(),
min: 10,
max: 100,
divisions: 9,
label: value.round().toString(),
onChanged: (value) {
limit.value = value.round();
},
),
)
],
) )
], ],
) );
], },
); ),
}, const SizedBox(height: 16),
), if (constrains.mdAndUp)
const SizedBox(height: 16), Row(
if (constrains.mdAndUp) crossAxisAlignment: CrossAxisAlignment.start,
Row( children: [
crossAxisAlignment: CrossAxisAlignment.start, Expanded(
children: [ child: countrySelector,
Expanded( ),
child: countrySelector, const SizedBox(width: 16),
), Expanded(
const SizedBox(width: 16), child: genreSelector,
Expanded( ),
child: genreSelector, ],
), )
else ...[
countrySelector,
const SizedBox(height: 16),
genreSelector,
], ],
) const SizedBox(height: 16),
else ...[ if (constrains.mdAndUp)
countrySelector, Row(
const SizedBox(height: 16), crossAxisAlignment: CrossAxisAlignment.start,
genreSelector, children: [
], Expanded(
const SizedBox(height: 16), child: artistAutoComplete,
if (constrains.mdAndUp) ),
Row( const SizedBox(width: 16),
crossAxisAlignment: CrossAxisAlignment.start, Expanded(
children: [ child: tracksAutocomplete,
Expanded( ),
child: artistAutoComplete, ],
), )
const SizedBox(width: 16), else ...[
Expanded( artistAutoComplete,
child: tracksAutocomplete, const SizedBox(height: 16),
), tracksAutocomplete,
], ],
) const SizedBox(height: 16),
else ...[ RecommendationAttributeDials(
artistAutoComplete, title: Text(context.l10n.acousticness),
const SizedBox(height: 16), values: acousticness.value,
tracksAutocomplete, onChanged: (value) {
], acousticness.value = value;
const SizedBox(height: 16), },
RecommendationAttributeDials( ),
title: Text(context.l10n.acousticness), RecommendationAttributeDials(
values: acousticness.value, title: Text(context.l10n.danceability),
onChanged: (value) { values: danceability.value,
acousticness.value = value; onChanged: (value) {
}, danceability.value = value;
), },
RecommendationAttributeDials( ),
title: Text(context.l10n.danceability), RecommendationAttributeDials(
values: danceability.value, title: Text(context.l10n.energy),
onChanged: (value) { values: energy.value,
danceability.value = value; onChanged: (value) {
}, energy.value = value;
), },
RecommendationAttributeDials( ),
title: Text(context.l10n.energy), RecommendationAttributeDials(
values: energy.value, title: Text(context.l10n.instrumentalness),
onChanged: (value) { values: instrumentalness.value,
energy.value = value; onChanged: (value) {
}, instrumentalness.value = value;
), },
RecommendationAttributeDials( ),
title: Text(context.l10n.instrumentalness), RecommendationAttributeDials(
values: instrumentalness.value, title: Text(context.l10n.liveness),
onChanged: (value) { values: liveness.value,
instrumentalness.value = value; onChanged: (value) {
}, liveness.value = value;
), },
RecommendationAttributeDials( ),
title: Text(context.l10n.liveness), RecommendationAttributeDials(
values: liveness.value, title: Text(context.l10n.loudness),
onChanged: (value) { values: loudness.value,
liveness.value = value; onChanged: (value) {
}, loudness.value = value;
), },
RecommendationAttributeDials( ),
title: Text(context.l10n.loudness), RecommendationAttributeDials(
values: loudness.value, title: Text(context.l10n.speechiness),
onChanged: (value) { values: speechiness.value,
loudness.value = value; onChanged: (value) {
}, speechiness.value = value;
), },
RecommendationAttributeDials( ),
title: Text(context.l10n.speechiness), RecommendationAttributeDials(
values: speechiness.value, title: Text(context.l10n.valence),
onChanged: (value) { values: valence.value,
speechiness.value = value; onChanged: (value) {
}, valence.value = value;
), },
RecommendationAttributeDials( ),
title: Text(context.l10n.valence), RecommendationAttributeDials(
values: valence.value, title: Text(context.l10n.popularity),
onChanged: (value) { values: popularity.value,
valence.value = value; base: 100,
}, onChanged: (value) {
), popularity.value = value;
RecommendationAttributeDials( },
title: Text(context.l10n.popularity), ),
values: popularity.value, RecommendationAttributeDials(
base: 100, title: Text(context.l10n.key),
onChanged: (value) { values: key.value,
popularity.value = value; base: 11,
}, onChanged: (value) {
), key.value = value;
RecommendationAttributeDials( },
title: Text(context.l10n.key), ),
values: key.value, RecommendationAttributeFields(
base: 11, title: Text(context.l10n.duration),
onChanged: (value) { values: (
key.value = value; max: durationMs.value.max / 1000,
}, target: durationMs.value.target / 1000,
), min: durationMs.value.min / 1000,
RecommendationAttributeFields( ),
title: Text(context.l10n.duration), onChanged: (value) {
values: ( durationMs.value = (
max: durationMs.value.max / 1000, max: value.max * 1000,
target: durationMs.value.target / 1000, target: value.target * 1000,
min: durationMs.value.min / 1000, min: value.min * 1000,
), );
onChanged: (value) { },
durationMs.value = ( presets: {
max: value.max * 1000, context.l10n.short: (min: 50, target: 90, max: 120),
target: value.target * 1000, context.l10n.medium: (min: 120, target: 180, max: 200),
min: value.min * 1000, context.l10n.long: (min: 480, target: 560, max: 640)
); },
}, ),
presets: { RecommendationAttributeFields(
context.l10n.short: (min: 50, target: 90, max: 120), title: Text(context.l10n.tempo),
context.l10n.medium: (min: 120, target: 180, max: 200), values: tempo.value,
context.l10n.long: (min: 480, target: 560, max: 640) onChanged: (value) {
}, tempo.value = value;
), },
RecommendationAttributeFields( ),
title: Text(context.l10n.tempo), RecommendationAttributeFields(
values: tempo.value, title: Text(context.l10n.mode),
onChanged: (value) { values: mode.value,
tempo.value = value; onChanged: (value) {
}, mode.value = value;
), },
RecommendationAttributeFields( ),
title: Text(context.l10n.mode), RecommendationAttributeFields(
values: mode.value, title: Text(context.l10n.time_signature),
onChanged: (value) { values: timeSignature.value,
mode.value = value; onChanged: (value) {
}, timeSignature.value = value;
), },
RecommendationAttributeFields( ),
title: Text(context.l10n.time_signature), const SizedBox(height: 20),
values: timeSignature.value, FilledButton.icon(
onChanged: (value) { icon: const Icon(SpotubeIcons.magic),
timeSignature.value = value; label: Text(context.l10n.generate_playlist),
}, onPressed: artists.value.isEmpty &&
), tracks.value.isEmpty &&
const SizedBox(height: 20), genres.value.isEmpty
FilledButton.icon( ? null
icon: const Icon(SpotubeIcons.magic), : () {
label: Text(context.l10n.generate_playlist), final PlaylistGenerateResultRouteState
onPressed: artists.value.isEmpty && routeState = (
tracks.value.isEmpty && seeds: (
genres.value.isEmpty artists:
? null artists.value.map((a) => a.id!).toList(),
: () { tracks:
final PlaylistGenerateResultRouteState routeState = ( tracks.value.map((t) => t.id!).toList(),
seeds: ( genres: genres.value
artists: artists.value.map((a) => a.id!).toList(), ),
tracks: tracks.value.map((t) => t.id!).toList(), market: market.value,
genres: genres.value limit: limit.value,
), parameters: (
market: market.value, acousticness: acousticness.value,
limit: limit.value, danceability: danceability.value,
parameters: ( energy: energy.value,
acousticness: acousticness.value, instrumentalness: instrumentalness.value,
danceability: danceability.value, liveness: liveness.value,
energy: energy.value, loudness: loudness.value,
instrumentalness: instrumentalness.value, speechiness: speechiness.value,
liveness: liveness.value, valence: valence.value,
loudness: loudness.value, popularity: popularity.value,
speechiness: speechiness.value, key: key.value,
valence: valence.value, duration_ms: durationMs.value,
popularity: popularity.value, tempo: tempo.value,
key: key.value, mode: mode.value,
duration_ms: durationMs.value, time_signature: timeSignature.value,
tempo: tempo.value, )
mode: mode.value, );
time_signature: timeSignature.value, GoRouter.of(context).push(
) "/library/generate/result",
); extra: routeState,
GoRouter.of(context).push( );
"/library/generate/result", },
extra: routeState, ),
); ],
}, );
), }),
], ),
); ),
}),
), ),
), ),
); );