Skip to content

Commit

Permalink
Merge mobile into main (#1)
Browse files Browse the repository at this point in the history
* [Refactor] refactor audio_controller

* [fix] uncaught exception in extern_api;
[fix] global audio_controller;
[Test] Test ios stop play by try to avoid Overflow

* [Feat] Add runtime log page.
[Refactor] use async wait in clearReplaceAllMusic.

* [Add] Add more log.
[Fix] Add music play, use remove music.

* [Add] add more log

* [Fix] clearReplaceAllMusic: FileMusic

* [Fix] background update

* [Test] DisplayPage only top widgets

* [Test] DisplayPage only top widgets

* [Test] delete blur and safearea.

* [Fix] Adjust ui

* [Change] Use getx directly in lyric comp

* [Fix] dispose stream in lyric comp

* [Test] Use stack to see if sound display in ios.

* [Test] no bottom in display page

* [Test] only button and volume

* [Test] only button and slider

* [Test] disable volume control in ios

* [Test] disable volume control all;
[Fix] fix change playing music quality;

* [Change] remove volume slider.

* [Test] Try to fix position error after seek in ios

* [Fix] slider default pressing false.

* [Test] try to fix seek error of ios.

* [Test] Add log in toAudioSource;

* [Test] Try fix file seek in ios by use my fork of just audio.

* [Fix] windows can't add music.

* [Chore] Remove unused dependency

* [Chore] remove unused dependency.
  • Loading branch information
canxin121 authored May 5, 2024
1 parent 7b761ea commit 5743bd6
Show file tree
Hide file tree
Showing 33 changed files with 1,303 additions and 1,082 deletions.
Binary file added assets/nature.mp3
Binary file not shown.
21 changes: 14 additions & 7 deletions lib/comp/card/music_card.dart
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
import 'dart:io';

import 'package:app_rhyme/src/rust/api/mirror.dart';
import 'package:app_rhyme/types/music.dart';
import 'package:app_rhyme/util/colors.dart';
import 'package:app_rhyme/util/default.dart';
import 'package:app_rhyme/util/helper.dart';
import 'package:app_rhyme/util/time_parse.dart';
import 'package:chinese_font_library/chinese_font_library.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';

class MusicCard extends StatefulWidget {
final DisplayMusic music;
final dynamic music;
final VoidCallback? onClick;
final VoidCallback? onPress;
final Future<bool>? hasCache;
Expand Down Expand Up @@ -61,9 +59,18 @@ class MusicCardState extends State<MusicCard> {
ClipRRect(
borderRadius: BorderRadius.circular(4.0),
child: info.artPic != null
? info.artPic!.contains("http")
? Image.network(info.artPic!, width: 40.0)
: Image.file(File(info.artPic!), width: 40.0)
? FutureBuilder(
future: useCacheImage(info.artPic!),
builder: (context, snapshot) {
if (snapshot.hasError ||
snapshot.connectionState ==
ConnectionState.waiting) {
return defaultArtPic;
} else {
return snapshot.data ?? defaultArtPic;
}
},
)
: defaultArtPic,
),
Expanded(
Expand Down
7 changes: 4 additions & 3 deletions lib/comp/card/playing_music_card.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';

// 这个组件唯一使用就是在 待播放列表的上方显示,将被合并
// 这个组件在 待播放列表和歌词的上方显示
class PlayingMusicCard extends StatefulWidget {
final VoidCallback? onClick;
final VoidCallback? onPress;
Expand All @@ -29,7 +29,8 @@ class PlayingMusicCardState extends State<PlayingMusicCard> {
// 根据isTaller参数决定卡片的高度
double cardHeight = 80.0;

return GestureDetector(
return SafeArea(
child: GestureDetector(
onTap: widget.onClick,
onLongPress: widget.onPress,
child: SizedBox(
Expand Down Expand Up @@ -96,6 +97,6 @@ class PlayingMusicCardState extends State<PlayingMusicCard> {
),
),
),
);
));
}
}
259 changes: 123 additions & 136 deletions lib/comp/music_bar/bar.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,148 +5,135 @@ import 'package:app_rhyme/util/helper.dart';
import 'package:app_rhyme/util/audio_controller.dart';
import 'package:flutter/cupertino.dart';
import 'package:get/get_state_manager/src/rx_flutter/rx_obx_widget.dart';
import 'package:pro_animated_blur/pro_animated_blur.dart';

class MusicPlayBar extends StatelessWidget {
const MusicPlayBar({super.key});
final double maxHeight;
const MusicPlayBar({super.key, required this.maxHeight});

@override
Widget build(BuildContext context) {
// 获取屏幕总高度
double screenHeight = MediaQuery.of(context).size.height;
// 计算组件的最大高度
double barHeight = screenHeight * 0.08;

return SafeArea(
child: ConstrainedBox(
constraints: BoxConstraints(
maxHeight: barHeight,
),
child: GestureDetector(
onVerticalDragUpdate: (details) {
// 当用户上滑时,details.delta.dy 会是一个负值
if (details.delta.dy < 0) {
navigateToSongDisplayPage(context);
}
},
onTap: () {
navigateToSongDisplayPage(context);
},
child: Container(
clipBehavior: Clip.antiAliasWithSaveLayer,
decoration: BoxDecoration(color: barBackgoundColor),
child: ProAnimatedBlur(
blur: 500,
duration: const Duration(milliseconds: 0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Padding(
padding: const EdgeInsets.all(8.0),
// 使用AspectRatio来保持图片的宽高比
child: Obx(() => FutureBuilder<Hero>(
future: playingMusicImage(), // 这是异步函数
builder: (BuildContext context,
AsyncSnapshot<Hero> snapshot) {
if (snapshot.connectionState ==
ConnectionState.waiting) {
return AspectRatio(
aspectRatio: 1,
child: Hero(
tag: "PlayingMusicPic",
child: defaultArtPic,
),
);
} else if (snapshot.hasError) {
return Text('Error: ${snapshot.error}');
} else {
return AspectRatio(
aspectRatio: 1,
child: snapshot.data ?? defaultArtPic,
);
}
},
)),
),
Expanded(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Obx(
() => Text(
playingMusicName,
style: const TextStyle(fontSize: 15.0),
textAlign: TextAlign.center,
overflow: TextOverflow.ellipsis,
maxLines: 1,
),
),
],
),
return ConstrainedBox(
constraints: BoxConstraints(
maxHeight: maxHeight,
),
child: GestureDetector(
onVerticalDragUpdate: (details) {
// 当用户上滑时,details.delta.dy 会是一个负值
if (details.delta.dy < 0) {
navigateToSongDisplayPage(context);
}
},
onTap: () {
navigateToSongDisplayPage(context);
},
child: Container(
clipBehavior: Clip.antiAliasWithSaveLayer,
decoration: BoxDecoration(color: barBackgoundColor),
child: Row(
children: <Widget>[
// 音乐图标
Padding(
padding: const EdgeInsets.all(8.0),
// 使用AspectRatio来保持图片的宽高比
child: Obx(() => FutureBuilder<Hero>(
future: playingMusicImage(), // 这是异步函数
builder:
(BuildContext context, AsyncSnapshot<Hero> snapshot) {
if (snapshot.connectionState ==
ConnectionState.waiting) {
return AspectRatio(
aspectRatio: 1,
child: Hero(
tag: "PlayingMusicPic",
child: defaultArtPic,
),
);
} else if (snapshot.hasError) {
return Text('Error: ${snapshot.error}');
} else {
return AspectRatio(
aspectRatio: 1,
child: snapshot.data ?? defaultArtPic,
);
}
},
)),
),
// 音乐名称
Expanded(
child: Obx(
() => Text(
playingMusicName,
style: const TextStyle(fontSize: 15.0),
textAlign: TextAlign.left,
overflow: TextOverflow.ellipsis,
maxLines: 1,
),
),
),
// 音乐控制按钮
Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Hero(
tag: "SkipToPreviousButton",
child: CupertinoButton(
padding: EdgeInsets.zero,
onPressed: () {
globalAudioHandler.seekToPrevious();
},
child: const Icon(
CupertinoIcons.backward_fill,
color: CupertinoColors.black,
),
Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Hero(
tag: "SkipToPreviousButton",
child: CupertinoButton(
padding: EdgeInsets.zero,
onPressed: () {
globalAudioServiceHandler.skipToNext();
},
child: const Icon(
CupertinoIcons.backward_fill,
color: CupertinoColors.black,
),
)),
Obx(() {
if (globalAudioUiController
.playerState.value.playing) {
return Hero(
tag: "PlayOrPauseButton",
child: CupertinoButton(
padding: EdgeInsets.zero,
child: const Icon(
CupertinoIcons.pause_solid,
color: CupertinoColors.black,
),
onPressed: () {
globalAudioServiceHandler.pause();
},
));
} else {
return Hero(
tag: "PlayOrPauseButton",
child: CupertinoButton(
padding: EdgeInsets.zero,
child: const Icon(
CupertinoIcons.play_arrow_solid,
color: CupertinoColors.black,
),
onPressed: () {
globalAudioServiceHandler.play();
},
));
}
}),
Hero(
tag: "SkipToNextButton",
child: CupertinoButton(
padding: EdgeInsets.zero,
onPressed: () {
globalAudioServiceHandler.skipToNext();
},
child: const Icon(
CupertinoIcons.forward_fill,
color: CupertinoColors.black,
),
)),
],
)),
Obx(() {
if (globalAudioUiController.playerState.value.playing) {
return Hero(
tag: "PlayOrPauseButton",
child: CupertinoButton(
padding: EdgeInsets.zero,
child: const Icon(
CupertinoIcons.pause_solid,
color: CupertinoColors.black,
),
onPressed: () {
globalAudioHandler.pause();
},
));
} else {
return Hero(
tag: "PlayOrPauseButton",
child: CupertinoButton(
padding: EdgeInsets.zero,
child: const Icon(
CupertinoIcons.play_arrow_solid,
color: CupertinoColors.black,
),
onPressed: () {
globalAudioHandler.play();
},
));
}
}),
Hero(
tag: "SkipToNextButton",
child: CupertinoButton(
padding: EdgeInsets.zero,
onPressed: () {
globalAudioHandler.seekToNext();
},
child: const Icon(
CupertinoIcons.forward_fill,
color: CupertinoColors.black,
),
],
),
),
))));
)),
],
),
],
),
),
),
);
}
}
15 changes: 8 additions & 7 deletions lib/comp/play_page_comp/botton_button.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,12 @@ enum PageState { home, lyric, list }
class BottomButton extends StatefulWidget {
final VoidCallback onList;
final VoidCallback onLyric;

const BottomButton({super.key, required this.onList, required this.onLyric});
final EdgeInsetsGeometry padding;
const BottomButton(
{super.key,
required this.onList,
required this.onLyric,
required this.padding});

@override
State<StatefulWidget> createState() => BottomButtonState();
Expand All @@ -23,18 +27,15 @@ class BottomButtonState extends State<BottomButton> {
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
CupertinoButton(
padding: const EdgeInsets.all(0),
padding: widget.padding,
child: Icon(
// 根据当前页面状态来决定图标
currentPage == PageState.lyric
? CupertinoIcons.quote_bubble_fill
: CupertinoIcons.quote_bubble,
color: CupertinoColors.white,
),
onPressed: () {
setState(() {
// 如果当前在歌词页面,点击则回到主页
// 否则,进入歌词页面
currentPage = currentPage == PageState.lyric
? PageState.home
: PageState.lyric;
Expand All @@ -43,7 +44,7 @@ class BottomButtonState extends State<BottomButton> {
},
),
CupertinoButton(
padding: const EdgeInsets.all(0),
padding: widget.padding,
child: Icon(
// 根据当前页面状态来决定图标
currentPage == PageState.list
Expand Down
Loading

0 comments on commit 5743bd6

Please sign in to comment.