Merge branch 'main' into design

This commit is contained in:
guozhigq
2024-12-02 22:49:55 +08:00
19 changed files with 139 additions and 96 deletions

View File

@ -1,3 +1,9 @@
plugins {
id "com.android.application"
id "kotlin-android"
id "dev.flutter.flutter-gradle-plugin"
}
def localProperties = new Properties() def localProperties = new Properties()
def localPropertiesFile = rootProject.file('local.properties') def localPropertiesFile = rootProject.file('local.properties')
if (localPropertiesFile.exists()) { if (localPropertiesFile.exists()) {
@ -6,10 +12,6 @@ if (localPropertiesFile.exists()) {
} }
} }
def flutterRoot = localProperties.getProperty('flutter.sdk')
if (flutterRoot == null) {
throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
}
def flutterVersionCode = localProperties.getProperty('flutter.versionCode') def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
if (flutterVersionCode == null) { if (flutterVersionCode == null) {
@ -21,9 +23,6 @@ if (flutterVersionName == null) {
flutterVersionName = '1.0' flutterVersionName = '1.0'
} }
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
def keystorePropertiesFile = rootProject.file('key.properties') def keystorePropertiesFile = rootProject.file('key.properties')
def keystoreProperties = new Properties() def keystoreProperties = new Properties()
@ -37,8 +36,9 @@ def _keyAlias = System.getenv("KEY_ALIAS") ?: keystoreProperties["keyAlias"]
def _keyPassword = System.getenv("KEY_PASSWORD") ?: keystoreProperties["keyPassword"] def _keyPassword = System.getenv("KEY_PASSWORD") ?: keystoreProperties["keyPassword"]
android { android {
namespace "com.guozhigq.pilipala"
compileSdkVersion flutter.compileSdkVersion compileSdkVersion flutter.compileSdkVersion
ndkVersion flutter.ndkVersion ndkVersion "27.0.12077973"
compileOptions { compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8 sourceCompatibility JavaVersion.VERSION_1_8
@ -91,9 +91,6 @@ flutter {
source '../..' source '../..'
} }
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
}
ext.abiCodes = ["x86_64": 1, "armeabi-v7a": 2, "arm64-v8a": 3] ext.abiCodes = ["x86_64": 1, "armeabi-v7a": 2, "arm64-v8a": 3]
import com.android.build.OutputFile import com.android.build.OutputFile

4
android/app/proguard-rules.pro vendored Normal file
View File

@ -0,0 +1,4 @@
# missing R8 error
-dontwarn javax.annotation.Nullable
-dontwarn org.conscrypt.Conscrypt
-dontwarn org.conscrypt.OpenSSLProvider

View File

@ -1,15 +1,3 @@
buildscript {
ext.kotlin_version = '1.9.0'
repositories {
google()
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:7.2.0'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
allprojects { allprojects {
repositories { repositories {
@ -20,6 +8,15 @@ allprojects {
rootProject.buildDir = '../build' rootProject.buildDir = '../build'
subprojects { subprojects {
afterEvaluate { project ->
if (project.hasProperty('android')) {
project.android {
if (namespace == null) {
namespace project.group
}
}
}
}
project.buildDir = "${rootProject.buildDir}/${project.name}" project.buildDir = "${rootProject.buildDir}/${project.name}"
} }
subprojects { subprojects {

View File

@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-all.zip

View File

@ -1,11 +1,25 @@
include ':app' pluginManagement {
def flutterSdkPath = {
def properties = new Properties()
file("local.properties").withInputStream { properties.load(it) }
def flutterSdkPath = properties.getProperty("flutter.sdk")
assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
return flutterSdkPath
}()
def localPropertiesFile = new File(rootProject.projectDir, "local.properties") includeBuild("$flutterSdkPath/packages/flutter_tools/gradle")
def properties = new Properties()
assert localPropertiesFile.exists() repositories {
localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } google()
mavenCentral()
gradlePluginPortal()
}
}
def flutterSdkPath = properties.getProperty("flutter.sdk") plugins {
assert flutterSdkPath != null, "flutter.sdk not set in local.properties" id "dev.flutter.flutter-plugin-loader" version "1.0.0"
apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" id "com.android.application" version "8.7.2" apply false
id "org.jetbrains.kotlin.android" version "1.9.0" apply false
}
include ":app"

View File

@ -1,5 +1,4 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:pilipala/common/constants.dart'; import 'package:pilipala/common/constants.dart';
@ -183,7 +182,7 @@ class _PagesBottomSheetState extends State<PagesBottomSheet>
isFixedHeight: true, isFixedHeight: true,
); );
} else { } else {
_listObserverControllerList![widget.currentEpisodeIndex!] _listObserverControllerList![widget.currentEpisodeIndex ?? 0]
.initialIndexModel = ObserverIndexPositionModel( .initialIndexModel = ObserverIndexPositionModel(
index: currentIndex, index: currentIndex,
isFixedHeight: true, isFixedHeight: true,

View File

@ -5,6 +5,8 @@ import 'package:pilipala/plugin/pl_gallery/hero_dialog_route.dart';
import 'package:pilipala/plugin/pl_gallery/interactiveviewer_gallery.dart'; import 'package:pilipala/plugin/pl_gallery/interactiveviewer_gallery.dart';
import 'package:pilipala/utils/highlight.dart'; import 'package:pilipala/utils/highlight.dart';
import '../../utils/global_data_cache.dart';
// ignore: must_be_immutable // ignore: must_be_immutable
class HtmlRender extends StatelessWidget { class HtmlRender extends StatelessWidget {
const HtmlRender({ const HtmlRender({
@ -41,6 +43,8 @@ class HtmlRender extends StatelessWidget {
TagExtension( TagExtension(
tagsToExtend: <String>{'img'}, tagsToExtend: <String>{'img'},
builder: (ExtensionContext extensionContext) { builder: (ExtensionContext extensionContext) {
int defaultImgQuality = 10;
defaultImgQuality = GlobalDataCache.imgQuality;
try { try {
final Map<String, dynamic> attributes = final Map<String, dynamic> attributes =
extensionContext.attributes; extensionContext.attributes;
@ -99,13 +103,13 @@ class HtmlRender extends StatelessWidget {
), ),
); );
}, },
child: CachedNetworkImage(imageUrl: imgUrl), child: ClipRRect(
borderRadius: BorderRadius.circular(12),
child: CachedNetworkImage(
imageUrl: '$imgUrl@${defaultImgQuality}q.webp',
),
),
); );
// return NetworkImgLayer(
// width: isEmote ? 22 : Get.size.width - 24,
// height: isEmote ? 22 : 200,
// src: imgUrl,
// );
} catch (err) { } catch (err) {
return const SizedBox(); return const SizedBox();
} }
@ -138,6 +142,14 @@ class HtmlRender extends StatelessWidget {
textAlign: TextAlign.justify, textAlign: TextAlign.justify,
), ),
'img': Style(margin: Margins.only(top: 4, bottom: 4)), 'img': Style(margin: Margins.only(top: 4, bottom: 4)),
'figcaption': Style(
textAlign: TextAlign.center,
margin: Margins.only(top: 8, bottom: 20),
color: Theme.of(context).colorScheme.secondary,
),
'figure': Style(
margin: Margins.zero,
),
}, },
); );
} }

View File

@ -103,7 +103,7 @@ class _DynamicDetailPageState extends State<DynamicDetailPage>
if (!isOpusId) { if (!isOpusId) {
_dynamicDetailController = _dynamicDetailController =
Get.put(DynamicDetailController(oid, replyType), tag: oid.toString()); Get.put(DynamicDetailController(oid, replyType), tag: oid.toString());
_futureBuilderFuture ??= _dynamicDetailController.queryReplyList(); _futureBuilderFuture = _dynamicDetailController.queryReplyList();
} }
} }

View File

@ -122,6 +122,7 @@ class LaterController extends GetxController {
'heroTag': heroTag, 'heroTag': heroTag,
'sourceType': 'watchLater', 'sourceType': 'watchLater',
'count': laterList.length, 'count': laterList.length,
'mediaId': userInfo!.mid,
}, },
); );
} }

