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';
// 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 {
bool get isXs => biggest.width <= 480;
bool get isSm => biggest.width > 480 && biggest.width <= 640;
bool get isMd => biggest.width > 640 && biggest.width <= 820;
bool get isLg => biggest.width > 820 && biggest.width <= 1024;
bool get isXl => biggest.width > 1024 && biggest.width <= 1280;
bool get is2Xl => biggest.width > 1280;
bool get isXs => biggest.width <= Breakpoints.xs;
bool get isSm =>
biggest.width > Breakpoints.xs && biggest.width <= Breakpoints.sm;
bool get isMd =>
biggest.width > Breakpoints.sm && biggest.width <= Breakpoints.md;
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 mdAndUp => isMd || isLg || isXl || is2Xl;
@ -20,12 +33,12 @@ extension ContainerBreakpoints on BoxConstraints {
}
extension ScreenBreakpoints on MediaQueryData {
bool get isXs => size.width <= 480;
bool get isSm => size.width > 480 && size.width <= 640;
bool get isMd => size.width > 640 && size.width <= 820;
bool get isLg => size.width > 820 && size.width <= 1024;
bool get isXl => size.width > 1024 && size.width <= 1280;
bool get is2Xl => size.width > 1280;
bool get isXs => size.width <= Breakpoints.xs;
bool get isSm => size.width > Breakpoints.xs && size.width <= Breakpoints.sm;
bool get isMd => size.width > Breakpoints.sm && size.width <= Breakpoints.md;
bool get isLg => size.width > Breakpoints.md && size.width <= Breakpoints.lg;
bool get isXl => size.width > Breakpoints.lg && size.width <= Breakpoints.xl;
bool get is2Xl => size.width > Breakpoints.xl;
bool get smAndUp => isSm || 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),
centerTitle: true,
),
body: SliderTheme(
data: const SliderThemeData(
overlayShape: RoundSliderOverlayShape(),
),
child: SafeArea(
child: LayoutBuilder(builder: (context, constrains) {
return ListView(
padding: const EdgeInsets.all(16),
children: [
ValueListenableBuilder(
valueListenable: limit,
builder: (context, value, child) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
context.l10n.number_of_tracks_generate,
style: textTheme.titleMedium,
),
Row(
body: Center(
child: ConstrainedBox(
constraints: BoxConstraints(maxWidth: Breakpoints.lg),
child: SliderTheme(
data: const SliderThemeData(
overlayShape: RoundSliderOverlayShape(),
),
child: SafeArea(
child: LayoutBuilder(builder: (context, constrains) {
return ListView(
padding: const EdgeInsets.all(16),
children: [
ValueListenableBuilder(
valueListenable: limit,
builder: (context, value, child) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
width: 40,
height: 40,
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,
),
),
Text(
context.l10n.number_of_tracks_generate,
style: textTheme.titleMedium,
),
Expanded(
child: Slider(
value: value.toDouble(),
min: 10,
max: 100,
divisions: 9,
label: value.round().toString(),
onChanged: (value) {
limit.value = value.round();
},
),
Row(
children: [
Container(
width: 40,
height: 40,
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(
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)
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: countrySelector,
),
const SizedBox(width: 16),
Expanded(
child: genreSelector,
),
);
},
),
const SizedBox(height: 16),
if (constrains.mdAndUp)
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: countrySelector,
),
const SizedBox(width: 16),
Expanded(
child: genreSelector,
),
],
)
else ...[
countrySelector,
const SizedBox(height: 16),
genreSelector,
],
)
else ...[
countrySelector,
const SizedBox(height: 16),
genreSelector,
],
const SizedBox(height: 16),
if (constrains.mdAndUp)
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: artistAutoComplete,
),
const SizedBox(width: 16),
Expanded(
child: tracksAutocomplete,
),
const SizedBox(height: 16),
if (constrains.mdAndUp)
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: artistAutoComplete,
),
const SizedBox(width: 16),
Expanded(
child: tracksAutocomplete,
),
],
)
else ...[
artistAutoComplete,
const SizedBox(height: 16),
tracksAutocomplete,
],
)
else ...[
artistAutoComplete,
const SizedBox(height: 16),
tracksAutocomplete,
],
const SizedBox(height: 16),
RecommendationAttributeDials(
title: Text(context.l10n.acousticness),
values: acousticness.value,
onChanged: (value) {
acousticness.value = value;
},
),
RecommendationAttributeDials(
title: Text(context.l10n.danceability),
values: danceability.value,
onChanged: (value) {
danceability.value = value;
},
),
RecommendationAttributeDials(
title: Text(context.l10n.energy),
values: energy.value,
onChanged: (value) {
energy.value = value;
},
),
RecommendationAttributeDials(
title: Text(context.l10n.instrumentalness),
values: instrumentalness.value,
onChanged: (value) {
instrumentalness.value = value;
},
),
RecommendationAttributeDials(
title: Text(context.l10n.liveness),
values: liveness.value,
onChanged: (value) {
liveness.value = value;
},
),
RecommendationAttributeDials(
title: Text(context.l10n.loudness),
values: loudness.value,
onChanged: (value) {
loudness.value = value;
},
),
RecommendationAttributeDials(
title: Text(context.l10n.speechiness),
values: speechiness.value,
onChanged: (value) {
speechiness.value = value;
},
),
RecommendationAttributeDials(
title: Text(context.l10n.valence),
values: valence.value,
onChanged: (value) {
valence.value = value;
},
),
RecommendationAttributeDials(
title: Text(context.l10n.popularity),
values: popularity.value,
base: 100,
onChanged: (value) {
popularity.value = value;
},
),
RecommendationAttributeDials(
title: Text(context.l10n.key),
values: key.value,
base: 11,
onChanged: (value) {
key.value = value;
},
),
RecommendationAttributeFields(
title: Text(context.l10n.duration),
values: (
max: durationMs.value.max / 1000,
target: durationMs.value.target / 1000,
min: durationMs.value.min / 1000,
),
onChanged: (value) {
durationMs.value = (
max: value.max * 1000,
target: value.target * 1000,
min: value.min * 1000,
);
},
presets: {
context.l10n.short: (min: 50, target: 90, max: 120),
context.l10n.medium: (min: 120, target: 180, max: 200),
context.l10n.long: (min: 480, target: 560, max: 640)
},
),
RecommendationAttributeFields(
title: Text(context.l10n.tempo),
values: tempo.value,
onChanged: (value) {
tempo.value = value;
},
),
RecommendationAttributeFields(
title: Text(context.l10n.mode),
values: mode.value,
onChanged: (value) {
mode.value = value;
},
),
RecommendationAttributeFields(
title: Text(context.l10n.time_signature),
values: timeSignature.value,
onChanged: (value) {
timeSignature.value = value;
},
),
const SizedBox(height: 20),
FilledButton.icon(
icon: const Icon(SpotubeIcons.magic),
label: Text(context.l10n.generate_playlist),
onPressed: artists.value.isEmpty &&
tracks.value.isEmpty &&
genres.value.isEmpty
? null
: () {
final PlaylistGenerateResultRouteState routeState = (
seeds: (
artists: artists.value.map((a) => a.id!).toList(),
tracks: tracks.value.map((t) => t.id!).toList(),
genres: genres.value
),
market: market.value,
limit: limit.value,
parameters: (
acousticness: acousticness.value,
danceability: danceability.value,
energy: energy.value,
instrumentalness: instrumentalness.value,
liveness: liveness.value,
loudness: loudness.value,
speechiness: speechiness.value,
valence: valence.value,
popularity: popularity.value,
key: key.value,
duration_ms: durationMs.value,
tempo: tempo.value,
mode: mode.value,
time_signature: timeSignature.value,
)
);
GoRouter.of(context).push(
"/library/generate/result",
extra: routeState,
);
},
),
],
);
}),
const SizedBox(height: 16),
RecommendationAttributeDials(
title: Text(context.l10n.acousticness),
values: acousticness.value,
onChanged: (value) {
acousticness.value = value;
},
),
RecommendationAttributeDials(
title: Text(context.l10n.danceability),
values: danceability.value,
onChanged: (value) {
danceability.value = value;
},
),
RecommendationAttributeDials(
title: Text(context.l10n.energy),
values: energy.value,
onChanged: (value) {
energy.value = value;
},
),
RecommendationAttributeDials(
title: Text(context.l10n.instrumentalness),
values: instrumentalness.value,
onChanged: (value) {
instrumentalness.value = value;
},
),
RecommendationAttributeDials(
title: Text(context.l10n.liveness),
values: liveness.value,
onChanged: (value) {
liveness.value = value;
},
),
RecommendationAttributeDials(
title: Text(context.l10n.loudness),
values: loudness.value,
onChanged: (value) {
loudness.value = value;
},
),
RecommendationAttributeDials(
title: Text(context.l10n.speechiness),
values: speechiness.value,
onChanged: (value) {
speechiness.value = value;
},
),
RecommendationAttributeDials(
title: Text(context.l10n.valence),
values: valence.value,
onChanged: (value) {
valence.value = value;
},
),
RecommendationAttributeDials(
title: Text(context.l10n.popularity),
values: popularity.value,
base: 100,
onChanged: (value) {
popularity.value = value;
},
),
RecommendationAttributeDials(
title: Text(context.l10n.key),
values: key.value,
base: 11,
onChanged: (value) {
key.value = value;
},
),
RecommendationAttributeFields(
title: Text(context.l10n.duration),
values: (
max: durationMs.value.max / 1000,
target: durationMs.value.target / 1000,
min: durationMs.value.min / 1000,
),
onChanged: (value) {
durationMs.value = (
max: value.max * 1000,
target: value.target * 1000,
min: value.min * 1000,
);
},
presets: {
context.l10n.short: (min: 50, target: 90, max: 120),
context.l10n.medium: (min: 120, target: 180, max: 200),
context.l10n.long: (min: 480, target: 560, max: 640)
},
),
RecommendationAttributeFields(
title: Text(context.l10n.tempo),
values: tempo.value,
onChanged: (value) {
tempo.value = value;
},
),
RecommendationAttributeFields(
title: Text(context.l10n.mode),
values: mode.value,
onChanged: (value) {
mode.value = value;
},
),
RecommendationAttributeFields(
title: Text(context.l10n.time_signature),
values: timeSignature.value,
onChanged: (value) {
timeSignature.value = value;
},
),
const SizedBox(height: 20),
FilledButton.icon(
icon: const Icon(SpotubeIcons.magic),
label: Text(context.l10n.generate_playlist),
onPressed: artists.value.isEmpty &&
tracks.value.isEmpty &&
genres.value.isEmpty
? null
: () {
final PlaylistGenerateResultRouteState
routeState = (
seeds: (
artists:
artists.value.map((a) => a.id!).toList(),
tracks:
tracks.value.map((t) => t.id!).toList(),
genres: genres.value
),
market: market.value,
limit: limit.value,
parameters: (
acousticness: acousticness.value,
danceability: danceability.value,
energy: energy.value,
instrumentalness: instrumentalness.value,
liveness: liveness.value,
loudness: loudness.value,
speechiness: speechiness.value,
valence: valence.value,
popularity: popularity.value,
key: key.value,
duration_ms: durationMs.value,
tempo: tempo.value,
mode: mode.value,
time_signature: timeSignature.value,
)
);
GoRouter.of(context).push(
"/library/generate/result",
extra: routeState,
);
},
),
],
);
}),
),
),
),
),
);