Skip to content

Commit

Permalink
feat: adaptive popup and bottom sheet list widget
Browse files Browse the repository at this point in the history
  • Loading branch information
KRTirtho committed Jun 12, 2023
1 parent d88d287 commit ddc1c5f
Show file tree
Hide file tree
Showing 2 changed files with 179 additions and 14 deletions.
146 changes: 146 additions & 0 deletions lib/components/shared/adaptive/adaptive_pop_sheet_list.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
import 'package:flutter/material.dart';
import 'package:spotube/collections/spotube_icons.dart';
import 'package:spotube/extensions/constrains.dart';

class PopSheetEntry<T> {
final T? value;
final VoidCallback? onTap;
final Widget child;
final bool enabled;

const PopSheetEntry({
required this.child,
this.value,
this.onTap,
this.enabled = true,
});
}

/// An adaptive widget that shows a [PopupMenuButton] when screen size is above
/// or equal to 640px
/// In smaller screen, a [IconButton] with a [showModalBottomSheet] is shown
class AdaptivePopSheetList<T> extends StatelessWidget {
final List<PopSheetEntry<T>> children;
final Widget? icon;
final Widget? child;
final bool useRootNavigator;

final List<Widget>? headings;
final String? tooltip;
final ValueChanged<T>? onSelected;

final BorderRadius borderRadius;

const AdaptivePopSheetList({
super.key,
required this.children,
this.icon,
this.child,
this.useRootNavigator = true,
this.headings,
this.onSelected,
this.borderRadius = const BorderRadius.all(Radius.circular(999)),
this.tooltip,
}) : assert(
icon != null || child != null,
'Either icon or child must be provided',
);

@override
Widget build(BuildContext context) {
final mediaQuery = MediaQuery.of(context);
final theme = Theme.of(context);

if (mediaQuery.mdAndUp) {
return PopupMenuButton(
icon: icon,
tooltip: tooltip,
child: IgnorePointer(child: child),
itemBuilder: (context) => children
.map(
(item) => PopupMenuItem(
padding: EdgeInsets.zero,
child: ListTile(
enabled: item.enabled,
onTap: () {
item.onTap?.call();
Navigator.pop(context);
if (item.value != null) {
onSelected?.call(item.value as T);
}
},
title: item.child,
),
),
)
.toList(),
);
}

void showSheet() {
showModalBottomSheet(
context: context,
useRootNavigator: useRootNavigator,
builder: (context) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: DefaultTextStyle(
style: theme.textTheme.titleMedium!,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
if (headings != null) ...[
...headings!,
Divider(
color: theme.colorScheme.primary,
thickness: 0.3,
endIndent: 16,
indent: 16,
),
],
...children.map(
(item) => ListTile(
onTap: () {
item.onTap?.call();
Navigator.pop(context);
if (item.value != null) {
onSelected?.call(item.value as T);
}
},
enabled: item.enabled,
title: item.child,
),
)
],
),
),
);
},
);
}

if (child != null) {
return Tooltip(
message: tooltip ?? '',
child: InkWell(
onTap: showSheet,
borderRadius: borderRadius,
child: IgnorePointer(child: child),
),
);
}

return IconButton(
icon: icon ?? const Icon(SpotubeIcons.moreVertical),
tooltip: tooltip,
style: theme.iconButtonTheme.style?.copyWith(
shape: MaterialStatePropertyAll(
RoundedRectangleBorder(
borderRadius: borderRadius,
),
),
),
onPressed: showSheet,
);
}
}
47 changes: 33 additions & 14 deletions lib/components/shared/sort_tracks_dropdown.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import 'package:flutter/material.dart';

import 'package:spotube/collections/spotube_icons.dart';
import 'package:spotube/components/library/user_local_tracks.dart';
import 'package:spotube/components/shared/adaptive/adaptive_pop_sheet_list.dart';
import 'package:spotube/extensions/context.dart';

class SortTracksDropdown extends StatelessWidget {
Expand All @@ -15,44 +16,62 @@ class SortTracksDropdown extends StatelessWidget {

@override
Widget build(BuildContext context) {
return PopupMenuButton<SortBy>(
itemBuilder: (context) {
return [
PopupMenuItem(
return ListTileTheme(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
child: AdaptivePopSheetList<SortBy>(
children: [
PopSheetEntry(
value: SortBy.none,
enabled: value != SortBy.none,
child: Text(context.l10n.none),
),
PopupMenuItem(
PopSheetEntry(
value: SortBy.ascending,
enabled: value != SortBy.ascending,
child: Text(context.l10n.sort_a_z),
),
PopupMenuItem(
PopSheetEntry(
value: SortBy.descending,
enabled: value != SortBy.descending,
child: Text(context.l10n.sort_z_a),
),
PopupMenuItem(
PopSheetEntry(
value: SortBy.dateAdded,
enabled: value != SortBy.dateAdded,
child: Text(context.l10n.sort_date),
),
PopupMenuItem(
PopSheetEntry(
value: SortBy.artist,
enabled: value != SortBy.artist,
child: Text(context.l10n.sort_artist),
),
PopupMenuItem(
PopSheetEntry(
value: SortBy.album,
enabled: value != SortBy.album,
child: Text(context.l10n.sort_album),
),
];
},
onSelected: onChanged,
tooltip: context.l10n.sort_tracks,
icon: const Icon(SpotubeIcons.sort),
],
headings: [
Text(context.l10n.sort_tracks),
],
onSelected: onChanged,
tooltip: context.l10n.sort_tracks,
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 8.0, vertical: 4.0),
child: DefaultTextStyle(
style: Theme.of(context).textTheme.titleSmall!,
child: Row(
children: [
const Icon(SpotubeIcons.sort),
const SizedBox(width: 8),
Text(context.l10n.sort_tracks),
],
),
),
),
),
);
}
}

0 comments on commit ddc1c5f

Please sign in to comment.