diff --git a/README.md b/README.md
index 2e8bf871d..37a2e36fa 100644
--- a/README.md
+++ b/README.md
@@ -22,22 +22,18 @@
-## 开发环境
-
-```bash
-[✓] Flutter (Channel stable, 3.24.0, on Microsoft Windows [版本 10.0.19045.4046], locale zh-CN)
-[✓] Android toolchain - develop for Android devices (Android SDK version 34.0.0)
-[✓] Xcode - develop for iOS and macOS (Xcode 15.1)
-[✓] Chrome - develop for the web
-[✓] Android Studio (version 2022.3)
-[✓] VS Code (version 1.85.1)
-[✓] Connected device (3 available)
-[✓] Network resources
-
-```
+## 适配平台
+
+- [x] Android
+- [x] iOS
+- [x] Pad
+- [x] Windows
+
+
+
## refactor
@@ -136,11 +132,6 @@
## 功能
-目前着重移动端(Android、iOS)和Pad端,暂时没有适配桌面端、手表端等
-
-
-
-
- [x] 推荐视频列表(app端)
- [x] 最热视频列表
- [x] 热门直播
diff --git a/assets/images/logo/logo_large.png b/assets/images/logo/logo_large.png
new file mode 100644
index 000000000..2370686ba
Binary files /dev/null and b/assets/images/logo/logo_large.png differ
diff --git a/lib/pages/emote/view.dart b/lib/pages/emote/view.dart
index c406afa34..7ceb19100 100644
--- a/lib/pages/emote/view.dart
+++ b/lib/pages/emote/view.dart
@@ -42,9 +42,11 @@ class _EmotePanelState extends State
ThemeData theme,
LoadingState?> loadingState,
) {
- late final color = Get.currentRoute.startsWith('/whisperDetail')
- ? theme.colorScheme.surface
- : theme.colorScheme.onInverseSurface;
+ late final color = ElevationOverlay.colorWithOverlay(
+ theme.colorScheme.surface,
+ theme.hoverColor,
+ Get.currentRoute.startsWith('/whisperDetail') ? 8 : 2,
+ );
return switch (loadingState) {
Loading() => loadingWidget,
Success(:var response) =>
diff --git a/lib/pages/episode_panel/view.dart b/lib/pages/episode_panel/view.dart
index 46a14db34..3873f4966 100644
--- a/lib/pages/episode_panel/view.dart
+++ b/lib/pages/episode_panel/view.dart
@@ -74,7 +74,7 @@ class EpisodePanel extends CommonSlidePage {
final int initialTabIndex;
final bool? isSupportReverse;
final bool? isReversed;
- final ValueChanged onChangeEpisode;
+ final Future Function(ugc.BaseEpisodeItem) onChangeEpisode;
final VoidCallback? onReverse;
final VoidCallback? onClose;
@@ -432,19 +432,23 @@ class _EpisodePanelState extends State
}
SmartDialog.showToast('切换到:$title');
widget.onClose?.call();
- if (!showTitle) {
- _currentItemIndex = index;
- }
- widget.onChangeEpisode(episode);
- if (widget.type == EpisodeType.season) {
- try {
- Get.find(
- tag: widget.ugcIntroController!.heroTag,
- ).seasonCid = episode.cid;
- } catch (_) {
- if (kDebugMode) rethrow;
+
+ widget.onChangeEpisode(episode).then((res) {
+ if (res) {
+ if (!showTitle) {
+ _currentItemIndex = index;
+ }
+ if (widget.type == EpisodeType.season) {
+ try {
+ Get.find(
+ tag: widget.ugcIntroController!.heroTag,
+ ).seasonCid = episode.cid;
+ } catch (_) {
+ if (kDebugMode) rethrow;
+ }
+ }
}
- }
+ });
},
onLongPress: () {
if (cover?.isNotEmpty == true) {
diff --git a/lib/pages/fav_create/view.dart b/lib/pages/fav_create/view.dart
index 8a703f5a0..22b74d8c9 100644
--- a/lib/pages/fav_create/view.dart
+++ b/lib/pages/fav_create/view.dart
@@ -259,57 +259,58 @@ class _CreateFavPageState extends State {
],
ListTile(
tileColor: theme.colorScheme.onInverseSurface,
- leading: Text.rich(
- style: const TextStyle(
- height: 1,
- fontSize: 14,
- ),
- TextSpan(
- children: [
- TextSpan(
- text: '*',
- style: TextStyle(
- fontSize: 14,
- height: 1,
- color: theme.colorScheme.error,
+ title: Row(
+ children: [
+ SizedBox(
+ width: 55,
+ child: Text.rich(
+ TextSpan(
+ children: [
+ TextSpan(
+ text: '*',
+ style: TextStyle(
+ fontSize: 14,
+ color: theme.colorScheme.error,
+ ),
+ ),
+ const TextSpan(
+ text: '名称',
+ style: TextStyle(fontSize: 14),
+ ),
+ ],
),
),
- const TextSpan(
- text: '名称',
+ ),
+ Expanded(
+ child: TextField(
+ autofocus: true,
+ readOnly: _attr != null && FavUtils.isDefaultFav(_attr!),
+ controller: _titleController,
style: TextStyle(
- height: 1,
fontSize: 14,
+ color: _attr != null && FavUtils.isDefaultFav(_attr!)
+ ? theme.colorScheme.outline
+ : null,
+ ),
+ inputFormatters: [
+ LengthLimitingTextInputFormatter(20),
+ ],
+ decoration: InputDecoration(
+ isDense: true,
+ hintText: '名称',
+ hintStyle: TextStyle(
+ fontSize: 14,
+ color: theme.colorScheme.outline,
+ ),
+ border: const OutlineInputBorder(
+ borderSide: BorderSide.none,
+ gapPadding: 0,
+ ),
+ contentPadding: EdgeInsets.zero,
),
),
- ],
- ),
- ),
- title: TextField(
- autofocus: true,
- readOnly: _attr != null && FavUtils.isDefaultFav(_attr!),
- controller: _titleController,
- style: TextStyle(
- fontSize: 14,
- color: _attr != null && FavUtils.isDefaultFav(_attr!)
- ? theme.colorScheme.outline
- : null,
- ),
- inputFormatters: [
- LengthLimitingTextInputFormatter(20),
+ ),
],
- decoration: InputDecoration(
- isDense: true,
- hintText: '名称',
- hintStyle: TextStyle(
- fontSize: 14,
- color: theme.colorScheme.outline,
- ),
- border: const OutlineInputBorder(
- borderSide: BorderSide.none,
- gapPadding: 0,
- ),
- contentPadding: EdgeInsets.zero,
- ),
),
),
const SizedBox(height: 16),
@@ -319,24 +320,16 @@ class _CreateFavPageState extends State {
title: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
- Text.rich(
- TextSpan(
- children: [
- TextSpan(
- text: '简介',
- style: TextStyle(
- fontSize: 14,
- color: theme.colorScheme.onSurfaceVariant,
- ),
- ),
- const TextSpan(
- text: '*',
- style: TextStyle(color: Colors.transparent),
- ),
- ],
+ SizedBox(
+ width: 55,
+ child: Text(
+ '简介',
+ style: TextStyle(
+ fontSize: 14,
+ color: theme.colorScheme.onSurfaceVariant,
+ ),
),
),
- const SizedBox(width: 16),
Expanded(
child: TextField(
minLines: 6,
diff --git a/lib/pages/history/view.dart b/lib/pages/history/view.dart
index f2ad12127..4f2fdf10a 100644
--- a/lib/pages/history/view.dart
+++ b/lib/pages/history/view.dart
@@ -254,20 +254,25 @@ class _HistoryPageState extends State
padding: const EdgeInsets.only(left: 16, right: 6),
child: Row(
children: [
- Icon(
- Icons.info_outline,
- size: 18,
- color: theme.onSecondaryContainer,
- ),
- const SizedBox(width: 4),
Expanded(
- child: Text(
- '历史记录功能已关闭',
+ child: Text.rich(
strutStyle: const StrutStyle(height: 1, leading: 0),
style: TextStyle(
height: 1,
color: theme.onSecondaryContainer,
),
+ TextSpan(
+ children: [
+ WidgetSpan(
+ child: Icon(
+ Icons.info_outline,
+ size: 18,
+ color: theme.onSecondaryContainer,
+ ),
+ ),
+ const TextSpan(text: ' 历史记录功能已关闭'),
+ ],
+ ),
),
),
GestureDetector(
diff --git a/lib/pages/live_emote/view.dart b/lib/pages/live_emote/view.dart
index fcc4cae73..535207c6a 100644
--- a/lib/pages/live_emote/view.dart
+++ b/lib/pages/live_emote/view.dart
@@ -45,7 +45,11 @@ class _LiveEmotePanelState extends State
Widget _buildBody(LoadingState?> loadingState) {
late final theme = Theme.of(context);
- late final color = theme.colorScheme.onInverseSurface;
+ late final color = ElevationOverlay.colorWithOverlay(
+ theme.colorScheme.surface,
+ theme.hoverColor,
+ 2,
+ );
return switch (loadingState) {
Loading() => loadingWidget,
Success(:var response) =>
diff --git a/lib/pages/live_room/widgets/chat_panel.dart b/lib/pages/live_room/widgets/chat_panel.dart
index 9b490a93f..1e0d486b0 100644
--- a/lib/pages/live_room/widgets/chat_panel.dart
+++ b/lib/pages/live_room/widgets/chat_panel.dart
@@ -140,7 +140,7 @@ class LiveRoomChatPanel extends StatelessWidget {
),
padding: const EdgeInsets.fromLTRB(10, 4, 4, 4),
child: Text.rich(
- style: const TextStyle(color: Colors.white),
+ style: const TextStyle(color: Colors.white, height: 1),
strutStyle: const StrutStyle(height: 1, leading: 0),
TextSpan(
children: [
diff --git a/lib/pages/main/view.dart b/lib/pages/main/view.dart
index 158002011..6e4bec5f8 100644
--- a/lib/pages/main/view.dart
+++ b/lib/pages/main/view.dart
@@ -51,8 +51,12 @@ class _MainAppState extends State
@override
void didChangeDependencies() {
super.didChangeDependencies();
+ final brightness = Theme.brightnessOf(context);
NetworkImgLayer.reduce =
- NetworkImgLayer.reduceLuxColor != null && context.isDarkMode;
+ NetworkImgLayer.reduceLuxColor != null && brightness.isDark;
+ if (Utils.isDesktop) {
+ windowManager.setBrightness(brightness);
+ }
PageUtils.routeObserver.subscribe(
this,
ModalRoute.of(context) as PageRoute,
@@ -160,6 +164,8 @@ class _MainAppState extends State
Future _handleTray() async {
if (Platform.isWindows) {
await trayManager.setIcon('assets/images/logo/app_icon.ico');
+ } else {
+ await trayManager.setIcon('assets/images/logo/logo_large.png');
}
if (!Platform.isLinux) {
await trayManager.setToolTip(Constants.appName);
diff --git a/lib/pages/video/ai_conclusion/view.dart b/lib/pages/video/ai_conclusion/view.dart
index cead90a61..30266886f 100644
--- a/lib/pages/video/ai_conclusion/view.dart
+++ b/lib/pages/video/ai_conclusion/view.dart
@@ -1,6 +1,7 @@
import 'package:PiliPlus/models_new/video/video_ai_conclusion/model_result.dart';
import 'package:PiliPlus/pages/common/slide/common_slide_page.dart';
import 'package:PiliPlus/pages/video/controller.dart';
+import 'package:PiliPlus/pages/video/introduction/ugc/widgets/selectable_text.dart';
import 'package:PiliPlus/utils/duration_utils.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
@@ -69,7 +70,7 @@ class _AiDetailState extends State
SliverToBoxAdapter(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 14),
- child: SelectableText(
+ child: selectableText(
widget.item.summary!,
style: const TextStyle(
fontSize: 15,
@@ -98,57 +99,59 @@ class _AiDetailState extends State
itemCount: widget.item.outline!.length,
itemBuilder: (context, index) {
final item = widget.item.outline![index];
- return Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- if (index != 0) const SizedBox(height: 10),
- SelectableText(
- item.title!,
- style: const TextStyle(
- fontSize: 14,
- fontWeight: FontWeight.bold,
- height: 1.5,
+ return SelectionArea(
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ if (index != 0) const SizedBox(height: 10),
+ Text(
+ item.title!,
+ style: const TextStyle(
+ fontSize: 14,
+ fontWeight: FontWeight.bold,
+ height: 1.5,
+ ),
),
- ),
- const SizedBox(height: 6),
- ...?item.partOutline?.map(
- (item) => Wrap(
- children: [
- SelectableText.rich(
- TextSpan(
- style: TextStyle(
- fontSize: 14,
- color: theme.colorScheme.onSurface,
- height: 1.5,
- ),
- children: [
- TextSpan(
- text: DurationUtils.formatDuration(
- item.timestamp,
- ),
- style: TextStyle(
- color: theme.colorScheme.primary,
- ),
- recognizer: TapGestureRecognizer()
- ..onTap = () {
- try {
- Get.find(
- tag: Get.arguments['heroTag'],
- ).plPlayerController.seekTo(
- Duration(seconds: item.timestamp!),
- );
- } catch (_) {}
- },
+ const SizedBox(height: 6),
+ ...?item.partOutline?.map(
+ (item) => Wrap(
+ children: [
+ Text.rich(
+ TextSpan(
+ style: TextStyle(
+ fontSize: 14,
+ color: theme.colorScheme.onSurface,
+ height: 1.5,
),
- const TextSpan(text: ' '),
- TextSpan(text: item.content!),
- ],
+ children: [
+ TextSpan(
+ text: DurationUtils.formatDuration(
+ item.timestamp,
+ ),
+ style: TextStyle(
+ color: theme.colorScheme.primary,
+ ),
+ recognizer: TapGestureRecognizer()
+ ..onTap = () {
+ try {
+ Get.find(
+ tag: Get.arguments['heroTag'],
+ ).plPlayerController.seekTo(
+ Duration(seconds: item.timestamp!),
+ );
+ } catch (_) {}
+ },
+ ),
+ const TextSpan(text: ' '),
+ TextSpan(text: item.content!),
+ ],
+ ),
),
- ),
- ],
+ ],
+ ),
),
- ),
- ],
+ ],
+ ),
);
},
),
diff --git a/lib/pages/video/introduction/pgc/controller.dart b/lib/pages/video/introduction/pgc/controller.dart
index 77d5dd40a..8cf3fa8c9 100644
--- a/lib/pages/video/introduction/pgc/controller.dart
+++ b/lib/pages/video/introduction/pgc/controller.dart
@@ -277,7 +277,7 @@ class PgcIntroController extends CommonIntroController {
}
// 修改分P或番剧分集
- Future onChangeEpisode(BaseEpisodeItem episode) async {
+ Future onChangeEpisode(BaseEpisodeItem episode) async {
try {
final int epId = episode.epId ?? episode.id!;
final String bvid = episode.bvid ?? this.bvid;
@@ -285,7 +285,7 @@ class PgcIntroController extends CommonIntroController {
final int? cid =
episode.cid ?? await SearchHttp.ab2c(aid: aid, bvid: bvid);
if (cid == null) {
- return;
+ return false;
}
final String? cover = episode.cover;
@@ -323,8 +323,10 @@ class PgcIntroController extends CommonIntroController {
this.cid.value = cid;
queryOnlineTotal();
queryVideoIntro(episode as EpisodeItem);
+ return true;
} catch (e) {
if (kDebugMode) debugPrint('pgc onChangeEpisode: $e');
+ return false;
}
}
diff --git a/lib/pages/video/introduction/pgc/widgets/intro_detail.dart b/lib/pages/video/introduction/pgc/widgets/intro_detail.dart
index 2c53c560b..497c17b56 100644
--- a/lib/pages/video/introduction/pgc/widgets/intro_detail.dart
+++ b/lib/pages/video/introduction/pgc/widgets/intro_detail.dart
@@ -9,6 +9,7 @@ import 'package:PiliPlus/models_new/video/video_tag/data.dart';
import 'package:PiliPlus/pages/common/slide/common_slide_page.dart';
import 'package:PiliPlus/pages/pgc_review/view.dart';
import 'package:PiliPlus/pages/search/widgets/search_text.dart';
+import 'package:PiliPlus/pages/video/introduction/ugc/widgets/selectable_text.dart';
import 'package:PiliPlus/utils/extension.dart';
import 'package:PiliPlus/utils/utils.dart';
import 'package:flutter/material.dart' hide TabBarView;
@@ -108,7 +109,7 @@ class _IntroDetailState extends State
bottom: MediaQuery.viewPaddingOf(context).bottom + 100,
),
children: [
- SelectableText(
+ selectableText(
widget.item.title!,
style: const TextStyle(fontSize: 16),
),
@@ -152,7 +153,7 @@ class _IntroDetailState extends State
style: theme.textTheme.titleMedium,
),
const SizedBox(height: 4),
- SelectableText(
+ selectableText(
widget.item.evaluate!,
style: textStyle,
),
diff --git a/lib/pages/video/introduction/ugc/controller.dart b/lib/pages/video/introduction/ugc/controller.dart
index 46d2be3a3..4ee8812b2 100644
--- a/lib/pages/video/introduction/ugc/controller.dart
+++ b/lib/pages/video/introduction/ugc/controller.dart
@@ -463,7 +463,7 @@ class UgcIntroController extends CommonIntroController with ReloadMixin {
}
// 修改分P或番剧分集
- Future onChangeEpisode(
+ Future onChangeEpisode(
BaseEpisodeItem episode, {
bool isStein = false,
}) async {
@@ -473,7 +473,7 @@ class UgcIntroController extends CommonIntroController with ReloadMixin {
final int? cid =
episode.cid ?? await SearchHttp.ab2c(aid: aid, bvid: bvid);
if (cid == null) {
- return;
+ return false;
}
final String? cover = episode.cover;
@@ -488,7 +488,7 @@ class UgcIntroController extends CommonIntroController with ReloadMixin {
cid: cid,
cover: cover,
);
- return;
+ return false;
}
}
@@ -546,8 +546,10 @@ class UgcIntroController extends CommonIntroController with ReloadMixin {
this.cid.value = cid;
queryOnlineTotal();
+ return true;
} catch (e) {
if (kDebugMode) debugPrint('ugc onChangeEpisode: $e');
+ return false;
}
}
diff --git a/lib/pages/video/introduction/ugc/view.dart b/lib/pages/video/introduction/ugc/view.dart
index 75a94d0e6..e080731cb 100644
--- a/lib/pages/video/introduction/ugc/view.dart
+++ b/lib/pages/video/introduction/ugc/view.dart
@@ -15,6 +15,7 @@ import 'package:PiliPlus/pages/video/introduction/ugc/controller.dart';
import 'package:PiliPlus/pages/video/introduction/ugc/widgets/action_item.dart';
import 'package:PiliPlus/pages/video/introduction/ugc/widgets/page.dart';
import 'package:PiliPlus/pages/video/introduction/ugc/widgets/season.dart';
+import 'package:PiliPlus/pages/video/introduction/ugc/widgets/selectable_text.dart';
import 'package:PiliPlus/pages/video/introduction/ugc/widgets/triple_state.dart';
import 'package:PiliPlus/utils/app_scheme.dart';
import 'package:PiliPlus/utils/date_utils.dart';
@@ -327,13 +328,9 @@ class _UgcIntroPanelState extends TripleState {
),
if (videoDetail.descV2?.isNotEmpty == true) ...[
const SizedBox(height: 8),
- SelectableText.rich(
+ selectableRichText(
style: const TextStyle(height: 1.4),
- TextSpan(
- children: [
- buildContent(theme, videoDetail),
- ],
- ),
+ buildContent(theme, videoDetail),
),
],
Obx(() {
@@ -601,7 +598,7 @@ class _UgcIntroPanelState extends TripleState {
caseSensitive: false,
);
- InlineSpan buildContent(ThemeData theme, VideoDetailData content) {
+ TextSpan buildContent(ThemeData theme, VideoDetailData content) {
if (content.descV2.isNullOrEmpty) {
return const TextSpan();
}
diff --git a/lib/pages/video/introduction/ugc/widgets/selectable_text.dart b/lib/pages/video/introduction/ugc/widgets/selectable_text.dart
new file mode 100644
index 000000000..be92da753
--- /dev/null
+++ b/lib/pages/video/introduction/ugc/widgets/selectable_text.dart
@@ -0,0 +1,38 @@
+import 'package:PiliPlus/utils/utils.dart';
+import 'package:flutter/material.dart';
+
+Widget selectableText(
+ String text, {
+ TextStyle? style,
+}) {
+ if (Utils.isDesktop) {
+ return SelectionArea(
+ child: Text(
+ style: style,
+ text,
+ ),
+ );
+ }
+ return SelectableText(
+ style: style,
+ text,
+ );
+}
+
+Widget selectableRichText(
+ TextSpan textSpan, {
+ TextStyle? style,
+}) {
+ if (Utils.isDesktop) {
+ return SelectionArea(
+ child: Text.rich(
+ style: style,
+ textSpan,
+ ),
+ );
+ }
+ return SelectableText.rich(
+ style: style,
+ textSpan,
+ );
+}
diff --git a/lib/pages/whisper_detail/view.dart b/lib/pages/whisper_detail/view.dart
index b66882069..3df80ad2c 100644
--- a/lib/pages/whisper_detail/view.dart
+++ b/lib/pages/whisper_detail/view.dart
@@ -44,6 +44,11 @@ class _WhisperDetailPageState
Widget build(BuildContext context) {
final ThemeData theme = Theme.of(context);
final padding = MediaQuery.viewPaddingOf(context);
+ late final containerColor = ElevationOverlay.colorWithOverlay(
+ theme.colorScheme.surface,
+ theme.hoverColor,
+ 1,
+ );
return Scaffold(
resizeToAvoidBottomInset: false,
appBar: AppBar(
@@ -145,8 +150,11 @@ class _WhisperDetailPageState
),
),
if (_whisperDetailController.mid != null) ...[
- _buildInputView(theme),
- buildPanelContainer(theme, theme.colorScheme.onInverseSurface),
+ _buildInputView(theme, containerColor),
+ buildPanelContainer(
+ theme,
+ containerColor,
+ ),
] else
SizedBox(height: padding.bottom),
],
@@ -228,11 +236,11 @@ class _WhisperDetailPageState
);
}
- Widget _buildInputView(ThemeData theme) {
+ Widget _buildInputView(ThemeData theme, Color containerColor) {
return Container(
padding: const EdgeInsets.symmetric(vertical: 8),
decoration: BoxDecoration(
- color: theme.colorScheme.onInverseSurface,
+ color: containerColor,
borderRadius: const BorderRadius.vertical(top: Radius.circular(16)),
),
child: Row(