View File

@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:pilipala/common/widgets/network_img_layer.dart'; import 'package:pilipala/common/widgets/network_img_layer.dart';
import 'package:pilipala/models/read/opus.dart'; import 'package:pilipala/models/read/opus.dart';
import 'controller.dart'; import 'controller.dart';
import 'text_helper.dart'; import 'text_helper.dart';
@ -26,16 +27,18 @@ class _OpusPageState extends State<OpusPage> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
appBar: _buildAppBar(), appBar: _buildAppBar(),
body: SingleChildScrollView( body: CustomScrollView(
controller: controller.scrollController, controller: controller.scrollController,
child: Column( slivers: [
mainAxisAlignment: MainAxisAlignment.start, SliverList(
crossAxisAlignment: CrossAxisAlignment.start, delegate: SliverChildListDelegate(
children: [ [
_buildTitle(), _buildTitle(),
_buildFutureContent(), _buildFutureContent(),
], ],
), ),
),
],
), ),
); );
} }

View File

@ -6,6 +6,7 @@ import 'package:pilipala/models/read/opus.dart';
import 'package:pilipala/models/read/read.dart'; import 'package:pilipala/models/read/read.dart';
import 'package:pilipala/pages/opus/text_helper.dart'; import 'package:pilipala/pages/opus/text_helper.dart';
import 'package:pilipala/utils/utils.dart'; import 'package:pilipala/utils/utils.dart';
import 'controller.dart'; import 'controller.dart';
class ReadPage extends StatefulWidget { class ReadPage extends StatefulWidget {
@ -38,16 +39,18 @@ class _ReadPageState extends State<ReadPage> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
appBar: _buildAppBar(), appBar: _buildAppBar(),
body: SingleChildScrollView( body: CustomScrollView(
controller: controller.scrollController, controller: controller.scrollController,
child: Column( slivers: [
mainAxisAlignment: MainAxisAlignment.start, SliverList(
crossAxisAlignment: CrossAxisAlignment.start, delegate: SliverChildListDelegate(
children: [ [
_buildTitle(), _buildTitle(),
_buildFutureContent(), _buildFutureContent(),
], ],
), ),
),
],
), ),
); );
} }

