Skip to content

Commit

Permalink
implement playlist card context menu features
Browse files Browse the repository at this point in the history
  • Loading branch information
YuiHrsw committed Oct 11, 2024
1 parent ac7c32a commit 6992dc1
Show file tree
Hide file tree
Showing 4 changed files with 184 additions and 34 deletions.
22 changes: 19 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Playboy

> 本项目目前通过 Github Actions 自动编译 Windows 和 Android 测试版本, 可[在此](https://github.com/Playboy-Player/Playboy/actions)下载体验.
使用 [Flutter](https://flutter.dev/) 开发的媒体播放器, 界面使用 [Material You](https://m3.material.io/) 设计风格.

![](https://m3-markdown-badges.vercel.app/stars/7/2/Playboy-Player/Playboy)
Expand Down Expand Up @@ -41,7 +43,7 @@

## 功能

[查看开发进度](https://github.com/orgs/Playboy-Player/projects/3)
[查看开发计划 & 进度](https://github.com/orgs/Playboy-Player/projects/3)

- [x] 主题颜色设置 & 深色模式支持
- [ ] 多语言支持
Expand Down Expand Up @@ -104,11 +106,25 @@ Doctor summary (to see all details, run flutter doctor -v):

### macOS

> 理论上兼容, 由于无编译环境, 暂未测试
> [可以运行](https://github.com/Playboy-Player/Playboy/issues/3), 但需要更多适配工作, 由于无编译环境, 开发进度暂时停滞.
### android

> 开发中
> 针对手机的布局优化尚未完成, 建议在平板设备上体验.
flutter doctor 输出内容示例:

```
Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel stable, 3.24.1, on Microsoft Windows [版本 10.0.22631.4169], locale zh-CN)
[✓] Windows Version (Installed version of Windows is version 10 or higher)
[✓] Android toolchain - develop for Android devices (Android SDK version 34.0.0)
[✓] Android Studio (version 2024.2)
[✓] Connected device (3 available)
[✓] Network resources
```

建议在 [Android Studio](https://developer.android.com/studio?hl=zh-cn#get-android-studio) 中运行项目.

## 为本项目做出贡献

Expand Down
15 changes: 11 additions & 4 deletions lib/backend/library_helper.dart
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,12 @@ class LibraryHelper {
await for (var item in dir.list()) {
if (item is File && extension(item.path) == '.json') {
var pl = PlaylistItem.fromJson(jsonDecode(await item.readAsString()));
var cover = '${withoutExtension(item.path)}.cover.jpg';
if (await File(cover).exists()) {
pl.cover = cover;
} else {
pl.cover = null;
}
playlists.add(pl);
}
}
Expand All @@ -176,6 +182,11 @@ class LibraryHelper {
if (fp.existsSync()) {
fp.deleteSync();
}

var cover = File('${AppStorage().dataPath}/playlists/${pl.uuid}.cover.jpg');
if (cover.existsSync()) {
cover.deleteSync();
}
}

static void addItemToPlaylist(PlaylistItem pl, PlayItem p) {
Expand All @@ -192,8 +203,4 @@ class LibraryHelper {
pl.title = name;
savePlaylist(pl);
}

static void setPlaylistCover(PlaylistItem pl, String path) {}

static void clearPlaylistCover(PlaylistItem pl) {}
}
25 changes: 16 additions & 9 deletions lib/pages/playlist/playlist_detail.dart
Original file line number Diff line number Diff line change
Expand Up @@ -28,21 +28,21 @@ class PlaylistDetailState extends State<PlaylistDetail> {
Navigator.pop(context);
},
),
titleSpacing: 0,
title: Text(widget.info.title),
// titleSpacing: 0,
// title: const Text('所有列表'),
scrolledUnderElevation: 0,
backgroundColor: Theme.of(context).colorScheme.surface,
actions: [
IconButton(
onPressed: () {},
icon: const Icon(Icons.drive_file_rename_outline),
),
IconButton(
onPressed: () {
Navigator.pop(context, true);
},
icon: const Icon(Icons.delete_outline),
),
IconButton(
onPressed: () {},
icon: const Icon(Icons.more_vert),
),
const SizedBox(
width: 10,
)
Expand All @@ -52,15 +52,19 @@ class PlaylistDetailState extends State<PlaylistDetail> {
slivers: [
SliverToBoxAdapter(
child: Padding(
padding: const EdgeInsets.all(24),
padding: const EdgeInsets.only(
left: 24,
right: 24,
bottom: 24,
),
child: Row(
// mainAxisAlignment: MainAxisAlignment.center,
// crossAxisAlignment: CrossAxisAlignment.end,
children: [
SizedBox(
width: 140,
child: AspectRatio(
aspectRatio: 1,
aspectRatio: 72 / 55,
child: widget.info.cover == null
? Container(
width: double.infinity,
Expand All @@ -78,7 +82,10 @@ class PlaylistDetailState extends State<PlaylistDetail> {
width: double.infinity,
child: ClipRRect(
borderRadius: BorderRadius.circular(20),
child: Image.file(File(widget.info.cover!)),
child: Image.file(
File(widget.info.cover!),
fit: BoxFit.cover,
),
),
),
),
Expand Down
156 changes: 138 additions & 18 deletions lib/pages/playlist/playlist_page.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import 'dart:io';
import 'dart:math';

import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart';
import 'package:playboy/backend/library_helper.dart';
import 'package:playboy/backend/models/playlist_item.dart';
Expand Down Expand Up @@ -212,6 +213,9 @@ class PlaylistState extends State<PlaylistPage> {
position: details.localPosition,
);
},
onLongPress: () {
menuController.open();
},
child: MenuAnchor(
controller: menuController,
style: MenuStyle(
Expand Down Expand Up @@ -251,8 +255,9 @@ class PlaylistState extends State<PlaylistPage> {
() {
AppStorage().closeMedia();
AppStorage().openPlaylist(
AppStorage().playlists[index],
true);
AppStorage().playlists[index],
true,
);
},
),
_buildMenuItem(
Expand All @@ -264,7 +269,8 @@ class PlaylistState extends State<PlaylistPage> {
),
() {
AppStorage().appendPlaylist(
AppStorage().playlists[index]);
AppStorage().playlists[index],
);
},
),
const Divider(),
Expand All @@ -275,7 +281,34 @@ class PlaylistState extends State<PlaylistPage> {
horizontal: 6),
child: Text('导出'),
),
() {},
() async {
final originalFile = File(
'${AppStorage().dataPath}/playlists/${AppStorage().playlists[index].uuid}.json',
);
String? newFilePath =
await FilePicker.platform
.saveFile(
dialogTitle: '另存为',
fileName:
'${AppStorage().playlists[index].uuid}.json',
);

if (newFilePath != null) {
final newFile = File(newFilePath);

await originalFile
.copy(newFile.path);
if (!context.mounted) return;
ScaffoldMessenger.of(context)
.showSnackBar(
SnackBar(
content: Text(
'文件已另存为: $newFilePath',
),
),
);
}
},
),
_buildMenuItem(
Icons.design_services_outlined,
Expand All @@ -284,7 +317,59 @@ class PlaylistState extends State<PlaylistPage> {
horizontal: 6),
child: Text('修改封面'),
),
() {},
() async {
String? coverPath = await FilePicker
.platform
.pickFiles(type: FileType.image)
.then(
(result) {
return result
?.files.single.path;
},
);
if (coverPath != null) {
var savePath =
'${AppStorage().dataPath}/playlists/${AppStorage().playlists[index].uuid}.cover.jpg';
var originalFile =
File(coverPath);
var newFile = File(
savePath,
);
AppStorage()
.playlists[index]
.cover = savePath;
await originalFile
.copy(newFile.path)
.then(
(value) {
setState(() {});
},
);
}
},
),
_buildMenuItem(
Icons.cleaning_services,
const Padding(
padding: EdgeInsets.symmetric(
horizontal: 6),
child: Text(
'清除封面',
),
),
() async {
setState(() {
AppStorage()
.playlists[index]
.cover = null;
});
var coverPath =
'${AppStorage().dataPath}/playlists/${AppStorage().playlists[index].uuid}.cover.jpg';
var cover = File(coverPath);
if (await cover.exists()) {
await cover.delete();
}
},
),
_buildMenuItem(
Icons.drive_file_rename_outline,
Expand All @@ -306,7 +391,8 @@ class PlaylistState extends State<PlaylistPage> {
surfaceTintColor:
Colors.transparent,
title: Text(
'重命名 ${AppStorage().playlists[index].title}'),
'重命名 ${AppStorage().playlists[index].title}',
),
content: TextField(
autofocus: true,
maxLines: 1,
Expand Down Expand Up @@ -363,18 +449,49 @@ class PlaylistState extends State<PlaylistPage> {
child: Text('删除'),
),
() {
LibraryHelper.deletePlaylist(
AppStorage().playlists[index]);
AppStorage()
.playlists
.removeAt(index);
setState(() {});
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: const Text("确认操作"),
content:
const Text("确定要删除播放列表吗?"),
actions: [
TextButton(
child: const Text("取消"),
onPressed: () {
Navigator.of(context)
.pop();
},
),
TextButton(
child: const Text("确认"),
onPressed: () {
LibraryHelper
.deletePlaylist(
AppStorage()
.playlists[index],
);
AppStorage()
.playlists
.removeAt(index);
setState(() {});
Navigator.of(context)
.pop();
},
),
],
);
},
);
},
),
const SizedBox(height: 10),
],
child:
buildPlaylistCard(index, colorScheme),
child: buildPlaylistCard(
index,
colorScheme,
),
),
);
},
Expand All @@ -385,8 +502,10 @@ class PlaylistState extends State<PlaylistPage> {
itemBuilder: (context, index) {
return SizedBox(
height: 80,
child:
buildPlaylistListCard(index, colorScheme),
child: buildPlaylistListCard(
index,
colorScheme,
),
);
},
itemCount: AppStorage().playlists.length,
Expand Down Expand Up @@ -454,8 +573,9 @@ class PlaylistState extends State<PlaylistPage> {
color: colorScheme.secondaryContainer,
image: DecorationImage(
fit: BoxFit.cover,
image: FileImage(
File(AppStorage().playlists[index].cover!),
image: MemoryImage(
File(AppStorage().playlists[index].cover!)
.readAsBytesSync(),
),
),
),
Expand Down

0 comments on commit 6992dc1

Please sign in to comment.