Merge branch 'main' into design

This commit is contained in:
guozhigq
2024-11-13 00:34:41 +08:00
97 changed files with 911 additions and 407 deletions

View File

@ -12,7 +12,7 @@ class BangumiController extends GetxController {
RxInt total = 0.obs;
int _currentPage = 1;
bool isLoadingMore = true;
Box userInfoCache = GStrorage.userInfo;
Box userInfoCache = GStorage.userInfo;
RxBool userLogin = false.obs;
late int mid;
var userInfo;

View File

@ -48,7 +48,7 @@ class BangumiIntroController extends GetxController {
RxBool hasCoin = false.obs;
// 是否收藏
RxBool hasFav = false.obs;
Box userInfoCache = GStrorage.userInfo;
Box userInfoCache = GStorage.userInfo;
bool userLogin = false;
Rx<FavFolderData> favFolderData = FavFolderData().obs;
List addMediaIdsNew = [];

View File

@ -116,7 +116,7 @@ class _BangumiInfoState extends State<BangumiInfo> {
String heroTag = Get.arguments['heroTag'];
late final BangumiIntroController bangumiIntroController;
late final VideoDetailController videoDetailCtr;
Box localCache = GStrorage.localCache;
Box localCache = GStorage.localCache;
late double sheetHeight;
int? cid;
bool isProcessing = false;

View File

@ -4,7 +4,7 @@ import 'package:pilipala/common/widgets/stat/danmu.dart';
import 'package:pilipala/common/widgets/stat/view.dart';
import 'package:pilipala/utils/storage.dart';
Box localCache = GStrorage.localCache;
Box localCache = GStorage.localCache;
late double sheetHeight;
class IntroDetail extends StatelessWidget {

View File

@ -36,7 +36,7 @@ class BangumiPanel extends StatefulWidget {
class _BangumiPanelState extends State<BangumiPanel> {
late RxInt currentIndex = (-1).obs;
final ScrollController listViewScrollCtr = ScrollController();
Box userInfoCache = GStrorage.userInfo;
Box userInfoCache = GStorage.userInfo;
dynamic userInfo;
// 默认未开通
int vipStatus = 0;

View File

@ -22,7 +22,7 @@ class _BlackListPageState extends State<BlackListPage> {
final ScrollController scrollController = ScrollController();
Future? _futureBuilderFuture;
bool _isLoadingMore = false;
Box setting = GStrorage.setting;
Box setting = GStorage.setting;
@override
void initState() {

View File

@ -32,7 +32,7 @@ class _PlDanmakuState extends State<PlDanmaku> {
late PlDanmakuController _plDanmakuController;
DanmakuController? _controller;
// bool danmuPlayStatus = true;
Box setting = GStrorage.setting;
Box setting = GStorage.setting;
late bool enableShowDanmaku;
late List blockTypes;
late double showArea;

View File

@ -50,11 +50,11 @@ class DynamicsController extends GetxController {
];
bool flag = false;
RxInt initialValue = 0.obs;
Box userInfoCache = GStrorage.userInfo;
Box userInfoCache = GStorage.userInfo;
RxBool userLogin = false.obs;
var userInfo;
RxBool isLoadingDynamic = false.obs;
Box setting = GStrorage.setting;
Box setting = GStorage.setting;
@override
void onInit() {

View File

@ -24,7 +24,7 @@ class DynamicDetailController extends GetxController {
ReplySortType _sortType = ReplySortType.time;
RxString sortTypeTitle = ReplySortType.time.titles.obs;
RxString sortTypeLabel = ReplySortType.time.labels.obs;
Box setting = GStrorage.setting;
Box setting = GStorage.setting;
RxInt replyReqCode = 200.obs;
bool isEnd = false;
@ -37,13 +37,13 @@ class DynamicDetailController extends GetxController {
acount.value =
int.parse(item!.modules!.moduleStat!.comment!.count ?? '0');
}
int deaultReplySortIndex =
int defaultReplySortIndex =
setting.get(SettingBoxKey.replySortType, defaultValue: 0);
if (deaultReplySortIndex == 2) {
if (defaultReplySortIndex == 2) {
setting.put(SettingBoxKey.replySortType, 0);
deaultReplySortIndex = 0;
defaultReplySortIndex = 0;
}
_sortType = ReplySortType.values[deaultReplySortIndex];
_sortType = ReplySortType.values[defaultReplySortIndex];
sortTypeTitle.value = _sortType.titles;
sortTypeLabel.value = _sortType.labels;
}

View File

@ -9,9 +9,7 @@ import 'package:pilipala/common/skeleton/dynamic_card.dart';
import 'package:pilipala/common/widgets/http_error.dart';
import 'package:pilipala/common/widgets/no_data.dart';
import 'package:pilipala/models/dynamics/result.dart';
import 'package:pilipala/plugin/pl_popup/index.dart';
import 'package:pilipala/utils/feed_back.dart';
import 'package:pilipala/utils/global_data_cache.dart';
import 'package:pilipala/utils/main_stream.dart';
import 'package:pilipala/utils/route_push.dart';
import 'package:pilipala/utils/storage.dart';
@ -19,7 +17,6 @@ import 'package:pilipala/utils/storage.dart';
import '../mine/controller.dart';
import 'controller.dart';
import 'widgets/dynamic_panel.dart';
import 'up_dynamic/route_panel.dart';
import 'widgets/up_panel.dart';
class DynamicsPage extends StatefulWidget {
@ -35,7 +32,7 @@ class _DynamicsPageState extends State<DynamicsPage>
final MineController mineController = Get.put(MineController());
late Future _futureBuilderFuture;
late Future _futureBuilderFutureUp;
Box userInfoCache = GStrorage.userInfo;
Box userInfoCache = GStorage.userInfo;
late ScrollController scrollController;
@override
@ -209,21 +206,7 @@ class _DynamicsPageState extends State<DynamicsPage>
return Obx(
() => UpPanel(
upData: _dynamicsController.upData.value,
onClickUpCb: (data) {
if (GlobalDataCache().enableDynamicSwitch) {
Navigator.push(
context,
PlPopupRoute(
child: OverlayPanel(
ctr: _dynamicsController,
upInfo: data,
),
),
);
} else {
_dynamicsController.onTapUp(data);
}
},
dynamicsController: _dynamicsController,
),
);
} else {

View File

@ -4,18 +4,22 @@ import 'package:get/get.dart';
import 'package:pilipala/common/widgets/network_img_layer.dart';
import 'package:pilipala/models/dynamics/up.dart';
import 'package:pilipala/models/live/item.dart';
import 'package:pilipala/plugin/pl_popup/index.dart';
import 'package:pilipala/utils/feed_back.dart';
import 'package:pilipala/utils/global_data_cache.dart';
import 'package:pilipala/utils/utils.dart';
import '../controller.dart';
import '../up_dynamic/route_panel.dart';
class UpPanel extends StatefulWidget {
final FollowUpModel upData;
final Function? onClickUpCb;
final DynamicsController dynamicsController;
const UpPanel({
super.key,
required this.upData,
this.onClickUpCb,
required this.dynamicsController,
});
@override
@ -39,7 +43,15 @@ class _UpPanelState extends State<UpPanel> {
void onClickUp(data, i) {
currentMid.value = data.mid;
widget.onClickUpCb?.call(data);
Navigator.push(
context,
PlPopupRoute(
child: OverlayPanel(
ctr: widget.dynamicsController,
upInfo: data,
),
),
).then((value) => {currentMid.value = -1});
}
void onClickUpAni(data, i) {
@ -49,7 +61,7 @@ class _UpPanelState extends State<UpPanel> {
final upLen = upList.length;
currentMid.value = data.mid;
widget.onClickUpCb?.call(data);
widget.dynamicsController.onTapUp(data);
double moveDistance = 0.0;
final totalItemsWidth = itemWidth * (upLen + liveLen);

View File

@ -6,7 +6,7 @@ import 'package:pilipala/models/fans/result.dart';
import 'package:pilipala/utils/storage.dart';
class FansController extends GetxController {
Box userInfoCache = GStrorage.userInfo;
Box userInfoCache = GStorage.userInfo;
int pn = 1;
int ps = 20;
int total = 0;

View File

@ -11,7 +11,7 @@ class FavController extends GetxController {
final ScrollController scrollController = ScrollController();
Rx<FavFolderData> favFolderData = FavFolderData().obs;
RxList<FavFolderItemData> favFolderList = <FavFolderItemData>[].obs;
Box userInfoCache = GStrorage.userInfo;
Box userInfoCache = GStorage.userInfo;
UserInfoData? userInfo;
int currentPage = 1;
int pageSize = 60;

View File

@ -11,7 +11,7 @@ import 'package:pilipala/utils/storage.dart';
/// 查看自己的关注时,可以查看分类
/// 查看其他人的关注时,只可以看全部
class FollowController extends GetxController with GetTickerProviderStateMixin {
Box userInfoCache = GStrorage.userInfo;
Box userInfoCache = GStorage.userInfo;
int pn = 1;
int ps = 20;
int total = 0;

View File

@ -12,11 +12,11 @@ class HistoryController extends GetxController {
RxList<HisListItem> historyList = <HisListItem>[].obs;
RxBool isLoadingMore = false.obs;
RxBool pauseStatus = false.obs;
Box localCache = GStrorage.localCache;
Box localCache = GStorage.localCache;
RxBool isLoading = false.obs;
RxBool enableMultiple = false.obs;
RxInt checkedCount = 0.obs;
Box userInfoCache = GStrorage.userInfo;
Box userInfoCache = GStorage.userInfo;
UserInfoData? userInfo;
@override

View File

@ -14,12 +14,12 @@ class HomeController extends GetxController with GetTickerProviderStateMixin {
late TabController tabController;
late List tabsCtrList;
late List<Widget> tabsPageList;
Box userInfoCache = GStrorage.userInfo;
Box settingStorage = GStrorage.setting;
Box userInfoCache = GStorage.userInfo;
Box settingStorage = GStorage.setting;
RxBool userLogin = false.obs;
RxString userFace = ''.obs;
var userInfo;
Box setting = GStrorage.setting;
Box setting = GStorage.setting;
late final StreamController<bool> searchBarStream =
StreamController<bool>.broadcast();
late bool hideSearchBar;

View File

@ -5,7 +5,7 @@ import 'package:hive/hive.dart';
import 'package:pilipala/common/widgets/network_img_layer.dart';
import 'package:pilipala/utils/storage.dart';
Box userInfoCache = GStrorage.userInfo;
Box userInfoCache = GStorage.userInfo;
class HomeAppBar extends StatelessWidget {
const HomeAppBar({super.key});

View File

@ -25,7 +25,7 @@ class HtmlRenderController extends GetxController {
ReplySortType _sortType = ReplySortType.time;
RxString sortTypeTitle = ReplySortType.time.titles.obs;
RxString sortTypeLabel = ReplySortType.time.labels.obs;
Box setting = GStrorage.setting;
Box setting = GStorage.setting;
@override
void onInit() {

View File

@ -13,7 +13,7 @@ class LaterController extends GetxController {
RxList<HotVideoItemModel> laterList = <HotVideoItemModel>[].obs;
int count = 0;
RxBool isLoading = false.obs;
Box userInfoCache = GStrorage.userInfo;
Box userInfoCache = GStorage.userInfo;
UserInfoData? userInfo;
@override

View File

@ -17,7 +17,7 @@ class LiveController extends GetxController {
RxInt liveFollowingCount = 0.obs;
bool flag = false;
OverlayEntry? popupDialog;
Box setting = GStrorage.setting;
Box setting = GStorage.setting;
@override
void onInit() {

View File

@ -7,7 +7,7 @@ import 'package:pilipala/utils/storage.dart';
class LiveFollowController extends GetxController {
RxInt crossAxisCount = 2.obs;
Box setting = GStrorage.setting;
Box setting = GStorage.setting;
int _currentPage = 1;
RxInt liveFollowingCount = 0.obs;
RxList<LiveFollowingItemModel> liveFollowingList =

View File

@ -33,7 +33,7 @@ class LiveRoomController extends GetxController {
int? tempCurrentQn;
late List<Map<String, dynamic>> acceptQnList;
RxString currentQnDesc = ''.obs;
Box userInfoCache = GStrorage.userInfo;
Box userInfoCache = GStorage.userInfo;
int userId = 0;
PlSocket? plSocket;
List<String> danmuHostList = [];

View File

@ -35,7 +35,7 @@ class _BottomControlState extends State<BottomControl> {
TextStyle subTitleStyle = const TextStyle(fontSize: 12);
TextStyle titleStyle = const TextStyle(fontSize: 14);
Size get preferredSize => const Size(double.infinity, kToolbarHeight);
Box localCache = GStrorage.localCache;
Box localCache = GStorage.localCache;
@override
void initState() {

View File

@ -20,12 +20,12 @@ class MainController extends GetxController {
late List<int> navBarSort;
final StreamController<bool> bottomBarStream =
StreamController<bool>.broadcast();
Box setting = GStrorage.setting;
Box setting = GStorage.setting;
DateTime? _lastPressedAt;
late bool hideTabBar;
late PageController pageController;
int selectedIndex = 0;
Box userInfoCache = GStrorage.userInfo;
Box userInfoCache = GStorage.userInfo;
dynamic userInfo;
RxBool userLogin = false.obs;
late Rx<DynamicBadgeMode> dynamicBadgeType = DynamicBadgeMode.number.obs;

View File

@ -30,7 +30,7 @@ class _MainAppState extends State<MainApp> with SingleTickerProviderStateMixin {
late MineController _mineController;
int? _lastSelectTime; //上次点击时间
Box setting = GStrorage.setting;
Box setting = GStorage.setting;
late bool enableMYBar;
@override
@ -113,14 +113,14 @@ class _MainAppState extends State<MainApp> with SingleTickerProviderStateMixin {
@override
void dispose() async {
await GStrorage.close();
await GStorage.close();
EventBus().off(EventName.loginEvent);
super.dispose();
}
@override
Widget build(BuildContext context) {
Box localCache = GStrorage.localCache;
Box localCache = GStorage.localCache;
double statusBarHeight = MediaQuery.of(context).padding.top;
double sheetHeight = MediaQuery.sizeOf(context).height -
MediaQuery.of(context).padding.top -

View File

@ -18,7 +18,7 @@ class MemberController extends GetxController {
late Map userStat;
RxString face = ''.obs;
String? heroTag;
Box userInfoCache = GStrorage.userInfo;
Box userInfoCache = GStorage.userInfo;
late int ownerMid;
// 投稿列表
RxList<VListItemModel>? archiveList = <VListItemModel>[].obs;

View File

@ -41,6 +41,7 @@ class MemberSeasonsPanel extends StatelessWidget {
'category': '1',
'mid': item.meta!.mid.toString(),
'seriesId': item.meta!.seriesId.toString(),
'seasonId': item.meta!.seasonId.toString(),
'seasonName': item.meta!.name!,
};
}

View File

@ -24,7 +24,8 @@ class MemberSeasonsController extends GetxController {
seasonId = int.parse(Get.parameters['seasonId']!);
}
if (category == '1') {
seriesId = int.parse(Get.parameters['seriesId']!);
seriesId = int.tryParse(Get.parameters['seriesId']!);
seasonId = int.tryParse(Get.parameters['seasonId']!);
}
}
@ -73,7 +74,27 @@ class MemberSeasonsController extends GetxController {
getSeasonDetail('onLoad');
}
if (category == '1') {
getSeriesDetail('onLoad');
if (seasonId != null) {
getSeasonDetail('onLoad');
}
if (seriesId != null) {
getSeriesDetail('onLoad');
}
}
}
// 下拉刷新
Future onRefresh() async {
if (category == '0') {
return getSeasonDetail('onRefresh');
}
if (category == '1') {
if (seasonId != null) {
return getSeasonDetail('onRefresh');
}
if (seriesId != null) {
return getSeriesDetail('onRefresh');
}
}
}
}

View File

@ -23,9 +23,7 @@ class _MemberSeasonsPageState extends State<MemberSeasonsPage> {
void initState() {
super.initState();
category = Get.parameters['category']!;
_futureBuilderFuture = category == '0'
? _memberSeasonsController.getSeasonDetail('onRefresh')
: _memberSeasonsController.getSeriesDetail('onRefresh');
_futureBuilderFuture = _memberSeasonsController.onRefresh();
scrollController = _memberSeasonsController.scrollController;
scrollController.addListener(
() {

View File

@ -136,6 +136,7 @@ class MessageUtils {
.replaceAll('}', '');
result[linkText] = match.group(0)!;
}
print('str: $str');
message += str;
}
} else {
@ -144,6 +145,10 @@ class MessageUtils {
}
lastMatchEnd = end;
}
// 处理剩余的未匹配部分
if (lastMatchEnd < text.length) {
message += text.substring(lastMatchEnd + 1);
}
result['message'] = message;
} else {
result['message'] = text;

View File

@ -17,8 +17,8 @@ class MineController extends GetxController {
Rx<UserInfoData> userInfo = UserInfoData().obs;
Rx<ThemeType> themeType = ThemeType.system.obs;
Rx<FavFolderData> favFolderData = FavFolderData().obs;
Box setting = GStrorage.setting;
Box userInfoCache = GStrorage.userInfo;
Box setting = GStorage.setting;
Box userInfoCache = GStorage.userInfo;
List menuList = [
{
'icon': Icons.history,

View File

@ -6,7 +6,7 @@ import 'package:pilipala/http/user.dart';
import 'package:pilipala/utils/storage.dart';
class MineEditController extends GetxController {
Box userInfoCache = GStrorage.userInfo;
Box userInfoCache = GStorage.userInfo;
final formKey = GlobalKey<FormState>();
final TextEditingController unameCtr = TextEditingController();
final TextEditingController useridCtr = TextEditingController();

View File

@ -14,7 +14,7 @@ class RankController extends GetxController with GetTickerProviderStateMixin {
late TabController tabController;
late List tabsCtrList;
late List<Widget> tabsPageList;
Box setting = GStrorage.setting;
Box setting = GStorage.setting;
late final StreamController<bool> searchBarStream =
StreamController<bool>.broadcast();

View File

@ -14,7 +14,7 @@ class RcmdController extends GetxController {
// RxList<RecVideoItemModel> webVideoList = <RecVideoItemModel>[].obs;
bool isLoadingMore = true;
OverlayEntry? popupDialog;
Box setting = GStrorage.setting;
Box setting = GStorage.setting;
RxInt crossAxisCount = 2.obs;
late bool enableSaveLastData;
late String defaultRcmdType = 'web';

View File

@ -15,7 +15,7 @@ class SSearchController extends GetxController {
RxString searchKeyWord = ''.obs;
Rx<TextEditingController> controller = TextEditingController().obs;
RxList<HotSearchItem> hotSearchList = <HotSearchItem>[].obs;
Box localCache = GStrorage.localCache;
Box localCache = GStorage.localCache;
List historyCacheList = [];
RxList historyList = [].obs;
RxList<SearchSuggestItem> searchSuggestList = <SearchSuggestItem>[].obs;
@ -23,7 +23,7 @@ class SSearchController extends GetxController {
Debouncer(delay: const Duration(milliseconds: 200)); // 设置延迟时间
String hintText = '搜索';
RxString defaultSearch = ''.obs;
Box setting = GStrorage.setting;
Box setting = GStorage.setting;
bool enableHotKey = true;
bool enableSearchSuggest = true;

View File

@ -13,9 +13,9 @@ import '../main/index.dart';
import 'widgets/select_dialog.dart';
class SettingController extends GetxController {
Box userInfoCache = GStrorage.userInfo;
Box setting = GStrorage.setting;
Box localCache = GStrorage.localCache;
Box userInfoCache = GStorage.userInfo;
Box setting = GStorage.setting;
Box localCache = GStorage.localCache;
RxBool userLogin = false.obs;
RxBool feedBackEnable = false.obs;

View File

@ -19,8 +19,8 @@ class ExtraSetting extends StatefulWidget {
}
class _ExtraSettingState extends State<ExtraSetting> {
Box setting = GStrorage.setting;
static Box localCache = GStrorage.localCache;
Box setting = GStorage.setting;
static Box localCache = GStorage.localCache;
late dynamic defaultReplySort;
late dynamic defaultDynamicType;
late dynamic enableSystemProxy;

View File

@ -13,7 +13,7 @@ class ActionMenuSetPage extends StatefulWidget {
}
class _ActionMenuSetPageState extends State<ActionMenuSetPage> {
Box setting = GStrorage.setting;
Box setting = GStorage.setting;
late List<String> actionTypeSort;
late List<Map> allLabels;

View File

@ -142,7 +142,7 @@ class _ColorSelectPageState extends State<ColorSelectPage> {
}
class ColorSelectController extends GetxController {
Box setting = GStrorage.setting;
Box setting = GStorage.setting;
RxBool dynamicColor = true.obs;
RxInt type = 0.obs;
late final List<Map<String, dynamic>> colorThemes;

View File

@ -16,7 +16,7 @@ class _SetDiaplayModeState extends State<SetDiaplayMode> {
List<DisplayMode> modes = <DisplayMode>[];
DisplayMode? active;
DisplayMode? preferred;
Box setting = GStrorage.setting;
Box setting = GStorage.setting;
final ValueNotifier<int> page = ValueNotifier<int>(0);
late final PageController controller = PageController()

View File

@ -11,7 +11,7 @@ class FontSizeSelectPage extends StatefulWidget {
}
class _FontSizeSelectPageState extends State<FontSizeSelectPage> {
Box setting = GStrorage.setting;
Box setting = GStorage.setting;
List<double> list = [0.9, 0.95, 1.0, 1.05, 1.1, 1.15, 1.2, 1.25, 1.3];
late double minsize;
late double maxSize;

View File

@ -12,7 +12,7 @@ class TabbarSetPage extends StatefulWidget {
}
class _TabbarSetPageState extends State<TabbarSetPage> {
Box settingStorage = GStrorage.setting;
Box settingStorage = GStorage.setting;
late List defaultTabs;
late List<String> tabbarSort;

View File

@ -13,7 +13,7 @@ class NavigationBarSetPage extends StatefulWidget {
}
class _NavigationbarSetPageState extends State<NavigationBarSetPage> {
Box settingStorage = GStrorage.setting;
Box settingStorage = GStorage.setting;
late List defaultNavTabs;
late List<int> navBarSort;

View File

@ -16,7 +16,7 @@ class PlayGesturePage extends StatefulWidget {
}
class _PlayGesturePageState extends State<PlayGesturePage> {
Box setting = GStrorage.setting;
Box setting = GStorage.setting;
late int fullScreenGestureMode;
@override

View File

@ -14,8 +14,8 @@ class PlaySpeedPage extends StatefulWidget {
}
class _PlaySpeedPageState extends State<PlaySpeedPage> {
Box videoStorage = GStrorage.video;
Box settingStorage = GStrorage.setting;
Box videoStorage = GStorage.video;
Box settingStorage = GStorage.setting;
late double playSpeedDefault;
late List<double> playSpeedSystem;
late double longPressSpeedDefault;

View File

@ -23,7 +23,7 @@ class PlaySetting extends StatefulWidget {
}
class _PlaySettingState extends State<PlaySetting> {
Box setting = GStrorage.setting;
Box setting = GStorage.setting;
late dynamic defaultVideoQa;
late dynamic defaultLiveQa;
late dynamic defaultAudioQa;

View File

@ -14,7 +14,7 @@ class PrivacySetting extends StatefulWidget {
class _PrivacySettingState extends State<PrivacySetting> {
bool userLogin = false;
Box userInfoCache = GStrorage.userInfo;
Box userInfoCache = GStorage.userInfo;
var userInfo;
@override

View File

@ -17,10 +17,10 @@ class RecommendSetting extends StatefulWidget {
}
class _RecommendSettingState extends State<RecommendSetting> {
Box setting = GStrorage.setting;
static Box localCache = GStrorage.localCache;
Box setting = GStorage.setting;
static Box localCache = GStorage.localCache;
late dynamic defaultRcmdType;
Box userInfoCache = GStrorage.userInfo;
Box userInfoCache = GStorage.userInfo;
late dynamic userInfo;
bool userLogin = false;
late dynamic accessKeyInfo;
@ -247,10 +247,9 @@ class _RecommendSettingState extends State<RecommendSetting> {
'* 其它(如热门视频、手动搜索、链接跳转等)均不受过滤器影响。\n'
'* 设定较严苛的条件可导致推荐项数锐减或多次请求,请酌情选择。\n'
'* 后续可能会增加更多过滤条件,敬请期待。',
style: Theme.of(context)
.textTheme
.labelSmall!
.copyWith(color: Theme.of(context).colorScheme.outline.withOpacity(0.7)),
style: Theme.of(context).textTheme.labelSmall!.copyWith(
color:
Theme.of(context).colorScheme.outline.withOpacity(0.7)),
),
)
],

View File

@ -28,7 +28,7 @@ class _StyleSettingState extends State<StyleSetting> {
final ColorSelectController colorSelectController =
Get.put(ColorSelectController());
Box setting = GStrorage.setting;
Box setting = GStorage.setting;
late int picQuality;
late ThemeType _tempThemeValue;
late dynamic defaultCustomRows;

View File

@ -19,7 +19,7 @@ class SetSelectItem extends StatefulWidget {
}
class _SetSelectItemState extends State<SetSelectItem> {
Box setting = GStrorage.setting;
Box setting = GStorage.setting;
late dynamic currentVal;
late int currentIndex;
late List menus;

View File

@ -28,7 +28,7 @@ class SetSwitchItem extends StatefulWidget {
class _SetSwitchItemState extends State<SetSwitchItem> {
// ignore: non_constant_identifier_names
Box Setting = GStrorage.setting;
Box Setting = GStorage.setting;
late bool val;
@override

View File

@ -11,7 +11,7 @@ import '../../models/user/sub_folder.dart';
class SubController extends GetxController {
final ScrollController scrollController = ScrollController();
Rx<SubFolderModelData> subFolderData = SubFolderModelData().obs;
Box userInfoCache = GStrorage.userInfo;
Box userInfoCache = GStorage.userInfo;
UserInfoData? userInfo;
int currentPage = 1;
int pageSize = 20;

View File

@ -6,11 +6,14 @@ import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:get/get.dart';
import 'package:hive/hive.dart';
import 'package:ns_danmaku/ns_danmaku.dart';
import 'package:pilipala/http/common.dart';
import 'package:pilipala/http/constants.dart';
import 'package:pilipala/http/user.dart';
import 'package:pilipala/http/video.dart';
import 'package:pilipala/models/common/reply_type.dart';
import 'package:pilipala/models/common/search_type.dart';
import 'package:pilipala/models/sponsor_block/segment.dart';
import 'package:pilipala/models/sponsor_block/segment_type.dart';
import 'package:pilipala/models/video/later.dart';
import 'package:pilipala/models/video/play/quality.dart';
import 'package:pilipala/models/video/play/url.dart';
@ -68,9 +71,9 @@ class VideoDetailController extends GetxController
RxBool enableHA = false.obs;
/// 本地存储
Box userInfoCache = GStrorage.userInfo;
Box localCache = GStrorage.localCache;
Box setting = GStrorage.setting;
Box userInfoCache = GStorage.userInfo;
Box localCache = GStorage.localCache;
Box setting = GStorage.setting;
RxInt oid = 0.obs;
// 评论id 请求楼中楼评论使用
@ -120,6 +123,8 @@ class VideoDetailController extends GetxController
RxBool isWatchLaterVisible = false.obs;
RxString watchLaterTitle = ''.obs;
RxInt watchLaterCount = 0.obs;
List<SegmentDataModel> skipSegments = <SegmentDataModel>[];
int? lastPosition;
@override
void onInit() {
@ -188,6 +193,11 @@ class VideoDetailController extends GetxController
tabCtr.addListener(() {
onTabChanged();
});
/// 仅投稿视频skip
if (videoType == SearchType.video) {
querySkipSegments();
}
}
showReplyReplyPanel(oid, fRpid, firstFloor, currentReply, loadMore) {
@ -305,6 +315,7 @@ class VideoDetailController extends GetxController
plPlayerController.headerControl = headerControl;
plPlayerController.subtitles.value = subtitles;
onPositionChanged();
}
// 视频链接
@ -706,6 +717,53 @@ class VideoDetailController extends GetxController
isWatchLaterVisible.value = tabCtr.index == 0;
}
// 获取sponsorBlock数据
Future querySkipSegments() async {
var res = await CommonHttp.querySkipSegments(bvid: bvid);
if (res['status']) {
/// TODO 根据segmentType过滤数据
skipSegments = res['data'] ?? [];
}
}
// 监听视频进度
void onPositionChanged() async {
final List<SegmentDataModel> sponsorSkipSegments = skipSegments
.where((e) => e.category!.value == SegmentType.sponsor.value)
.toList();
if (sponsorSkipSegments.isEmpty) {
return;
}
plPlayerController.videoPlayerController?.stream.position
.listen((Duration position) async {
final int positionMs = position.inSeconds;
// 如果当前秒与上次处理的秒相同,则直接返回
if (lastPosition != null && lastPosition! == positionMs) {
return;
}
lastPosition = positionMs;
for (SegmentDataModel segment in sponsorSkipSegments) {
try {
final segmentStart = segment.segment!.first.toInt();
final segmentEnd = segment.segment!.last.toInt();
/// 只有顺序播放时才skip跳转时间点不会skip
if (positionMs == segmentStart && !segment.isSkip) {
await plPlayerController.videoPlayerController
?.seek(Duration(seconds: segmentEnd));
segment.isSkip = true;
SmartDialog.showToast('已跳过${segment.category!.label}片段');
}
} catch (err) {
SmartDialog.showToast('skipSegments error: $err');
}
}
});
}
@override
void onClose() {
super.onClose();

View File

@ -41,7 +41,7 @@ class VideoIntroController extends GetxController {
RxBool hasFav = false.obs;
// 是否不喜欢
RxBool hasDisLike = false.obs;
Box userInfoCache = GStrorage.userInfo;
Box userInfoCache = GStorage.userInfo;
bool userLogin = false;
Rx<FavFolderData> favFolderData = FavFolderData().obs;
List addMediaIdsNew = [];
@ -63,6 +63,7 @@ class VideoIntroController extends GetxController {
PersistentBottomSheetController? bottomSheetController;
late bool enableRelatedVideo;
UgcSeason? ugcSeason;
RxList<Part> pages = <Part>[].obs;
@override
void onInit() {
@ -84,18 +85,20 @@ class VideoIntroController extends GetxController {
}
// 获取视频简介&分p
Future queryVideoIntro() async {
Future queryVideoIntro({cover}) async {
var result = await VideoHttp.videoIntro(bvid: bvid);
if (result['status']) {
videoDetail.value = result['data']!;
ugcSeason = result['data']!.ugcSeason;
if (videoDetail.value.pages!.isNotEmpty && lastPlayCid.value == 0) {
lastPlayCid.value = videoDetail.value.pages!.first.cid!;
pages.value = result['data']!.pages!;
lastPlayCid.value = videoDetail.value.cid!;
if (pages.isNotEmpty) {
lastPlayCid.value = pages.first.cid!;
}
final VideoDetailController videoDetailCtr =
Get.find<VideoDetailController>(tag: heroTag);
videoDetailCtr.tabs.value = ['简介', '评论 ${result['data']?.stat?.reply}'];
videoDetailCtr.cover.value = result['data'].pic ?? '';
videoDetailCtr.cover.value = cover ?? result['data'].pic ?? '';
// 获取到粉丝数再返回
await queryUserStat();
}
@ -470,8 +473,7 @@ class VideoIntroController extends GetxController {
videoReplyCtr.queryReplyList(type: 'init');
} catch (_) {}
this.bvid = bvid;
lastPlayCid.value = cid;
await queryVideoIntro();
await queryVideoIntro(cover: cover);
}
void startTimer() {
@ -521,9 +523,8 @@ class VideoIntroController extends GetxController {
final List<EpisodeItem> episodesList = sections[i].episodes!;
episodes.addAll(episodesList);
}
} else if (videoDetail.value.pages != null) {
} else if (pages.isNotEmpty) {
isPages = true;
final List<Part> pages = videoDetail.value.pages!;
episodes.addAll(pages);
}
@ -621,10 +622,9 @@ class VideoIntroController extends GetxController {
}
}
}
if (videoDetail.value.pages != null &&
videoDetail.value.pages!.length > 1) {
if (pages.length > 1) {
dataType = VideoEpidoesType.videoPart;
episodes = videoDetail.value.pages!;
episodes = pages;
}
DrawerUtils.showRightDialog(

View File

@ -137,8 +137,8 @@ class _VideoInfoState extends State<VideoInfo> with TickerProviderStateMixin {
late String heroTag;
late final VideoIntroController videoIntroController;
late final VideoDetailController videoDetailCtr;
final Box<dynamic> localCache = GStrorage.localCache;
final Box<dynamic> setting = GStrorage.setting;
final Box<dynamic> localCache = GStorage.localCache;
final Box<dynamic> setting = GStorage.setting;
late double sheetHeight;
late final dynamic owner;
late int mid;
@ -404,27 +404,18 @@ class _VideoInfoState extends State<VideoInfo> with TickerProviderStateMixin {
Obx(
() => SeasonPanel(
ugcSeason: widget.videoDetail!.ugcSeason!,
cid: videoIntroController.lastPlayCid.value != 0
? videoIntroController.lastPlayCid.value
: widget.videoDetail!.pages!.first.cid,
cid: videoIntroController.lastPlayCid.value,
sheetHeight: videoDetailCtr.sheetHeight.value,
changeFuc: (bvid, cid, aid, cover) =>
videoIntroController.changeSeasonOrbangu(
bvid,
cid,
aid,
cover,
),
changeFuc: videoIntroController.changeSeasonOrbangu,
videoIntroCtr: videoIntroController,
),
)
],
// 合集 videoEpisode
if (widget.videoDetail!.pages != null &&
widget.videoDetail!.pages!.length > 1) ...[
if (videoIntroController.pages.length > 1) ...[
Obx(
() => PagesPanel(
pages: widget.videoDetail!.pages!,
pages: videoIntroController.pages,
cid: videoIntroController.lastPlayCid.value,
sheetHeight: videoDetailCtr.sheetHeight.value,
changeFuc: (cid, cover) =>

View File

@ -16,7 +16,7 @@ class FavPanel extends StatefulWidget {
}
class _FavPanelState extends State<FavPanel> {
final Box<dynamic> localCache = GStrorage.localCache;
final Box<dynamic> localCache = GStorage.localCache;
late Future _futureBuilderFuture;
@override

View File

@ -18,7 +18,7 @@ class GroupPanel extends StatefulWidget {
}
class _GroupPanelState extends State<GroupPanel> {
final Box<dynamic> localCache = GStrorage.localCache;
final Box<dynamic> localCache = GStorage.localCache;
late Future _futureBuilderFuture;
late List<MemberTagItemModel> tagsList;
bool showDefault = true;

View File

@ -3,7 +3,6 @@ import 'dart:math';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:pilipala/models/video_detail_res.dart';
import 'package:pilipala/pages/video/detail/index.dart';
import 'package:pilipala/pages/video/detail/introduction/index.dart';
import '../../../../../common/pages_bottom_sheet.dart';
import '../../../../../models/common/video_episode_type.dart';
@ -32,25 +31,26 @@ class _PagesPanelState extends State<PagesPanel> {
late int cid;
late RxInt currentIndex = (-1).obs;
final String heroTag = Get.arguments['heroTag'];
late VideoDetailController _videoDetailController;
final ScrollController listViewScrollCtr = ScrollController();
late PersistentBottomSheetController? _bottomSheetController;
PersistentBottomSheetController? _bottomSheetController;
@override
void initState() {
super.initState();
cid = widget.cid;
episodes = widget.pages;
_videoDetailController = Get.find<VideoDetailController>(tag: heroTag);
currentIndex.value = episodes.indexWhere((Part e) => e.cid == cid);
scrollToIndex();
_videoDetailController.cid.listen((int p0) {
updateCurrentIndexAndScroll();
widget.videoIntroCtr.lastPlayCid.listen((int p0) {
cid = p0;
currentIndex.value = episodes.indexWhere((Part e) => e.cid == cid);
scrollToIndex();
updateCurrentIndexAndScroll();
});
}
void updateCurrentIndexAndScroll() {
currentIndex.value = widget.pages.indexWhere((Part e) => e.cid == cid);
scrollToIndex();
}
@override
void dispose() {
listViewScrollCtr.dispose();
@ -60,7 +60,10 @@ class _PagesPanelState extends State<PagesPanel> {
void changeFucCall(item, i) async {
widget.changeFuc?.call(item.cid, item.cover);
currentIndex.value = i;
_bottomSheetController?.close();
cid = item.cid;
if (_bottomSheetController != null) {
_bottomSheetController?.close();
}
scrollToIndex();
}
@ -112,7 +115,7 @@ class _PagesPanelState extends State<PagesPanel> {
widget.videoIntroCtr.bottomSheetController =
_bottomSheetController = EpisodeBottomSheet(
currentCid: cid,
episodes: episodes,
episodes: widget.pages,
changeFucCall: changeFucCall,
sheetHeight: widget.sheetHeight,
dataType: VideoEpidoesType.videoPart,

View File

@ -33,6 +33,7 @@ class _SeasonPanelState extends State<SeasonPanel> {
final String heroTag = Get.arguments['heroTag'];
late VideoDetailController _videoDetailController;
late PersistentBottomSheetController? _bottomSheetController;
int currentEpisodeIndex = -1;
@override
void initState() {
@ -41,13 +42,12 @@ class _SeasonPanelState extends State<SeasonPanel> {
_videoDetailController = Get.find<VideoDetailController>(tag: heroTag);
/// 根据 cid 找到对应集,找到对应 episodes
/// 有多个episodes时只显示其中一个
/// TODO 同时显示多个合集
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;
}
@ -55,10 +55,10 @@ class _SeasonPanelState extends State<SeasonPanel> {
}
/// 取对应 season_id 的 episodes
currentIndex.value = episodes.indexWhere((EpisodeItem e) => e.cid == cid);
getCurrentIndex();
_videoDetailController.cid.listen((int p0) {
cid = p0;
currentIndex.value = episodes.indexWhere((EpisodeItem e) => e.cid == cid);
getCurrentIndex();
});
}
@ -73,6 +73,23 @@ class _SeasonPanelState extends State<SeasonPanel> {
_bottomSheetController?.close();
}
// 获取currentIndex
void getCurrentIndex() {
currentIndex.value = episodes.indexWhere((EpisodeItem e) => e.cid == cid);
final List<SectionItem> sections = widget.ugcSeason.sections!;
if (sections.length == 1 && sections.first.type == 1) {
final List<EpisodeItem> episodesList = sections.first.episodes!;
for (int i = 0; i < episodesList.length; i++) {
for (int j = 0; j < episodesList[i].pages!.length; j++) {
if (episodesList[i].pages![j].cid == cid) {
currentIndex.value = i;
continue;
}
}
}
}
}
Widget buildEpisodeListItem(
EpisodeItem episode,
int index,
@ -125,6 +142,8 @@ class _SeasonPanelState extends State<SeasonPanel> {
sheetHeight: widget.sheetHeight,
dataType: VideoEpidoesType.videoEpisode,
ugcSeason: widget.ugcSeason,
currentEpisodeIndex: currentEpisodeIndex,
currentIndex: currentIndex.value,
).show(context);
},
child: Padding(

View File

@ -32,20 +32,20 @@ class VideoReplyController extends GetxController {
RxString sortTypeTitle = ReplySortType.time.titles.obs;
RxString sortTypeLabel = ReplySortType.time.labels.obs;
Box setting = GStrorage.setting;
Box setting = GStorage.setting;
RxInt replyReqCode = 200.obs;
bool isEnd = false;
@override
void onInit() {
super.onInit();
int deaultReplySortIndex =
int defaultReplySortIndex =
setting.get(SettingBoxKey.replySortType, defaultValue: 0) as int;
if (deaultReplySortIndex == 2) {
if (defaultReplySortIndex == 2) {
setting.put(SettingBoxKey.replySortType, 0);
deaultReplySortIndex = 0;
defaultReplySortIndex = 0;
}
_sortType = ReplySortType.values[deaultReplySortIndex];
_sortType = ReplySortType.values[defaultReplySortIndex];
sortTypeTitle.value = _sortType.titles;
sortTypeLabel.value = _sortType.labels;
}

View File

@ -26,7 +26,7 @@ import 'package:pilipala/utils/utils.dart';
import 'reply_save.dart';
import 'zan.dart';
Box setting = GStrorage.setting;
Box setting = GStorage.setting;
class ReplyItem extends StatelessWidget {
const ReplyItem({
@ -235,32 +235,33 @@ class ReplyItem extends StatelessWidget {
// title
Container(
margin: const EdgeInsets.only(top: 10, left: 45, right: 6, bottom: 4),
child: !replySave
? LayoutBuilder(builder:
(BuildContext context, BoxConstraints boxConstraints) {
String text = replyItem?.content?.message ?? '';
bool didExceedMaxLines = false;
final double maxWidth = boxConstraints.maxWidth;
TextPainter? textPainter;
final int maxLines =
replyItem!.content!.isText! && replyLevel == '1'
? 6
: 999;
try {
textPainter = TextPainter(
text: TextSpan(text: text),
maxLines: maxLines,
textDirection: Directionality.of(context),
);
textPainter.layout(maxWidth: maxWidth);
didExceedMaxLines = textPainter.didExceedMaxLines;
} catch (e) {
debugPrint('Error while measuring text: $e');
didExceedMaxLines = false;
}
return replyContent(context, didExceedMaxLines, textPainter);
})
: replyContent(context, false, null),
child: Text.rich(
overflow: TextOverflow.ellipsis,
maxLines:
replyLevel == '1' && replyItem!.content!.isText! ? 5 : 999,
style: const TextStyle(height: 1.75),
TextSpan(
children: [
if (replyItem!.isTop!)
const WidgetSpan(
alignment: PlaceholderAlignment.top,
child: PBadge(
text: 'TOP',
size: 'small',
stack: 'normal',
type: 'line',
fs: 9,
),
),
buildContent(
context,
replyItem!,
replyReply,
null,
),
],
),
),
),
// 操作区域
bottonAction(context, replyItem!.replyControl, replySave),
@ -281,36 +282,6 @@ class ReplyItem extends StatelessWidget {
);
}
Widget replyContent(
BuildContext context, bool? didExceedMaxLines, TextPainter? textPainter) {
return Text.rich(
style: const TextStyle(height: 1.75),
TextSpan(
children: [
if (replyItem!.isTop!)
const WidgetSpan(
alignment: PlaceholderAlignment.top,
child: PBadge(
text: 'TOP',
size: 'small',
stack: 'normal',
type: 'line',
fs: 9,
),
),
buildContent(
context,
replyItem!,
replyReply,
null,
didExceedMaxLines ?? false,
textPainter,
),
],
),
);
}
// 感谢、回复、复制
Widget bottonAction(BuildContext context, replyControl, replySave) {
ColorScheme colorScheme = Theme.of(context).colorScheme;
@ -493,8 +464,12 @@ class ReplyItemRow extends StatelessWidget {
fs: 9,
),
),
buildContent(context, replies![i], replyReply,
replyItem, false, null),
buildContent(
context,
replies![i],
replyReply,
replyItem,
),
],
),
),
@ -540,8 +515,6 @@ InlineSpan buildContent(
replyItem,
replyReply,
fReplyItem,
bool didExceedMaxLines,
TextPainter? textPainter,
) {
final String routePath = Get.currentRoute;
bool isVideoPage = routePath.startsWith('/video');
@ -553,25 +526,6 @@ InlineSpan buildContent(
final content = replyItem.content;
final List<InlineSpan> spanChilds = <InlineSpan>[];
if (didExceedMaxLines && content.message != '') {
final textSize = textPainter!.size;
var position = textPainter.getPositionForOffset(
Offset(
textSize.width,
textSize.height,
),
);
final endOffset = textPainter.getOffsetBefore(position.offset);
if (endOffset != null && endOffset > 0) {
content.message = content.message.substring(0, endOffset);
} else {
content.message = content.message.substring(0, position.offset);
}
} else {
content.message = content.message2;
}
// 投票
if (content.vote.isNotEmpty) {
content.message.splitMapJoin(RegExp(r"\{vote:.*?\}"),
@ -921,17 +875,6 @@ InlineSpan buildContent(
}
}
if (didExceedMaxLines) {
spanChilds.add(
TextSpan(
text: '\n查看更多',
style: TextStyle(
color: colorScheme.primary,
),
),
);
}
// 图片渲染
if (content.pictures.isNotEmpty) {
final List<String> picList = <String>[];

View File

@ -42,7 +42,7 @@ class VideoReplyReplyPanel extends StatefulWidget {
class _VideoReplyReplyPanelState extends State<VideoReplyReplyPanel> {
late VideoReplyReplyController _videoReplyReplyController;
late AnimationController replyAnimationCtl;
final Box<dynamic> localCache = GStrorage.localCache;
final Box<dynamic> localCache = GStorage.localCache;
Future? _futureBuilderFuture;
late ScrollController scrollController;

View File

@ -54,8 +54,8 @@ class _VideoDetailPageState extends State<VideoDetailPage>
Rx<PlayerStatus> playerStatus = PlayerStatus.playing.obs;
double doubleOffset = 0;
final Box<dynamic> localCache = GStrorage.localCache;
final Box<dynamic> setting = GStrorage.setting;
final Box<dynamic> localCache = GStorage.localCache;
final Box<dynamic> setting = GStorage.setting;
late double statusBarHeight;
final double videoHeight = Get.size.width * 9 / 16;
late Future _futureBuilderFuture;
@ -101,7 +101,9 @@ class _VideoDetailPageState extends State<VideoDetailPage>
videoSourceInit();
appbarStreamListen();
fullScreenStatusListener();
if (autoPlayEnable) {
fullScreenStatusListener();
}
if (Platform.isAndroid) {
floating = vdCtr.floating!;
}
@ -137,7 +139,7 @@ class _VideoDetailPageState extends State<VideoDetailPage>
autoEnterPip(status: status);
if (status == PlayerStatus.completed) {
// 结束播放退出全屏
if (autoExitFullcreen) {
if (autoExitFullcreen && plPlayerController!.isFullScreen.value) {
plPlayerController!.triggerFullScreen(status: false);
}
shutdownTimerService.handleWaitingFinished();
@ -184,6 +186,7 @@ class _VideoDetailPageState extends State<VideoDetailPage>
await vdCtr.playerInit(autoplay: true);
plPlayerController = vdCtr.plPlayerController;
plPlayerController!.addStatusLister(playerListener);
fullScreenStatusListener();
vdCtr.autoPlay.value = true;
vdCtr.isShowCover.value = false;
isShowing.value = true;

View File

@ -52,8 +52,8 @@ class _HeaderControlState extends State<HeaderControl> {
static const TextStyle subTitleStyle = TextStyle(fontSize: 12);
static const TextStyle titleStyle = TextStyle(fontSize: 14);
Size get preferredSize => const Size(double.infinity, kToolbarHeight);
final Box<dynamic> localCache = GStrorage.localCache;
final Box<dynamic> videoStorage = GStrorage.video;
final Box<dynamic> localCache = GStorage.localCache;
final Box<dynamic> videoStorage = GStorage.video;
late List<double> speedsList;
double buttonSpace = 8;
RxBool isFullScreen = false.obs;

View File

@ -20,7 +20,7 @@ class WhisperDetailController extends GetxController {
//表情转换图片规则
RxList<dynamic> eInfos = [].obs;
final TextEditingController replyContentController = TextEditingController();
Box userInfoCache = GStrorage.userInfo;
Box userInfoCache = GStorage.userInfo;
List emoteList = [];
List<String> picList = [];

View File

@ -30,7 +30,7 @@ class _WhisperDetailPageState extends State<WhisperDetailPage>
late double emoteHeight = 230.0;
double keyboardHeight = 0.0; // 键盘高度
RxString toolbarType = ''.obs;
Box userInfoCache = GStrorage.userInfo;
Box userInfoCache = GStorage.userInfo;
@override
void initState() {

View File

@ -56,8 +56,7 @@ class ChatItem extends StatelessWidget {
@override
Widget build(BuildContext context) {
bool isOwner =
item.senderUid == GStrorage.userInfo.get('userInfoCache').mid;
bool isOwner = item.senderUid == GStorage.userInfo.get('userInfoCache').mid;
bool isPic = item.msgType == MsgType.pic.value; // 图片
bool isText = item.msgType == MsgType.text.value; // 文本