View File

@ -624,10 +624,8 @@ class VideoDetailController extends GetxController
} }
void toggeleWatchLaterVisible(bool val) { void toggeleWatchLaterVisible(bool val) {
if (sourceType.value == 'watchLater' || if (['watchLater', 'fav', 'up_archive'].contains(sourceType.value)) {
sourceType.value == 'fav' || isWatchLaterVisible.value = val;
sourceType.value == 'up_archive') {
isWatchLaterVisible.value = !isWatchLaterVisible.value;
} }
} }

View File

@ -523,7 +523,7 @@ class VideoIntroController extends GetxController {
Get.find<VideoDetailController>(tag: heroTag); Get.find<VideoDetailController>(tag: heroTag);
/// 优先稍后再看、收藏夹 /// 优先稍后再看、收藏夹
if (videoDetailCtr.isWatchLaterVisible.value) { if (videoDetailCtr.sourceType.value != 'normal') {
episodes.addAll(videoDetailCtr.mediaList); episodes.addAll(videoDetailCtr.mediaList);
} else if (videoDetail.value.ugcSeason != null) { } else if (videoDetail.value.ugcSeason != null) {
final UgcSeason ugcSeason = videoDetail.value.ugcSeason!; final UgcSeason ugcSeason = videoDetail.value.ugcSeason!;
@ -617,6 +617,7 @@ class VideoIntroController extends GetxController {
// 播放器底栏 选集 回调 // 播放器底栏 选集 回调
void showEposideHandler() { void showEposideHandler() {
late List episodes; late List episodes;
int currentEpisodeIndex = 0;
VideoEpidoesType dataType = VideoEpidoesType.videoEpisode; VideoEpidoesType dataType = VideoEpidoesType.videoEpisode;
if (videoDetail.value.ugcSeason != null) { if (videoDetail.value.ugcSeason != null) {
dataType = VideoEpidoesType.videoEpisode; dataType = VideoEpidoesType.videoEpisode;
@ -625,6 +626,7 @@ class VideoIntroController extends GetxController {
final List<EpisodeItem> episodesList = sections[i].episodes!; final List<EpisodeItem> episodesList = sections[i].episodes!;
for (int j = 0; j < episodesList.length; j++) { for (int j = 0; j < episodesList.length; j++) {
if (episodesList[j].cid == lastPlayCid.value) { if (episodesList[j].cid == lastPlayCid.value) {
currentEpisodeIndex = i;
episodes = episodesList; episodes = episodesList;
continue; continue;
} }
@ -644,6 +646,7 @@ class VideoIntroController extends GetxController {
sheetHeight: Get.size.height, sheetHeight: Get.size.height,
isFullScreen: true, isFullScreen: true,
ugcSeason: ugcSeason, ugcSeason: ugcSeason,
currentEpisodeIndex: currentEpisodeIndex,
changeFucCall: (item, index) { changeFucCall: (item, index) {
if (dataType == VideoEpidoesType.videoEpisode) { if (dataType == VideoEpidoesType.videoEpisode) {
changeSeasonOrbangu( changeSeasonOrbangu(

View File

@ -42,23 +42,14 @@ class _SeasonPanelState extends State<SeasonPanel> {
_videoDetailController = Get.find<VideoDetailController>(tag: heroTag); _videoDetailController = Get.find<VideoDetailController>(tag: heroTag);
/// 根据 cid 找到对应集,找到对应 episodes /// 根据 cid 找到对应集,找到对应 episodes
final List<SectionItem> sections = widget.ugcSeason.sections!; getCurrentEpisodeIndex();
for (int i = 0; i < sections.length; i++) {
final List<EpisodeItem> episodesList = sections[i].episodes!;
for (int j = 0; j < episodesList.length; j++) {
if (episodesList[j].cid == cid) {
currentEpisodeIndex = i;
episodes = episodesList;
continue;
}
}
}
/// 取对应 season_id 的 episodes /// 取对应 season_id 的 episodes
getCurrentIndex(); getCurrentIndex();
_videoDetailController.cid.listen((int p0) { _videoDetailController.cid.listen((int p0) {
cid = p0; cid = p0;
getCurrentIndex(); getCurrentIndex();
getCurrentEpisodeIndex();
}); });
} }
@ -94,6 +85,21 @@ class _SeasonPanelState extends State<SeasonPanel> {
} }
} }
// 获取currentEpisodeIndex
void getCurrentEpisodeIndex() {
final List<SectionItem> sections = widget.ugcSeason.sections!;
for (int i = 0; i < sections.length; i++) {
final List<EpisodeItem> episodesList = sections[i].episodes!;
for (int j = 0; j < episodesList.length; j++) {
if (episodesList[j].cid == cid) {
currentEpisodeIndex = i;
episodes = episodesList;
continue;
}
}
}
}
Widget buildEpisodeListItem( Widget buildEpisodeListItem(
EpisodeItem episode, EpisodeItem episode,
int index, int index,

View File

@ -206,12 +206,12 @@ class _VideoDetailPageState extends State<VideoDetailPage>
vdCtr.bottomList.insert(3, BottomControlType.episode); vdCtr.bottomList.insert(3, BottomControlType.episode);
} }
} }
vdCtr.toggeleWatchLaterVisible(false);
} else { } else {
if (vdCtr.bottomList.contains(BottomControlType.episode)) { if (vdCtr.bottomList.contains(BottomControlType.episode)) {
vdCtr.bottomList.removeAt(3); vdCtr.bottomList.removeAt(3);
} }
} }
vdCtr.toggeleWatchLaterVisible(!isFullScreen);
}); });
} }
@ -554,6 +554,11 @@ class _VideoDetailPageState extends State<VideoDetailPage>
playerController: plPlayerController!, playerController: plPlayerController!,
), ),
bottomList: vdCtr.bottomList, bottomList: vdCtr.bottomList,
fullScreenCb: (bool status) {
if (vdCtr.videoDirection.value == 'vertical') {
videoHeight.value = status ? Get.size.height : verticalHeight;
}
},
showEposideCb: () => vdCtr.videoType == SearchType.video showEposideCb: () => vdCtr.videoType == SearchType.video
? videoIntroController.showEposideHandler() ? videoIntroController.showEposideHandler()
: bangumiIntroController.showEposideHandler(), : bangumiIntroController.showEposideHandler(),
@ -825,9 +830,8 @@ class _VideoDetailPageState extends State<VideoDetailPage>
/// 稍后再看列表 /// 稍后再看列表
Obx( Obx(
() => Visibility( () => Visibility(
visible: vdCtr.sourceType.value == 'watchLater' || visible: ['watchLater', 'fav', 'up_archive']
vdCtr.sourceType.value == 'fav' || .contains(vdCtr.sourceType.value),
vdCtr.sourceType.value == 'up_archive',
child: AnimatedPositioned( child: AnimatedPositioned(
duration: const Duration(milliseconds: 400), duration: const Duration(milliseconds: 400),
curve: Curves.easeInOut, curve: Curves.easeInOut,

View File

@ -85,9 +85,12 @@ class _MediaListPanelState extends State<MediaListPanel> {
AppBar( AppBar(
toolbarHeight: 45, toolbarHeight: 45,
automaticallyImplyLeading: false, automaticallyImplyLeading: false,
title: Text( title: Padding(
widget.panelTitle ?? '稍后再看', padding: const EdgeInsets.only(left: 12),
style: Theme.of(context).textTheme.titleSmall, child: Text(
widget.panelTitle ?? '稍后再看',
style: Theme.of(context).textTheme.titleSmall,
),
), ),
actions: [ actions: [
IconButton( IconButton(

View File

@ -81,7 +81,7 @@ class PlPlayerController {
final Rx<bool> _subTitleOpen = false.obs; final Rx<bool> _subTitleOpen = false.obs;
final Rx<int> _subTitleCode = (-1).obs; final Rx<int> _subTitleCode = (-1).obs;
// 默认投稿视频格式 // 默认投稿视频格式
static Rx<String> _videoType = 'archive'.obs; static String _videoType = 'archive';
final Rx<String> _direction = 'horizontal'.obs; final Rx<String> _direction = 'horizontal'.obs;
@ -127,7 +127,6 @@ class PlPlayerController {
PreferredSizeWidget? bottomControl; PreferredSizeWidget? bottomControl;
Widget? danmuWidget; Widget? danmuWidget;
RxList subtitles = [].obs; RxList subtitles = [].obs;
String videoType = 'archive';
/// 数据加载监听 /// 数据加载监听
Stream<DataStatus> get onDataStatusChanged => dataStatus.status.stream; Stream<DataStatus> get onDataStatusChanged => dataStatus.status.stream;
@ -225,7 +224,7 @@ class PlPlayerController {
Rx<int> get playerCount => _playerCount; Rx<int> get playerCount => _playerCount;
/// ///
// Rx<String> get videoType => _videoType; String get videoType => _videoType;
/// 弹幕开关 /// 弹幕开关
Rx<bool> isOpenDanmu = false.obs; Rx<bool> isOpenDanmu = false.obs;
@ -279,7 +278,7 @@ class PlPlayerController {
} }
// 添加一个私有构造函数 // 添加一个私有构造函数
PlPlayerController._internal(this.videoType) { PlPlayerController._internal() {
isOpenDanmu.value = GlobalDataCache.isOpenDanmu; isOpenDanmu.value = GlobalDataCache.isOpenDanmu;
blockTypes = GlobalDataCache.blockTypes; blockTypes = GlobalDataCache.blockTypes;
showArea = GlobalDataCache.showArea; showArea = GlobalDataCache.showArea;
@ -306,11 +305,11 @@ class PlPlayerController {
String videoType = 'archive', String videoType = 'archive',
}) { }) {
// 如果实例尚未创建,则创建一个新实例 // 如果实例尚未创建,则创建一个新实例
_instance ??= PlPlayerController._internal(videoType); _instance ??= PlPlayerController._internal();
if (videoType != 'none') { if (videoType != 'none') {
_instance!._playerCount.value += 1; _instance!._playerCount.value += 1;
_videoType.value = videoType;
} }
_videoType = videoType;
return _instance!; return _instance!;
} }

View File

@ -85,10 +85,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: audio_service name: audio_service
sha256: "4547c312a94f9cb2c48b60823fb190767cbd63454a83c73049384d5d3cba4650" sha256: "9dd5ba7e77567b290c35908b1950d61485b4dfdd3a0ac398e98cfeec04651b75"
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "0.18.13" version: "0.18.15"
audio_service_platform_interface: audio_service_platform_interface:
dependency: transitive dependency: transitive
description: description:
@ -101,18 +101,18 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: audio_service_web name: audio_service_web
sha256: "9d7d5ae5f98a5727f2580fad73062f2484f400eef6cef42919413268e62a363e" sha256: "4cdc2127cd4562b957fb49227dc58e3303fafb09bde2573bc8241b938cf759d9"
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "0.1.2" version: "0.1.3"
audio_session: audio_session:
dependency: "direct main" dependency: "direct main"
description: description:
name: audio_session name: audio_session
sha256: "6fdf255ed3af86535c96452c33ecff1245990bb25a605bfb1958661ccc3d467f" sha256: "343e83bc7809fbda2591a49e525d6b63213ade10c76f15813be9aed6657b3261"
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "0.1.18" version: "0.1.21"
audio_video_progress_bar: audio_video_progress_bar:
dependency: "direct main" dependency: "direct main"
description: description:

View File

@ -89,8 +89,8 @@ dependencies:
media_kit_libs_video: ^1.0.4 media_kit_libs_video: ^1.0.4
# 媒体通知 # 媒体通知
audio_service: ^0.18.13 audio_service: ^0.18.15
audio_session: ^0.1.18 audio_session: ^0.1.21
# 音量、亮度、屏幕控制 # 音量、亮度、屏幕控制
flutter_volume_controller: ^1.3.2 flutter_volume_controller: ^1.3.2