Merge branch 'main' into design
This commit is contained in:
@ -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;
|
||||
|
||||
@ -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 = [];
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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() {
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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() {
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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});
|
||||
|
||||
@ -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() {
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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() {
|
||||
|
||||
@ -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 =
|
||||
|
||||
@ -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 = [];
|
||||
|
||||
@ -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() {
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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 -
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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!,
|
||||
};
|
||||
}
|
||||
|
||||
@ -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');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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(
|
||||
() {
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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();
|
||||
|
||||
|
||||
@ -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';
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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()
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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)),
|
||||
),
|
||||
)
|
||||
],
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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(
|
||||
|
||||
@ -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) =>
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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(
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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>[];
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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 = [];
|
||||
|
||||
|
||||
@ -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() {
|
||||
|
||||
@ -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; // 文本
|
||||
|
||||
Reference in New Issue
Block a user