Skip to content

Commit

Permalink
feat: Implement responsive design for the controller
Browse files Browse the repository at this point in the history
  • Loading branch information
Losses committed Oct 2, 2024
1 parent 69642ce commit eca847c
Show file tree
Hide file tree
Showing 6 changed files with 194 additions and 80 deletions.
6 changes: 1 addition & 5 deletions database/src/actions/mixes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -723,11 +723,7 @@ pub async fn query_mix_media_files(
.into()
};

let recommend_n = if let Some(query_limit) = pipe_limit {
query_limit
} else {
30
};
let recommend_n = pipe_limit.unwrap_or(30);

let file_ids =
get_recommendation_by_parameter(recommend_db, virtual_point, recommend_n as usize)
Expand Down
6 changes: 1 addition & 5 deletions database/src/actions/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,7 @@ impl DatabaseExecutor for DatabaseConnection {}
impl DatabaseExecutor for DatabaseTransaction {}

pub fn first_char(s: &str) -> char {
if let Some(first_char) = deunicode(s).chars().next() {
first_char
} else {
'#'
}
deunicode(s).chars().next().unwrap_or('#')
}

pub fn generate_group_name(x: &str) -> String {
Expand Down
21 changes: 17 additions & 4 deletions lib/main.dart
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import 'dart:io';

import 'package:player/providers/playback_controller.dart';
import 'package:player/providers/volume.dart';
import 'package:rinf/rinf.dart';
import 'package:provider/provider.dart';
import 'package:flutter/foundation.dart';
import 'package:get_storage/get_storage.dart';
import 'package:system_theme/system_theme.dart';
import 'package:fluent_ui/fluent_ui.dart' hide Page;
import 'package:responsive_framework/responsive_framework.dart';
import 'package:flutter_acrylic/flutter_acrylic.dart' as flutter_acrylic;

import 'utils/platform.dart';
Expand All @@ -18,10 +17,12 @@ import 'config/navigation.dart';

import 'messages/generated.dart';

import 'providers/volume.dart';
import 'providers/status.dart';
import 'providers/playlist.dart';
import 'providers/library_path.dart';
import 'providers/library_manager.dart';
import 'providers/playback_controller.dart';
import 'providers/transition_calculation.dart';

import 'theme.dart';
Expand All @@ -37,7 +38,9 @@ void main() async {
[
TargetPlatform.windows,
TargetPlatform.android,
].contains(defaultTargetPlatform)) {
].contains(
defaultTargetPlatform,
)) {
SystemTheme.accentColor.load();
}

Expand Down Expand Up @@ -110,7 +113,17 @@ class Rune extends StatelessWidget {
: Colors.transparent,
child: Directionality(
textDirection: appTheme.textDirection,
child: child!,
child: ResponsiveBreakpoints.builder(
breakpoints: [
const Breakpoint(start: 0, end: 480, name: PHONE),
const Breakpoint(start: 481, end: 650, name: MOBILE),
const Breakpoint(start: 651, end: 800, name: TABLET),
const Breakpoint(start: 801, end: 1920, name: DESKTOP),
const Breakpoint(
start: 1921, end: double.infinity, name: '4K'),
],
child: child!,
),
));
},
);
Expand Down
232 changes: 166 additions & 66 deletions lib/widgets/playback_controller/playback_controller.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import 'package:material_symbols_icons/symbols.dart';
import 'package:player/widgets/playback_controller/constants/controller_items.dart';
import 'package:player/widgets/tile/cover_art.dart';
import 'package:provider/provider.dart';
import 'package:fluent_ui/fluent_ui.dart';
import 'package:material_symbols_icons/symbols.dart';
import 'package:responsive_framework/responsive_framework.dart';

import '../../utils/format_time.dart';
import '../../messages/playback.pb.dart';
Expand All @@ -18,18 +21,15 @@ class PlaybackController extends StatefulWidget {
PlaybackControllerState createState() => PlaybackControllerState();
}

const scaleY = 0.9;

class PlaybackControllerState extends State<PlaybackController> {
@override
Widget build(BuildContext context) {
return Consumer<PlaybackStatusProvider>(
builder: (context, playbackStatusProvider, child) {
final theme = FluentTheme.of(context);
final typography = theme.typography;

final s = playbackStatusProvider.playbackStatus;

const scaleY = 0.9;

final notReady = s?.ready == null || s?.ready == false;

return SizedBox(
Expand All @@ -52,70 +52,160 @@ class PlaybackControllerState extends State<PlaybackController> {
),
),
),
SizedBox.expand(
child: Center(
child: Container(
constraints:
const BoxConstraints(minWidth: 200, maxWidth: 360),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 10),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Expanded(
child: Text(
s != null ? s.title : "",
NowPlaying(notReady: notReady, status: s),
ControllerButtons(notReady: notReady, status: s)
],
),
);
},
);
}
}

class NowPlaying extends StatelessWidget {
const NowPlaying({
super.key,
required this.status,
required this.notReady,
});

final PlaybackStatus? status;
final bool notReady;

@override
Widget build(BuildContext context) {
final theme = FluentTheme.of(context);
final typography = theme.typography;

final tablet = ResponsiveBreakpoints.of(context).isTablet;
final mobile = ResponsiveBreakpoints.of(context).isMobile;
final phone = ResponsiveBreakpoints.of(context).isPhone;

final miniLayout = tablet || mobile || phone;
final hideProgress = phone;

final progress = Progress(notReady: notReady, status: status);

return SizedBox.expand(
child: Align(
alignment: miniLayout ? Alignment.centerLeft : Alignment.center,
child: miniLayout
? Row(
children: [
const SizedBox(width: 16),
CoverArt(
path: status?.coverArtPath,
hint: status != null
? (
status!.album,
status!.artist,
'Total Time ${formatTime(status!.duration)}'
)
: null,
size: 48,
),
if (phone) const SizedBox(width: 10),
hideProgress
? Expanded(
child: ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 116),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
status?.title ?? "",
overflow: TextOverflow.ellipsis,
style: typography.caption,
),
),
Padding(
padding:
const EdgeInsetsDirectional.only(start: 16),
child: LikeButton(fileId: s?.id),
)
],
),
),
Slider(
value: s != null ? s.progressPercentage * 100 : 0,
onChanged: s != null && !notReady
? (v) => SeekRequest(
positionSeconds: (v / 100) * s.duration,
).sendSignalToRust()
: null,
style: const SliderThemeData(useThumbBall: false),
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 10),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
formatTime(s != null ? s.progressSeconds : 0),
style: typography.caption,
),
Text(
'-${formatTime(s != null ? s.duration - s.progressSeconds : 0)}',
style: typography.caption,
),
],
const SizedBox(height: 4),
Text(
status?.artist ?? "",
overflow: TextOverflow.ellipsis,
style: typography.caption?.apply(
color: theme.inactiveColor.withAlpha(160),
),
),
],
),
),
),
],
),
)
: progress,
if (phone) const SizedBox(width: 88),
],
)
: progress,
),
);
}
}

class Progress extends StatelessWidget {
const Progress({
super.key,
required this.status,
required this.notReady,
});

final PlaybackStatus? status;
final bool notReady;

@override
Widget build(BuildContext context) {
final theme = FluentTheme.of(context);
final typography = theme.typography;

return Container(
constraints: const BoxConstraints(minWidth: 200, maxWidth: 360),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 10),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Expanded(
child: Text(
status?.title ?? "",
overflow: TextOverflow.ellipsis,
style: typography.caption,
),
),
),
ControllerButtons(notReady: notReady, status: s)
],
Padding(
padding: const EdgeInsetsDirectional.only(start: 16),
child: LikeButton(fileId: status?.id),
)
],
),
),
);
},
Slider(
value: status != null ? status?.progressPercentage ?? 0 * 100 : 0,
onChanged: status != null && !notReady
? (v) => SeekRequest(
positionSeconds: (v / 100) * (status?.duration ?? 0),
).sendSignalToRust()
: null,
style: const SliderThemeData(useThumbBall: false),
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 10),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
formatTime(status?.progressSeconds ?? 0),
style: typography.caption,
),
Text(
'-${formatTime((status?.duration ?? 0) - (status?.progressSeconds ?? 0))}',
style: typography.caption,
),
],
),
),
],
),
);
}
}
Expand Down Expand Up @@ -145,6 +235,11 @@ class _ControllerButtonsState extends State<ControllerButtons> {

@override
Widget build(BuildContext context) {
final mobile = ResponsiveBreakpoints.of(context).isMobile;
final phone = ResponsiveBreakpoints.of(context).isPhone;

final miniLayout = phone || mobile;

final provider = Provider.of<PlaybackControllerProvider>(context);
final entries = provider.entries;
final hiddenIndex = entries.indexWhere((entry) => entry.id == 'hidden');
Expand All @@ -153,10 +248,12 @@ class _ControllerButtonsState extends State<ControllerButtons> {
final hiddenEntries =
hiddenIndex != -1 ? entries.sublist(hiddenIndex + 1) : [];

final miniEntries = [controllerItems[1], controllerItems[2]];

return Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
for (var entry in visibleEntries)
for (var entry in miniLayout ? miniEntries : visibleEntries)
entry.controllerButtonBuilder(widget.notReady, widget.status),
if (hiddenEntries.isNotEmpty)
FlyoutTarget(
Expand All @@ -170,7 +267,10 @@ class _ControllerButtonsState extends State<ControllerButtons> {
items: [
for (var entry in hiddenEntries)
entry.flyoutEntryBuilder(
context, widget.notReady, widget.status),
context,
widget.notReady,
widget.status,
),
],
);
},
Expand Down
8 changes: 8 additions & 0 deletions pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -787,6 +787,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "0.6.0"
responsive_framework:
dependency: "direct main"
description:
name: responsive_framework
sha256: a8e1c13d4ba980c60cbf6fa1e9907cd60662bf2585184d7c96ca46c43de91552
url: "https://pub.dev"
source: hosted
version: "1.5.1"
rinf:
dependency: "direct main"
description:
Expand Down
1 change: 1 addition & 0 deletions pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ dependencies:
macos_window_utils: ^1.5.0
rinf: ^6.15.0
fixnum: ^1.1.0
responsive_framework: ^1.5.1

dev_dependencies:
build_runner: ^2.4.11
Expand Down

0 comments on commit eca847c

Please sign in to comment.