diff --git a/lib/common/widgets/animated_dialog.dart b/lib/common/widgets/animated_dialog.dart deleted file mode 100644 index 9a8d641e..00000000 --- a/lib/common/widgets/animated_dialog.dart +++ /dev/null @@ -1,79 +0,0 @@ -import 'package:PiliPlus/common/widgets/no_splash_factory.dart'; -import 'package:PiliPlus/common/widgets/overlay_pop.dart'; -import 'package:PiliPlus/models/model_video.dart'; -import 'package:flutter/material.dart'; - -class AnimatedDialog extends StatefulWidget { - const AnimatedDialog({ - super.key, - required this.videoItem, - required this.closeFn, - }); - - final BaseVideoItemModel videoItem; - final Function closeFn; - - @override - State createState() => AnimatedDialogState(); -} - -class AnimatedDialogState extends State - with SingleTickerProviderStateMixin { - late AnimationController controller; - late Animation opacityAnimation; - late Animation scaleAnimation; - - @override - void initState() { - super.initState(); - - controller = AnimationController( - vsync: this, duration: const Duration(milliseconds: 255)); - opacityAnimation = Tween(begin: 0.0, end: 0.6) - .animate(CurvedAnimation(parent: controller, curve: Curves.linear)); - scaleAnimation = CurvedAnimation(parent: controller, curve: Curves.linear); - controller.addListener(listener); - controller.forward(); - } - - void listener() { - setState(() {}); - } - - @override - void dispose() { - controller.removeListener(listener); - controller.dispose(); - super.dispose(); - } - - void closeFn() async { - await controller.reverse(); - widget.closeFn(); - } - - @override - Widget build(BuildContext context) { - return Material( - color: Colors.black.withOpacity(opacityAnimation.value), - child: InkWell( - highlightColor: Colors.transparent, - splashColor: Colors.transparent, - splashFactory: NoSplashFactory(), - onTap: closeFn, - child: Center( - child: FadeTransition( - opacity: scaleAnimation, - child: ScaleTransition( - scale: scaleAnimation, - child: OverlayPop( - videoItem: widget.videoItem, - closeFn: closeFn, - ), - ), - ), - ), - ), - ); - } -} diff --git a/lib/common/widgets/app_expansion_panel_list.dart b/lib/common/widgets/app_expansion_panel_list.dart deleted file mode 100644 index b0fc16f0..00000000 --- a/lib/common/widgets/app_expansion_panel_list.dart +++ /dev/null @@ -1,351 +0,0 @@ -import 'package:flutter/material.dart'; - -const double _kPanelHeaderCollapsedHeight = kMinInteractiveDimension; - -class _SaltedKey extends LocalKey { - const _SaltedKey(this.salt, this.value); - - final S salt; - final V value; - - @override - bool operator ==(Object other) { - if (other.runtimeType != runtimeType) return false; - return other is _SaltedKey && - other.salt == salt && - other.value == value; - } - - @override - int get hashCode => Object.hash(runtimeType, salt, value); - - @override - String toString() { - final String saltString = S == String ? "<'$salt'>" : '<$salt>'; - final String valueString = V == String ? "<'$value'>" : '<$value>'; - return '[$saltString $valueString]'; - } -} - -class AppExpansionPanelList extends StatefulWidget { - /// Creates an expansion panel list widget. The [expansionCallback] is - /// triggered when an expansion panel expand/collapse button is pushed. - /// - /// The [children] and [animationDuration] arguments must not be null. - const AppExpansionPanelList({ - super.key, - required this.children, - this.expansionCallback, - this.animationDuration = kThemeAnimationDuration, - this.expandedHeaderPadding = EdgeInsets.zero, - this.dividerColor, - this.elevation = 2, - }) : _allowOnlyOnePanelOpen = false, - initialOpenPanelValue = null; - - /// The children of the expansion panel list. They are laid out in a similar - /// fashion to [ListBody]. - final List children; - - /// The callback that gets called whenever one of the expand/collapse buttons - /// is pressed. The arguments passed to the callback are the index of the - /// pressed panel and whether the panel is currently expanded or not. - /// - /// If AppExpansionPanelList.radio is used, the callback may be called a - /// second time if a different panel was previously open. The arguments - /// passed to the second callback are the index of the panel that will close - /// and false, marking that it will be closed. - /// - /// For AppExpansionPanelList, the callback needs to setState when it's notified - /// about the closing/opening panel. On the other hand, the callback for - /// AppExpansionPanelList.radio is simply meant to inform the parent widget of - /// changes, as the radio panels' open/close states are managed internally. - /// - /// This callback is useful in order to keep track of the expanded/collapsed - /// panels in a parent widget that may need to react to these changes. - final ExpansionPanelCallback? expansionCallback; - - /// The duration of the expansion animation. - final Duration animationDuration; - - // Whether multiple panels can be open simultaneously - final bool _allowOnlyOnePanelOpen; - - /// The value of the panel that initially begins open. (This value is - /// only used when initializing with the [AppExpansionPanelList.radio] - /// constructor.) - final Object? initialOpenPanelValue; - - /// The padding that surrounds the panel header when expanded. - /// - /// By default, 16px of space is added to the header vertically (above and below) - /// during expansion. - final EdgeInsets expandedHeaderPadding; - - /// Defines color for the divider when [AppExpansionPanel.isExpanded] is false. - /// - /// If `dividerColor` is null, then [DividerThemeData.color] is used. If that - /// is null, then [ThemeData.dividerColor] is used. - final Color? dividerColor; - - /// Defines elevation for the [AppExpansionPanel] while it's expanded. - /// - /// By default, the value of elevation is 2. - final double elevation; - - @override - State createState() => _AppExpansionPanelListState(); -} - -class _AppExpansionPanelListState extends State { - ExpansionPanelRadio? _currentOpenPanel; - - @override - void initState() { - super.initState(); - if (widget._allowOnlyOnePanelOpen) { - assert(_allIdentifiersUnique(), - 'All ExpansionPanelRadio identifier values must be unique.'); - if (widget.initialOpenPanelValue != null) { - _currentOpenPanel = searchPanelByValue( - widget.children.cast(), - widget.initialOpenPanelValue); - } - } - } - - @override - void didUpdateWidget(AppExpansionPanelList oldWidget) { - super.didUpdateWidget(oldWidget); - - if (widget._allowOnlyOnePanelOpen) { - assert(_allIdentifiersUnique(), - 'All ExpansionPanelRadio identifier values must be unique.'); - // If the previous widget was non-radio AppExpansionPanelList, initialize the - // open panel to widget.initialOpenPanelValue - if (!oldWidget._allowOnlyOnePanelOpen) { - _currentOpenPanel = searchPanelByValue( - widget.children.cast(), - widget.initialOpenPanelValue); - } - } else { - _currentOpenPanel = null; - } - } - - bool _allIdentifiersUnique() { - final Map identifierMap = {}; - for (final ExpansionPanelRadio child - in widget.children.cast()) { - identifierMap[child.value] = true; - } - return identifierMap.length == widget.children.length; - } - - bool _isChildExpanded(int index) { - if (widget._allowOnlyOnePanelOpen) { - final ExpansionPanelRadio radioWidget = - widget.children[index] as ExpansionPanelRadio; - return _currentOpenPanel?.value == radioWidget.value; - } - return widget.children[index].isExpanded; - } - - void _handlePressed(bool isExpanded, int index) { - widget.expansionCallback?.call(index, isExpanded); - - if (widget._allowOnlyOnePanelOpen) { - final ExpansionPanelRadio pressedChild = - widget.children[index] as ExpansionPanelRadio; - - // If another ExpansionPanelRadio was already open, apply its - // expansionCallback (if any) to false, because it's closing. - for (int childIndex = 0; - childIndex < widget.children.length; - childIndex += 1) { - final ExpansionPanelRadio child = - widget.children[childIndex] as ExpansionPanelRadio; - if (widget.expansionCallback != null && - childIndex != index && - child.value == _currentOpenPanel?.value) { - widget.expansionCallback?.call(childIndex, false); - } - } - - setState(() { - _currentOpenPanel = isExpanded ? null : pressedChild; - }); - } - } - - ExpansionPanelRadio? searchPanelByValue( - List panels, Object? value) { - for (final ExpansionPanelRadio panel in panels) { - if (panel.value == value) return panel; - } - return null; - } - - @override - Widget build(BuildContext context) { - assert( - kElevationToShadow.containsKey(widget.elevation), - 'Invalid value for elevation. See the kElevationToShadow constant for' - ' possible elevation values.', - ); - - final List items = []; - - for (int index = 0; index < widget.children.length; index += 1) { - //todo: Uncomment to add gap between selected panels - /*if (_isChildExpanded(index) && index != 0 && !_isChildExpanded(index - 1)) - items.add(MaterialGap(key: _SaltedKey(context, index * 2 - 1)));*/ - - final AppExpansionPanel child = widget.children[index]; - final Widget headerWidget = child.headerBuilder( - context, - _isChildExpanded(index), - ); - - Widget? expandIconContainer = ExpandIcon( - isExpanded: _isChildExpanded(index), - onPressed: !child.canTapOnHeader - ? (bool isExpanded) => _handlePressed(isExpanded, index) - : null, - ); - if (!child.canTapOnHeader) { - final MaterialLocalizations localizations = - MaterialLocalizations.of(context); - expandIconContainer = Semantics( - label: _isChildExpanded(index) - ? localizations.expandedIconTapHint - : localizations.collapsedIconTapHint, - container: true, - child: expandIconContainer, - ); - } - - final iconContainer = child.iconBuilder; - if (iconContainer != null) { - expandIconContainer = iconContainer( - expandIconContainer, - _isChildExpanded(index), - ); - } - - Widget header = Row( - children: [ - Expanded( - child: AnimatedContainer( - duration: widget.animationDuration, - curve: Curves.fastOutSlowIn, - margin: _isChildExpanded(index) - ? widget.expandedHeaderPadding - : EdgeInsets.zero, - child: ConstrainedBox( - constraints: const BoxConstraints( - minHeight: _kPanelHeaderCollapsedHeight), - child: headerWidget, - ), - ), - ), - if (expandIconContainer != null) expandIconContainer, - ], - ); - if (child.canTapOnHeader) { - header = MergeSemantics( - child: InkWell( - onTap: () => _handlePressed(_isChildExpanded(index), index), - child: header, - ), - ); - } - items.add( - MaterialSlice( - key: _SaltedKey(context, index * 2), - color: child.backgroundColor, - child: Column( - children: [ - header, - AnimatedCrossFade( - firstChild: Container(height: 0.0), - secondChild: child.body, - firstCurve: - const Interval(0.0, 0.6, curve: Curves.fastOutSlowIn), - secondCurve: - const Interval(0.4, 1.0, curve: Curves.fastOutSlowIn), - sizeCurve: Curves.fastOutSlowIn, - crossFadeState: _isChildExpanded(index) - ? CrossFadeState.showSecond - : CrossFadeState.showFirst, - duration: widget.animationDuration, - ), - ], - ), - ), - ); - - if (_isChildExpanded(index) && index != widget.children.length - 1) { - items.add(MaterialGap( - key: _SaltedKey(context, index * 2 + 1))); - } - } - - return MergeableMaterial( - hasDividers: true, - dividerColor: widget.dividerColor, - elevation: widget.elevation, - children: items, - ); - } -} - -typedef ExpansionPanelIconBuilder = Widget? Function( - Widget child, - bool isExpanded, -); - -class AppExpansionPanel { - /// Creates an expansion panel to be used as a child for [ExpansionPanelList]. - /// See [ExpansionPanelList] for an example on how to use this widget. - /// - /// The [headerBuilder], [body], and [isExpanded] arguments must not be null. - AppExpansionPanel({ - required this.headerBuilder, - required this.body, - this.iconBuilder, - this.isExpanded = false, - this.canTapOnHeader = false, - this.backgroundColor, - }); - - /// The widget builder that builds the expansion panels' header. - final ExpansionPanelHeaderBuilder headerBuilder; - - /// The widget builder that builds the expansion panels' icon. - /// - /// If not pass any function, then default icon will be displayed. - /// - /// If builder function return null, then icon will not displayed. - final ExpansionPanelIconBuilder? iconBuilder; - - /// The body of the expansion panel that's displayed below the header. - /// - /// This widget is visible only when the panel is expanded. - final Widget body; - - /// Whether the panel is expanded. - /// - /// Defaults to false. - final bool isExpanded; - - /// Whether tapping on the panel's header will expand/collapse it. - /// - /// Defaults to false. - final bool canTapOnHeader; - - /// Defines the background color of the panel. - /// - /// Defaults to [ThemeData.cardColor]. - final Color? backgroundColor; -} diff --git a/lib/common/widgets/appbar.dart b/lib/common/widgets/appbar.dart deleted file mode 100644 index fa376c50..00000000 --- a/lib/common/widgets/appbar.dart +++ /dev/null @@ -1,32 +0,0 @@ -import 'package:flutter/material.dart'; - -class AppBarWidget extends StatelessWidget implements PreferredSizeWidget { - const AppBarWidget({ - required this.child, - required this.controller, - required this.visible, - super.key, - }); - - final PreferredSizeWidget child; - final AnimationController controller; - final bool visible; - - @override - Size get preferredSize => child.preferredSize; - - @override - Widget build(BuildContext context) { - visible ? controller.reverse() : controller.forward(); - return SlideTransition( - position: Tween( - begin: Offset.zero, - end: const Offset(0, -1), - ).animate(CurvedAnimation( - parent: controller, - curve: Curves.easeInOutBack, - )), - child: child, - ); - } -} diff --git a/lib/common/widgets/content_container.dart b/lib/common/widgets/content_container.dart deleted file mode 100644 index 66f76713..00000000 --- a/lib/common/widgets/content_container.dart +++ /dev/null @@ -1,47 +0,0 @@ -import 'package:flutter/material.dart'; - -class ContentContainer extends StatelessWidget { - final Widget? contentWidget; - final Widget? bottomWidget; - final bool isScrollable; - final Clip? childClipBehavior; - - const ContentContainer({ - super.key, - this.contentWidget, - this.bottomWidget, - this.isScrollable = true, - this.childClipBehavior, - }); - - @override - Widget build(BuildContext context) { - return LayoutBuilder( - builder: (BuildContext context, BoxConstraints constraints) { - return SingleChildScrollView( - clipBehavior: childClipBehavior ?? Clip.hardEdge, - physics: isScrollable ? null : const NeverScrollableScrollPhysics(), - child: ConstrainedBox( - constraints: constraints.copyWith( - minHeight: constraints.maxHeight, - maxHeight: double.infinity, - ), - child: IntrinsicHeight( - child: Column( - children: [ - if (contentWidget != null) - Expanded( - child: contentWidget!, - ) - else - const Spacer(), - if (bottomWidget != null) bottomWidget!, - ], - ), - ), - ), - ); - }, - ); - } -} diff --git a/lib/common/widgets/episode_panel.dart b/lib/common/widgets/episode_panel.dart index 34f0423f..a940b7d9 100644 --- a/lib/common/widgets/episode_panel.dart +++ b/lib/common/widgets/episode_panel.dart @@ -468,10 +468,7 @@ class _EpisodePanelState extends CommonSlidePageState Utils.dateFormat(pubdate), maxLines: 1, style: TextStyle( - fontSize: Theme.of(context) - .textTheme - .labelSmall! - .fontSize, + fontSize: 12, height: 1, color: Theme.of(context).colorScheme.outline, overflow: TextOverflow.clip, diff --git a/lib/common/widgets/live_card.dart b/lib/common/widgets/live_card.dart deleted file mode 100644 index 910b1334..00000000 --- a/lib/common/widgets/live_card.dart +++ /dev/null @@ -1,142 +0,0 @@ -import 'package:flutter/material.dart'; -import '../../utils/utils.dart'; -import '../constants.dart'; -import 'network_img_layer.dart'; - -class LiveCard extends StatelessWidget { - final dynamic liveItem; - - const LiveCard({ - super.key, - required this.liveItem, - }); - - @override - Widget build(BuildContext context) { - final String heroTag = Utils.makeHeroTag(liveItem.roomid); - - return Card( - elevation: 0, - clipBehavior: Clip.hardEdge, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(0), - side: BorderSide( - color: Theme.of(context).dividerColor.withOpacity(0.08), - ), - ), - margin: EdgeInsets.zero, - child: InkWell( - onTap: () {}, - child: Column( - children: [ - AspectRatio( - aspectRatio: StyleString.aspectRatio, - child: LayoutBuilder(builder: - (BuildContext context, BoxConstraints boxConstraints) { - final double maxWidth = boxConstraints.maxWidth; - final double maxHeight = boxConstraints.maxHeight; - return Stack( - children: [ - Hero( - tag: heroTag, - child: NetworkImgLayer( - src: liveItem.cover as String, - type: 'emote', - width: maxWidth, - height: maxHeight, - ), - ), - Positioned( - left: 0, - right: 0, - bottom: 0, - child: AnimatedOpacity( - opacity: 1, - duration: const Duration(milliseconds: 200), - child: liveStat(context), - ), - ), - ], - ); - }), - ), - liveContent(context) - ], - ), - ), - ); - } - - Widget liveContent(context) { - return Padding( - // 多列 - padding: const EdgeInsets.fromLTRB(8, 8, 6, 7), - // 单列 - // padding: const EdgeInsets.fromLTRB(14, 10, 4, 8), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - liveItem.title as String, - textAlign: TextAlign.start, - style: const TextStyle(fontSize: 13), - maxLines: 2, - overflow: TextOverflow.ellipsis, - ), - SizedBox( - width: double.infinity, - child: Text( - liveItem.uname as String, - maxLines: 1, - style: TextStyle( - fontSize: Theme.of(context).textTheme.labelMedium!.fontSize, - color: Theme.of(context).colorScheme.outline, - ), - ), - ), - ], - ), - ); - } - - Widget liveStat(context) { - return Container( - height: 45, - padding: const EdgeInsets.only(top: 22, left: 8, right: 8), - decoration: const BoxDecoration( - gradient: LinearGradient( - begin: Alignment.topCenter, - end: Alignment.bottomCenter, - colors: [ - Colors.transparent, - Colors.black54, - ], - tileMode: TileMode.mirror, - ), - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - // Row( - // children: [ - // StatView( - // theme: 'white', - // view: view, - // ), - // const SizedBox(width: 8), - // StatDanMu( - // theme: 'white', - // danmu: danmaku, - // ), - // ], - // ), - Text( - liveItem.online.toString(), - style: const TextStyle(fontSize: 11, color: Colors.white), - ) - ], - ), - ); - } -} diff --git a/lib/common/widgets/no_splash_factory.dart b/lib/common/widgets/no_splash_factory.dart deleted file mode 100644 index f8ba95e0..00000000 --- a/lib/common/widgets/no_splash_factory.dart +++ /dev/null @@ -1,34 +0,0 @@ -import 'package:flutter/material.dart'; - -class NoSplashFactory extends InteractiveInkFeatureFactory { - @override - InteractiveInkFeature create( - {required MaterialInkController controller, - required RenderBox referenceBox, - required Offset position, - required Color color, - required TextDirection textDirection, - bool containedInkWell = false, - RectCallback? rectCallback, - BorderRadius? borderRadius, - ShapeBorder? customBorder, - double? radius, - VoidCallback? onRemoved}) { - return _NoInteractiveInkFeature( - controller: controller, - referenceBox: referenceBox, - color: color, - onRemoved: onRemoved); - } -} - -class _NoInteractiveInkFeature extends InteractiveInkFeature { - @override - void paintFeature(Canvas canvas, Matrix4 transform) {} - _NoInteractiveInkFeature({ - required super.controller, - required super.referenceBox, - required super.color, - super.onRemoved, - }); -} diff --git a/lib/common/widgets/overlay_pop.dart b/lib/common/widgets/overlay_pop.dart deleted file mode 100644 index 8a5a161c..00000000 --- a/lib/common/widgets/overlay_pop.dart +++ /dev/null @@ -1,99 +0,0 @@ -import 'dart:math'; - -import 'package:PiliPlus/grpc/app/card/v1/card.pb.dart' as card; -import 'package:flutter/material.dart'; -import 'package:get/get.dart'; -import '../../utils/download.dart'; -import '../constants.dart'; -import 'network_img_layer.dart'; - -class OverlayPop extends StatelessWidget { - const OverlayPop({super.key, this.videoItem, this.closeFn}); - - final dynamic videoItem; - final Function? closeFn; - - @override - Widget build(BuildContext context) { - final double imgWidth = min(Get.height, Get.width) - 8 * 2; - return Container( - margin: const EdgeInsets.symmetric(horizontal: 8), - width: imgWidth, - decoration: BoxDecoration( - color: Theme.of(context).colorScheme.surface, - borderRadius: BorderRadius.circular(10.0), - ), - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Stack( - children: [ - NetworkImgLayer( - width: imgWidth, - height: imgWidth / StyleString.aspectRatio, - src: videoItem is card.Card - ? (videoItem as card.Card).smallCoverV5.base.cover - : videoItem.pic, - quality: 100, - ), - Positioned( - right: 8, - top: 8, - child: Container( - width: 30, - height: 30, - decoration: BoxDecoration( - color: Colors.black.withOpacity(0.3), - borderRadius: - const BorderRadius.all(Radius.circular(20))), - child: IconButton( - tooltip: '关闭', - style: ButtonStyle( - padding: WidgetStateProperty.all(EdgeInsets.zero), - ), - onPressed: () => closeFn?.call(), - icon: const Icon( - Icons.close, - size: 18, - color: Colors.white, - ), - ), - ), - ), - ], - ), - Padding( - padding: const EdgeInsets.fromLTRB(12, 10, 8, 10), - child: Row( - children: [ - Expanded( - child: SelectableText( - videoItem is card.Card - ? (videoItem as card.Card).smallCoverV5.base.title - : videoItem.title, - ), - ), - const SizedBox(width: 4), - IconButton( - tooltip: '保存封面图', - onPressed: () async { - await DownloadUtils.downloadImg( - context, - [ - videoItem is card.Card - ? (videoItem as card.Card).smallCoverV5.base.cover - : videoItem.pic ?? videoItem.cover - ], - ); - closeFn?.call(); - }, - icon: const Icon(Icons.download, size: 20), - ) - ], - )), - ], - ), - ); - } -} diff --git a/lib/common/widgets/sliver_header.dart b/lib/common/widgets/sliver_header.dart deleted file mode 100644 index 13877a53..00000000 --- a/lib/common/widgets/sliver_header.dart +++ /dev/null @@ -1,24 +0,0 @@ -import 'package:flutter/material.dart'; - -class SliverHeaderDelegate extends SliverPersistentHeaderDelegate { - SliverHeaderDelegate({required this.height, required this.child}); - - final double height; - final Widget child; - - @override - Widget build( - BuildContext context, double shrinkOffset, bool overlapsContent) { - return child; - } - - @override - double get maxExtent => height; - - @override - double get minExtent => height; - - @override - bool shouldRebuild(covariant SliverPersistentHeaderDelegate oldDelegate) => - true; -} diff --git a/lib/common/widgets/stat/stat.dart b/lib/common/widgets/stat/stat.dart index a83904dd..83ba3db2 100644 --- a/lib/common/widgets/stat/stat.dart +++ b/lib/common/widgets/stat/stat.dart @@ -5,7 +5,6 @@ abstract class _StatItemBase extends StatelessWidget { final BuildContext context; final Object value; final String? theme; - final String? size; final Color? textColor; final double iconSize; @@ -13,7 +12,6 @@ abstract class _StatItemBase extends StatelessWidget { required this.context, required this.value, this.theme, - this.size, this.textColor, this.iconSize = 13, }); @@ -42,7 +40,7 @@ abstract class _StatItemBase extends StatelessWidget { const SizedBox(width: 2), Text( Utils.numFormat(value), - style: TextStyle(fontSize: size == 'medium' ? 12 : 11, color: color), + style: TextStyle(fontSize: 12, color: color), overflow: TextOverflow.clip, semanticsLabel: semanticsLabel, ) @@ -59,7 +57,6 @@ class StatView extends _StatItemBase { required super.value, this.goto, super.theme, - super.size, super.textColor, }) : super(iconSize: 13); @@ -81,7 +78,6 @@ class StatDanMu extends _StatItemBase { required super.context, required super.value, super.theme, - super.size, super.textColor, }) : super(iconSize: 14); diff --git a/lib/common/widgets/video_card_h.dart b/lib/common/widgets/video_card_h.dart index 46058ded..c19e0d2c 100644 --- a/lib/common/widgets/video_card_h.dart +++ b/lib/common/widgets/video_card_h.dart @@ -42,9 +42,6 @@ class VideoCardH extends StatelessWidget { final int aid = videoItem.aid!; final String bvid = videoItem.bvid!; String type = 'video'; - // try { - // type = videoItem.type; - // } catch (_) {} if (videoItem is SearchVideoItemModel) { var typeOrNull = (videoItem as SearchVideoItemModel).type; if (typeOrNull?.isNotEmpty == true) { @@ -59,11 +56,6 @@ class VideoCardH extends StatelessWidget { Semantics( label: Utils.videoItemSemantics(videoItem), excludeSemantics: true, - // customSemanticsActions: { - // for (var item in actions) - // CustomSemanticsAction( - // label: item.title.isEmpty ? 'label' : item.title): item.onTap!, - // }, child: InkWell( onLongPress: () { if (onLongPress != null) { @@ -181,10 +173,6 @@ class VideoCardH extends StatelessWidget { bottom: 6.0, type: 'primary', ), - // if (videoItem.rcmdReason != null && - // videoItem.rcmdReason.content != '') - // pBadge(videoItem.rcmdReason.content, context, - // 6.0, 6.0, null, null), ], ); }, @@ -261,36 +249,15 @@ class VideoCardH extends StatelessWidget { overflow: TextOverflow.ellipsis, ), ), - // const Spacer(), - // if (videoItem.rcmdReason != null && - // videoItem.rcmdReason.content != '') - // Container( - // padding: const EdgeInsets.symmetric(vertical: 2, horizontal: 5), - // decoration: BoxDecoration( - // borderRadius: BorderRadius.circular(4), - // border: Border.all( - // color: Theme.of(context).colorScheme.surfaceTint), - // ), - // child: Text( - // videoItem.rcmdReason.content, - // style: TextStyle( - // fontSize: 9, - // color: Theme.of(context).colorScheme.surfaceTint), - // ), - // ), - // const SizedBox(height: 4), if (showOwner || showPubdate) - Expanded( - flex: 0, - child: Text( - "$pubdate ${showOwner ? videoItem.owner.name : ''}", - maxLines: 1, - style: TextStyle( - fontSize: Theme.of(context).textTheme.labelSmall!.fontSize, - height: 1, - color: Theme.of(context).colorScheme.outline, - overflow: TextOverflow.clip, - ), + Text( + "$pubdate ${showOwner ? videoItem.owner.name : ''}", + maxLines: 1, + style: TextStyle( + fontSize: 12, + height: 1, + color: Theme.of(context).colorScheme.outline, + overflow: TextOverflow.clip, ), ), const SizedBox(height: 3), diff --git a/lib/common/widgets/video_card_h_grpc.dart b/lib/common/widgets/video_card_h_grpc.dart index cc6c5c94..3b41d3a3 100644 --- a/lib/common/widgets/video_card_h_grpc.dart +++ b/lib/common/widgets/video_card_h_grpc.dart @@ -29,107 +29,84 @@ class VideoCardHGrpc extends StatelessWidget { @override Widget build(BuildContext context) { final int aid = videoItem.smallCoverV5.base.args.aid.toInt(); - // final String bvid = IdUtils.av2bv(aid); String type = 'video'; - // try { - // type = videoItem.type; - // } catch (_) {} - // List actions = - // VideoCustomActions(videoItem, context).actions; final String heroTag = Utils.makeHeroTag(aid); - return Stack(children: [ - Semantics( - // label: Utils.videoItemSemantics(videoItem), - excludeSemantics: true, - // customSemanticsActions: { - // for (var item in actions) - // CustomSemanticsAction(label: item.title): item.onTap!, - // }, - child: InkWell( - borderRadius: BorderRadius.circular(12), - onLongPress: () => imageSaveDialog( - context: context, - title: videoItem.smallCoverV5.base.title, - cover: videoItem.smallCoverV5.base.cover, - ), - onTap: () async { - if (type == 'ketang') { - SmartDialog.showToast('课堂视频暂不支持播放'); - return; - } - try { - PiliScheme.routePushFromUrl(videoItem.smallCoverV5.base.uri); - } catch (err) { - SmartDialog.showToast(err.toString()); - } - }, - child: LayoutBuilder( - builder: (BuildContext context, BoxConstraints boxConstraints) { - return Row( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - AspectRatio( - aspectRatio: StyleString.aspectRatio, - child: LayoutBuilder( - builder: (BuildContext context, - BoxConstraints boxConstraints) { - final double maxWidth = boxConstraints.maxWidth; - final double maxHeight = boxConstraints.maxHeight; - return Stack( - children: [ - Hero( - tag: heroTag, - child: NetworkImgLayer( - src: videoItem.smallCoverV5.base.cover, - width: maxWidth, - height: maxHeight, - ), - ), - if (videoItem - .smallCoverV5.coverRightText1.isNotEmpty) - PBadge( - text: Utils.timeFormat( - videoItem.smallCoverV5.coverRightText1), - right: 6.0, - bottom: 6.0, - type: 'gray', - ), - if (type != 'video') - PBadge( - text: type, - left: 6.0, - bottom: 6.0, - type: 'primary', - ), - // if (videoItem.rcmdReason != null && - // videoItem.rcmdReason.content != '') - // pBadge(videoItem.rcmdReason.content, context, - // 6.0, 6.0, null, null), - ], - ); - }, - ), - ), - const SizedBox(width: 10), - videoContent(context), - ], - ); + return Stack( + children: [ + Semantics( + excludeSemantics: true, + child: InkWell( + borderRadius: BorderRadius.circular(12), + onLongPress: () => imageSaveDialog( + context: context, + title: videoItem.smallCoverV5.base.title, + cover: videoItem.smallCoverV5.base.cover, + ), + onTap: () async { + if (type == 'ketang') { + SmartDialog.showToast('课堂视频暂不支持播放'); + return; + } + try { + PiliScheme.routePushFromUrl(videoItem.smallCoverV5.base.uri); + } catch (err) { + SmartDialog.showToast(err.toString()); + } }, + child: LayoutBuilder( + builder: (BuildContext context, BoxConstraints boxConstraints) { + return Row( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + AspectRatio( + aspectRatio: StyleString.aspectRatio, + child: LayoutBuilder( + builder: (BuildContext context, + BoxConstraints boxConstraints) { + final double maxWidth = boxConstraints.maxWidth; + final double maxHeight = boxConstraints.maxHeight; + return Stack( + children: [ + Hero( + tag: heroTag, + child: NetworkImgLayer( + src: videoItem.smallCoverV5.base.cover, + width: maxWidth, + height: maxHeight, + ), + ), + if (videoItem + .smallCoverV5.coverRightText1.isNotEmpty) + PBadge( + text: Utils.timeFormat( + videoItem.smallCoverV5.coverRightText1), + right: 6.0, + bottom: 6.0, + type: 'gray', + ), + if (type != 'video') + PBadge( + text: type, + left: 6.0, + bottom: 6.0, + type: 'primary', + ), + ], + ); + }, + ), + ), + const SizedBox(width: 10), + videoContent(context), + ], + ); + }, + ), ), ), - ), - // if (source == 'normal') - // Positioned( - // bottom: 0, - // right: 0, - // child: VideoPopupMenu( - // size: 29, - // iconSize: 17, - // actions: actions, - // ), - // ), - ]); + ], + ); } Widget videoContent(context) { @@ -150,24 +127,6 @@ class VideoCardHGrpc extends StatelessWidget { overflow: TextOverflow.ellipsis, ), ), - // const Spacer(), - // if (videoItem.rcmdReason != null && - // videoItem.rcmdReason.content != '') - // Container( - // padding: const EdgeInsets.symmetric(vertical: 2, horizontal: 5), - // decoration: BoxDecoration( - // borderRadius: BorderRadius.circular(4), - // border: Border.all( - // color: Theme.of(context).colorScheme.surfaceTint), - // ), - // child: Text( - // videoItem.rcmdReason.content, - // style: TextStyle( - // fontSize: 9, - // color: Theme.of(context).colorScheme.surfaceTint), - // ), - // ), - // const SizedBox(height: 4), if (showOwner || showPubdate) Text( videoItem.smallCoverV5.rightDesc1, @@ -190,24 +149,6 @@ class VideoCardHGrpc extends StatelessWidget { overflow: TextOverflow.clip, ), ), - // Row( - // children: [ - // if (showView) ...[ - // StatView( - // theme: 'gray', - // view: videoItem.stat.view as int, - // ), - // const SizedBox(width: 8), - // ], - // if (showDanmaku) - // StatDanMu( - // theme: 'gray', - // danmu: videoItem.stat.danmu as int, - // ), - // const Spacer(), - // if (source == 'normal') const SizedBox(width: 24), - // ], - // ), ], ), ); diff --git a/lib/common/widgets/video_card_h_member_video.dart b/lib/common/widgets/video_card_h_member_video.dart index 9aa364eb..eb0f5954 100644 --- a/lib/common/widgets/video_card_h_member_video.dart +++ b/lib/common/widgets/video_card_h_member_video.dart @@ -80,7 +80,6 @@ class VideoCardHMemberVideo extends StatelessWidget { children: [ NetworkImgLayer( src: videoItem.cover, - // videoItem.season?['cover'] ?? videoItem.cover, width: maxWidth, height: maxHeight, ), @@ -191,7 +190,6 @@ class VideoCardHMemberVideo extends StatelessWidget { children: [ Expanded( child: Text( - // videoItem.season?['title'] ?? videoItem.title ?? '', videoItem.title, textAlign: TextAlign.start, style: TextStyle( @@ -215,7 +213,7 @@ class VideoCardHMemberVideo extends StatelessWidget { : videoItem.publishTimeText ?? '', maxLines: 1, style: TextStyle( - fontSize: Theme.of(context).textTheme.labelMedium!.fontSize, + fontSize: 12, height: 1, color: Theme.of(context).colorScheme.outline, overflow: TextOverflow.clip, @@ -227,15 +225,12 @@ class VideoCardHMemberVideo extends StatelessWidget { StatView( context: context, theme: 'gray', - // view: videoItem.season?['view_content'] ?? - // videoItem.viewContent, value: videoItem.stat.viewStr, ), const SizedBox(width: 8), StatDanMu( context: context, theme: 'gray', - // danmu: videoItem.season?['danmaku'] ?? videoItem.danmaku, value: videoItem.stat.danmuStr, ), ], diff --git a/lib/common/widgets/video_card_v.dart b/lib/common/widgets/video_card_v.dart index beea8629..d2c51547 100644 --- a/lib/common/widgets/video_card_v.dart +++ b/lib/common/widgets/video_card_v.dart @@ -94,10 +94,6 @@ class VideoCardV extends StatelessWidget { Semantics( label: Utils.videoItemSemantics(videoItem), excludeSemantics: true, - // customSemanticsActions: { - // for (var item in actions) - // CustomSemanticsAction(label: item.title): item.onTap!, - // }, child: Card( clipBehavior: Clip.hardEdge, margin: EdgeInsets.zero, @@ -109,6 +105,7 @@ class VideoCardV extends StatelessWidget { cover: videoItem.pic, ), child: Column( + crossAxisAlignment: CrossAxisAlignment.start, children: [ AspectRatio( aspectRatio: StyleString.aspectRatio, @@ -129,8 +126,6 @@ class VideoCardV extends StatelessWidget { size: 'small', type: 'gray', text: Utils.timeFormat(videoItem.duration), - // semanticsLabel: - // '时长${Utils.durationReadFormat(Utils.timeFormat(videoItem.duration))}', ) ], ); @@ -162,23 +157,17 @@ class VideoCardV extends StatelessWidget { padding: const EdgeInsets.fromLTRB(6, 5, 6, 5), child: Column( crossAxisAlignment: CrossAxisAlignment.start, - // mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Row( - children: [ - Expanded( - child: Text("${videoItem.title}\n", - // semanticsLabel: "${videoItem.title}", - maxLines: 2, - overflow: TextOverflow.ellipsis, - style: const TextStyle( - height: 1.38, - )), + Expanded( + child: Text( + "${videoItem.title}\n", + maxLines: 2, + overflow: TextOverflow.ellipsis, + style: const TextStyle( + height: 1.38, ), - ], + ), ), - const Spacer(), - // const SizedBox(height: 2), videoStat(context), Row( children: [ @@ -224,7 +213,6 @@ class VideoCardV extends StatelessWidget { flex: 1, child: Text( videoItem.owner.name.toString(), - // semanticsLabel: "Up主:${videoItem.owner.name}", maxLines: 1, overflow: TextOverflow.clip, style: TextStyle( @@ -260,46 +248,32 @@ class VideoCardV extends StatelessWidget { theme: 'gray', value: videoItem.stat.danmuStr, ), - if (videoItem is RecVideoItemModel) ...[ + if (videoItem is RecVideoItemModel) ...[ const Spacer(), - Expanded( - flex: 0, - child: Text.rich( - maxLines: 1, - TextSpan( - style: TextStyle( - fontSize: - Theme.of(context).textTheme.labelSmall!.fontSize, - color: Theme.of(context) - .colorScheme - .outline - .withOpacity(0.8), - ), - text: - Utils.formatTimestampToRelativeTime(videoItem.pubdate)), - )), + Text.rich( + maxLines: 1, + TextSpan( + style: TextStyle( + fontSize: Theme.of(context).textTheme.labelSmall!.fontSize, + color: Theme.of(context).colorScheme.outline.withOpacity(0.8), + ), + text: Utils.formatTimestampToRelativeTime(videoItem.pubdate)), + ), const SizedBox(width: 2), - ], - if (videoItem is RecVideoItemAppModel && + ] else if (videoItem is RecVideoItemAppModel && videoItem.desc != null && - videoItem.desc!.contains(' · ')) ...[ + videoItem.desc!.contains(' · ')) ...[ const Spacer(), - Expanded( - flex: 0, - child: Text.rich( - maxLines: 1, - TextSpan( - style: TextStyle( - fontSize: - Theme.of(context).textTheme.labelSmall!.fontSize, - color: Theme.of(context) - .colorScheme - .outline - .withOpacity(0.8), - ), - text: Utils.shortenChineseDateString( - videoItem.desc!.split(' · ').last)), - )), + Text.rich( + maxLines: 1, + TextSpan( + style: TextStyle( + fontSize: Theme.of(context).textTheme.labelSmall!.fontSize, + color: Theme.of(context).colorScheme.outline.withOpacity(0.8), + ), + text: Utils.shortenChineseDateString( + videoItem.desc!.split(' · ').last)), + ), const SizedBox(width: 2), ] ], diff --git a/lib/common/widgets/video_card_v_member_home.dart b/lib/common/widgets/video_card_v_member_home.dart index 5aec8282..7fcac04c 100644 --- a/lib/common/widgets/video_card_v_member_home.dart +++ b/lib/common/widgets/video_card_v_member_home.dart @@ -40,55 +40,11 @@ class VideoCardVMemberHome extends StatelessWidget { Utils.toViewPage( 'bvid=${bvid ?? IdUtils.av2bv(int.parse(aid!))}&cid=$cid', arguments: { - // 'videoItem': videoItem, 'pic': videoItem.cover, 'heroTag': heroTag, }, ); break; - // 动态 - // case 'picture': - // try { - // String dynamicType = 'picture'; - // String uri = videoItem.uri; - // String id = ''; - // if (videoItem.uri.startsWith('bilibili://article/')) { - // // https://www.bilibili.com/read/cv27063554 - // dynamicType = 'read'; - // RegExp regex = RegExp(r'\d+'); - // Match match = regex.firstMatch(videoItem.uri)!; - // String matchedNumber = match.group(0)!; - // videoItem.param = int.parse(matchedNumber); - // id = 'cv${videoItem.param}'; - // } - // if (uri.startsWith('http')) { - // String path = Uri.parse(uri).path; - // if (isStringNumeric(path.split('/')[1])) { - // // 请求接口 - // var res = - // await DynamicsHttp.dynamicDetail(id: path.split('/')[1]); - // if (res['status']) { - // Get.toNamed('/dynamicDetail', arguments: { - // 'item': res['data'], - // 'floor': 1, - // 'action': 'detail' - // }); - // } else { - // SmartDialog.showToast(res['msg']); - // } - // return; - // } - // } - // Get.toNamed('/htmlRender', parameters: { - // 'url': uri, - // 'title': videoItem.title, - // 'id': id, - // 'dynamicType': dynamicType - // }); - // } catch (err) { - // SmartDialog.showToast(err.toString()); - // } - // break; default: SmartDialog.showToast(goto); Utils.handleWebview(videoItem.uri ?? ''); @@ -97,70 +53,57 @@ class VideoCardVMemberHome extends StatelessWidget { @override Widget build(BuildContext context) { - // List actions = - // VideoCustomActions(videoItem, context).actions; - return Stack(children: [ - Semantics( - // label: Utils.videoItemSemantics(videoItem), - excludeSemantics: true, - // customSemanticsActions: { - // for (var item in actions) - // CustomSemanticsAction(label: item.title): item.onTap!, - // }, - child: Card( - clipBehavior: Clip.hardEdge, - margin: EdgeInsets.zero, - child: InkWell( - onTap: () => onPushDetail(Utils.makeHeroTag(videoItem.bvid)), - onLongPress: () => imageSaveDialog( - context: context, - title: videoItem.title, - cover: videoItem.cover, - ), - child: Column( - children: [ - AspectRatio( - aspectRatio: StyleString.aspectRatio, - child: LayoutBuilder(builder: (context, boxConstraints) { - double maxWidth = boxConstraints.maxWidth; - double maxHeight = boxConstraints.maxHeight; - return Stack( - children: [ - NetworkImgLayer( - src: videoItem.cover, - width: maxWidth, - height: maxHeight, - ), - if ((videoItem.duration ?? -1) > 0) - PBadge( - bottom: 6, - right: 7, - size: 'small', - type: 'gray', - text: Utils.timeFormat(videoItem.duration), - // semanticsLabel: - // '时长${Utils.durationReadFormat(Utils.timeFormat(videoItem.duration))}', - ) - ], - ); - }), - ), - videoContent(context, videoItem) - ], + return Stack( + children: [ + Semantics( + excludeSemantics: true, + child: Card( + clipBehavior: Clip.hardEdge, + margin: EdgeInsets.zero, + child: InkWell( + onTap: () => onPushDetail(Utils.makeHeroTag(videoItem.bvid)), + onLongPress: () => imageSaveDialog( + context: context, + title: videoItem.title, + cover: videoItem.cover, + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + AspectRatio( + aspectRatio: StyleString.aspectRatio, + child: LayoutBuilder( + builder: (context, boxConstraints) { + double maxWidth = boxConstraints.maxWidth; + double maxHeight = boxConstraints.maxHeight; + return Stack( + children: [ + NetworkImgLayer( + src: videoItem.cover, + width: maxWidth, + height: maxHeight, + ), + if ((videoItem.duration ?? -1) > 0) + PBadge( + bottom: 6, + right: 7, + size: 'small', + type: 'gray', + text: Utils.timeFormat(videoItem.duration), + ) + ], + ); + }, + ), + ), + videoContent(context, videoItem) + ], + ), ), ), ), - ), - // if (videoItem.goto == 'av') - // Positioned( - // right: -5, - // bottom: -2, - // child: VideoPopupMenu( - // size: 29, - // iconSize: 17, - // actions: actions, - // )), - ]); + ], + ); } } @@ -168,136 +111,14 @@ Widget videoContent(BuildContext context, Item videoItem) { return Expanded( child: Padding( padding: const EdgeInsets.fromLTRB(6, 5, 6, 5), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - // mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Row( - children: [ - Expanded( - child: Text('${videoItem.title}\n', - // semanticsLabel: "${videoItem.title}", - maxLines: 2, - overflow: TextOverflow.ellipsis, - style: const TextStyle( - height: 1.38, - )), - ), - ], - ), - // const Spacer(), - // const SizedBox(height: 2), - // VideoStat( - // videoItem: videoItem, - // ), - // Row( - // children: [ - // if (videoItem.goto == 'bangumi') ...[ - // PBadge( - // text: videoItem.bangumiBadge, - // stack: 'normal', - // size: 'small', - // type: 'line', - // fs: 9, - // ) - // ], - // if (videoItem.rcmdReason != null) ...[ - // PBadge( - // text: videoItem.rcmdReason, - // stack: 'normal', - // size: 'small', - // type: 'color', - // ) - // ], - // if (videoItem.goto == 'picture') ...[ - // const PBadge( - // text: '动态', - // stack: 'normal', - // size: 'small', - // type: 'line', - // fs: 9, - // ) - // ], - // if (videoItem.isFollowed == 1) ...[ - // const PBadge( - // text: '已关注', - // stack: 'normal', - // size: 'small', - // type: 'color', - // ) - // ], - // Expanded( - // flex: 1, - // child: Text( - // videoItem.author ?? '', - // // semanticsLabel: "Up主:${videoItem.owner.name}", - // maxLines: 1, - // overflow: TextOverflow.clip, - // style: TextStyle( - // height: 1.5, - // fontSize: Theme.of(context).textTheme.labelMedium!.fontSize, - // color: Theme.of(context).colorScheme.outline, - // ), - // ), - // ), - // if (videoItem.goto == 'av') const SizedBox(width: 10) - // ], - // ), - ], + child: Text( + '${videoItem.title}\n', + maxLines: 2, + overflow: TextOverflow.ellipsis, + style: const TextStyle( + height: 1.38, + ), ), ), ); } - -// Widget videoStat(BuildContext context, Item videoItem) { -// return Row( -// children: [ -// StatView( -// theme: 'gray', -// view: videoItem.stat.view, -// goto: videoItem.goto, -// ), -// const SizedBox(width: 6), -// if (videoItem.goto != 'picture') -// StatDanMu( -// theme: 'gray', -// danmu: videoItem.stat.danmu, -// ), -// if (videoItem is RecVideoItemModel) ...[ -// const Spacer(), -// Expanded( -// flex: 0, -// child: RichText( -// maxLines: 1, -// text: TextSpan( -// style: TextStyle( -// fontSize: Theme.of(context).textTheme.labelSmall!.fontSize, -// color: -// Theme.of(context).colorScheme.outline.withOpacity(0.8), -// ), -// text: Utils.formatTimestampToRelativeTime(videoItem.pubdate)), -// )), -// const SizedBox(width: 2), -// ], -// if (videoItem is RecVideoItemAppModel && -// videoItem.desc != null && -// videoItem.desc.contains(' · ')) ...[ -// const Spacer(), -// Expanded( -// flex: 0, -// child: RichText( -// maxLines: 1, -// text: TextSpan( -// style: TextStyle( -// fontSize: Theme.of(context).textTheme.labelSmall!.fontSize, -// color: -// Theme.of(context).colorScheme.outline.withOpacity(0.8), -// ), -// text: Utils.shortenChineseDateString( -// videoItem.desc.split(' · ').last)), -// )), -// const SizedBox(width: 2), -// ] -// ], -// ); -// } diff --git a/lib/http/member.dart b/lib/http/member.dart index a388c8f6..6f07321b 100644 --- a/lib/http/member.dart +++ b/lib/http/member.dart @@ -10,7 +10,7 @@ import 'package:PiliPlus/models/space_archive/data.dart' as space_archive; import 'package:PiliPlus/models/space_article/data.dart' as space_article; import 'package:PiliPlus/models/space/data.dart' as space_; import 'package:PiliPlus/models/space_fav/space_fav.dart'; -import 'package:PiliPlus/pages/member/new/content/member_contribute/member_contribute.dart' +import 'package:PiliPlus/pages/member/content/member_contribute/member_contribute.dart' show ContributeType; import 'package:PiliPlus/utils/storage.dart'; import 'package:dio/dio.dart'; diff --git a/lib/models/user/history.dart b/lib/models/user/history.dart index d18d3ce1..921410cd 100644 --- a/lib/models/user/history.dart +++ b/lib/models/user/history.dart @@ -87,7 +87,6 @@ class HisListItem with MultiSelectData { int? kid; String? tagName; int? liveStatus; - dynamic isFullScreen; HisListItem.fromJson(Map json) { title = json['title']; diff --git a/lib/pages/bangumi/introduction/view.dart b/lib/pages/bangumi/introduction/view.dart index 3bbe324e..26251ecf 100644 --- a/lib/pages/bangumi/introduction/view.dart +++ b/lib/pages/bangumi/introduction/view.dart @@ -341,7 +341,6 @@ class _BangumiInfoState extends State { value: Utils.numFormat(!widget.isLoading ? widget.bangumiDetail!.stat!['views'] : bangumiItem!.stat!['views']), - size: 'medium', ), const SizedBox(width: 6), StatDanMu( @@ -351,7 +350,6 @@ class _BangumiInfoState extends State { ? widget .bangumiDetail!.stat!['danmakus'] : bangumiItem!.stat!['danmakus']), - size: 'medium', ), if (isLandscape) ...[ const SizedBox(width: 6), diff --git a/lib/pages/bangumi/introduction/widgets/intro_detail.dart b/lib/pages/bangumi/introduction/widgets/intro_detail.dart index bfede2d1..533e8009 100644 --- a/lib/pages/bangumi/introduction/widgets/intro_detail.dart +++ b/lib/pages/bangumi/introduction/widgets/intro_detail.dart @@ -83,14 +83,12 @@ class _IntroDetailState extends CommonCollapseSlidePageState { context: context, theme: 'gray', value: Utils.numFormat(widget.bangumiDetail.stat!['views']), - size: 'medium', ), const SizedBox(width: 6), StatDanMu( context: context, theme: 'gray', value: Utils.numFormat(widget.bangumiDetail.stat!['danmakus']), - size: 'medium', ), ], ), diff --git a/lib/pages/bangumi/widgets/bangumi_card_v.dart b/lib/pages/bangumi/widgets/bangumi_card_v.dart index 7b62271d..27a14413 100644 --- a/lib/pages/bangumi/widgets/bangumi_card_v.dart +++ b/lib/pages/bangumi/widgets/bangumi_card_v.dart @@ -89,13 +89,9 @@ class BangumiCardV extends StatelessWidget { Widget bagumiContent(context) { return Expanded( child: Padding( - // 多列 padding: const EdgeInsets.fromLTRB(4, 5, 0, 3), - // 单列 - // padding: const EdgeInsets.fromLTRB(14, 10, 4, 8), child: Column( crossAxisAlignment: CrossAxisAlignment.start, - // mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( bangumiItem.title, diff --git a/lib/pages/bangumi/widgets/bangumi_card_v_member_home.dart b/lib/pages/bangumi/widgets/bangumi_card_v_member_home.dart index 91391909..48ee4f82 100644 --- a/lib/pages/bangumi/widgets/bangumi_card_v_member_home.dart +++ b/lib/pages/bangumi/widgets/bangumi_card_v_member_home.dart @@ -55,22 +55,6 @@ class BangumiCardVMemberHome extends StatelessWidget { height: maxHeight, ), ), - // if (bangumiItem.badge != null) - // PBadge( - // text: bangumiItem.badge, - // top: 6, - // right: 6, - // bottom: null, - // left: null), - // if (bangumiItem.order != null) - // PBadge( - // text: bangumiItem.order, - // top: null, - // right: null, - // bottom: 6, - // left: 6, - // type: 'gray', - // ), ], ); }), @@ -87,13 +71,9 @@ class BangumiCardVMemberHome extends StatelessWidget { Widget bangumiContent(Item bangumiItem) { return Expanded( child: Padding( - // 多列 padding: const EdgeInsets.fromLTRB(4, 5, 0, 3), - // 单列 - // padding: const EdgeInsets.fromLTRB(14, 10, 4, 8), child: Column( crossAxisAlignment: CrossAxisAlignment.start, - // mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( bangumiItem.title, @@ -105,24 +85,6 @@ Widget bangumiContent(Item bangumiItem) { overflow: TextOverflow.ellipsis, ), const SizedBox(height: 1), - // if (bangumiItem.indexShow != null) - // Text( - // bangumiItem.indexShow, - // maxLines: 1, - // style: TextStyle( - // fontSize: Theme.of(context).textTheme.labelMedium!.fontSize, - // color: Theme.of(context).colorScheme.outline, - // ), - // ), - // if (bangumiItem.progress != null) - // Text( - // bangumiItem.progress, - // maxLines: 1, - // style: TextStyle( - // fontSize: Theme.of(context).textTheme.labelMedium!.fontSize, - // color: Theme.of(context).colorScheme.outline, - // ), - // ), ], ), ), diff --git a/lib/pages/bangumi/widgets/bangumi_card_v_pgc_index.dart b/lib/pages/bangumi/widgets/bangumi_card_v_pgc_index.dart index 5a8f614a..9b6767c2 100644 --- a/lib/pages/bangumi/widgets/bangumi_card_v_pgc_index.dart +++ b/lib/pages/bangumi/widgets/bangumi_card_v_pgc_index.dart @@ -75,13 +75,9 @@ class BangumiCardVPgcIndex extends StatelessWidget { Widget bagumiContent(context) { return Expanded( child: Padding( - // 多列 padding: const EdgeInsets.fromLTRB(4, 5, 0, 3), - // 单列 - // padding: const EdgeInsets.fromLTRB(14, 10, 4, 8), child: Column( crossAxisAlignment: CrossAxisAlignment.start, - // mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( bangumiItem['title'], @@ -102,15 +98,6 @@ class BangumiCardVPgcIndex extends StatelessWidget { color: Theme.of(context).colorScheme.outline, ), ), - // if (bangumiItem.progress != null) - // Text( - // bangumiItem.progress, - // maxLines: 1, - // style: TextStyle( - // fontSize: Theme.of(context).textTheme.labelMedium!.fontSize, - // color: Theme.of(context).colorScheme.outline, - // ), - // ), ], ), ), diff --git a/lib/pages/dynamics/widgets/up_panel.dart b/lib/pages/dynamics/widgets/up_panel.dart index e22a12eb..0d376f2d 100644 --- a/lib/pages/dynamics/widgets/up_panel.dart +++ b/lib/pages/dynamics/widgets/up_panel.dart @@ -69,16 +69,8 @@ class _UpPanelState extends State { ), ), ), - const SliverToBoxAdapter( - child: SizedBox(height: 10), - ), - SliverGrid( - gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: 1, - mainAxisExtent: 76, - crossAxisSpacing: 0, - mainAxisSpacing: 0, - ), + const SliverToBoxAdapter(child: SizedBox(height: 10)), + SliverList( delegate: SliverChildListDelegate( [ if (widget.dynamicsController.showLiveItems && @@ -102,9 +94,7 @@ class _UpPanelState extends State { ], ), ), - const SliverToBoxAdapter( - child: SizedBox(height: 200), - ), + const SliverToBoxAdapter(child: SizedBox(height: 200)), ], ); } @@ -112,119 +102,122 @@ class _UpPanelState extends State { Widget upItemBuild(data, i) { bool isCurrent = widget.dynamicsController.currentMid == data.mid || widget.dynamicsController.currentMid == -1; - return InkWell( - onTap: () { - feedBack(); - if (data.type == 'up') { - widget.dynamicsController.currentMid = data.mid; - // dynamicsController.mid.value = data.mid; - widget.dynamicsController - ..upInfo.value = data - ..onSelectUp(data.mid); - // int liveLen = liveList.length; - // int upLen = upList.length; - // double itemWidth = contentWidth + itemPadding.horizontal; - // double screenWidth = MediaQuery.sizeOf(context).width; - // double moveDistance = 0.0; - // if (itemWidth * (upList.length + liveList.length) <= screenWidth) { - // } else if ((upLen - i - 0.5) * itemWidth > screenWidth / 2) { - // moveDistance = - // (i + liveLen + 0.5) * itemWidth + 46 - screenWidth / 2; - // } else { - // moveDistance = (upLen + liveLen) * itemWidth + 46 - screenWidth; - // } - data.hasUpdate = false; - // scrollController.animateTo( - // moveDistance, - // duration: const Duration(milliseconds: 500), - // curve: Curves.easeInOut, - // ); - setState(() {}); - } else if (data.type == 'live') { - // LiveItemModel liveItem = LiveItemModel.fromJson({ - // 'title': data.title, - // 'uname': data.uname, - // 'face': data.face, - // 'roomid': data.roomId, - // }); - Get.toNamed('/liveRoom?roomid=${data.roomId}'); - } - }, - onLongPress: () { - if (data.mid == -1) { - return; - } - String heroTag = Utils.makeHeroTag(data.mid); - Get.toNamed('/member?mid=${data.mid}', - arguments: {'face': data.face, 'heroTag': heroTag}); - }, - child: AnimatedOpacity( - opacity: isCurrent ? 1 : 0.6, - duration: const Duration(milliseconds: 200), - curve: Curves.easeInOut, - child: Column( - mainAxisSize: MainAxisSize.min, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Stack( - clipBehavior: Clip.none, - children: [ - Padding( - padding: const EdgeInsets.symmetric(horizontal: 4), - child: data.face != '' - ? NetworkImgLayer( - width: 38, - height: 38, - src: data.face, - type: 'avatar', - ) - : const CircleAvatar( - backgroundColor: Color(0xFF5CB67B), - backgroundImage: AssetImage( - 'assets/images/logo/logo.png', + return SizedBox( + height: 76, + child: InkWell( + onTap: () { + feedBack(); + if (data.type == 'up') { + widget.dynamicsController.currentMid = data.mid; + // dynamicsController.mid.value = data.mid; + widget.dynamicsController + ..upInfo.value = data + ..onSelectUp(data.mid); + // int liveLen = liveList.length; + // int upLen = upList.length; + // double itemWidth = contentWidth + itemPadding.horizontal; + // double screenWidth = MediaQuery.sizeOf(context).width; + // double moveDistance = 0.0; + // if (itemWidth * (upList.length + liveList.length) <= screenWidth) { + // } else if ((upLen - i - 0.5) * itemWidth > screenWidth / 2) { + // moveDistance = + // (i + liveLen + 0.5) * itemWidth + 46 - screenWidth / 2; + // } else { + // moveDistance = (upLen + liveLen) * itemWidth + 46 - screenWidth; + // } + data.hasUpdate = false; + // scrollController.animateTo( + // moveDistance, + // duration: const Duration(milliseconds: 500), + // curve: Curves.easeInOut, + // ); + setState(() {}); + } else if (data.type == 'live') { + // LiveItemModel liveItem = LiveItemModel.fromJson({ + // 'title': data.title, + // 'uname': data.uname, + // 'face': data.face, + // 'roomid': data.roomId, + // }); + Get.toNamed('/liveRoom?roomid=${data.roomId}'); + } + }, + onLongPress: () { + if (data.mid == -1) { + return; + } + String heroTag = Utils.makeHeroTag(data.mid); + Get.toNamed('/member?mid=${data.mid}', + arguments: {'face': data.face, 'heroTag': heroTag}); + }, + child: AnimatedOpacity( + opacity: isCurrent ? 1 : 0.6, + duration: const Duration(milliseconds: 200), + curve: Curves.easeInOut, + child: Column( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Stack( + clipBehavior: Clip.none, + children: [ + Padding( + padding: const EdgeInsets.symmetric(horizontal: 4), + child: data.face != '' + ? NetworkImgLayer( + width: 38, + height: 38, + src: data.face, + type: 'avatar', + ) + : const CircleAvatar( + backgroundColor: Color(0xFF5CB67B), + backgroundImage: AssetImage( + 'assets/images/logo/logo.png', + ), ), - ), - ), - Positioned( - top: data.type == 'live' ? -5 : 0, - right: data.type == 'live' ? -6 : 4, - child: Badge( - smallSize: 8, - label: data.type == 'live' ? const Text(' Live ') : null, - textColor: - Theme.of(context).colorScheme.onSecondaryContainer, - alignment: AlignmentDirectional.topStart, - isLabelVisible: data.type == 'live' || - (data.type == 'up' && (data.hasUpdate ?? false)), - backgroundColor: data.type == 'live' - ? Theme.of(context) - .colorScheme - .secondaryContainer - .withOpacity(0.75) - : Theme.of(context).colorScheme.primary, + ), + Positioned( + top: data.type == 'live' ? -5 : 0, + right: data.type == 'live' ? -6 : 4, + child: Badge( + smallSize: 8, + label: data.type == 'live' ? const Text(' Live ') : null, + textColor: + Theme.of(context).colorScheme.onSecondaryContainer, + alignment: AlignmentDirectional.topStart, + isLabelVisible: data.type == 'live' || + (data.type == 'up' && (data.hasUpdate ?? false)), + backgroundColor: data.type == 'live' + ? Theme.of(context) + .colorScheme + .secondaryContainer + .withOpacity(0.75) + : Theme.of(context).colorScheme.primary, + ), + ), + ], + ), + const SizedBox(height: 3), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 4), + child: Text( + data.uname, + overflow: TextOverflow.clip, + maxLines: 2, + softWrap: true, + textAlign: TextAlign.center, + style: TextStyle( + color: widget.dynamicsController.currentMid == data.mid + ? Theme.of(context).colorScheme.primary + : Theme.of(context).colorScheme.outline, + height: 1.1, + fontSize: 12.5, ), ), - ], - ), - const SizedBox(height: 3), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 4), - child: Text( - data.uname, - overflow: TextOverflow.clip, - maxLines: 2, - softWrap: true, - textAlign: TextAlign.center, - style: TextStyle( - color: widget.dynamicsController.currentMid == data.mid - ? Theme.of(context).colorScheme.primary - : Theme.of(context).colorScheme.outline, - height: 1.1, - fontSize: 12.5, - ), ), - ), - ], + ], + ), ), ), ); diff --git a/lib/pages/fan/view.dart b/lib/pages/fan/view.dart index 26ff197d..bae864ce 100644 --- a/lib/pages/fan/view.dart +++ b/lib/pages/fan/view.dart @@ -59,7 +59,7 @@ class _FansPageState extends State { sliver: SliverGrid( gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent( maxCrossAxisExtent: Grid.smallCardWidth * 2, - mainAxisExtent: 56, + mainAxisExtent: 66, ), delegate: SliverChildBuilderDelegate( (BuildContext context, int index) { diff --git a/lib/pages/fan/widgets/fan_item.dart b/lib/pages/fan/widgets/fan_item.dart index 3633e491..7504233f 100644 --- a/lib/pages/fan/widgets/fan_item.dart +++ b/lib/pages/fan/widgets/fan_item.dart @@ -11,13 +11,16 @@ Widget fanItem({item}) { leading: Hero( tag: heroTag, child: NetworkImgLayer( - width: 38, - height: 38, + width: 45, + height: 45, type: 'avatar', src: item.face, ), ), - title: Text(item.uname), + title: Text( + item.uname, + style: const TextStyle(fontSize: 14), + ), subtitle: Text( item.sign, maxLines: 1, diff --git a/lib/pages/fav/article/view.dart b/lib/pages/fav/article/view.dart index a0cefcf9..dc59c020 100644 --- a/lib/pages/fav/article/view.dart +++ b/lib/pages/fav/article/view.dart @@ -43,11 +43,7 @@ class _FavArticlePageState extends State Widget _buildBody(LoadingState?> loadingState) { return switch (loadingState) { Loading() => SliverGrid( - gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent( - mainAxisSpacing: 2, - maxCrossAxisExtent: Grid.mediumCardWidth * 2, - childAspectRatio: StyleString.aspectRatio * 2.2, - ), + gridDelegate: Grid.videoCardHDelegate(context), delegate: SliverChildBuilderDelegate( (context, index) { return const VideoCardHSkeleton(); @@ -62,11 +58,7 @@ class _FavArticlePageState extends State bottom: MediaQuery.paddingOf(context).bottom + 80, ), sliver: SliverGrid( - gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent( - mainAxisSpacing: 2, - maxCrossAxisExtent: Grid.mediumCardWidth * 2, - childAspectRatio: StyleString.aspectRatio * 2.6, - ), + gridDelegate: Grid.videoCardHDelegate(context), delegate: SliverChildBuilderDelegate( (context, index) { if (index == loadingState.response!.length - 1) { diff --git a/lib/pages/fav/article/widget/item.dart b/lib/pages/fav/article/widget/item.dart index a79dd921..932e0bde 100644 --- a/lib/pages/fav/article/widget/item.dart +++ b/lib/pages/fav/article/widget/item.dart @@ -56,12 +56,21 @@ class FavArticleItem extends StatelessWidget { mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text( - item['content'], - maxLines: 2, - overflow: TextOverflow.ellipsis, + Expanded( + child: Text( + item['content'], + style: TextStyle( + fontSize: Theme.of(context) + .textTheme + .bodyMedium! + .fontSize, + height: 1.42, + letterSpacing: 0.3, + ), + maxLines: 2, + overflow: TextOverflow.ellipsis, + ), ), - const Spacer(), Row( children: [ StatView( @@ -83,12 +92,15 @@ class FavArticleItem extends StatelessWidget { ), ], ), - const SizedBox(height: 4), + const SizedBox(height: 3), Text( '${item['author']['name']} · ${item['pub_time']}', + maxLines: 1, style: TextStyle( fontSize: 13, + height: 1, color: Theme.of(context).colorScheme.outline, + overflow: TextOverflow.clip, ), ), ], diff --git a/lib/pages/fav/note/child_view.dart b/lib/pages/fav/note/child_view.dart index 70a1a99f..a6835466 100644 --- a/lib/pages/fav/note/child_view.dart +++ b/lib/pages/fav/note/child_view.dart @@ -1,4 +1,3 @@ -import 'package:PiliPlus/common/constants.dart'; import 'package:PiliPlus/common/skeleton/video_card_h.dart'; import 'package:PiliPlus/common/widgets/dialog.dart'; import 'package:PiliPlus/common/widgets/http_error.dart'; @@ -136,11 +135,7 @@ class _FavNoteChildPageState extends State Widget _buildBody(LoadingState?> loadingState) { return switch (loadingState) { Loading() => SliverGrid( - gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent( - mainAxisSpacing: 2, - maxCrossAxisExtent: Grid.mediumCardWidth * 2, - childAspectRatio: StyleString.aspectRatio * 2.2, - ), + gridDelegate: Grid.videoCardHDelegate(context), delegate: SliverChildBuilderDelegate( (context, index) { return const VideoCardHSkeleton(); @@ -153,11 +148,7 @@ class _FavNoteChildPageState extends State padding: EdgeInsets.only( bottom: MediaQuery.paddingOf(context).bottom + 80), sliver: SliverGrid( - gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent( - mainAxisSpacing: 2, - maxCrossAxisExtent: Grid.mediumCardWidth * 2, - childAspectRatio: StyleString.aspectRatio * 2.6, - ), + gridDelegate: Grid.videoCardHDelegate(context), delegate: SliverChildBuilderDelegate( (context, index) { if (index == loadingState.response!.length - 1) { diff --git a/lib/pages/fav/note/widget/item.dart b/lib/pages/fav/note/widget/item.dart index 6aa55c8e..956f8ce5 100644 --- a/lib/pages/fav/note/widget/item.dart +++ b/lib/pages/fav/note/widget/item.dart @@ -70,14 +70,21 @@ class FavNoteItem extends StatelessWidget { item.summary ?? '', maxLines: 1, style: TextStyle( + fontSize: 13, + height: 1, color: Theme.of(context).colorScheme.outline, + overflow: TextOverflow.clip, ), ), + const SizedBox(height: 3), Text( item.message ?? '', maxLines: 1, style: TextStyle( + fontSize: 13, + height: 1, color: Theme.of(context).colorScheme.outline, + overflow: TextOverflow.clip, ), ), ], diff --git a/lib/pages/fav/pgc/child_view.dart b/lib/pages/fav/pgc/child_view.dart index 72595d91..fc5928d6 100644 --- a/lib/pages/fav/pgc/child_view.dart +++ b/lib/pages/fav/pgc/child_view.dart @@ -1,4 +1,3 @@ -import 'package:PiliPlus/common/constants.dart'; import 'package:PiliPlus/common/skeleton/video_card_h.dart'; import 'package:PiliPlus/common/widgets/dialog.dart'; import 'package:PiliPlus/common/widgets/http_error.dart'; @@ -160,11 +159,7 @@ class _FavPgcChildPageState extends State Widget _buildBody(LoadingState?> loadingState) { return switch (loadingState) { Loading() => SliverGrid( - gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent( - mainAxisSpacing: 2, - maxCrossAxisExtent: Grid.mediumCardWidth * 2, - childAspectRatio: StyleString.aspectRatio * 2.2, - ), + gridDelegate: Grid.videoCardHDelegate(context), delegate: SliverChildBuilderDelegate( (context, index) { return const VideoCardHSkeleton(); @@ -177,11 +172,7 @@ class _FavPgcChildPageState extends State padding: EdgeInsets.only( bottom: MediaQuery.paddingOf(context).bottom + 80), sliver: SliverGrid( - gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent( - mainAxisSpacing: 2, - maxCrossAxisExtent: Grid.mediumCardWidth * 2, - childAspectRatio: StyleString.aspectRatio * 2.6, - ), + gridDelegate: Grid.videoCardHDelegate(context), delegate: SliverChildBuilderDelegate( (context, index) { if (index == loadingState.response!.length - 1) { diff --git a/lib/pages/fav/video/view.dart b/lib/pages/fav/video/view.dart index e4fb3db0..7bb59193 100644 --- a/lib/pages/fav/video/view.dart +++ b/lib/pages/fav/video/view.dart @@ -48,11 +48,7 @@ class _FavVideoPageState extends State Widget _buildBody(LoadingState?> loadingState) { return switch (loadingState) { Loading() => SliverGrid( - gridDelegate: SliverGridDelegateWithExtentAndRatio( - mainAxisSpacing: 2, - maxCrossAxisExtent: Grid.mediumCardWidth * 2, - childAspectRatio: StyleString.aspectRatio * 2.2, - ), + gridDelegate: Grid.videoCardHDelegate(context), delegate: SliverChildBuilderDelegate( (BuildContext context, int index) { return const VideoCardHSkeleton(); @@ -67,11 +63,7 @@ class _FavVideoPageState extends State bottom: 80 + MediaQuery.paddingOf(context).bottom, ), sliver: SliverGrid( - gridDelegate: SliverGridDelegateWithExtentAndRatio( - mainAxisSpacing: 2, - maxCrossAxisExtent: Grid.mediumCardWidth * 2, - childAspectRatio: StyleString.aspectRatio * 2.2, - ), + gridDelegate: Grid.videoCardHDelegate(context), delegate: SliverChildBuilderDelegate( childCount: loadingState.response!.length, (BuildContext context, int index) { diff --git a/lib/pages/fav_detail/view.dart b/lib/pages/fav_detail/view.dart index 3085f98e..6d25ce82 100644 --- a/lib/pages/fav_detail/view.dart +++ b/lib/pages/fav_detail/view.dart @@ -430,11 +430,7 @@ class _FavDetailPageState extends State { Widget _buildBody(LoadingState?> loadingState) { return switch (loadingState) { Loading() => SliverGrid( - gridDelegate: SliverGridDelegateWithExtentAndRatio( - mainAxisSpacing: 2, - maxCrossAxisExtent: Grid.mediumCardWidth * 2, - childAspectRatio: StyleString.aspectRatio * 2.2, - ), + gridDelegate: Grid.videoCardHDelegate(context, minHeight: 110), delegate: SliverChildBuilderDelegate( (context, index) { return const VideoCardHSkeleton(); @@ -448,11 +444,7 @@ class _FavDetailPageState extends State { bottom: MediaQuery.of(context).padding.bottom + 85, ), sliver: SliverGrid( - gridDelegate: SliverGridDelegateWithExtentAndRatio( - mainAxisSpacing: 2, - maxCrossAxisExtent: Grid.mediumCardWidth * 2, - childAspectRatio: StyleString.aspectRatio * 2.2, - ), + gridDelegate: Grid.videoCardHDelegate(context, minHeight: 110), delegate: SliverChildBuilderDelegate( (context, index) { if (index == loadingState.response!.length) { diff --git a/lib/pages/fav_detail/widget/fav_video_card.dart b/lib/pages/fav_detail/widget/fav_video_card.dart index e75ee63f..8ac32369 100644 --- a/lib/pages/fav_detail/widget/fav_video_card.dart +++ b/lib/pages/fav_detail/widget/fav_video_card.dart @@ -66,15 +66,6 @@ class FavVideoCardH extends StatelessWidget { return; } onViewFav?.call(); - // Utils.toViewPage( - // 'bvid=$bvid&cid=${videoItem.cid}${epId?.isNotEmpty == true ? '&epId=$epId' : ''}', - // arguments: { - // 'videoItem': videoItem, - // 'heroTag': Utils.makeHeroTag(id), - // 'videoType': - // epId != null ? SearchType.media_bangumi : SearchType.video, - // }, - // ); }, onLongPress: isSort == true ? null @@ -180,7 +171,7 @@ class FavVideoCardH extends StatelessWidget { Text( videoItem.owner.name!, style: TextStyle( - fontSize: Theme.of(context).textTheme.labelMedium!.fontSize, + fontSize: 12, color: Theme.of(context).colorScheme.outline, ), ), diff --git a/lib/pages/fav_search/view.dart b/lib/pages/fav_search/view.dart index 234893c3..f91e91cb 100644 --- a/lib/pages/fav_search/view.dart +++ b/lib/pages/fav_search/view.dart @@ -73,7 +73,10 @@ class _FavSearchPageState extends State { Loading() => errorWidget(), Success() => loadingState.response?.isNotEmpty == true ? switch (_favSearchCtr.searchType) { - SearchType.fav || SearchType.history => CustomScrollView( + SearchType.fav || + SearchType.history || + SearchType.later => + CustomScrollView( physics: const AlwaysScrollableScrollPhysics(), controller: _favSearchCtr.scrollController, slivers: [ @@ -82,111 +85,71 @@ class _FavSearchPageState extends State { bottom: MediaQuery.of(context).padding.bottom + 80, ), sliver: SliverGrid( - gridDelegate: SliverGridDelegateWithExtentAndRatio( - mainAxisSpacing: 2, - maxCrossAxisExtent: Grid.mediumCardWidth * 2, - childAspectRatio: StyleString.aspectRatio * 2.2, - ), + gridDelegate: _favSearchCtr.searchType == SearchType.fav + ? Grid.videoCardHDelegate(context, minHeight: 110) + : Grid.videoCardHDelegate(context), delegate: SliverChildBuilderDelegate( (context, index) { if (index == loadingState.response!.length - 1) { _favSearchCtr.onLoadMore(); } final item = loadingState.response![index]; - return _favSearchCtr.searchType == SearchType.fav - ? FavVideoCardH( - videoItem: item, - onDelFav: _favSearchCtr.isOwner == true - ? () { - _favSearchCtr.onCancelFav( - index, - item.id!, - item.type, - ); - } - : null, - onViewFav: () { - Utils.toViewPage( - 'bvid=${item.bvid}&cid=${item.cid}', - arguments: { - 'videoItem': item, - 'heroTag': - Utils.makeHeroTag(item.bvid), - 'sourceType': 'fav', - 'mediaId': Get.arguments['mediaId'], - 'oid': item.id, - 'favTitle': Get.arguments['title'], - 'count': Get.arguments['count'], - 'desc': true, - 'isContinuePlaying': true, - }, - ); - }, - ) - : HistoryItem( - videoItem: item, - ctr: _favSearchCtr, - onChoose: null, - onDelete: (kid, business) { - _favSearchCtr.onDelHistory( - index, kid, business); + if (_favSearchCtr.searchType == SearchType.fav) { + return FavVideoCardH( + videoItem: item, + onDelFav: _favSearchCtr.isOwner == true + ? () { + _favSearchCtr.onCancelFav( + index, + item.id!, + item.type, + ); + } + : null, + onViewFav: () { + Utils.toViewPage( + 'bvid=${item.bvid}&cid=${item.cid}', + arguments: { + 'videoItem': item, + 'heroTag': Utils.makeHeroTag(item.bvid), + 'sourceType': 'fav', + 'mediaId': Get.arguments['mediaId'], + 'oid': item.id, + 'favTitle': Get.arguments['title'], + 'count': Get.arguments['count'], + 'desc': true, + 'isContinuePlaying': true, }, ); - }, - childCount: loadingState.response!.length, - ), - ), - ), - ], - ), - SearchType.follow => ListView.builder( - padding: EdgeInsets.only( - bottom: MediaQuery.of(context).padding.bottom + 80, - ), - controller: _favSearchCtr.scrollController, - itemCount: loadingState.response!.length, - itemBuilder: ((context, index) { - if (index == loadingState.response!.length - 1) { - _favSearchCtr.onLoadMore(); - } - return FollowItem( - item: loadingState.response![index], - ); - }), - ), - SearchType.later => CustomScrollView( - physics: const AlwaysScrollableScrollPhysics(), - controller: _favSearchCtr.scrollController, - slivers: [ - SliverPadding( - padding: EdgeInsets.only( - bottom: MediaQuery.of(context).padding.bottom + 80, - ), - sliver: SliverGrid( - gridDelegate: SliverGridDelegateWithExtentAndRatio( - mainAxisSpacing: 2, - maxCrossAxisExtent: Grid.mediumCardWidth * 2, - childAspectRatio: StyleString.aspectRatio * 2.2, - ), - delegate: SliverChildBuilderDelegate( - (context, index) { - if (index == loadingState.response!.length - 1) { - _favSearchCtr.onLoadMore(); + }, + ); } - var videoItem = loadingState.response![index]; + + if (_favSearchCtr.searchType == + SearchType.history) { + return HistoryItem( + videoItem: item, + ctr: _favSearchCtr, + onChoose: null, + onDelete: (kid, business) { + _favSearchCtr.onDelHistory( + index, kid, business); + }, + ); + } + return Stack( children: [ VideoCardH( - videoItem: videoItem, + videoItem: item, source: 'later', onViewLater: (cid) { Utils.toViewPage( - 'bvid=${videoItem.bvid}&cid=$cid', + 'bvid=${item.bvid}&cid=$cid', arguments: { - 'videoItem': videoItem, - 'oid': videoItem.aid, - 'heroTag': - Utils.makeHeroTag(videoItem.bvid), + 'videoItem': item, + 'oid': item.aid, + 'heroTag': Utils.makeHeroTag(item.bvid), 'sourceType': 'watchLater', 'count': Get.arguments['count'], 'favTitle': '稍后再看', @@ -205,8 +168,7 @@ class _FavSearchPageState extends State { child: LayoutBuilder( builder: (context, constraints) => AnimatedOpacity( - opacity: - videoItem.checked == true ? 1 : 0, + opacity: item.checked == true ? 1 : 0, duration: const Duration(milliseconds: 200), child: Container( @@ -224,9 +186,8 @@ class _FavSearchPageState extends State { width: 34, height: 34, child: AnimatedScale( - scale: videoItem.checked == true - ? 1 - : 0, + scale: + item.checked == true ? 1 : 0, duration: const Duration( milliseconds: 250), curve: Curves.easeInOut, @@ -272,7 +233,7 @@ class _FavSearchPageState extends State { _favSearchCtr.toViewDel( context, index, - videoItem.aid, + item.aid, ); }, icon: Icons.clear, @@ -291,6 +252,21 @@ class _FavSearchPageState extends State { ), ], ), + SearchType.follow => ListView.builder( + padding: EdgeInsets.only( + bottom: MediaQuery.of(context).padding.bottom + 80, + ), + controller: _favSearchCtr.scrollController, + itemCount: loadingState.response!.length, + itemBuilder: ((context, index) { + if (index == loadingState.response!.length - 1) { + _favSearchCtr.onLoadMore(); + } + return FollowItem( + item: loadingState.response![index], + ); + }), + ), } : errorWidget( callback: _favSearchCtr.onReload, diff --git a/lib/pages/follow/view.dart b/lib/pages/follow/view.dart index 5949fe33..c3ebcf1b 100644 --- a/lib/pages/follow/view.dart +++ b/lib/pages/follow/view.dart @@ -121,22 +121,3 @@ class _FollowPageState extends State { ); } } - -// class _FakeAPI { -// static const List _kOptions = [ -// 'aardvark', -// 'bobcat', -// 'chameleon', -// ]; -// // Searches the options, but injects a fake "network" delay. -// static Future> search(String query) async { -// await Future.delayed( -// const Duration(seconds: 1)); // Fake 1 second delay. -// if (query == '') { -// return const Iterable.empty(); -// } -// return _kOptions.where((String option) { -// return option.contains(query.toLowerCase()); -// }); -// } -// } diff --git a/lib/pages/follow/widgets/follow_item.dart b/lib/pages/follow/widgets/follow_item.dart index 31fe540e..defacd83 100644 --- a/lib/pages/follow/widgets/follow_item.dart +++ b/lib/pages/follow/widgets/follow_item.dart @@ -82,7 +82,6 @@ class FollowItem extends StatelessWidget { mid: item.mid, isFollow: item.attribute != -1, callback: callback, - // followStatus: {'special': item.special, 'tag': item.tag}, ); }, style: FilledButton.styleFrom( diff --git a/lib/pages/history/view.dart b/lib/pages/history/view.dart index 3a85d01c..7f5c2ed0 100644 --- a/lib/pages/history/view.dart +++ b/lib/pages/history/view.dart @@ -251,11 +251,7 @@ class _HistoryPageState extends State Widget _buildBody(LoadingState?> loadingState) { return switch (loadingState) { Loading() => SliverGrid( - gridDelegate: SliverGridDelegateWithExtentAndRatio( - mainAxisSpacing: 2, - maxCrossAxisExtent: Grid.mediumCardWidth * 2, - childAspectRatio: StyleString.aspectRatio * 2.2, - ), + gridDelegate: Grid.videoCardHDelegate(context), delegate: SliverChildBuilderDelegate( (context, index) { return const VideoCardHSkeleton(); @@ -270,11 +266,7 @@ class _HistoryPageState extends State bottom: MediaQuery.of(context).padding.bottom + 80, ), sliver: SliverGrid( - gridDelegate: SliverGridDelegateWithExtentAndRatio( - mainAxisSpacing: 2, - maxCrossAxisExtent: Grid.mediumCardWidth * 2, - childAspectRatio: StyleString.aspectRatio * 2.2, - ), + gridDelegate: Grid.videoCardHDelegate(context), delegate: SliverChildBuilderDelegate( (context, index) { if (index == loadingState.response!.length - 1) { diff --git a/lib/pages/history/widgets/item.dart b/lib/pages/history/widgets/item.dart index 8ceb1eba..9988cf28 100644 --- a/lib/pages/history/widgets/item.dart +++ b/lib/pages/history/widgets/item.dart @@ -47,17 +47,6 @@ class HistoryItem extends StatelessWidget { return; } if (videoItem.history.business?.contains('article') == true) { - // int cid = videoItem.history.cid ?? - // // videoItem.history.oid ?? - // await SearchHttp.ab2c(aid: aid, bvid: bvid); - // Get.toNamed( - // '/webview', - // parameters: { - // 'url': 'https://www.bilibili.com/read/cv$cid', - // 'type': 'note', - // 'pageTitle': videoItem.title - // }, - // ); Utils.toDupNamed( '/htmlRender', parameters: { @@ -69,21 +58,12 @@ class HistoryItem extends StatelessWidget { ); } else if (videoItem.history.business == 'live') { if (videoItem.liveStatus == 1) { - // LiveItemModel liveItem = LiveItemModel.fromJson({ - // 'face': videoItem.authorFace, - // 'roomid': videoItem.history.oid, - // 'pic': videoItem.cover, - // 'title': videoItem.title, - // 'uname': videoItem.authorName, - // 'cover': videoItem.cover, - // }); Get.toNamed('/liveRoom?roomid=${videoItem.history.oid}'); } else { SmartDialog.showToast('直播未开播'); } } else if (videoItem.history.business == 'pgc' || videoItem.tagName?.contains('动画') == true) { - /// hack var bvid = videoItem.history.bvid; if (bvid != null && bvid != '') { var result = await VideoHttp.videoIntro(bvid: bvid); @@ -113,7 +93,6 @@ class HistoryItem extends StatelessWidget { } } else { int cid = videoItem.history.cid ?? - // videoItem.history.oid ?? await SearchHttp.ab2c(aid: aid, bvid: bvid); Utils.toViewPage( 'bvid=$bvid&cid=$cid', @@ -138,137 +117,217 @@ class HistoryItem extends StatelessWidget { onChoose?.call(); } }, - child: Padding( - padding: const EdgeInsets.symmetric( - horizontal: StyleString.safeSpace, - vertical: 5, - ), - child: LayoutBuilder( - builder: (context, boxConstraints) { - double width = - (boxConstraints.maxWidth - StyleString.cardSpace * 6) / 2; - return SizedBox( - height: width / StyleString.aspectRatio, - child: Row( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Stack( - clipBehavior: Clip.none, + child: Stack( + children: [ + Padding( + padding: const EdgeInsets.symmetric( + horizontal: StyleString.safeSpace, + vertical: 5, + ), + child: LayoutBuilder( + builder: (context, boxConstraints) { + double width = + (boxConstraints.maxWidth - StyleString.cardSpace * 6) / 2; + return SizedBox( + height: width / StyleString.aspectRatio, + child: Row( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, children: [ - AspectRatio( - aspectRatio: StyleString.aspectRatio, - child: LayoutBuilder( - builder: (context, boxConstraints) { - double maxWidth = boxConstraints.maxWidth; - double maxHeight = boxConstraints.maxHeight; - return Stack( - clipBehavior: Clip.none, - children: [ - NetworkImgLayer( - src: (videoItem.cover.isNullOrEmpty - ? videoItem.covers?.first ?? '' - : videoItem.cover), - width: maxWidth, - height: maxHeight, - ), - if (!BusinessType - .hiddenDurationType.hiddenDurationType - .contains(videoItem.history.business)) - PBadge( - text: videoItem.progress == -1 - ? '已看完' - : '${Utils.timeFormat(videoItem.progress)}/${Utils.timeFormat(videoItem.duration!)}', - right: 6.0, - bottom: 8.0, - type: 'gray', - ), - // 右上角 - if (BusinessType.showBadge.showBadge - .contains(videoItem.history.business) || - videoItem.history.business == - BusinessType.live.type) - PBadge( - text: videoItem.badge, - top: 6.0, - right: 6.0, - bottom: null, - left: null, - ), - ], - ); - }, - ), - ), - Positioned.fill( - child: AnimatedOpacity( - opacity: videoItem.checked == true ? 1 : 0, - duration: const Duration(milliseconds: 200), - child: Container( - alignment: Alignment.center, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(10), - color: Colors.black.withOpacity(0.6), + Stack( + clipBehavior: Clip.none, + children: [ + AspectRatio( + aspectRatio: StyleString.aspectRatio, + child: LayoutBuilder( + builder: (context, boxConstraints) { + double maxWidth = boxConstraints.maxWidth; + double maxHeight = boxConstraints.maxHeight; + return Stack( + clipBehavior: Clip.none, + children: [ + NetworkImgLayer( + src: (videoItem.cover.isNullOrEmpty + ? videoItem.covers?.firstOrNull ?? '' + : videoItem.cover), + width: maxWidth, + height: maxHeight, + ), + if (!BusinessType + .hiddenDurationType.hiddenDurationType + .contains(videoItem.history.business)) + PBadge( + text: videoItem.progress == -1 + ? '已看完' + : '${Utils.timeFormat(videoItem.progress)}/${Utils.timeFormat(videoItem.duration!)}', + right: 6.0, + bottom: 8.0, + type: 'gray', + ), + // 右上角 + if (BusinessType.showBadge.showBadge + .contains( + videoItem.history.business) || + videoItem.history.business == + BusinessType.live.type) + PBadge( + text: videoItem.badge, + top: 6.0, + right: 6.0, + bottom: null, + left: null, + ), + ], + ); + }, ), - child: SizedBox( - width: 34, - height: 34, - child: AnimatedScale( - scale: videoItem.checked == true ? 1 : 0, - duration: const Duration(milliseconds: 250), - curve: Curves.easeInOut, - child: IconButton( - tooltip: '取消选择', - style: ButtonStyle( - padding: WidgetStateProperty.all( - EdgeInsets.zero), - backgroundColor: - WidgetStateProperty.resolveWith( - (states) { - return Theme.of(context) - .colorScheme - .surface - .withOpacity(0.8); + ), + Positioned.fill( + child: AnimatedOpacity( + opacity: videoItem.checked == true ? 1 : 0, + duration: const Duration(milliseconds: 200), + child: Container( + alignment: Alignment.center, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(10), + color: Colors.black.withOpacity(0.6), + ), + child: SizedBox( + width: 34, + height: 34, + child: AnimatedScale( + scale: videoItem.checked == true ? 1 : 0, + duration: const Duration(milliseconds: 250), + curve: Curves.easeInOut, + child: IconButton( + tooltip: '取消选择', + style: ButtonStyle( + padding: WidgetStateProperty.all( + EdgeInsets.zero), + backgroundColor: + WidgetStateProperty.resolveWith( + (states) { + return Theme.of(context) + .colorScheme + .surface + .withOpacity(0.8); + }, + ), + ), + onPressed: () { + feedBack(); + onChoose?.call(); }, + icon: Icon(Icons.done_all_outlined, + color: Theme.of(context) + .colorScheme + .primary), ), ), - onPressed: () { - feedBack(); - onChoose?.call(); - }, - icon: Icon(Icons.done_all_outlined, - color: Theme.of(context) - .colorScheme - .primary), ), ), ), ), - ), + if (videoItem.duration != null && + videoItem.duration != 0 && + videoItem.progress != null && + videoItem.progress != 0) + Positioned( + left: 0, + right: 0, + bottom: 0, + child: videoProgressIndicator( + videoItem.progress == -1 + ? 1 + : videoItem.progress! / videoItem.duration!, + ), + ), + ], ), - if (videoItem.duration != null && - videoItem.duration != 0 && - videoItem.progress != null && - videoItem.progress != 0) - Positioned( - left: 0, - right: 0, - bottom: 0, - child: videoProgressIndicator( - videoItem.progress == -1 - ? 1 - : videoItem.progress! / videoItem.duration!, - ), - ), + const SizedBox(width: 10), + videoContent(context), ], ), - const SizedBox(width: 10), - videoContent(context), + ); + }, + ), + ), + Positioned( + right: 12, + bottom: 12, + child: SizedBox( + width: 29, + height: 29, + child: PopupMenuButton( + padding: EdgeInsets.zero, + tooltip: '功能菜单', + icon: Icon( + Icons.more_vert_outlined, + color: Theme.of(context).colorScheme.outline, + size: 18, + ), + position: PopupMenuPosition.under, + itemBuilder: (BuildContext context) => >[ + if (videoItem.authorMid != null && + videoItem.authorName?.isNotEmpty == true) + PopupMenuItem( + onTap: () { + Get.toNamed( + '/member?mid=${videoItem.authorMid}', + arguments: { + 'heroTag': '${videoItem.authorMid}', + }, + ); + }, + height: 35, + child: Row( + children: [ + Icon(MdiIcons.accountCircleOutline, size: 16), + SizedBox(width: 6), + Text( + '访问:${videoItem.authorName}', + style: TextStyle(fontSize: 13), + ) + ], + ), + ), + if (videoItem.history.business != 'pgc' && + videoItem.badge != '番剧' && + videoItem.tagName?.contains('动画') != true && + videoItem.history.business != 'live' && + videoItem.history.business?.contains('article') != true) + PopupMenuItem( + onTap: () async { + var res = await UserHttp.toViewLater( + bvid: videoItem.history.bvid); + SmartDialog.showToast(res['msg']); + }, + height: 35, + child: const Row( + children: [ + Icon(Icons.watch_later_outlined, size: 16), + SizedBox(width: 6), + Text('稍后再看', style: TextStyle(fontSize: 13)) + ], + ), + ), + PopupMenuItem( + onTap: () => + onDelete(videoItem.kid, videoItem.history.business), + height: 35, + child: const Row( + children: [ + Icon(Icons.close_outlined, size: 16), + SizedBox(width: 6), + Text('删除记录', style: TextStyle(fontSize: 13)) + ], + ), + ), ], ), - ); - }, - ), + ), + ), + ], ), ); } @@ -278,123 +337,34 @@ class HistoryItem extends StatelessWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text( - videoItem.title, - textAlign: TextAlign.start, - style: const TextStyle( - letterSpacing: 0.3, - ), - maxLines: videoItem.videos! > 1 ? 1 : 2, - overflow: TextOverflow.ellipsis, - ), - if (videoItem.isFullScreen != null) ...[ - const SizedBox(height: 2), - Text( - videoItem.isFullScreen, + Expanded( + child: Text( + videoItem.title, textAlign: TextAlign.start, style: TextStyle( - fontSize: Theme.of(context).textTheme.labelMedium!.fontSize, - color: Theme.of(context).colorScheme.outline), - maxLines: 1, + fontSize: Theme.of(context).textTheme.bodyMedium!.fontSize, + height: 1.42, + letterSpacing: 0.3, + ), + maxLines: videoItem.videos! > 1 ? 1 : 2, overflow: TextOverflow.ellipsis, ), - ], - const Spacer(), + ), if (videoItem.authorName != '') - Row( - children: [ - Text( - videoItem.authorName!, - style: TextStyle( - fontSize: Theme.of(context).textTheme.labelMedium!.fontSize, - color: Theme.of(context).colorScheme.outline, - ), - ), - ], + Text( + videoItem.authorName!, + style: TextStyle( + fontSize: Theme.of(context).textTheme.labelMedium!.fontSize, + color: Theme.of(context).colorScheme.outline, + ), + ), + const SizedBox(height: 2), + Text( + Utils.dateFormat(videoItem.viewAt!), + style: TextStyle( + fontSize: Theme.of(context).textTheme.labelMedium!.fontSize, + color: Theme.of(context).colorScheme.outline, ), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - Utils.dateFormat(videoItem.viewAt!), - style: TextStyle( - fontSize: Theme.of(context).textTheme.labelMedium!.fontSize, - color: Theme.of(context).colorScheme.outline), - ), - // if (videoItem is HisListItem) - SizedBox( - width: 29, - height: 29, - child: PopupMenuButton( - padding: EdgeInsets.zero, - tooltip: '功能菜单', - icon: Icon( - Icons.more_vert_outlined, - color: Theme.of(context).colorScheme.outline, - size: 18, - ), - position: PopupMenuPosition.under, - itemBuilder: (BuildContext context) => - >[ - if (videoItem.authorMid != null && - videoItem.authorName?.isNotEmpty == true) - PopupMenuItem( - onTap: () { - Get.toNamed( - '/member?mid=${videoItem.authorMid}', - arguments: { - 'heroTag': '${videoItem.authorMid}', - }, - ); - }, - height: 35, - child: Row( - children: [ - Icon(MdiIcons.accountCircleOutline, size: 16), - SizedBox(width: 6), - Text( - '访问:${videoItem.authorName}', - style: TextStyle(fontSize: 13), - ) - ], - ), - ), - if (videoItem.history.business != 'pgc' && - videoItem.badge != '番剧' && - videoItem.tagName?.contains('动画') != true && - videoItem.history.business != 'live' && - videoItem.history.business?.contains('article') != true) - PopupMenuItem( - onTap: () async { - var res = await UserHttp.toViewLater( - bvid: videoItem.history.bvid); - SmartDialog.showToast(res['msg']); - }, - height: 35, - child: const Row( - children: [ - Icon(Icons.watch_later_outlined, size: 16), - SizedBox(width: 6), - Text('稍后再看', style: TextStyle(fontSize: 13)) - ], - ), - ), - PopupMenuItem( - onTap: () => - onDelete(videoItem.kid, videoItem.history.business), - height: 35, - child: const Row( - children: [ - Icon(Icons.close_outlined, size: 16), - SizedBox(width: 6), - Text('删除记录', style: TextStyle(fontSize: 13)) - ], - ), - ), - ], - ), - ), - ], ), ], ), diff --git a/lib/pages/home/widgets/app_bar.dart b/lib/pages/home/widgets/app_bar.dart deleted file mode 100644 index d46deae9..00000000 --- a/lib/pages/home/widgets/app_bar.dart +++ /dev/null @@ -1,101 +0,0 @@ -import 'package:flutter/cupertino.dart'; -import 'package:flutter/material.dart'; -import 'package:get/get.dart'; -import 'package:PiliPlus/common/widgets/network_img_layer.dart'; -import 'package:PiliPlus/pages/mine/view.dart'; -import 'package:PiliPlus/utils/storage.dart'; - -class HomeAppBar extends StatelessWidget { - const HomeAppBar({super.key}); - - @override - Widget build(BuildContext context) { - dynamic userInfo = GStorage.userInfo.get('userInfoCache'); - return SliverAppBar( - // forceElevated: true, - toolbarHeight: MediaQuery.of(context).padding.top, - expandedHeight: kToolbarHeight + MediaQuery.of(context).padding.top, - automaticallyImplyLeading: false, - pinned: true, - floating: true, - primary: false, - flexibleSpace: LayoutBuilder( - builder: (context, constraints) { - return FlexibleSpaceBar( - background: Column( - children: [ - AppBar( - title: const Text( - 'PiLiPlus', - style: TextStyle( - fontSize: 20, - fontWeight: FontWeight.bold, - letterSpacing: 1, - fontFamily: 'ArchivoNarrow', - ), - ), - actions: [ - Hero( - tag: 'searchTag', - child: IconButton( - tooltip: '搜索', - onPressed: () { - Get.toNamed('/search'); - }, - icon: const Icon(CupertinoIcons.search, size: 22), - ), - ), - // IconButton( - // onPressed: () {}, - // icon: const Icon(CupertinoIcons.bell, size: 22), - // ), - const SizedBox(width: 6), - - /// TODO - if (userInfo != null) ...[ - GestureDetector( - onTap: () => showModalBottomSheet( - context: context, - builder: (context) => const SizedBox( - height: 450, - child: MinePage(), - ), - clipBehavior: Clip.hardEdge, - isScrollControlled: true, - ), - child: NetworkImgLayer( - type: 'avatar', - width: 32, - height: 32, - src: userInfo.face, - semanticsLabel: '我的', - ), - ), - const SizedBox(width: 10), - ] else ...[ - IconButton( - tooltip: '登录', - onPressed: () => showModalBottomSheet( - context: context, - builder: (context) => const SizedBox( - height: 450, - child: MinePage(), - ), - clipBehavior: Clip.hardEdge, - isScrollControlled: true, - ), - icon: const Icon(CupertinoIcons.person, size: 22), - ), - ], - - const SizedBox(width: 10) - ], - ), - ], - ), - ); - }, - ), - ); - } -} diff --git a/lib/pages/hot/view.dart b/lib/pages/hot/view.dart index 5038e5d2..7291aca7 100644 --- a/lib/pages/hot/view.dart +++ b/lib/pages/hot/view.dart @@ -147,11 +147,7 @@ class _HotPageState extends CommonPageState Widget _buildSkeleton() { return SliverGrid( - gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent( - mainAxisSpacing: 2, - maxCrossAxisExtent: Grid.mediumCardWidth * 2, - childAspectRatio: StyleString.aspectRatio * 2.2, - ), + gridDelegate: Grid.videoCardHDelegate(context), delegate: SliverChildBuilderDelegate( (context, index) { return const VideoCardHSkeleton(); @@ -166,11 +162,7 @@ class _HotPageState extends CommonPageState Loading() => _buildSkeleton(), Success() => loadingState.response?.isNotEmpty == true ? SliverGrid( - gridDelegate: SliverGridDelegateWithExtentAndRatio( - mainAxisSpacing: 2, - maxCrossAxisExtent: Grid.mediumCardWidth * 2, - childAspectRatio: StyleString.aspectRatio * 2.2, - ), + gridDelegate: Grid.videoCardHDelegate(context), delegate: SliverChildBuilderDelegate( (context, index) { if (index == loadingState.response!.length - 1) { diff --git a/lib/pages/later/child_view.dart b/lib/pages/later/child_view.dart index a68b73ae..bb8964a3 100644 --- a/lib/pages/later/child_view.dart +++ b/lib/pages/later/child_view.dart @@ -62,11 +62,7 @@ class _LaterViewChildPageState extends State Widget _buildBody(LoadingState?> loadingState) { return switch (loadingState) { Loading() => SliverGrid( - gridDelegate: SliverGridDelegateWithExtentAndRatio( - mainAxisSpacing: 2, - maxCrossAxisExtent: Grid.mediumCardWidth * 2, - childAspectRatio: StyleString.aspectRatio * 2.2, - ), + gridDelegate: Grid.videoCardHDelegate(context), delegate: SliverChildBuilderDelegate( (context, index) { return const VideoCardHSkeleton(); @@ -76,11 +72,7 @@ class _LaterViewChildPageState extends State ), Success() => loadingState.response?.isNotEmpty == true ? SliverGrid( - gridDelegate: SliverGridDelegateWithExtentAndRatio( - mainAxisSpacing: 2, - maxCrossAxisExtent: Grid.mediumCardWidth * 2, - childAspectRatio: StyleString.aspectRatio * 2.2, - ), + gridDelegate: Grid.videoCardHDelegate(context), delegate: SliverChildBuilderDelegate( (context, index) { if (index == loadingState.response!.length - 1) { diff --git a/lib/pages/live/widgets/live_item.dart b/lib/pages/live/widgets/live_item.dart index 0a35b06e..2a30e85c 100644 --- a/lib/pages/live/widgets/live_item.dart +++ b/lib/pages/live/widgets/live_item.dart @@ -142,19 +142,6 @@ class LiveCardV extends StatelessWidget { ), ], ), - - // child: RichText( - // maxLines: 1, - // textAlign: TextAlign.justify, - // softWrap: false, - // text: TextSpan( - // style: const TextStyle(fontSize: 11, color: Colors.white), - // children: [ - // TextSpan(text: liveItem!.areaName!), - // TextSpan(text: liveItem!.watchedShow!['text_small']), - // ], - // ), - // ), ); } } diff --git a/lib/pages/live/widgets/live_item_follow.dart b/lib/pages/live/widgets/live_item_follow.dart index 1df7e5a9..85ef3f10 100644 --- a/lib/pages/live/widgets/live_item_follow.dart +++ b/lib/pages/live/widgets/live_item_follow.dart @@ -140,19 +140,6 @@ class LiveCardVFollow extends StatelessWidget { ), ], ), - - // child: RichText( - // maxLines: 1, - // textAlign: TextAlign.justify, - // softWrap: false, - // text: TextSpan( - // style: const TextStyle(fontSize: 11, color: Colors.white), - // children: [ - // TextSpan(text: liveItem!.areaName!), - // TextSpan(text: liveItem!.watchedShow!['text_small']), - // ], - // ), - // ), ); } } diff --git a/lib/pages/member/new/content/member_contribute/content/article/member_article.dart b/lib/pages/member/content/member_contribute/content/article/member_article.dart similarity index 80% rename from lib/pages/member/new/content/member_contribute/content/article/member_article.dart rename to lib/pages/member/content/member_contribute/content/article/member_article.dart index 9bad7afa..140118df 100644 --- a/lib/pages/member/new/content/member_contribute/content/article/member_article.dart +++ b/lib/pages/member/content/member_contribute/content/article/member_article.dart @@ -1,10 +1,9 @@ -import 'package:PiliPlus/common/constants.dart'; import 'package:PiliPlus/common/widgets/loading_widget.dart'; import 'package:PiliPlus/common/widgets/refresh_indicator.dart'; import 'package:PiliPlus/http/loading_state.dart'; import 'package:PiliPlus/models/space_article/item.dart'; -import 'package:PiliPlus/pages/member/new/content/member_contribute/content/article/member_article_ctr.dart'; -import 'package:PiliPlus/pages/member/new/content/member_contribute/content/article/widget/item.dart'; +import 'package:PiliPlus/pages/member/content/member_contribute/content/article/member_article_ctr.dart'; +import 'package:PiliPlus/pages/member/content/member_contribute/content/article/widget/item.dart'; import 'package:PiliPlus/utils/grid.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; @@ -50,11 +49,7 @@ class _MemberArticleState extends State child: CustomScrollView( slivers: [ SliverGrid( - gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent( - mainAxisSpacing: 2, - maxCrossAxisExtent: Grid.mediumCardWidth * 2, - childAspectRatio: StyleString.aspectRatio * 2.2, - ), + gridDelegate: Grid.videoCardHDelegate(context), delegate: SliverChildBuilderDelegate( (context, index) { if (index == loadingState.response!.length - 1) { diff --git a/lib/pages/member/new/content/member_contribute/content/article/member_article_ctr.dart b/lib/pages/member/content/member_contribute/content/article/member_article_ctr.dart similarity index 100% rename from lib/pages/member/new/content/member_contribute/content/article/member_article_ctr.dart rename to lib/pages/member/content/member_contribute/content/article/member_article_ctr.dart diff --git a/lib/pages/member/new/content/member_contribute/content/article/widget/item.dart b/lib/pages/member/content/member_contribute/content/article/widget/item.dart similarity index 83% rename from lib/pages/member/new/content/member_contribute/content/article/widget/item.dart rename to lib/pages/member/content/member_contribute/content/article/widget/item.dart index c93bdd91..06136f12 100644 --- a/lib/pages/member/new/content/member_contribute/content/article/widget/item.dart +++ b/lib/pages/member/content/member_contribute/content/article/widget/item.dart @@ -59,27 +59,36 @@ class MemberArticleItem extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, children: [ if (item.title?.isNotEmpty == true) ...[ - Text( - item.title!, - maxLines: 2, - overflow: TextOverflow.ellipsis, + Expanded( + child: Text( + item.title!, + maxLines: 2, + overflow: TextOverflow.ellipsis, + style: TextStyle( + fontSize: Theme.of(context) + .textTheme + .bodyMedium! + .fontSize, + height: 1.42, + letterSpacing: 0.3, + ), + ), ), - const Spacer(), ], Text( '${item.publishTimeText}', style: TextStyle( fontSize: 12, + height: 1, color: Theme.of(context).colorScheme.outline, ), ), - const SizedBox(height: 4), + const SizedBox(height: 3), Row( children: [ StatView( context: context, value: item.stats?.view ?? 0, - size: 'medium', goto: 'picture', textColor: Theme.of(context).colorScheme.outline, ), @@ -87,7 +96,6 @@ class MemberArticleItem extends StatelessWidget { StatView( context: context, goto: 'reply', - size: 'medium', value: item.stats?.reply ?? 0, textColor: Theme.of(context).colorScheme.outline, ), diff --git a/lib/pages/member/new/content/member_contribute/content/audio/member_audio.dart b/lib/pages/member/content/member_contribute/content/audio/member_audio.dart similarity index 100% rename from lib/pages/member/new/content/member_contribute/content/audio/member_audio.dart rename to lib/pages/member/content/member_contribute/content/audio/member_audio.dart diff --git a/lib/pages/member/new/content/member_contribute/content/bangumi/member_bangumi.dart b/lib/pages/member/content/member_contribute/content/bangumi/member_bangumi.dart similarity index 96% rename from lib/pages/member/new/content/member_contribute/content/bangumi/member_bangumi.dart rename to lib/pages/member/content/member_contribute/content/bangumi/member_bangumi.dart index 3bbeb69a..0de0e3dc 100644 --- a/lib/pages/member/new/content/member_contribute/content/bangumi/member_bangumi.dart +++ b/lib/pages/member/content/member_contribute/content/bangumi/member_bangumi.dart @@ -4,7 +4,7 @@ import 'package:PiliPlus/common/widgets/refresh_indicator.dart'; import 'package:PiliPlus/http/loading_state.dart'; import 'package:PiliPlus/models/space_archive/item.dart'; import 'package:PiliPlus/pages/bangumi/widgets/bangumi_card_v_member_home.dart'; -import 'package:PiliPlus/pages/member/new/content/member_contribute/content/bangumi/member_bangumi_ctr.dart'; +import 'package:PiliPlus/pages/member/content/member_contribute/content/bangumi/member_bangumi_ctr.dart'; import 'package:PiliPlus/utils/grid.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; diff --git a/lib/pages/member/new/content/member_contribute/content/bangumi/member_bangumi_ctr.dart b/lib/pages/member/content/member_contribute/content/bangumi/member_bangumi_ctr.dart similarity index 90% rename from lib/pages/member/new/content/member_contribute/content/bangumi/member_bangumi_ctr.dart rename to lib/pages/member/content/member_contribute/content/bangumi/member_bangumi_ctr.dart index bc3cdd4d..2fee50c7 100644 --- a/lib/pages/member/new/content/member_contribute/content/bangumi/member_bangumi_ctr.dart +++ b/lib/pages/member/content/member_contribute/content/bangumi/member_bangumi_ctr.dart @@ -3,9 +3,9 @@ import 'package:PiliPlus/http/member.dart'; import 'package:PiliPlus/models/space_archive/data.dart'; import 'package:PiliPlus/models/space_archive/item.dart'; import 'package:PiliPlus/pages/common/common_list_controller.dart'; -import 'package:PiliPlus/pages/member/new/content/member_contribute/member_contribute.dart' +import 'package:PiliPlus/pages/member/content/member_contribute/member_contribute.dart' show ContributeType; -import 'package:PiliPlus/pages/member/new/controller.dart'; +import 'package:PiliPlus/pages/member/controller.dart'; import 'package:get/get.dart'; import 'package:PiliPlus/models/space/data.dart' as space; diff --git a/lib/pages/member/new/content/member_contribute/content/favorite/member_favorite.dart b/lib/pages/member/content/member_contribute/content/favorite/member_favorite.dart similarity index 95% rename from lib/pages/member/new/content/member_contribute/content/favorite/member_favorite.dart rename to lib/pages/member/content/member_contribute/content/favorite/member_favorite.dart index 252e4ff1..11cff622 100644 --- a/lib/pages/member/new/content/member_contribute/content/favorite/member_favorite.dart +++ b/lib/pages/member/content/member_contribute/content/favorite/member_favorite.dart @@ -3,8 +3,8 @@ import 'package:PiliPlus/common/widgets/refresh_indicator.dart'; import 'package:PiliPlus/http/loading_state.dart'; import 'package:PiliPlus/models/space_fav/datum.dart'; import 'package:PiliPlus/models/space_fav/list.dart'; -import 'package:PiliPlus/pages/member/new/content/member_contribute/content/favorite/member_favorite_ctr.dart'; -import 'package:PiliPlus/pages/member/new/content/member_contribute/content/favorite/widget/item.dart'; +import 'package:PiliPlus/pages/member/content/member_contribute/content/favorite/member_favorite_ctr.dart'; +import 'package:PiliPlus/pages/member/content/member_contribute/content/favorite/widget/item.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; diff --git a/lib/pages/member/new/content/member_contribute/content/favorite/member_favorite_ctr.dart b/lib/pages/member/content/member_contribute/content/favorite/member_favorite_ctr.dart similarity index 100% rename from lib/pages/member/new/content/member_contribute/content/favorite/member_favorite_ctr.dart rename to lib/pages/member/content/member_contribute/content/favorite/member_favorite_ctr.dart diff --git a/lib/pages/member/new/content/member_contribute/content/favorite/widget/item.dart b/lib/pages/member/content/member_contribute/content/favorite/widget/item.dart similarity index 100% rename from lib/pages/member/new/content/member_contribute/content/favorite/widget/item.dart rename to lib/pages/member/content/member_contribute/content/favorite/widget/item.dart diff --git a/lib/pages/member/new/content/member_contribute/content/season_series/controller.dart b/lib/pages/member/content/member_contribute/content/season_series/controller.dart similarity index 100% rename from lib/pages/member/new/content/member_contribute/content/season_series/controller.dart rename to lib/pages/member/content/member_contribute/content/season_series/controller.dart diff --git a/lib/pages/member/new/content/member_contribute/content/season_series/season_series_page.dart b/lib/pages/member/content/member_contribute/content/season_series/season_series_page.dart similarity index 83% rename from lib/pages/member/new/content/member_contribute/content/season_series/season_series_page.dart rename to lib/pages/member/content/member_contribute/content/season_series/season_series_page.dart index 4e9cd602..733bb823 100644 --- a/lib/pages/member/new/content/member_contribute/content/season_series/season_series_page.dart +++ b/lib/pages/member/content/member_contribute/content/season_series/season_series_page.dart @@ -1,10 +1,10 @@ import 'package:PiliPlus/common/constants.dart'; import 'package:PiliPlus/common/widgets/loading_widget.dart'; import 'package:PiliPlus/http/loading_state.dart'; -import 'package:PiliPlus/pages/member/new/content/member_contribute/content/season_series/controller.dart'; -import 'package:PiliPlus/pages/member/new/content/member_contribute/content/season_series/widget/season_series_card.dart'; -import 'package:PiliPlus/pages/member/new/content/member_contribute/content/video/member_video.dart'; -import 'package:PiliPlus/pages/member/new/content/member_contribute/member_contribute.dart'; +import 'package:PiliPlus/pages/member/content/member_contribute/content/season_series/controller.dart'; +import 'package:PiliPlus/pages/member/content/member_contribute/content/season_series/widget/season_series_card.dart'; +import 'package:PiliPlus/pages/member/content/member_contribute/content/video/member_video.dart'; +import 'package:PiliPlus/pages/member/content/member_contribute/member_contribute.dart'; import 'package:PiliPlus/utils/grid.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; @@ -51,11 +51,7 @@ class _SeasonSeriesPageState extends State bottom: MediaQuery.paddingOf(context).bottom + 80, ), sliver: SliverGrid( - gridDelegate: SliverGridDelegateWithExtentAndRatio( - mainAxisSpacing: 2, - maxCrossAxisExtent: Grid.mediumCardWidth * 2, - childAspectRatio: StyleString.aspectRatio * 2.2, - ), + gridDelegate: Grid.videoCardHDelegate(context), delegate: SliverChildBuilderDelegate( (context, index) { if (index == loadingState.response!.length - 1) { diff --git a/lib/pages/member/new/content/member_contribute/content/season_series/widget/season_series_card.dart b/lib/pages/member/content/member_contribute/content/season_series/widget/season_series_card.dart similarity index 97% rename from lib/pages/member/new/content/member_contribute/content/season_series/widget/season_series_card.dart rename to lib/pages/member/content/member_contribute/content/season_series/widget/season_series_card.dart index 3e71fcf8..d9e58658 100644 --- a/lib/pages/member/new/content/member_contribute/content/season_series/widget/season_series_card.dart +++ b/lib/pages/member/content/member_contribute/content/season_series/widget/season_series_card.dart @@ -87,7 +87,7 @@ class SeasonSeriesCard extends StatelessWidget { Utils.dateFormat(item['meta']['ptime']), maxLines: 1, style: TextStyle( - fontSize: Theme.of(context).textTheme.labelSmall!.fontSize, + fontSize: 12, height: 1, color: Theme.of(context).colorScheme.outline, overflow: TextOverflow.clip, diff --git a/lib/pages/member/new/content/member_contribute/content/video/member_video.dart b/lib/pages/member/content/member_contribute/content/video/member_video.dart similarity index 94% rename from lib/pages/member/new/content/member_contribute/content/video/member_video.dart rename to lib/pages/member/content/member_contribute/content/video/member_video.dart index e834580e..1ec420e1 100644 --- a/lib/pages/member/new/content/member_contribute/content/video/member_video.dart +++ b/lib/pages/member/content/member_contribute/content/video/member_video.dart @@ -6,10 +6,10 @@ import 'package:PiliPlus/common/widgets/scroll_physics.dart'; import 'package:PiliPlus/common/widgets/video_card_h_member_video.dart'; import 'package:PiliPlus/http/loading_state.dart'; import 'package:PiliPlus/models/space_archive/item.dart'; -import 'package:PiliPlus/pages/member/new/content/member_contribute/content/video/member_video_ctr.dart'; -import 'package:PiliPlus/pages/member/new/content/member_contribute/member_contribute.dart' +import 'package:PiliPlus/pages/member/content/member_contribute/content/video/member_video_ctr.dart'; +import 'package:PiliPlus/pages/member/content/member_contribute/member_contribute.dart' show ContributeType; -import 'package:PiliPlus/pages/member/new/controller.dart'; +import 'package:PiliPlus/pages/member/controller.dart'; import 'package:PiliPlus/utils/grid.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; @@ -178,11 +178,7 @@ class _MemberVideoState extends State bottom: MediaQuery.of(context).padding.bottom + 80, ), sliver: SliverGrid( - gridDelegate: SliverGridDelegateWithExtentAndRatio( - mainAxisSpacing: 2, - maxCrossAxisExtent: Grid.mediumCardWidth * 2, - childAspectRatio: StyleString.aspectRatio * 2.2, - ), + gridDelegate: Grid.videoCardHDelegate(context), delegate: SliverChildBuilderDelegate( (context, index) { if (widget.type != ContributeType.season && diff --git a/lib/pages/member/new/content/member_contribute/content/video/member_video_ctr.dart b/lib/pages/member/content/member_contribute/content/video/member_video_ctr.dart similarity index 98% rename from lib/pages/member/new/content/member_contribute/content/video/member_video_ctr.dart rename to lib/pages/member/content/member_contribute/content/video/member_video_ctr.dart index 8844aa9a..931c29bf 100644 --- a/lib/pages/member/new/content/member_contribute/content/video/member_video_ctr.dart +++ b/lib/pages/member/content/member_contribute/content/video/member_video_ctr.dart @@ -5,7 +5,7 @@ import 'package:PiliPlus/models/space_archive/data.dart'; import 'package:PiliPlus/models/space_archive/episodic_button.dart'; import 'package:PiliPlus/models/space_archive/item.dart'; import 'package:PiliPlus/pages/common/common_list_controller.dart'; -import 'package:PiliPlus/pages/member/new/content/member_contribute/member_contribute.dart' +import 'package:PiliPlus/pages/member/content/member_contribute/member_contribute.dart' show ContributeType; import 'package:PiliPlus/utils/extension.dart'; import 'package:PiliPlus/utils/id_utils.dart'; diff --git a/lib/pages/member/new/content/member_contribute/member_contribute.dart b/lib/pages/member/content/member_contribute/member_contribute.dart similarity index 88% rename from lib/pages/member/new/content/member_contribute/member_contribute.dart rename to lib/pages/member/content/member_contribute/member_contribute.dart index 78a8d5fc..85ea741b 100644 --- a/lib/pages/member/new/content/member_contribute/member_contribute.dart +++ b/lib/pages/member/content/member_contribute/member_contribute.dart @@ -1,8 +1,8 @@ -import 'package:PiliPlus/pages/member/new/content/member_contribute/content/article/member_article.dart'; -import 'package:PiliPlus/pages/member/new/content/member_contribute/content/audio/member_audio.dart'; -import 'package:PiliPlus/pages/member/new/content/member_contribute/content/season_series/season_series_page.dart'; -import 'package:PiliPlus/pages/member/new/content/member_contribute/content/video/member_video.dart'; -import 'package:PiliPlus/pages/member/new/content/member_contribute/member_contribute_ctr.dart'; +import 'package:PiliPlus/pages/member/content/member_contribute/content/article/member_article.dart'; +import 'package:PiliPlus/pages/member/content/member_contribute/content/audio/member_audio.dart'; +import 'package:PiliPlus/pages/member/content/member_contribute/content/season_series/season_series_page.dart'; +import 'package:PiliPlus/pages/member/content/member_contribute/content/video/member_video.dart'; +import 'package:PiliPlus/pages/member/content/member_contribute/member_contribute_ctr.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; diff --git a/lib/pages/member/new/content/member_contribute/member_contribute_ctr.dart b/lib/pages/member/content/member_contribute/member_contribute_ctr.dart similarity index 93% rename from lib/pages/member/new/content/member_contribute/member_contribute_ctr.dart rename to lib/pages/member/content/member_contribute/member_contribute_ctr.dart index 18c3ef00..68bee3a3 100644 --- a/lib/pages/member/new/content/member_contribute/member_contribute_ctr.dart +++ b/lib/pages/member/content/member_contribute/member_contribute_ctr.dart @@ -3,12 +3,12 @@ import 'dart:math'; import 'package:PiliPlus/http/loading_state.dart'; import 'package:PiliPlus/models/space/tab2.dart'; import 'package:PiliPlus/pages/common/common_data_controller.dart'; -import 'package:PiliPlus/pages/member/new/controller.dart'; +import 'package:PiliPlus/pages/member/controller.dart'; import 'package:PiliPlus/utils/extension.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; -import '../../../../../models/space/item.dart'; +import '../../../../models/space/item.dart'; class MemberContributeCtr extends CommonDataController with GetTickerProviderStateMixin { diff --git a/lib/pages/member/new/content/member_home/member_home.dart b/lib/pages/member/content/member_home/member_home.dart similarity index 95% rename from lib/pages/member/new/content/member_home/member_home.dart rename to lib/pages/member/content/member_home/member_home.dart index 868b109b..f7e6f226 100644 --- a/lib/pages/member/new/content/member_home/member_home.dart +++ b/lib/pages/member/content/member_home/member_home.dart @@ -7,10 +7,10 @@ import 'package:PiliPlus/http/loading_state.dart'; import 'package:PiliPlus/models/space/data.dart'; import 'package:PiliPlus/models/space/item.dart'; import 'package:PiliPlus/pages/bangumi/widgets/bangumi_card_v_member_home.dart'; -import 'package:PiliPlus/pages/member/new/content/member_contribute/content/article/widget/item.dart'; -import 'package:PiliPlus/pages/member/new/content/member_contribute/member_contribute_ctr.dart'; -import 'package:PiliPlus/pages/member/new/content/member_home/widget/fav_item.dart'; -import 'package:PiliPlus/pages/member/new/controller.dart'; +import 'package:PiliPlus/pages/member/content/member_contribute/content/article/widget/item.dart'; +import 'package:PiliPlus/pages/member/content/member_contribute/member_contribute_ctr.dart'; +import 'package:PiliPlus/pages/member/content/member_home/widget/fav_item.dart'; +import 'package:PiliPlus/pages/member/controller.dart'; import 'package:PiliPlus/pages/member_coin/index.dart'; import 'package:PiliPlus/pages/member_like/index.dart'; import 'package:PiliPlus/utils/grid.dart'; @@ -172,11 +172,7 @@ class _MemberHomeState extends State count: loadingState.response.article.count, ), SliverGrid( - gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent( - mainAxisSpacing: 2, - maxCrossAxisExtent: Grid.mediumCardWidth * 2, - childAspectRatio: StyleString.aspectRatio * 2.2, - ), + gridDelegate: Grid.videoCardHDelegate(context), delegate: SliverChildBuilderDelegate( (context, index) { return MemberArticleItem( diff --git a/lib/pages/member/new/content/member_home/widget/fav_item.dart b/lib/pages/member/content/member_home/widget/fav_item.dart similarity index 100% rename from lib/pages/member/new/content/member_home/widget/fav_item.dart rename to lib/pages/member/content/member_home/widget/fav_item.dart diff --git a/lib/pages/member/controller.dart b/lib/pages/member/controller.dart index dca59c5f..dc6f5320 100644 --- a/lib/pages/member/controller.dart +++ b/lib/pages/member/controller.dart @@ -1,205 +1,150 @@ +import 'dart:math'; + +import 'package:PiliPlus/http/loading_state.dart'; +import 'package:PiliPlus/http/member.dart'; +import 'package:PiliPlus/http/video.dart'; +import 'package:PiliPlus/models/space/data.dart'; +import 'package:PiliPlus/models/space/item.dart'; +import 'package:PiliPlus/models/space/tab2.dart'; +import 'package:PiliPlus/pages/common/common_data_controller.dart'; +import 'package:PiliPlus/utils/storage.dart'; import 'package:PiliPlus/utils/utils.dart'; import 'package:flutter/material.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; -import 'package:PiliPlus/http/member.dart'; -import 'package:PiliPlus/http/user.dart'; -import 'package:PiliPlus/http/video.dart'; -import 'package:PiliPlus/models/member/coin.dart'; -import 'package:PiliPlus/models/member/info.dart'; -import 'package:PiliPlus/utils/storage.dart'; +import 'package:intl/intl.dart'; -import '../video/detail/introduction/widgets/group_panel.dart'; +enum MemberTabType { none, home, dynamic, contribute, favorite, bangumi } -class MemberController extends GetxController { - int? mid; - MemberController({this.mid}); - Rx memberInfo = MemberInfoModel().obs; - late Map userStat; - RxString face = ''.obs; - String? heroTag; - late int ownerMid; - bool specialFollowed = false; - // 投稿列表 - dynamic userInfo; - RxInt attribute = (-1).obs; - RxString attributeText = '关注'.obs; - RxList recentCoinsList = [].obs; - String? wwebid; +extension MemberTabTypeExt on MemberTabType { + String get title => ['默认', '首页', '动态', '投稿', '收藏', '番剧'][index]; +} + +class MemberControllerNew extends CommonDataController + with GetTickerProviderStateMixin { + MemberControllerNew({required this.mid}); + int mid; + RxBool showUname = false.obs; + String? username; + int? ownerMid; + RxBool isFollow = false.obs; + RxInt relation = 1.obs; + TabController? tabController; + late List tabs; + List? tab2; + RxInt contributeInitialIndex = 0.obs; + double top = 0; + bool? hasSeasonOrSeries; + final fromViewAid = Get.parameters['from_view_aid']; @override - void onInit() async { + void onInit() { super.onInit(); - mid = mid ?? int.parse(Get.parameters['mid']!); - userInfo = GStorage.userInfo.get('userInfoCache'); - ownerMid = userInfo != null ? userInfo.mid : -1; - try { - face.value = Get.arguments['face'] ?? ''; - heroTag = Get.arguments['heroTag'] ?? ''; - } catch (_) {} - relationSearch(); + ownerMid = Accounts.main.mid; + queryData(); } - // 获取用户信息 - Future> getInfo() { - return Future.wait([getMemberInfo(), getMemberStat(), getMemberView()]) - .then((res) => res[0]); - } + dynamic live; - Future> getMemberInfo() async { - wwebid ??= await Utils.getWwebid(mid); - await getMemberStat(); - await getMemberView(); - var res = await MemberHttp.memberInfo(mid: mid, wwebid: wwebid); - if (res['status']) { - memberInfo.value = res['data']; - face.value = res['data'].face; - } - return res; - } + int? silence; + String? endTime; - // 获取用户状态 - Future> getMemberStat() async { - var res = await MemberHttp.memberStat(mid: mid); - if (res['status']) { - userStat = res['data']; - } - return res; - } + late final implTabs = const [ + 'home', + 'dynamic', + 'contribute', + 'favorite', + 'bangumi', + ]; - // 获取用户播放数 获赞数 - Future> getMemberView() async { - var res = await MemberHttp.memberView(mid: mid!); - if (res['status']) { - userStat.addAll(res['data']); + @override + bool customHandleResponse(bool isRefresh, Success response) { + Data data = response.response; + username = data.card?.name ?? ''; + isFollow.value = data.card?.relation?.isFollow == 1; + relation.value = data.relSpecial == 1 ? 2 : data.relation ?? 1; + tab2 = data.tab2; + live = data.live; + silence = data.card?.silence; + if ((data.ugcSeason?.count != null && data.ugcSeason?.count != 0) || + data.series?.item?.isNotEmpty == true) { + hasSeasonOrSeries = true; } - return res; - } - - Future delayedUpdateRelation() async { - await Future.delayed(const Duration(milliseconds: 1000), () async { - SmartDialog.showToast('更新状态'); - await relationSearch(); - memberInfo.update((val) {}); - }); - } - - // 关注/取关up - Future actionRelationMod(BuildContext context) async { - if (userInfo == null) { - SmartDialog.showToast('账号未登录'); - return; + if (data.card?.endTime != null) { + if (data.card!.endTime == 0) { + endTime = ': 永久封禁'; + } else if (data.card!.endTime! > + DateTime.now().millisecondsSinceEpoch ~/ 1000) { + endTime = + ':至 ${DateFormat('yyyy-MM-dd HH:mm:ss').format(DateTime.fromMillisecondsSinceEpoch(data.card!.endTime! * 1000))}'; + } } - if (memberInfo.value.mid == null) { - SmartDialog.showToast('尚未获取到用户信息'); - return; - } - if (attribute.value == 128) { - blockUser(context); - return; - } - await showDialog( - context: context, - builder: (context) { - return AlertDialog( - title: const Text('操作'), - actions: [ - if (memberInfo.value.isFollowed!) ...[ - TextButton( - onPressed: () async { - final res = await MemberHttp.addUsers( - mid, specialFollowed ? '0' : '-10'); - SmartDialog.showToast(res['msg']); - if (res['status']) { - specialFollowed = !specialFollowed; - } - Get.back(); - }, - child: Text(specialFollowed ? '移除特别关注' : '加入特别关注'), - ), - TextButton( - onPressed: () async { - await Get.bottomSheet( - GroupPanel(mid: mid), - isScrollControlled: true, - backgroundColor: Theme.of(context).colorScheme.surface, - ); - Get.back(); - }, - child: const Text('设置分组'), - ), - ], - TextButton( - onPressed: () async { - var res = await VideoHttp.relationMod( - mid: mid!, - act: memberInfo.value.isFollowed! ? 2 : 1, - reSrc: 11, - ); - SmartDialog.showToast(res['status'] ? "操作成功" : res['msg']); - if (res['status']) { - memberInfo.value.isFollowed = !memberInfo.value.isFollowed!; - } - Get.back(); - }, - child: Text(memberInfo.value.isFollowed! ? '取消关注' : '关注'), - ), - TextButton( - onPressed: () => Get.back(), - child: Text( - '取消', - style: TextStyle(color: Theme.of(context).colorScheme.outline), - ), - ), - ], + tab2?.retainWhere((item) => implTabs.contains(item.param)); + if (tab2?.isNotEmpty == true) { + if (!data.tab!.toJson().values.contains(true) && + tab2!.first.param == 'home') { + // remove empty home tab + tab2!.removeAt(0); + } + if (tab2!.isNotEmpty) { + int initialIndex = -1; + MemberTabType memberTab = GStorage.memberTab; + if (memberTab != MemberTabType.none) { + initialIndex = tab2!.indexWhere((item) { + return item.param == memberTab.name; + }); + } + if (initialIndex == -1) { + if (data.defaultTab == 'video') { + data.defaultTab = 'contribute'; + } + initialIndex = tab2!.indexWhere((item) { + return item.param == data.defaultTab; + }); + } + tabs = tab2!.map((item) => Tab(text: item.title ?? '')).toList(); + tabController = TabController( + vsync: this, + length: tabs.length, + initialIndex: max(0, initialIndex), ); - }, - ); - await delayedUpdateRelation(); - } - - // 关系查询 - Future relationSearch() async { - if (userInfo == null) return; - if (mid == ownerMid) return; - var res = await UserHttp.hasFollow(mid!); - if (res['status']) { - attribute.value = res['data']['attribute']; - switch (attribute.value) { - case 1: - attributeText.value = '悄悄关注'; - memberInfo.value.isFollowed = true; - break; - case 2: - attributeText.value = '已关注'; - memberInfo.value.isFollowed = true; - break; - case 6: - attributeText.value = '已互关'; - memberInfo.value.isFollowed = true; - break; - case 128: - attributeText.value = '已拉黑'; - memberInfo.value.isFollowed = false; - break; - default: - attributeText.value = '关注'; - memberInfo.value.isFollowed = false; } - if (res['data']['special'] == 1) { - specialFollowed = true; - attributeText.value += ' 🔔'; - } else { - specialFollowed = false; - } - } else { - SmartDialog.showToast(res['msg']); } + loadingState.value = response; + return true; } - // 拉黑用户 + @override + bool handleError(String? errMsg) { + tab2 = [ + Tab2(title: '动态', param: 'dynamic'), + Tab2( + title: '投稿', + param: 'contribute', + items: [Item(title: '视频', param: 'video')], + ), + Tab2(title: '收藏', param: 'favorite'), + Tab2(title: '追番', param: 'bangumi'), + ]; + tabs = tab2!.map((item) => Tab(text: item.title)).toList(); + tabController = TabController( + vsync: this, + length: tabs.length, + ); + showUname.value = true; + username = errMsg; + loadingState.value = LoadingState.success(null); + return true; + } + + @override + Future> customGetData() => MemberHttp.space( + mid: mid, + fromViewAid: fromViewAid, + ); + Future blockUser(BuildContext context) async { - if (userInfo == null) { + if (ownerMid == 0) { SmartDialog.showToast('账号未登录'); return; } @@ -208,10 +153,10 @@ class MemberController extends GetxController { builder: (context) { return AlertDialog( title: const Text('提示'), - content: Text(attribute.value != 128 ? '确定拉黑UP主?' : '从黑名单移除UP主'), + content: Text(relation.value != -1 ? '确定拉黑UP主?' : '从黑名单移除UP主'), actions: [ TextButton( - onPressed: () => Get.back(), + onPressed: Get.back, child: Text( '点错了', style: TextStyle(color: Theme.of(context).colorScheme.outline), @@ -220,18 +165,7 @@ class MemberController extends GetxController { TextButton( onPressed: () async { Get.back(); - var res = await VideoHttp.relationMod( - mid: mid!, - act: attribute.value != 128 ? 5 : 6, - reSrc: 11, - ); - if (res['status']) { - attribute.value = attribute.value != 128 ? 128 : 0; - attributeText.value = attribute.value == 128 ? '已拉黑' : '关注'; - memberInfo.value.isFollowed = false; - relationSearch(); - memberInfo.update((val) {}); - } + _onBlock(); }, child: const Text('确认'), ) @@ -242,41 +176,46 @@ class MemberController extends GetxController { } void shareUser() { - Utils.shareText( - '${memberInfo.value.name} - https://space.bilibili.com/$mid'); + Utils.shareText('https://space.bilibili.com/$mid'); } - // 请求专栏 - Future getMemberSeasons() async { - if (userInfo == null) return; - var res = await MemberHttp.getMemberSeasons(mid, 1, 10); - if (!res['status']) { - SmartDialog.showToast("用户专栏请求异常:${res['msg']}"); + void _onBlock() async { + dynamic res = await VideoHttp.relationMod( + mid: mid, + act: relation.value != -1 ? 5 : 6, + reSrc: 11, + ); + if (res['status']) { + relation.value = relation.value != -1 ? -1 : 1; + isFollow.value = false; } - return res; } - // 请求投币视频 - Future getRecentCoinVideo() async { - // if (userInfo == null) return; - // var res = await MemberHttp.getRecentCoinVideo(mid: mid!); - // recentCoinsList.value = res['data']; - // return res; + void onFollow(BuildContext context) async { + if (mid == ownerMid) { + Get.toNamed('/editProfile'); + } else if (relation.value == -1) { + _onBlock(); + } else { + if (ownerMid == null) { + SmartDialog.showToast('账号未登录'); + return; + } + Utils.actionRelationMod( + context: context, + mid: mid, + isFollow: isFollow.value, + callback: (attribute) { + relation.value = attribute; + isFollow.value = attribute != 0; + }, + ); + } } - // 跳转查看动态 - void pushDynamicsPage() => Get.toNamed('/memberDynamics?mid=$mid'); - - // 跳转查看投稿 - void pushArchivesPage() async { - wwebid ??= await Utils.getWwebid(mid); - Get.toNamed('/memberArchive?mid=$mid&wwebid=$wwebid'); - } - - // 跳转查看专栏 - void pushSeasonsPage() {} - // 跳转查看最近投币 - void pushRecentCoinsPage() async { - if (recentCoinsList.isNotEmpty) {} + @override + void onClose() { + tabController?.dispose(); + super.onClose(); } } diff --git a/lib/pages/member/index.dart b/lib/pages/member/index.dart deleted file mode 100644 index c422fb09..00000000 --- a/lib/pages/member/index.dart +++ /dev/null @@ -1,4 +0,0 @@ -library member; - -export './controller.dart'; -export './view.dart'; diff --git a/lib/pages/member/new/member_page.dart b/lib/pages/member/member_page.dart similarity index 72% rename from lib/pages/member/new/member_page.dart rename to lib/pages/member/member_page.dart index ea9cfcb4..c3fbc252 100644 --- a/lib/pages/member/new/member_page.dart +++ b/lib/pages/member/member_page.dart @@ -1,19 +1,21 @@ import 'package:PiliPlus/common/widgets/dynamic_sliver_appbar.dart'; import 'package:PiliPlus/common/widgets/loading_widget.dart'; +import 'package:PiliPlus/common/widgets/radio_widget.dart'; import 'package:PiliPlus/http/loading_state.dart'; +import 'package:PiliPlus/http/member.dart'; import 'package:PiliPlus/models/space/data.dart'; -import 'package:PiliPlus/pages/member/new/content/member_contribute/content/bangumi/member_bangumi.dart'; -import 'package:PiliPlus/pages/member/new/content/member_contribute/content/favorite/member_favorite.dart'; -import 'package:PiliPlus/pages/member/new/content/member_contribute/member_contribute.dart'; -import 'package:PiliPlus/pages/member/new/content/member_home/member_home.dart'; -import 'package:PiliPlus/pages/member/new/controller.dart'; -import 'package:PiliPlus/pages/member/new/widget/user_info_card.dart'; -import 'package:PiliPlus/pages/member/view.dart'; +import 'package:PiliPlus/pages/member/content/member_contribute/content/bangumi/member_bangumi.dart'; +import 'package:PiliPlus/pages/member/content/member_contribute/content/favorite/member_favorite.dart'; +import 'package:PiliPlus/pages/member/content/member_contribute/member_contribute.dart'; +import 'package:PiliPlus/pages/member/content/member_home/member_home.dart'; +import 'package:PiliPlus/pages/member/controller.dart'; +import 'package:PiliPlus/pages/member/widget/user_info_card.dart'; import 'package:PiliPlus/pages/member_dynamics/view.dart'; import 'package:PiliPlus/utils/extension.dart'; import 'package:PiliPlus/utils/utils.dart'; import 'package:extended_nested_scroll_view/extended_nested_scroll_view.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; import 'package:PiliPlus/common/widgets/scroll_physics.dart'; @@ -298,3 +300,124 @@ class _MemberPageNewState extends State { }; } } + +class ReportPanel extends StatefulWidget { + const ReportPanel({ + super.key, + required this.name, + required this.mid, + }); + + final dynamic name; + final dynamic mid; + + @override + State createState() => _ReportPanelState(); +} + +class _ReportPanelState extends State { + final List _reasonList = List.generate(3, (_) => false).toList(); + final Set _reason = {}; + int? _reasonV2; + + @override + Widget build(BuildContext context) { + return SingleChildScrollView( + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + '举报: ${widget.name}', + style: const TextStyle(fontSize: 18), + ), + const SizedBox(height: 4), + Text('uid: ${widget.mid}'), + const SizedBox(height: 10), + const Text('举报内容(必选,可多选)'), + ...List.generate( + 3, + (index) => _checkBoxWidget( + _reasonList[index], + (value) { + setState(() => _reasonList[index] = value); + if (value) { + _reason.add(index + 1); + } else { + _reason.remove(index + 1); + } + }, + ['头像违规', '昵称违规', '签名违规'][index], + ), + ), + const Text('举报理由(单选,非必选)'), + ...List.generate( + 5, + (index) => RadioWidget( + value: index, + groupValue: _reasonV2, + onChanged: (value) { + setState(() => _reasonV2 = value); + }, + title: const ['色情低俗', '不实信息', '违禁', '人身攻击', '赌博诈骗'][index], + ), + ), + const SizedBox(height: 10), + Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + TextButton( + onPressed: Get.back, + child: Text( + '取消', + style: + TextStyle(color: Theme.of(context).colorScheme.outline), + ), + ), + TextButton( + onPressed: () async { + if (_reason.isEmpty) { + SmartDialog.showToast('至少选择一项作为举报内容'); + } else { + Get.back(); + dynamic result = await MemberHttp.reportMember( + widget.mid, + reason: _reason.join(','), + reasonV2: _reasonV2 != null ? _reasonV2! + 1 : null, + ); + if (result['msg'] is String && result['msg'].isNotEmpty) { + SmartDialog.showToast(result['msg']); + } else { + SmartDialog.showToast('举报失败'); + } + } + }, + child: const Text('确定'), + ), + ], + ), + ], + ), + ); + } +} + +Widget _checkBoxWidget( + bool defValue, + ValueChanged onChanged, + String title, +) { + return InkWell( + onTap: () => onChanged(!defValue), + child: Row( + children: [ + Checkbox( + value: defValue, + onChanged: onChanged, + materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, + ), + Text(title), + ], + ), + ); +} diff --git a/lib/pages/member/new/controller.dart b/lib/pages/member/new/controller.dart deleted file mode 100644 index dc6f5320..00000000 --- a/lib/pages/member/new/controller.dart +++ /dev/null @@ -1,221 +0,0 @@ -import 'dart:math'; - -import 'package:PiliPlus/http/loading_state.dart'; -import 'package:PiliPlus/http/member.dart'; -import 'package:PiliPlus/http/video.dart'; -import 'package:PiliPlus/models/space/data.dart'; -import 'package:PiliPlus/models/space/item.dart'; -import 'package:PiliPlus/models/space/tab2.dart'; -import 'package:PiliPlus/pages/common/common_data_controller.dart'; -import 'package:PiliPlus/utils/storage.dart'; -import 'package:PiliPlus/utils/utils.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; -import 'package:get/get.dart'; -import 'package:intl/intl.dart'; - -enum MemberTabType { none, home, dynamic, contribute, favorite, bangumi } - -extension MemberTabTypeExt on MemberTabType { - String get title => ['默认', '首页', '动态', '投稿', '收藏', '番剧'][index]; -} - -class MemberControllerNew extends CommonDataController - with GetTickerProviderStateMixin { - MemberControllerNew({required this.mid}); - int mid; - RxBool showUname = false.obs; - String? username; - int? ownerMid; - RxBool isFollow = false.obs; - RxInt relation = 1.obs; - TabController? tabController; - late List tabs; - List? tab2; - RxInt contributeInitialIndex = 0.obs; - double top = 0; - bool? hasSeasonOrSeries; - final fromViewAid = Get.parameters['from_view_aid']; - - @override - void onInit() { - super.onInit(); - ownerMid = Accounts.main.mid; - queryData(); - } - - dynamic live; - - int? silence; - String? endTime; - - late final implTabs = const [ - 'home', - 'dynamic', - 'contribute', - 'favorite', - 'bangumi', - ]; - - @override - bool customHandleResponse(bool isRefresh, Success response) { - Data data = response.response; - username = data.card?.name ?? ''; - isFollow.value = data.card?.relation?.isFollow == 1; - relation.value = data.relSpecial == 1 ? 2 : data.relation ?? 1; - tab2 = data.tab2; - live = data.live; - silence = data.card?.silence; - if ((data.ugcSeason?.count != null && data.ugcSeason?.count != 0) || - data.series?.item?.isNotEmpty == true) { - hasSeasonOrSeries = true; - } - if (data.card?.endTime != null) { - if (data.card!.endTime == 0) { - endTime = ': 永久封禁'; - } else if (data.card!.endTime! > - DateTime.now().millisecondsSinceEpoch ~/ 1000) { - endTime = - ':至 ${DateFormat('yyyy-MM-dd HH:mm:ss').format(DateTime.fromMillisecondsSinceEpoch(data.card!.endTime! * 1000))}'; - } - } - tab2?.retainWhere((item) => implTabs.contains(item.param)); - if (tab2?.isNotEmpty == true) { - if (!data.tab!.toJson().values.contains(true) && - tab2!.first.param == 'home') { - // remove empty home tab - tab2!.removeAt(0); - } - if (tab2!.isNotEmpty) { - int initialIndex = -1; - MemberTabType memberTab = GStorage.memberTab; - if (memberTab != MemberTabType.none) { - initialIndex = tab2!.indexWhere((item) { - return item.param == memberTab.name; - }); - } - if (initialIndex == -1) { - if (data.defaultTab == 'video') { - data.defaultTab = 'contribute'; - } - initialIndex = tab2!.indexWhere((item) { - return item.param == data.defaultTab; - }); - } - tabs = tab2!.map((item) => Tab(text: item.title ?? '')).toList(); - tabController = TabController( - vsync: this, - length: tabs.length, - initialIndex: max(0, initialIndex), - ); - } - } - loadingState.value = response; - return true; - } - - @override - bool handleError(String? errMsg) { - tab2 = [ - Tab2(title: '动态', param: 'dynamic'), - Tab2( - title: '投稿', - param: 'contribute', - items: [Item(title: '视频', param: 'video')], - ), - Tab2(title: '收藏', param: 'favorite'), - Tab2(title: '追番', param: 'bangumi'), - ]; - tabs = tab2!.map((item) => Tab(text: item.title)).toList(); - tabController = TabController( - vsync: this, - length: tabs.length, - ); - showUname.value = true; - username = errMsg; - loadingState.value = LoadingState.success(null); - return true; - } - - @override - Future> customGetData() => MemberHttp.space( - mid: mid, - fromViewAid: fromViewAid, - ); - - Future blockUser(BuildContext context) async { - if (ownerMid == 0) { - SmartDialog.showToast('账号未登录'); - return; - } - await showDialog( - context: context, - builder: (context) { - return AlertDialog( - title: const Text('提示'), - content: Text(relation.value != -1 ? '确定拉黑UP主?' : '从黑名单移除UP主'), - actions: [ - TextButton( - onPressed: Get.back, - child: Text( - '点错了', - style: TextStyle(color: Theme.of(context).colorScheme.outline), - ), - ), - TextButton( - onPressed: () async { - Get.back(); - _onBlock(); - }, - child: const Text('确认'), - ) - ], - ); - }, - ); - } - - void shareUser() { - Utils.shareText('https://space.bilibili.com/$mid'); - } - - void _onBlock() async { - dynamic res = await VideoHttp.relationMod( - mid: mid, - act: relation.value != -1 ? 5 : 6, - reSrc: 11, - ); - if (res['status']) { - relation.value = relation.value != -1 ? -1 : 1; - isFollow.value = false; - } - } - - void onFollow(BuildContext context) async { - if (mid == ownerMid) { - Get.toNamed('/editProfile'); - } else if (relation.value == -1) { - _onBlock(); - } else { - if (ownerMid == null) { - SmartDialog.showToast('账号未登录'); - return; - } - Utils.actionRelationMod( - context: context, - mid: mid, - isFollow: isFollow.value, - callback: (attribute) { - relation.value = attribute; - isFollow.value = attribute != 0; - }, - ); - } - } - - @override - void onClose() { - tabController?.dispose(); - super.onClose(); - } -} diff --git a/lib/pages/member/view.dart b/lib/pages/member/view.dart deleted file mode 100644 index dea10b98..00000000 --- a/lib/pages/member/view.dart +++ /dev/null @@ -1,652 +0,0 @@ -import 'dart:async'; - -import 'package:PiliPlus/common/widgets/radio_widget.dart'; -import 'package:PiliPlus/http/member.dart'; -import 'package:PiliPlus/utils/extension.dart'; -import 'package:cached_network_image/cached_network_image.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; -import 'package:font_awesome_flutter/font_awesome_flutter.dart'; -import 'package:get/get.dart'; -import 'package:PiliPlus/common/constants.dart'; -import 'package:PiliPlus/common/widgets/network_img_layer.dart'; -import 'package:PiliPlus/pages/member/index.dart'; -import 'package:PiliPlus/utils/utils.dart'; - -import 'widgets/conis.dart'; -import 'widgets/profile.dart'; -import 'widgets/seasons.dart'; - -@Deprecated('Use MemberPageNew instead') -class MemberPage extends StatefulWidget { - const MemberPage({super.key}); - - @override - State createState() => _MemberPageState(); -} - -class _MemberPageState extends State { - late String heroTag; - late MemberController _memberController; - late Future _futureBuilderFuture; - late Future _memberSeasonsFuture; - late Future _memberCoinsFuture; - final ScrollController _extendNestCtr = ScrollController(); - final StreamController appbarStream = StreamController(); - late int mid; - - @override - void initState() { - super.initState(); - mid = int.parse(Get.parameters['mid']!); - heroTag = Get.arguments['heroTag'] ?? Utils.makeHeroTag(mid); - _memberController = Get.put(MemberController(), tag: heroTag); - _futureBuilderFuture = _memberController.getInfo(); - _memberSeasonsFuture = _memberController.getMemberSeasons(); - _memberCoinsFuture = _memberController.getRecentCoinVideo(); - _extendNestCtr.addListener(listener); - } - - void listener() { - final double offset = _extendNestCtr.position.pixels; - if (offset > 100) { - appbarStream.add(true); - } else { - appbarStream.add(false); - } - } - - @override - void dispose() { - _extendNestCtr.removeListener(listener); - _extendNestCtr.dispose(); - appbarStream.close(); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - bool isHorizontal = context.width > context.height; - return Scaffold( - primary: true, - body: Column( - children: [ - AppBar( - title: StreamBuilder( - stream: appbarStream.stream.distinct(), - initialData: false, - builder: (BuildContext context, AsyncSnapshot snapshot) { - return AnimatedOpacity( - opacity: snapshot.data ? 1 : 0, - curve: Curves.easeOut, - duration: const Duration(milliseconds: 500), - child: Row( - children: [ - Row( - children: [ - Obx( - () => NetworkImgLayer( - width: 35, - height: 35, - type: 'avatar', - src: _memberController.face.value, - ), - ), - const SizedBox(width: 10), - Obx( - () => Text( - _memberController.memberInfo.value.name ?? '', - style: TextStyle( - color: - Theme.of(context).colorScheme.onSurface, - fontSize: 14), - ), - ), - ], - ) - ], - ), - ); - }, - ), - actions: [ - IconButton( - tooltip: '搜索', - onPressed: () => Get.toNamed( - '/memberSearch?mid=$mid&uname=${_memberController.memberInfo.value.name!}'), - icon: const Icon(Icons.search_outlined), - ), - PopupMenuButton( - icon: const Icon(Icons.more_vert), - itemBuilder: (BuildContext context) => [ - if (_memberController.ownerMid != _memberController.mid) ...[ - PopupMenuItem( - onTap: () => _memberController.blockUser(context), - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - const Icon(Icons.block, size: 19), - const SizedBox(width: 10), - Text(_memberController.attribute.value != 128 - ? '加入黑名单' - : '移除黑名单'), - ], - ), - ) - ], - PopupMenuItem( - onTap: () => _memberController.shareUser(), - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - const Icon(Icons.share_outlined, size: 19), - const SizedBox(width: 10), - Text(_memberController.ownerMid != _memberController.mid - ? '分享UP主' - : '分享我的主页'), - ], - ), - ), - if (_memberController.userInfo != null) ...[ - const PopupMenuDivider(), - PopupMenuItem( - onTap: () { - showDialog( - context: context, - builder: (context) => AlertDialog( - clipBehavior: Clip.hardEdge, - contentPadding: const EdgeInsets.symmetric( - horizontal: 20, - vertical: 16, - ), - content: ReportPanel( - name: _memberController.memberInfo.value.name, - mid: mid, - ), - ), - ); - }, - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - Icon( - Icons.error_outline, - size: 19, - color: Theme.of(context).colorScheme.error, - ), - const SizedBox(width: 10), - Text( - '举报', - style: TextStyle( - color: Theme.of(context).colorScheme.error), - ), - ], - ), - ), - ], - ], - ), - const SizedBox(width: 4), - ], - ), - Expanded( - child: SingleChildScrollView( - physics: const AlwaysScrollableScrollPhysics( - parent: BouncingScrollPhysics(), - ), - controller: _extendNestCtr, - child: Padding( - padding: EdgeInsets.only( - bottom: MediaQuery.of(context).padding.bottom + 20, - ), - child: Column( - children: [ - profileWidget(isHorizontal), - Row(children: [ - const Spacer(), - InkWell( - onTap: _memberController.pushDynamicsPage, - child: const Row( - children: [ - Text('Ta的动态', style: TextStyle(height: 2)), - SizedBox(width: 5), - Icon(Icons.arrow_forward_ios, size: 19), - ], - ), - ), - const Spacer(), - InkWell( - onTap: _memberController.pushArchivesPage, - child: const Row( - children: [ - Text('Ta的投稿', style: TextStyle(height: 2)), - SizedBox(width: 5), - Icon(Icons.arrow_forward_ios, size: 19), - ], - ), - ), - const Spacer(), - InkWell( - onTap: () {}, - child: const Row( - children: [ - Text('Ta的专栏', style: TextStyle(height: 2)), - SizedBox(width: 5), - ], - ), - ), - const Spacer(), - ]), - MediaQuery.removePadding( - removeTop: true, - removeBottom: true, - context: context, - child: Padding( - padding: const EdgeInsets.only( - left: StyleString.safeSpace, - right: StyleString.safeSpace, - ), - child: FutureBuilder( - future: _memberSeasonsFuture, - builder: (context, snapshot) { - if (snapshot.connectionState == - ConnectionState.done) { - if (snapshot.data == null) { - return const SizedBox(); - } - if (snapshot.data['status']) { - Map data = snapshot.data as Map; - if (data['data'].seasonsList.isEmpty) { - return commonWidget('用户没有设置专栏'); - } else { - return MemberSeasonsPanel(data: data['data']); - } - } else { - // 请求错误 - return const SizedBox(); - } - } else { - return const SizedBox(); - } - }, - ), - ), - ), - - /// 收藏 - - /// 追番 - /// 最近投币 - Obx( - () => _memberController.recentCoinsList.isNotEmpty - ? ListTile( - onTap: () {}, - title: const Text('最近投币的视频'), - // trailing: const Icon(Icons.arrow_forward_outlined, - // size: 19), - ) - : const SizedBox(), - ), - MediaQuery.removePadding( - removeTop: true, - removeBottom: true, - context: context, - child: Padding( - padding: const EdgeInsets.only( - left: StyleString.safeSpace, - right: StyleString.safeSpace, - ), - child: FutureBuilder( - future: _memberCoinsFuture, - builder: (context, snapshot) { - if (snapshot.connectionState == - ConnectionState.done) { - if (snapshot.data == null) { - return const SizedBox(); - } - if (snapshot.data['status']) { - Map data = snapshot.data as Map; - return MemberCoinsPanel(data: data['data']); - } else { - // 请求错误 - return const SizedBox(); - } - } else { - return const SizedBox(); - } - }, - ), - ), - ), - // 最近点赞 - // ListTile( - // onTap: () {}, - // title: const Text('最近点赞的视频'), - // trailing: - // const Icon(Icons.arrow_forward_outlined, size: 19), - // ), - ], - ), - ), - ), - ), - ], - ), - ); - } - - Widget profileWidget(bool isHorizontal) { - return Padding( - padding: const EdgeInsets.only(left: 18, right: 18, bottom: 20), - child: FutureBuilder( - future: _futureBuilderFuture, - builder: (context, snapshot) { - if (snapshot.connectionState == ConnectionState.done && - snapshot.hasData) { - Map data = snapshot.data!; - if (data['status']) { - return Obx( - () => Stack( - alignment: AlignmentDirectional.center, - children: [profilePanelAndDetailInfo(isHorizontal, false)]), - ); - } else { - return const SizedBox(); - } - } else { - // 骨架屏 - return profilePanelAndDetailInfo(isHorizontal, true); - } - }, - ), - ); - } - - Widget profilePanelAndDetailInfo(bool isHorizontal, bool loadingStatus) { - if (isHorizontal) { - return Row( - children: [ - Expanded( - child: ProfilePanel( - ctr: _memberController, loadingStatus: loadingStatus)), - const SizedBox(width: 20), - Expanded(child: profileDetailInfo()), - ], - ); - } - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - ProfilePanel(ctr: _memberController, loadingStatus: loadingStatus), - const SizedBox(height: 20), - profileDetailInfo(), - ], - ); - } - - Widget profileDetailInfo() { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - Flexible( - child: Text( - _memberController.memberInfo.value.name ?? '', - maxLines: 1, - overflow: TextOverflow.ellipsis, - style: Theme.of(context).textTheme.titleMedium!.copyWith( - fontWeight: FontWeight.bold, - color: _memberController.memberInfo.value.vip?.status != - null && - _memberController.memberInfo.value.vip!.status! > - 0 && - _memberController.memberInfo.value.vip!.type == 2 - ? context.vipColor - : Theme.of(context).colorScheme.onSurface, - ), - )), - const SizedBox(width: 2), - if (_memberController.memberInfo.value.sex == '女') - const Icon( - FontAwesomeIcons.venus, - size: 14, - color: Colors.pink, - semanticLabel: '女', - ), - if (_memberController.memberInfo.value.sex == '男') - const Icon( - FontAwesomeIcons.mars, - size: 14, - color: Colors.blue, - semanticLabel: '男', - ), - const SizedBox(width: 4), - if (_memberController.memberInfo.value.level != null) - Image.asset( - 'assets/images/lv/lv${_memberController.memberInfo.value.level}.png', - height: 11, - semanticLabel: '等级${_memberController.memberInfo.value.level}', - ), - const SizedBox(width: 6), - if (_memberController.memberInfo.value.vip?.status == 1) ...[ - if (_memberController - .memberInfo.value.vip?.label?['img_label_uri_hans'] != - '') - CachedNetworkImage( - imageUrl: (_memberController.memberInfo.value.vip! - .label!['img_label_uri_hans'] as String) - .http2https, - height: 20, - // semanticLabel: - // _memberController.memberInfo.value.vip!.label!['text'], - ) - else if (_memberController.memberInfo.value.vip - ?.label?['img_label_uri_hans_static'] != - '') - CachedNetworkImage( - imageUrl: (_memberController.memberInfo.value.vip! - .label!['img_label_uri_hans_static'] as String) - .http2https, - height: 20, - // semanticLabel: - // _memberController.memberInfo.value.vip!.label!['text'], - ), - ], - const SizedBox(width: 5), - GestureDetector( - onTap: () { - Utils.copyText(_memberController.mid.toString()); - }, - child: Container( - padding: - const EdgeInsets.symmetric(horizontal: 8, vertical: 2.5), - decoration: BoxDecoration( - color: Theme.of(context).colorScheme.secondaryContainer, - borderRadius: const BorderRadius.all(Radius.circular(12)), - ), - child: Text( - 'UID: ${_memberController.mid}', - style: TextStyle( - height: 1, - fontSize: 12, - color: Theme.of(context).colorScheme.onSecondaryContainer, - ), - strutStyle: const StrutStyle( - height: 1, - leading: 0, - fontSize: 12, - ), - ), - ), - ), - ], - ), - if (_memberController.memberInfo.value.official != null && - _memberController.memberInfo.value.official!['title'] != '') ...[ - const SizedBox(height: 6), - Text.rich( - maxLines: 2, - TextSpan( - text: _memberController.memberInfo.value.official!['role'] == 1 - ? '个人认证:' - : '机构认证:', - style: TextStyle( - color: Theme.of(context).colorScheme.primary, - ), - children: [ - TextSpan( - text: _memberController.memberInfo.value.official!['title'], - ), - ], - ), - softWrap: true, - ), - ], - const SizedBox(height: 6), - SelectableText( - _memberController.memberInfo.value.sign ?? '', - ), - ], - ); - } - - Widget commonWidget(msg) { - return Padding( - padding: const EdgeInsets.only( - top: 20, - bottom: 30, - ), - child: Center( - child: Text( - msg, - style: Theme.of(context) - .textTheme - .labelMedium! - .copyWith(color: Theme.of(context).colorScheme.outline), - ), - ), - ); - } -} - -class ReportPanel extends StatefulWidget { - const ReportPanel({ - super.key, - required this.name, - required this.mid, - }); - - final dynamic name; - final dynamic mid; - - @override - State createState() => _ReportPanelState(); -} - -class _ReportPanelState extends State { - final List _reasonList = List.generate(3, (_) => false).toList(); - final Set _reason = {}; - int? _reasonV2; - - @override - Widget build(BuildContext context) { - return SingleChildScrollView( - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - '举报: ${widget.name}', - style: const TextStyle(fontSize: 18), - ), - const SizedBox(height: 4), - Text('uid: ${widget.mid}'), - const SizedBox(height: 10), - const Text('举报内容(必选,可多选)'), - ...List.generate( - 3, - (index) => _checkBoxWidget( - _reasonList[index], - (value) { - setState(() => _reasonList[index] = value); - if (value) { - _reason.add(index + 1); - } else { - _reason.remove(index + 1); - } - }, - ['头像违规', '昵称违规', '签名违规'][index], - ), - ), - const Text('举报理由(单选,非必选)'), - ...List.generate( - 5, - (index) => RadioWidget( - value: index, - groupValue: _reasonV2, - onChanged: (value) { - setState(() => _reasonV2 = value); - }, - title: const ['色情低俗', '不实信息', '违禁', '人身攻击', '赌博诈骗'][index], - ), - ), - const SizedBox(height: 10), - Row( - mainAxisAlignment: MainAxisAlignment.end, - children: [ - TextButton( - onPressed: Get.back, - child: Text( - '取消', - style: - TextStyle(color: Theme.of(context).colorScheme.outline), - ), - ), - TextButton( - onPressed: () async { - if (_reason.isEmpty) { - SmartDialog.showToast('至少选择一项作为举报内容'); - } else { - Get.back(); - dynamic result = await MemberHttp.reportMember( - widget.mid, - reason: _reason.join(','), - reasonV2: _reasonV2 != null ? _reasonV2! + 1 : null, - ); - if (result['msg'] is String && result['msg'].isNotEmpty) { - SmartDialog.showToast(result['msg']); - } else { - SmartDialog.showToast('举报失败'); - } - } - }, - child: const Text('确定'), - ), - ], - ), - ], - ), - ); - } -} - -Widget _checkBoxWidget( - bool defValue, - ValueChanged onChanged, - String title, -) { - return InkWell( - onTap: () => onChanged(!defValue), - child: Row( - children: [ - Checkbox( - value: defValue, - onChanged: onChanged, - materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, - ), - Text(title), - ], - ), - ); -} diff --git a/lib/pages/member/new/widget/edit_profile_page.dart b/lib/pages/member/widget/edit_profile_page.dart similarity index 100% rename from lib/pages/member/new/widget/edit_profile_page.dart rename to lib/pages/member/widget/edit_profile_page.dart diff --git a/lib/pages/member/new/widget/user_info_card.dart b/lib/pages/member/widget/user_info_card.dart similarity index 100% rename from lib/pages/member/new/widget/user_info_card.dart rename to lib/pages/member/widget/user_info_card.dart diff --git a/lib/pages/member/widgets/conis.dart b/lib/pages/member/widgets/conis.dart deleted file mode 100644 index 0c69825c..00000000 --- a/lib/pages/member/widgets/conis.dart +++ /dev/null @@ -1,31 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:PiliPlus/common/constants.dart'; -import 'package:PiliPlus/models/member/coin.dart'; -import 'package:PiliPlus/pages/member_coin/widgets/item.dart'; - -class MemberCoinsPanel extends StatelessWidget { - final List? data; - const MemberCoinsPanel({super.key, this.data}); - - @override - Widget build(BuildContext context) { - return LayoutBuilder( - builder: (context, boxConstraints) { - return GridView.builder( - gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: 2, // Use a fixed count for GridView - crossAxisSpacing: StyleString.safeSpace, - mainAxisSpacing: StyleString.safeSpace, - childAspectRatio: 0.94, - ), - physics: const NeverScrollableScrollPhysics(), - shrinkWrap: true, - itemCount: data!.length, - itemBuilder: (context, i) { - return MemberCoinsItem(coinItem: data![i]); - }, - ); - }, - ); - } -} diff --git a/lib/pages/member/widgets/profile.dart b/lib/pages/member/widgets/profile.dart deleted file mode 100644 index ef64500a..00000000 --- a/lib/pages/member/widgets/profile.dart +++ /dev/null @@ -1,272 +0,0 @@ -import 'package:PiliPlus/common/widgets/interactiveviewer_gallery/interactiveviewer_gallery.dart' - show SourceModel; -import 'package:PiliPlus/utils/extension.dart'; -import 'package:flutter/material.dart'; -import 'package:get/get.dart'; -import 'package:PiliPlus/common/widgets/network_img_layer.dart'; -import 'package:PiliPlus/models/member/info.dart'; -import 'package:PiliPlus/utils/utils.dart'; - -class ProfilePanel extends StatelessWidget { - final dynamic ctr; - final bool loadingStatus; - const ProfilePanel({ - super.key, - required this.ctr, - this.loadingStatus = false, - }); - - @override - Widget build(BuildContext context) { - MemberInfoModel memberInfo = ctr.memberInfo.value; - return Builder( - builder: ((context) { - return Row( - children: [ - Hero( - tag: !loadingStatus ? memberInfo.face : ctr.face.value, - child: Stack( - children: [ - GestureDetector( - onTap: () => context.imageView( - imgList: [ - SourceModel( - url: - !loadingStatus ? memberInfo.face : ctr.face.value, - ) - ], - ), - child: NetworkImgLayer( - width: 90, - height: 90, - type: 'avatar', - src: !loadingStatus ? memberInfo.face : ctr.face.value, - ), - ), - if (!loadingStatus && - memberInfo.liveRoom != null && - memberInfo.liveRoom!.liveStatus == 1) - Positioned( - bottom: 0, - left: 14, - child: GestureDetector( - onTap: () { - // LiveItemModel liveItem = LiveItemModel.fromJson({ - // 'title': memberInfo.liveRoom!.title, - // 'uname': memberInfo.name, - // 'face': memberInfo.face, - // 'roomid': memberInfo.liveRoom!.roomId, - // 'watched_show': memberInfo.liveRoom!.watchedShow, - // }); - Get.toNamed( - '/liveRoom?roomid=${memberInfo.liveRoom!.roomId}', - ); - }, - child: Container( - padding: const EdgeInsets.fromLTRB(6, 2, 6, 2), - decoration: BoxDecoration( - color: Theme.of(context).colorScheme.primary, - borderRadius: - const BorderRadius.all(Radius.circular(10)), - ), - child: Row(children: [ - Image.asset( - 'assets/images/live.gif', - height: 10, - ), - Text( - ' 直播中', - style: TextStyle( - color: Colors.white, - fontSize: Theme.of(context) - .textTheme - .labelSmall! - .fontSize), - ) - ]), - ), - ), - ) - ], - ), - ), - const SizedBox(width: 12), - Expanded( - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Padding( - padding: - const EdgeInsets.only(top: 10, left: 10, right: 10), - child: Row( - mainAxisSize: MainAxisSize.max, - mainAxisAlignment: MainAxisAlignment.spaceAround, - children: [ - InkWell( - onTap: () { - Get.toNamed( - '/follow?mid=${memberInfo.mid}&name=${memberInfo.name}'); - }, - child: Column( - children: [ - Text( - !loadingStatus - ? ctr.userStat!['following'].toString() - : '-', - style: const TextStyle( - fontWeight: FontWeight.bold), - ), - Text( - '关注', - style: TextStyle( - fontSize: Theme.of(context) - .textTheme - .labelMedium! - .fontSize), - ) - ], - ), - ), - InkWell( - onTap: () { - Get.toNamed( - '/fan?mid=${memberInfo.mid}&name=${memberInfo.name}'); - }, - child: Column( - children: [ - Text( - !loadingStatus - ? ctr.userStat!['follower'] != null - ? Utils.numFormat( - ctr.userStat!['follower'], - ) - : '-' - : '-', - style: const TextStyle( - fontWeight: FontWeight.bold)), - Text( - '粉丝', - style: TextStyle( - fontSize: Theme.of(context) - .textTheme - .labelMedium! - .fontSize), - ) - ], - ), - ), - InkWell( - onTap: null, - child: Column( - children: [ - Text( - !loadingStatus - ? ctr.userStat!['likes'] != null - ? Utils.numFormat( - ctr.userStat!['likes'], - ) - : '-' - : '-', - style: const TextStyle( - fontWeight: FontWeight.bold)), - Text( - '获赞', - style: TextStyle( - fontSize: Theme.of(context) - .textTheme - .labelMedium! - .fontSize), - ) - ], - )), - ], - ), - ), - const SizedBox(height: 10), - if (ctr.ownerMid != ctr.mid && ctr.ownerMid != -1) ...[ - Row( - children: [ - Obx( - () => Expanded( - child: TextButton( - onPressed: () => ctr.actionRelationMod(context), - style: TextButton.styleFrom( - foregroundColor: ctr.attribute.value == -1 - ? Colors.transparent - : ctr.attribute.value != 0 - ? Theme.of(context).colorScheme.outline - : Theme.of(context) - .colorScheme - .onPrimary, - backgroundColor: ctr.attribute.value != 0 - ? Theme.of(context) - .colorScheme - .onInverseSurface - : Theme.of(context).colorScheme.primary, - ), - child: Obx(() => Text(ctr.attributeText.value)), - ), - ), - ), - const SizedBox(width: 8), - Expanded( - child: TextButton( - onPressed: () { - Get.toNamed( - '/whisperDetail', - parameters: { - 'talkerId': ctr.mid.toString(), - 'name': memberInfo.name!, - 'face': memberInfo.face!, - 'mid': ctr.mid.toString(), - }, - ); - }, - style: TextButton.styleFrom( - backgroundColor: Theme.of(context) - .colorScheme - .onInverseSurface, - ), - child: const Text('发消息'), - ), - ) - ], - ) - ], - if (ctr.ownerMid == ctr.mid && ctr.ownerMid != -1) ...[ - TextButton( - onPressed: () { - Get.toNamed('/webview', parameters: { - 'url': 'https://account.bilibili.com/account/home', - 'pageTitle': '个人中心(建议浏览器打开)', - 'type': 'url' - }); - }, - style: TextButton.styleFrom( - foregroundColor: - Theme.of(context).colorScheme.onPrimary, - backgroundColor: Theme.of(context).colorScheme.primary, - ), - child: const Text(' 个人中心(web) '), - ) - ], - if (ctr.ownerMid == -1) ...[ - TextButton( - onPressed: () {}, - style: TextButton.styleFrom( - foregroundColor: Theme.of(context).colorScheme.outline, - backgroundColor: - Theme.of(context).colorScheme.onInverseSurface, - ), - child: const Text(' 未登录 '), - ) - ] - ], - ), - ), - ], - ); - }), - ); - } -} diff --git a/lib/pages/member/widgets/seasons.dart b/lib/pages/member/widgets/seasons.dart deleted file mode 100644 index 03d1d560..00000000 --- a/lib/pages/member/widgets/seasons.dart +++ /dev/null @@ -1,86 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:get/get.dart'; -import 'package:PiliPlus/common/constants.dart'; -import 'package:PiliPlus/common/widgets/badge.dart'; -import 'package:PiliPlus/models/member/seasons.dart'; -import 'package:PiliPlus/pages/member_seasons/widgets/item.dart'; - -import '../../../utils/grid.dart'; - -class MemberSeasonsPanel extends StatelessWidget { - final MemberSeasonsDataModel? data; - const MemberSeasonsPanel({super.key, this.data}); - - @override - Widget build(BuildContext context) { - return ListView.builder( - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - itemCount: data!.seasonsList!.length, - itemBuilder: (context, index) { - MemberSeasonsList item = data!.seasonsList![index]; - return Padding( - padding: const EdgeInsets.only(bottom: 12, right: 4), - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: const EdgeInsets.only(bottom: 12, left: 4), - child: Row( - children: [ - Text( - item.meta!.name!, - maxLines: 1, - style: Theme.of(context).textTheme.titleSmall!, - ), - const SizedBox(width: 10), - PBadge( - stack: 'relative', - size: 'small', - text: item.meta!.total.toString(), - ), - SizedBox( - width: 30, - height: 30, - child: IconButton( - tooltip: '前往', - onPressed: () => Get.toNamed( - '/memberSeasons?mid=${item.meta!.mid}&seasonId=${item.meta!.seasonId}'), - style: ButtonStyle( - padding: WidgetStateProperty.all(EdgeInsets.zero), - ), - icon: const Icon( - Icons.arrow_forward_ios, - size: 20, - ), - ), - ) - ], - ), - ), - LayoutBuilder( - builder: (context, boxConstraints) { - return GridView.builder( - gridDelegate: SliverGridDelegateWithExtentAndRatio( - mainAxisSpacing: StyleString.cardSpace, - crossAxisSpacing: StyleString.cardSpace, - maxCrossAxisExtent: Grid.smallCardWidth, - childAspectRatio: 0.94, - ), - physics: const NeverScrollableScrollPhysics(), - shrinkWrap: true, - itemCount: item.archives!.length, - itemBuilder: (context, i) { - return MemberSeasonsItem(seasonItem: item.archives![i]); - }, - ); - }, - ), - ], - ), - ); - }, - ); - } -} diff --git a/lib/pages/member_archive/controller.dart b/lib/pages/member_archive/controller.dart deleted file mode 100644 index 6aaab8bf..00000000 --- a/lib/pages/member_archive/controller.dart +++ /dev/null @@ -1,73 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; -import 'package:get/get.dart'; -import 'package:PiliPlus/http/member.dart'; -import 'package:PiliPlus/models/member/archive.dart'; - -class MemberArchiveController extends GetxController { - final ScrollController scrollController = ScrollController(); - late int mid; - late String wwebid; - int pn = 1; - int count = 0; - RxMap currentOrder = {}.obs; - static const List> orderList = [ - {'type': 'pubdate', 'label': '最新发布'}, - {'type': 'click', 'label': '最多播放'}, - {'type': 'stow', 'label': '最多收藏'}, - ]; - RxList archivesList = [].obs; - - @override - void onInit() { - super.onInit(); - mid = int.parse(Get.parameters['mid']!); - wwebid = Get.parameters['wwebid']!; - currentOrder.value = orderList.first; - } - - // 获取用户投稿 - Future getMemberArchive(type) async { - if (type == 'init') { - pn = 1; - } - var res = await MemberHttp.memberArchive( - mid: mid, - pn: pn, - order: currentOrder['type']!, - wwebid: wwebid, - ); - if (res['status']) { - if (type == 'init') { - archivesList.value = res['data'].list.vlist; - } else if (type == 'onLoad') { - archivesList.addAll(res['data'].list.vlist); - } - count = res['data'].page['count']; - pn += 1; - } else { - SmartDialog.showToast(res['msg']); - } - return res; - } - - toggleSort() { - List typeList = orderList.map((e) => e['type']!).toList(); - int index = typeList.indexOf(currentOrder['type']!); - if (index == orderList.length - 1) { - currentOrder.value = orderList.first; - } else { - currentOrder.value = orderList[index + 1]; - } - getMemberArchive('init'); - } - - // 上拉加载 - Future onLoad() => getMemberArchive('onLoad'); - - @override - void onClose() { - scrollController.dispose(); - super.onClose(); - } -} diff --git a/lib/pages/member_archive/index.dart b/lib/pages/member_archive/index.dart deleted file mode 100644 index 4c7551da..00000000 --- a/lib/pages/member_archive/index.dart +++ /dev/null @@ -1,4 +0,0 @@ -library member_archive; - -export './controller.dart'; -export './view.dart'; diff --git a/lib/pages/member_archive/view.dart b/lib/pages/member_archive/view.dart deleted file mode 100644 index f3f3f76a..00000000 --- a/lib/pages/member_archive/view.dart +++ /dev/null @@ -1,137 +0,0 @@ -import 'package:easy_debounce/easy_throttle.dart'; -import 'package:flutter/material.dart'; -import 'package:get/get.dart'; -import 'package:PiliPlus/common/widgets/video_card_h.dart'; -import 'package:PiliPlus/utils/utils.dart'; -import '../../common/constants.dart'; -import '../../common/widgets/http_error.dart'; -import '../../utils/grid.dart'; -import 'controller.dart'; - -class MemberArchivePage extends StatefulWidget { - const MemberArchivePage({super.key}); - - @override - State createState() => _MemberArchivePageState(); -} - -class _MemberArchivePageState extends State { - late MemberArchiveController _memberArchivesController; - late Future _futureBuilderFuture; - late int mid; - - @override - void dispose() { - _memberArchivesController.scrollController.removeListener(listener); - super.dispose(); - } - - @override - void initState() { - super.initState(); - mid = int.parse(Get.parameters['mid']!); - final String heroTag = Utils.makeHeroTag(mid); - _memberArchivesController = - Get.put(MemberArchiveController(), tag: heroTag); - _futureBuilderFuture = _memberArchivesController.getMemberArchive('init'); - _memberArchivesController.scrollController.addListener(listener); - } - - void listener() { - if (_memberArchivesController.scrollController.position.pixels >= - _memberArchivesController.scrollController.position.maxScrollExtent - - 200) { - EasyThrottle.throttle( - 'member_archives', const Duration(milliseconds: 500), () { - _memberArchivesController.onLoad(); - }); - } - } - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: const Text('Ta的投稿'), - actions: [ - Obx( - () => TextButton.icon( - icon: const Icon(Icons.sort, size: 20), - onPressed: _memberArchivesController.toggleSort, - label: Text(_memberArchivesController.currentOrder['label']!), - ), - ), - const SizedBox(width: 6), - ], - ), - body: CustomScrollView( - physics: const AlwaysScrollableScrollPhysics(), - controller: _memberArchivesController.scrollController, - slivers: [ - SliverPadding( - padding: - const EdgeInsets.symmetric(horizontal: StyleString.safeSpace), - sliver: FutureBuilder( - future: _futureBuilderFuture, - builder: (BuildContext context, snapshot) { - if (snapshot.connectionState == ConnectionState.done) { - if (snapshot.data != null) { - // TODO: refactor - if (snapshot.data is! Map) { - return HttpError( - callback: () => setState(() { - _futureBuilderFuture = _memberArchivesController - .getMemberArchive('init'); - }), - ); - } - Map data = snapshot.data as Map; - final list = _memberArchivesController.archivesList; - if (data['status']) { - return Obx( - () => list.isNotEmpty - ? SliverGrid( - gridDelegate: - SliverGridDelegateWithExtentAndRatio( - mainAxisSpacing: StyleString.safeSpace, - crossAxisSpacing: StyleString.safeSpace, - maxCrossAxisExtent: Grid.mediumCardWidth * 2, - childAspectRatio: - StyleString.aspectRatio * 2.4, - ), - delegate: SliverChildBuilderDelegate( - (BuildContext context, index) { - return VideoCardH( - videoItem: list[index], - showOwner: false, - showPubdate: true, - ); - }, - childCount: list.length, - ), - ) - : const SliverToBoxAdapter(), - ); - } else { - return HttpError( - errMsg: snapshot.data['msg'], - callback: () {}, - ); - } - } else { - return HttpError( - errMsg: "投稿页出现错误", - callback: () {}, - ); - } - } else { - return const SliverToBoxAdapter(); - } - }, - ), - ) - ], - ), - ); - } -} diff --git a/lib/pages/member_search/controller.dart b/lib/pages/member_search/controller.dart index 089c5b28..e6ecc941 100644 --- a/lib/pages/member_search/controller.dart +++ b/lib/pages/member_search/controller.dart @@ -22,13 +22,15 @@ class MemberSearchController extends GetxController int archivePn = 1; RxInt archiveCount = (-1).obs; bool isEndArchive = false; - Rx archiveState = LoadingState.loading().obs; + Rx?>> archiveState = + LoadingState?>.loading().obs; String offset = ''; int dynamicPn = 1; RxInt dynamicCount = (-1).obs; bool isEndDynamic = false; - Rx dynamicState = LoadingState.loading().obs; + Rx?>> dynamicState = + LoadingState?>.loading().obs; dynamic wwebid; diff --git a/lib/pages/member_search/search_archive.dart b/lib/pages/member_search/search_archive.dart index 0d195832..62e6253c 100644 --- a/lib/pages/member_search/search_archive.dart +++ b/lib/pages/member_search/search_archive.dart @@ -3,6 +3,7 @@ import 'package:PiliPlus/common/widgets/loading_widget.dart'; import 'package:PiliPlus/common/widgets/refresh_indicator.dart'; import 'package:PiliPlus/common/widgets/video_card_h.dart'; import 'package:PiliPlus/http/loading_state.dart'; +import 'package:PiliPlus/models/member/archive.dart'; import 'package:PiliPlus/pages/member_search/controller.dart'; import 'package:PiliPlus/utils/grid.dart'; import 'package:easy_debounce/easy_throttle.dart'; @@ -29,10 +30,11 @@ class _SearchArchiveState extends State return Obx(() => _buildBody(context, widget.ctr.archiveState.value)); } - Widget _buildBody(BuildContext context, LoadingState loadingState) { + Widget _buildBody( + BuildContext context, LoadingState?> loadingState) { return switch (loadingState) { Loading() => loadingWidget, - Success() => (loadingState.response as List?)?.isNotEmpty == true + Success() => loadingState.response?.isNotEmpty == true ? refreshIndicator( onRefresh: () async { await widget.ctr.refreshArchive(); @@ -46,24 +48,20 @@ class _SearchArchiveState extends State bottom: MediaQuery.paddingOf(context).bottom + 80, ), sliver: SliverGrid( - gridDelegate: SliverGridDelegateWithExtentAndRatio( - mainAxisSpacing: 2, - maxCrossAxisExtent: Grid.mediumCardWidth * 2, - childAspectRatio: StyleString.aspectRatio * 2.2, - ), + gridDelegate: Grid.videoCardHDelegate(context), delegate: SliverChildBuilderDelegate( (context, index) { - if (index == loadingState.response.length - 1) { + if (index == loadingState.response!.length - 1) { EasyThrottle.throttle('searchArchives', const Duration(milliseconds: 500), () { widget.ctr.searchArchives(false); }); } return VideoCardH( - videoItem: loadingState.response[index], + videoItem: loadingState.response![index], ); }, - childCount: loadingState.response.length, + childCount: loadingState.response!.length, ), ), ), diff --git a/lib/pages/member_search/search_dynamic.dart b/lib/pages/member_search/search_dynamic.dart index 9faba84a..a86507ad 100644 --- a/lib/pages/member_search/search_dynamic.dart +++ b/lib/pages/member_search/search_dynamic.dart @@ -2,6 +2,7 @@ import 'package:PiliPlus/common/constants.dart'; import 'package:PiliPlus/common/widgets/loading_widget.dart'; import 'package:PiliPlus/common/widgets/refresh_indicator.dart'; import 'package:PiliPlus/http/loading_state.dart'; +import 'package:PiliPlus/models/dynamics/result.dart'; import 'package:PiliPlus/pages/dynamics/widgets/dynamic_panel.dart'; import 'package:PiliPlus/pages/member_search/controller.dart'; import 'package:PiliPlus/utils/grid.dart'; @@ -31,12 +32,13 @@ class _SearchDynamicState extends State return Obx(() => _buildBody(context, widget.ctr.dynamicState.value)); } - Widget _buildBody(BuildContext context, LoadingState loadingState) { + Widget _buildBody(BuildContext context, + LoadingState?> loadingState) { bool dynamicsWaterfallFlow = GStorage.setting .get(SettingBoxKey.dynamicsWaterfallFlow, defaultValue: true); return switch (loadingState) { Loading() => loadingWidget, - Success() => (loadingState.response as List?)?.isNotEmpty == true + Success() => loadingState.response?.isNotEmpty == true ? refreshIndicator( onRefresh: () async { await widget.ctr.refreshDynamic(); @@ -54,13 +56,13 @@ class _SearchDynamicState extends State crossAxisSpacing: StyleString.safeSpace, mainAxisSpacing: StyleString.safeSpace, lastChildLayoutTypeBuilder: (index) { - if (index == loadingState.response.length - 1) { + if (index == loadingState.response!.length - 1) { EasyThrottle.throttle('member_dynamics', const Duration(milliseconds: 1000), () { widget.ctr.searchDynamic(false); }); } - return index == loadingState.response.length + return index == loadingState.response!.length ? LastChildLayoutType.foot : LastChildLayoutType.none; }, @@ -77,7 +79,7 @@ class _SearchDynamicState extends State delegate: SliverChildBuilderDelegate( (context, index) { if (index == - loadingState.response.length - 1) { + loadingState.response!.length - 1) { EasyThrottle.throttle('member_dynamics', const Duration(milliseconds: 1000), () { @@ -85,10 +87,10 @@ class _SearchDynamicState extends State }); } return DynamicPanel( - item: loadingState.response[index], + item: loadingState.response![index], ); }, - childCount: loadingState.response.length, + childCount: loadingState.response!.length, ), ), ), diff --git a/lib/pages/member_seasons/controller.dart b/lib/pages/member_seasons/controller.dart deleted file mode 100644 index da0a7e67..00000000 --- a/lib/pages/member_seasons/controller.dart +++ /dev/null @@ -1,53 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:get/get.dart'; -import 'package:PiliPlus/http/member.dart'; -import 'package:PiliPlus/models/member/seasons.dart'; - -class MemberSeasonsController extends GetxController { - final ScrollController scrollController = ScrollController(); - late int mid; - late int seasonId; - int pn = 1; - int ps = 30; - int count = 0; - RxList seasonsList = [].obs; - late Map page; - - @override - void onInit() { - super.onInit(); - mid = int.parse(Get.parameters['mid']!); - seasonId = int.parse(Get.parameters['seasonId']!); - } - - // 获取专栏详情 - Future getSeasonDetail(type) async { - if (type == 'onRefresh') { - pn = 1; - } - var res = await MemberHttp.getSeasonDetail( - mid: mid, - seasonId: seasonId, - pn: pn, - ps: ps, - sortReverse: false, - ); - if (res['status']) { - seasonsList.addAll(res['data'].archives); - page = res['data'].page; - pn += 1; - } - return res; - } - - // 上拉加载 - Future onLoad() async { - getSeasonDetail('onLoad'); - } - - @override - void onClose() { - scrollController.dispose(); - super.onClose(); - } -} diff --git a/lib/pages/member_seasons/index.dart b/lib/pages/member_seasons/index.dart deleted file mode 100644 index 4a4dc63d..00000000 --- a/lib/pages/member_seasons/index.dart +++ /dev/null @@ -1,4 +0,0 @@ -library member_seasons; - -export 'controller.dart'; -export 'view.dart'; diff --git a/lib/pages/member_seasons/view.dart b/lib/pages/member_seasons/view.dart deleted file mode 100644 index dde4d890..00000000 --- a/lib/pages/member_seasons/view.dart +++ /dev/null @@ -1,120 +0,0 @@ -import 'package:PiliPlus/common/widgets/http_error.dart'; -import 'package:PiliPlus/models/member/seasons.dart'; -import 'package:easy_debounce/easy_throttle.dart'; -import 'package:flutter/material.dart'; -import 'package:get/get.dart'; -import 'package:PiliPlus/common/constants.dart'; -import '../../utils/grid.dart'; -import 'controller.dart'; -import 'widgets/item.dart'; - -class MemberSeasonsPage extends StatefulWidget { - const MemberSeasonsPage({super.key}); - - @override - State createState() => _MemberSeasonsPageState(); -} - -class _MemberSeasonsPageState extends State { - final MemberSeasonsController _memberSeasonsController = - Get.put(MemberSeasonsController()); - late Future _futureBuilderFuture; - - @override - void dispose() { - _memberSeasonsController.scrollController.removeListener(listener); - super.dispose(); - } - - @override - void initState() { - super.initState(); - _futureBuilderFuture = - _memberSeasonsController.getSeasonDetail('onRefresh'); - _memberSeasonsController.scrollController.addListener(listener); - } - - void listener() { - if (_memberSeasonsController.scrollController.position.pixels >= - _memberSeasonsController.scrollController.position.maxScrollExtent - - 200) { - EasyThrottle.throttle( - 'member_archives', const Duration(milliseconds: 500), () { - _memberSeasonsController.onLoad(); - }); - } - } - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar(title: const Text('Ta的专栏')), - body: Padding( - padding: const EdgeInsets.only( - left: StyleString.safeSpace, - right: StyleString.safeSpace, - ), - child: SingleChildScrollView( - controller: _memberSeasonsController.scrollController, - child: FutureBuilder( - future: _futureBuilderFuture, - builder: (context, snapshot) { - if (snapshot.connectionState == ConnectionState.done) { - if (snapshot.data != null) { - // TODO: refactor - if (snapshot.data is! Map) { - return HttpError( - isSliver: false, - callback: () => setState(() { - _futureBuilderFuture = _memberSeasonsController - .getSeasonDetail('onRefresh'); - }), - ); - } - Map data = snapshot.data as Map; - List list = - _memberSeasonsController.seasonsList; - if (data['status']) { - return Obx( - () => list.isNotEmpty - ? LayoutBuilder( - builder: (context, boxConstraints) { - return GridView.builder( - gridDelegate: - SliverGridDelegateWithExtentAndRatio( - mainAxisSpacing: StyleString.cardSpace, - crossAxisSpacing: StyleString.cardSpace, - maxCrossAxisExtent: Grid.smallCardWidth, - childAspectRatio: 0.94, - ), - physics: const NeverScrollableScrollPhysics(), - shrinkWrap: true, - itemCount: _memberSeasonsController - .seasonsList.length, - itemBuilder: (context, i) { - return MemberSeasonsItem( - seasonItem: _memberSeasonsController - .seasonsList[i], - ); - }, - ); - }, - ) - : const SizedBox(), - ); - } else { - return const SizedBox(); - } - } else { - return const SizedBox(); - } - } else { - return const SizedBox(); - } - }, - ), - ), - ), - ); - } -} diff --git a/lib/pages/member_seasons/widgets/item.dart b/lib/pages/member_seasons/widgets/item.dart deleted file mode 100644 index 21cba7cc..00000000 --- a/lib/pages/member_seasons/widgets/item.dart +++ /dev/null @@ -1,101 +0,0 @@ -import 'package:PiliPlus/common/widgets/stat/stat.dart'; -import 'package:PiliPlus/models/member/seasons.dart'; -import 'package:flutter/material.dart'; -import 'package:PiliPlus/common/constants.dart'; -import 'package:PiliPlus/common/widgets/badge.dart'; -import 'package:PiliPlus/common/widgets/network_img_layer.dart'; -import 'package:PiliPlus/http/search.dart'; -import 'package:PiliPlus/utils/utils.dart'; - -class MemberSeasonsItem extends StatelessWidget { - final MemberArchiveItem seasonItem; - - const MemberSeasonsItem({ - super.key, - required this.seasonItem, - }); - - @override - Widget build(BuildContext context) { - return Card( - elevation: 0, - clipBehavior: Clip.hardEdge, - margin: EdgeInsets.zero, - child: InkWell( - onTap: () async { - int cid = - await SearchHttp.ab2c(aid: seasonItem.aid, bvid: seasonItem.bvid); - Utils.toViewPage( - 'bvid=${seasonItem.bvid}&cid=$cid', - arguments: { - 'videoItem': seasonItem, - 'heroTag': Utils.makeHeroTag(seasonItem.aid) - }, - ); - }, - child: Column( - children: [ - AspectRatio( - aspectRatio: StyleString.aspectRatio, - child: LayoutBuilder(builder: (context, boxConstraints) { - double maxWidth = boxConstraints.maxWidth; - double maxHeight = boxConstraints.maxHeight; - return Stack( - children: [ - NetworkImgLayer( - src: seasonItem.pic, - width: maxWidth, - height: maxHeight, - ), - if (seasonItem.pubdate != null) - PBadge( - bottom: 6, - right: 6, - type: 'gray', - text: Utils.customStampStr( - timestamp: seasonItem.pubdate, date: 'YY-MM-DD'), - ) - ], - ); - }), - ), - Padding( - padding: const EdgeInsets.fromLTRB(5, 6, 0, 0), - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - seasonItem.title!, - maxLines: 2, - overflow: TextOverflow.ellipsis, - ), - const SizedBox(height: 4), - Row( - children: [ - StatView( - context: context, - value: Utils.numFormat(seasonItem.view!), - theme: 'gray', - ), - const Spacer(), - Text( - Utils.customStampStr( - timestamp: seasonItem.pubdate, date: 'YY-MM-DD'), - style: TextStyle( - fontSize: 11, - color: Theme.of(context).colorScheme.outline, - ), - ), - const SizedBox(width: 6) - ], - ), - ], - ), - ), - ], - ), - ), - ); - } -} diff --git a/lib/pages/rank/zone/view.dart b/lib/pages/rank/zone/view.dart index 2c91d662..cd53d19d 100644 --- a/lib/pages/rank/zone/view.dart +++ b/lib/pages/rank/zone/view.dart @@ -57,11 +57,7 @@ class _ZonePageState extends CommonPageState Widget _buildSkeleton() { return SliverGrid( - gridDelegate: SliverGridDelegateWithExtentAndRatio( - mainAxisSpacing: 2, - maxCrossAxisExtent: Grid.mediumCardWidth * 2, - childAspectRatio: StyleString.aspectRatio * 2.2, - ), + gridDelegate: Grid.videoCardHDelegate(context), delegate: SliverChildBuilderDelegate( (context, index) { return const VideoCardHSkeleton(); @@ -76,11 +72,7 @@ class _ZonePageState extends CommonPageState Loading() => _buildSkeleton(), Success() => loadingState.response?.isNotEmpty == true ? SliverGrid( - gridDelegate: SliverGridDelegateWithExtentAndRatio( - mainAxisSpacing: 2, - maxCrossAxisExtent: Grid.mediumCardWidth * 2, - childAspectRatio: StyleString.aspectRatio * 2.2, - ), + gridDelegate: Grid.videoCardHDelegate(context), delegate: SliverChildBuilderDelegate( (context, index) { return VideoCardH( diff --git a/lib/pages/search/view.dart b/lib/pages/search/view.dart index be99b635..057dc6e9 100644 --- a/lib/pages/search/view.dart +++ b/lib/pages/search/view.dart @@ -76,6 +76,7 @@ class _SearchPageState extends State { ), ), body: SingleChildScrollView( + padding: MediaQuery.paddingOf(context).copyWith(top: 0), child: Column( children: [ // 搜索建议 @@ -89,10 +90,16 @@ class _SearchPageState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ if (_searchController.enableHotKey) - Expanded(child: hotSearch()), + Expanded( + child: Column( + children: [ + hotSearch(), + if (_searchController.enableSearchRcmd) + hotSearch(false) + ], + ), + ), Expanded(child: _history()), - if (_searchController.enableSearchRcmd) - Expanded(child: hotSearch(false)), ], ), ], @@ -143,7 +150,7 @@ class _SearchPageState extends State { .copyWith(height: 1, fontWeight: FontWeight.bold), ); return Padding( - padding: const EdgeInsets.fromLTRB(10, 25, 4, 25), + padding: EdgeInsets.fromLTRB(10, isHot ? 25 : 4, 4, 25), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ diff --git a/lib/pages/search_panel/view.dart b/lib/pages/search_panel/view.dart index 45c823d8..cbfec44b 100644 --- a/lib/pages/search_panel/view.dart +++ b/lib/pages/search_panel/view.dart @@ -67,19 +67,15 @@ class _SearchPanelState extends State physics: const AlwaysScrollableScrollPhysics(), slivers: [ SliverGrid( - gridDelegate: SliverGridDelegateWithExtentAndRatio( - mainAxisSpacing: 2, - maxCrossAxisExtent: (widget.searchType == SearchType.video || - widget.searchType == SearchType.article - ? Grid.mediumCardWidth - : Grid.smallCardWidth) * - 2, - childAspectRatio: StyleString.aspectRatio * - (widget.searchType == SearchType.media_bangumi || - widget.searchType == SearchType.media_ft - ? 1.5 - : 2.2), - ), + gridDelegate: widget.searchType == SearchType.media_bangumi || + widget.searchType == SearchType.media_ft + ? SliverGridDelegateWithExtentAndRatio( + mainAxisSpacing: 2, + maxCrossAxisExtent: Grid.smallCardWidth * 2, + childAspectRatio: StyleString.aspectRatio * 1.5, + minHeight: MediaQuery.textScalerOf(context).scale(155), + ) + : Grid.videoCardHDelegate(context), delegate: SliverChildBuilderDelegate( (context, index) { switch (widget.searchType) { diff --git a/lib/pages/search_panel/widgets/article_panel.dart b/lib/pages/search_panel/widgets/article_panel.dart index d508b862..af9d15b2 100644 --- a/lib/pages/search_panel/widgets/article_panel.dart +++ b/lib/pages/search_panel/widgets/article_panel.dart @@ -3,7 +3,6 @@ import 'dart:math'; import 'package:PiliPlus/common/widgets/custom_sliver_persistent_header_delegate.dart'; import 'package:PiliPlus/common/widgets/http_error.dart'; import 'package:PiliPlus/common/widgets/image_save.dart'; -import 'package:PiliPlus/common/widgets/loading_widget.dart'; import 'package:PiliPlus/http/loading_state.dart'; import 'package:PiliPlus/pages/search/widgets/search_text.dart'; import 'package:PiliPlus/pages/search_panel/controller.dart'; @@ -82,7 +81,6 @@ Widget searchArticlePanel( ), ), switch (loadingState) { - Loading() => errorWidget(), Success() => loadingState.response?.isNotEmpty == true ? SliverPadding( padding: EdgeInsets.only( @@ -90,11 +88,7 @@ Widget searchArticlePanel( MediaQuery.of(context).padding.bottom, ), sliver: SliverGrid( - gridDelegate: SliverGridDelegateWithExtentAndRatio( - mainAxisSpacing: 2, - maxCrossAxisExtent: Grid.mediumCardWidth * 2, - childAspectRatio: StyleString.aspectRatio * 2.2, - ), + gridDelegate: Grid.videoCardHDelegate(context), delegate: SliverChildBuilderDelegate( (BuildContext context, int index) { if (index == loadingState.response!.length - 1) { diff --git a/lib/pages/search_panel/widgets/live_panel.dart b/lib/pages/search_panel/widgets/live_panel.dart index e1d0bbcc..0035ed51 100644 --- a/lib/pages/search_panel/widgets/live_panel.dart +++ b/lib/pages/search_panel/widgets/live_panel.dart @@ -11,7 +11,6 @@ import '../../../utils/grid.dart'; Widget searchLivePanel( BuildContext context, ctr, LoadingState?> loadingState) { return switch (loadingState) { - Loading() => loadingWidget, Success() => loadingState.response?.isNotEmpty == true ? GridView.builder( physics: const AlwaysScrollableScrollPhysics(), diff --git a/lib/pages/search_panel/widgets/media_bangumi_panel.dart b/lib/pages/search_panel/widgets/media_bangumi_panel.dart index cd4310ef..72d1ee57 100644 --- a/lib/pages/search_panel/widgets/media_bangumi_panel.dart +++ b/lib/pages/search_panel/widgets/media_bangumi_panel.dart @@ -13,7 +13,6 @@ Widget searchBangumiPanel( context, ctr, LoadingState?> loadingState) { late TextStyle style = TextStyle(fontSize: 13); return switch (loadingState) { - Loading() => loadingWidget, Success() => loadingState.response?.isNotEmpty == true ? CustomScrollView( controller: ctr.scrollController, @@ -146,10 +145,10 @@ Widget searchBangumiPanel( ), ], ) - : errorWidget( + : scrollErrorWidget( callback: ctr.onReload, ), - Error() => errorWidget( + Error() => scrollErrorWidget( errMsg: loadingState.errMsg, callback: ctr.onReload, ), diff --git a/lib/pages/search_panel/widgets/user_panel.dart b/lib/pages/search_panel/widgets/user_panel.dart index bd48e287..cce6cfca 100644 --- a/lib/pages/search_panel/widgets/user_panel.dart +++ b/lib/pages/search_panel/widgets/user_panel.dart @@ -2,7 +2,6 @@ import 'dart:math'; import 'package:PiliPlus/common/widgets/custom_sliver_persistent_header_delegate.dart'; import 'package:PiliPlus/common/widgets/http_error.dart'; -import 'package:PiliPlus/common/widgets/loading_widget.dart'; import 'package:PiliPlus/http/loading_state.dart'; import 'package:PiliPlus/pages/search/widgets/search_text.dart'; import 'package:PiliPlus/pages/search_panel/controller.dart'; @@ -80,7 +79,6 @@ Widget searchUserPanel( ), ), switch (loadingState) { - Loading() => errorWidget(), Success() => loadingState.response?.isNotEmpty == true ? SliverPadding( padding: EdgeInsets.only( @@ -89,7 +87,7 @@ Widget searchUserPanel( sliver: SliverGrid( gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent( maxCrossAxisExtent: Grid.smallCardWidth * 2, - mainAxisExtent: 56, + mainAxisExtent: 66, ), delegate: SliverChildBuilderDelegate( (BuildContext context, int index) { diff --git a/lib/pages/search_panel/widgets/video_panel.dart b/lib/pages/search_panel/widgets/video_panel.dart index 6d4b2f4a..96b4ec4d 100644 --- a/lib/pages/search_panel/widgets/video_panel.dart +++ b/lib/pages/search_panel/widgets/video_panel.dart @@ -2,7 +2,6 @@ import 'dart:math'; import 'package:PiliPlus/common/widgets/custom_sliver_persistent_header_delegate.dart'; import 'package:PiliPlus/common/widgets/http_error.dart'; -import 'package:PiliPlus/common/widgets/loading_widget.dart'; import 'package:PiliPlus/http/loading_state.dart'; import 'package:PiliPlus/pages/search/widgets/search_text.dart'; import 'package:flutter/material.dart'; @@ -13,7 +12,6 @@ import 'package:PiliPlus/models/common/search_type.dart'; import 'package:PiliPlus/pages/search_panel/index.dart'; import 'package:intl/intl.dart'; -import '../../../common/constants.dart'; import '../../../utils/grid.dart'; Widget searchVideoPanel( @@ -92,18 +90,13 @@ Widget searchVideoPanel( ), ), switch (loadingState) { - Loading() => errorWidget(), Success() => loadingState.response?.isNotEmpty == true ? SliverPadding( padding: EdgeInsets.only( bottom: MediaQuery.of(context).padding.bottom + 80, ), sliver: SliverGrid( - gridDelegate: SliverGridDelegateWithExtentAndRatio( - mainAxisSpacing: 2, - maxCrossAxisExtent: Grid.mediumCardWidth * 2, - childAspectRatio: StyleString.aspectRatio * 2.2, - ), + gridDelegate: Grid.videoCardHDelegate(context), delegate: SliverChildBuilderDelegate( (BuildContext context, int index) { if (index == loadingState.response!.length - 1) { diff --git a/lib/pages/setting/widgets/model.dart b/lib/pages/setting/widgets/model.dart index 3d3a5f88..04e1d602 100644 --- a/lib/pages/setting/widgets/model.dart +++ b/lib/pages/setting/widgets/model.dart @@ -22,7 +22,7 @@ import 'package:PiliPlus/models/video/play/subtitle.dart'; import 'package:PiliPlus/pages/home/controller.dart'; import 'package:PiliPlus/pages/hot/controller.dart'; import 'package:PiliPlus/pages/main/controller.dart'; -import 'package:PiliPlus/pages/member/new/controller.dart'; +import 'package:PiliPlus/pages/member/controller.dart'; import 'package:PiliPlus/pages/mine/controller.dart'; import 'package:PiliPlus/pages/rcmd/controller.dart'; import 'package:PiliPlus/pages/setting/pages/color_select.dart'; @@ -247,7 +247,7 @@ List get styleSettings => [ builder: (context) { return SlideDialog( title: '中卡最大列宽度(默认280dp)', - value: GStorage.mediumCardWidth, + value: GStorage.smallCardWidth, min: 150.0, max: 500.0, divisions: 35, @@ -255,7 +255,7 @@ List get styleSettings => [ ); }); if (result != null) { - await GStorage.setting.put(SettingBoxKey.mediumCardWidth, result); + await GStorage.setting.put(SettingBoxKey.smallCardWidth, result); SmartDialog.showToast('重启生效'); setState(); } @@ -263,7 +263,7 @@ List get styleSettings => [ leading: const Icon(Icons.calendar_view_week_outlined), title: '中卡列表宽度(dp)限制', getSubtitle: () => - '当前:${GStorage.mediumCardWidth.toInt()}dp,屏幕宽度:${MediaQuery.of(Get.context!).size.width.toPrecision(2)}dp。宽度越小列数越多。', + '当前:${GStorage.smallCardWidth.toInt()}dp,屏幕宽度:${MediaQuery.of(Get.context!).size.width.toPrecision(2)}dp。宽度越小列数越多。', ), SettingsModel( settingsType: SettingsType.sw1tch, diff --git a/lib/pages/subscription/view.dart b/lib/pages/subscription/view.dart index 37c16f80..2bbcf9ca 100644 --- a/lib/pages/subscription/view.dart +++ b/lib/pages/subscription/view.dart @@ -1,4 +1,3 @@ -import 'package:PiliPlus/common/constants.dart'; import 'package:PiliPlus/common/skeleton/video_card_h.dart'; import 'package:PiliPlus/common/widgets/refresh_indicator.dart'; import 'package:PiliPlus/http/loading_state.dart'; @@ -45,11 +44,7 @@ class _SubPageState extends State { Widget _buildBody(LoadingState?> loadingState) { return switch (loadingState) { Loading() => SliverGrid( - gridDelegate: SliverGridDelegateWithExtentAndRatio( - mainAxisSpacing: 2, - maxCrossAxisExtent: Grid.mediumCardWidth * 2, - childAspectRatio: StyleString.aspectRatio * 2.2, - ), + gridDelegate: Grid.videoCardHDelegate(context), delegate: SliverChildBuilderDelegate( (context, index) => const VideoCardHSkeleton(), childCount: 10, @@ -57,11 +52,7 @@ class _SubPageState extends State { ), Success() => loadingState.response?.isNotEmpty == true ? SliverGrid( - gridDelegate: SliverGridDelegateWithExtentAndRatio( - mainAxisSpacing: 2, - maxCrossAxisExtent: Grid.mediumCardWidth * 2, - childAspectRatio: StyleString.aspectRatio * 2.2, - ), + gridDelegate: Grid.videoCardHDelegate(context), delegate: SliverChildBuilderDelegate( childCount: loadingState.response!.length, (BuildContext context, int index) { diff --git a/lib/pages/subscription_detail/view.dart b/lib/pages/subscription_detail/view.dart index 69536ab9..ee5f9c34 100644 --- a/lib/pages/subscription_detail/view.dart +++ b/lib/pages/subscription_detail/view.dart @@ -1,6 +1,5 @@ import 'dart:async'; -import 'package:PiliPlus/common/constants.dart'; import 'package:PiliPlus/models/user/sub_detail.dart'; import 'package:PiliPlus/utils/grid.dart'; import 'package:easy_debounce/easy_throttle.dart'; @@ -227,13 +226,7 @@ class _SubDetailPageState extends State { MediaQuery.paddingOf(context).bottom + 80, ), sliver: SliverGrid( - gridDelegate: - SliverGridDelegateWithExtentAndRatio( - mainAxisSpacing: 2, - maxCrossAxisExtent: Grid.mediumCardWidth * 2, - childAspectRatio: - StyleString.aspectRatio * 2.2, - ), + gridDelegate: Grid.videoCardHDelegate(context), delegate: SliverChildBuilderDelegate( childCount: subList.length, (BuildContext context, int index) { @@ -258,11 +251,7 @@ class _SubDetailPageState extends State { } else { // 骨架屏 return SliverGrid( - gridDelegate: SliverGridDelegateWithExtentAndRatio( - mainAxisSpacing: 2, - maxCrossAxisExtent: Grid.mediumCardWidth * 2, - childAspectRatio: StyleString.aspectRatio * 2.2, - ), + gridDelegate: Grid.videoCardHDelegate(context), delegate: SliverChildBuilderDelegate( (context, index) => const VideoCardHSkeleton(), childCount: 10, diff --git a/lib/pages/subscription_detail/widget/sub_video_card.dart b/lib/pages/subscription_detail/widget/sub_video_card.dart index 8df1491e..c7f3b655 100644 --- a/lib/pages/subscription_detail/widget/sub_video_card.dart +++ b/lib/pages/subscription_detail/widget/sub_video_card.dart @@ -75,15 +75,6 @@ class SubVideoCardH extends StatelessWidget { bottom: 6.0, type: 'gray', ), - // if (videoItem.ogv != null) ...[ - // PBadge( - // text: videoItem.ogv['type_name'], - // top: 6.0, - // right: 6.0, - // bottom: null, - // left: null, - // ), - // ], ], ); }, @@ -107,20 +98,23 @@ class SubVideoCardH extends StatelessWidget { Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text( - '${videoItem.title}', - textAlign: TextAlign.start, - style: const TextStyle( - letterSpacing: 0.3, + Expanded( + child: Text( + '${videoItem.title}', + textAlign: TextAlign.start, + style: const TextStyle( + letterSpacing: 0.3, + ), + maxLines: 2, + overflow: TextOverflow.ellipsis, ), - maxLines: 2, - overflow: TextOverflow.ellipsis, ), - const Spacer(), Text( Utils.dateFormat(videoItem.pubtime), style: TextStyle( - fontSize: 11, color: Theme.of(context).colorScheme.outline), + fontSize: 12, + color: Theme.of(context).colorScheme.outline, + ), ), Padding( padding: const EdgeInsets.only(top: 2), diff --git a/lib/pages/video/detail/introduction/view.dart b/lib/pages/video/detail/introduction/view.dart index 13ec3ede..873da1f1 100644 --- a/lib/pages/video/detail/introduction/view.dart +++ b/lib/pages/video/detail/introduction/view.dart @@ -612,14 +612,13 @@ class _VideoInfoState extends State { Stack( children: [ Row( - children: [ + children: [ StatView( context: context, theme: 'gray', value: Utils.numFormat(!widget.loadingStatus ? videoDetail.stat?.view ?? '-' : videoItem['stat']?.view ?? '-'), - size: 'medium', textColor: t.colorScheme.outline, ), const SizedBox(width: 10), @@ -629,7 +628,6 @@ class _VideoInfoState extends State { value: Utils.numFormat(!widget.loadingStatus ? videoDetail.stat?.danmaku ?? '-' : videoItem['stat']?.danmu ?? '-'), - size: 'medium', textColor: t.colorScheme.outline, ), const SizedBox(width: 10), diff --git a/lib/pages/video/detail/introduction/widgets/intro_detail.dart b/lib/pages/video/detail/introduction/widgets/intro_detail.dart deleted file mode 100644 index 3cefda5f..00000000 --- a/lib/pages/video/detail/introduction/widgets/intro_detail.dart +++ /dev/null @@ -1,211 +0,0 @@ -import 'package:PiliPlus/common/constants.dart'; -import 'package:PiliPlus/pages/search/widgets/search_text.dart'; -import 'package:flutter/gestures.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; -import 'package:get/get.dart'; -import 'package:PiliPlus/common/widgets/stat/stat.dart'; -import 'package:PiliPlus/utils/utils.dart'; - -@Deprecated('deprecated') -class IntroDetail extends StatelessWidget { - const IntroDetail({ - super.key, - this.videoDetail, - this.videoTags, - }); - final dynamic videoDetail; - final dynamic videoTags; - - @override - Widget build(BuildContext context) { - return Material( - color: Theme.of(context).colorScheme.surface, - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 14), - child: Column( - children: [ - InkWell( - onTap: () => Get.back(), - child: Container( - height: 35, - padding: const EdgeInsets.only(bottom: 2), - child: Center( - child: Container( - width: 32, - height: 3, - decoration: BoxDecoration( - color: Theme.of(context).colorScheme.primary, - borderRadius: - const BorderRadius.all(Radius.circular(3))), - ), - ), - ), - ), - Expanded( - child: SingleChildScrollView( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - SelectableText( - videoDetail!.title, - style: const TextStyle(fontSize: 16), - ), - const SizedBox(height: 6), - Row( - children: [ - StatView( - context: context, - theme: 'gray', - value: Utils.numFormat(videoDetail!.stat!.view), - size: 'medium', - ), - const SizedBox(width: 10), - StatDanMu( - context: context, - theme: 'gray', - value: Utils.numFormat(videoDetail!.stat!.danmu), - size: 'medium', - ), - const SizedBox(width: 10), - Text( - Utils.dateFormat(videoDetail!.pubdate, - formatType: 'detail'), - style: TextStyle( - fontSize: 12, - color: Theme.of(context).colorScheme.outline, - ), - ), - ], - ), - if (videoTags is List && videoTags.isNotEmpty) ...[ - const SizedBox(height: 10), - Wrap( - spacing: 8, - runSpacing: 8, - children: (videoTags as List) - .map( - (item) => SearchText( - fontSize: 13, - text: item['tag_name'], - onTap: (_) => Get.toNamed('/searchResult', - parameters: {'keyword': item['tag_name']}), - onLongPress: (_) => - Utils.copyText(item['tag_name']), - ), - ) - .toList(), - ) - ], - const SizedBox(height: 10), - SizedBox( - width: double.infinity, - child: SelectableRegion( - focusNode: FocusNode(), - selectionControls: MaterialTextSelectionControls(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - videoDetail!.bvid!, - style: TextStyle( - fontSize: 13, - color: Theme.of(context).colorScheme.primary, - ), - ), - const SizedBox(height: 10), - Text.rich( - style: const TextStyle( - height: 1.4, - // fontSize: 13, - ), - TextSpan( - children: [ - buildContent(context, videoDetail!), - ], - ), - ), - ], - ), - ), - ), - const SizedBox(height: 100), - ], - ), - ), - ) - ], - ), - ), - ); - } - - InlineSpan buildContent(BuildContext context, content) { - final List descV2 = content.descV2; - // type - // 1 普通文本 - // 2 @用户 - final List spanChildren = List.generate(descV2.length, (index) { - final currentDesc = descV2[index]; - switch (currentDesc.type) { - case 1: - final List spanChildren = []; - final RegExp urlRegExp = RegExp(Constants.urlPattern); - final Iterable matches = - urlRegExp.allMatches(currentDesc.rawText); - - int previousEndIndex = 0; - for (final Match match in matches) { - if (match.start > previousEndIndex) { - spanChildren.add(TextSpan( - text: currentDesc.rawText - .substring(previousEndIndex, match.start))); - } - spanChildren.add( - TextSpan( - text: match.group(0), - style: TextStyle( - color: Theme.of(context).colorScheme.primary), // 设置颜色为蓝色 - recognizer: TapGestureRecognizer() - ..onTap = () { - // 处理点击事件 - try { - Utils.handleWebview(match.group(0)!); - } catch (err) { - SmartDialog.showToast(err.toString()); - } - }, - ), - ); - previousEndIndex = match.end; - } - - if (previousEndIndex < currentDesc.rawText.length) { - spanChildren.add(TextSpan( - text: currentDesc.rawText.substring(previousEndIndex))); - } - - final TextSpan result = TextSpan(children: spanChildren); - return result; - case 2: - final Color colorSchemePrimary = - Theme.of(context).colorScheme.primary; - final String heroTag = Utils.makeHeroTag(currentDesc.bizId); - return TextSpan( - text: '@${currentDesc.rawText}', - style: TextStyle(color: colorSchemePrimary), - recognizer: TapGestureRecognizer() - ..onTap = () { - Get.toNamed( - '/member?mid=${currentDesc.bizId}', - arguments: {'face': '', 'heroTag': heroTag}, - ); - }, - ); - default: - return const TextSpan(); - } - }); - return TextSpan(children: spanChildren); - } -} diff --git a/lib/pages/video/detail/member/controller.dart b/lib/pages/video/detail/member/controller.dart index 4411abec..1426d9fa 100644 --- a/lib/pages/video/detail/member/controller.dart +++ b/lib/pages/video/detail/member/controller.dart @@ -4,7 +4,7 @@ import 'package:PiliPlus/models/member/info.dart'; import 'package:PiliPlus/models/space_archive/data.dart'; import 'package:PiliPlus/models/space_archive/item.dart'; import 'package:PiliPlus/pages/common/common_data_controller.dart'; -import 'package:PiliPlus/pages/member/new/content/member_contribute/member_contribute.dart' +import 'package:PiliPlus/pages/member/content/member_contribute/member_contribute.dart' show ContributeType; import 'package:PiliPlus/utils/utils.dart'; import 'package:get/get.dart'; diff --git a/lib/pages/video/detail/member/horizontal_member_page.dart b/lib/pages/video/detail/member/horizontal_member_page.dart index 435ca29c..830f49e6 100644 --- a/lib/pages/video/detail/member/horizontal_member_page.dart +++ b/lib/pages/video/detail/member/horizontal_member_page.dart @@ -1,4 +1,3 @@ -import 'package:PiliPlus/common/constants.dart'; import 'package:PiliPlus/common/widgets/custom_sliver_persistent_header_delegate.dart'; import 'package:PiliPlus/common/widgets/icon_button.dart'; import 'package:PiliPlus/common/widgets/interactiveviewer_gallery/interactiveviewer_gallery.dart' @@ -191,11 +190,7 @@ class _HorizontalMemberPageState extends State { bottom: MediaQuery.of(context).padding.bottom + 80, ), sliver: SliverGrid( - gridDelegate: SliverGridDelegateWithExtentAndRatio( - mainAxisSpacing: 2, - maxCrossAxisExtent: Grid.mediumCardWidth * 2, - childAspectRatio: StyleString.aspectRatio * 2.2, - ), + gridDelegate: Grid.videoCardHDelegate(context), delegate: SliverChildBuilderDelegate( (context, index) { if (index == loadingState.response.length - 1 && diff --git a/lib/pages/video/detail/related/view.dart b/lib/pages/video/detail/related/view.dart index 41144419..ecf73f8e 100644 --- a/lib/pages/video/detail/related/view.dart +++ b/lib/pages/video/detail/related/view.dart @@ -36,11 +36,7 @@ class _RelatedVideoPanelState extends State Widget _buildBody(LoadingState?> loadingState) { return switch (loadingState) { Loading() => SliverGrid( - gridDelegate: SliverGridDelegateWithExtentAndRatio( - mainAxisSpacing: 2, - maxCrossAxisExtent: Grid.mediumCardWidth * 2, - childAspectRatio: StyleString.aspectRatio * 2.2, - ), + gridDelegate: Grid.videoCardHDelegate(context), delegate: SliverChildBuilderDelegate( (context, index) { return const VideoCardHSkeleton(); @@ -54,11 +50,7 @@ class _RelatedVideoPanelState extends State bottom: MediaQuery.of(context).padding.bottom, ), sliver: SliverGrid( - gridDelegate: SliverGridDelegateWithExtentAndRatio( - mainAxisSpacing: 2, - maxCrossAxisExtent: Grid.mediumCardWidth * 2, - childAspectRatio: StyleString.aspectRatio * 2.2, - ), + gridDelegate: Grid.videoCardHDelegate(context), delegate: SliverChildBuilderDelegate((context, index) { return VideoCardH( videoItem: loadingState.response![index], diff --git a/lib/pages/video/detail/reply/widgets/reply_item.dart b/lib/pages/video/detail/reply/widgets/reply_item.dart deleted file mode 100644 index fddb5550..00000000 --- a/lib/pages/video/detail/reply/widgets/reply_item.dart +++ /dev/null @@ -1,1226 +0,0 @@ -import 'dart:math'; - -import 'package:PiliPlus/common/constants.dart'; -import 'package:PiliPlus/common/widgets/image_view.dart'; -import 'package:PiliPlus/common/widgets/report.dart'; -import 'package:PiliPlus/http/init.dart'; -import 'package:PiliPlus/http/video.dart'; -import 'package:PiliPlus/models/dynamics/result.dart'; -import 'package:PiliPlus/utils/extension.dart'; -import 'package:PiliPlus/utils/global_data.dart'; -import 'package:cached_network_image/cached_network_image.dart'; -import 'package:dio/dio.dart'; -import 'package:flutter/gestures.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; -import 'package:get/get.dart'; -import 'package:PiliPlus/common/widgets/badge.dart'; -import 'package:PiliPlus/common/widgets/network_img_layer.dart'; -import 'package:PiliPlus/models/common/reply_type.dart'; -import 'package:PiliPlus/models/video/reply/item.dart'; -import 'package:PiliPlus/pages/video/detail/index.dart'; -import 'package:PiliPlus/utils/feed_back.dart'; -import 'package:PiliPlus/utils/storage.dart'; -import 'package:PiliPlus/utils/url_utils.dart'; -import 'package:PiliPlus/utils/utils.dart'; -import 'zan.dart'; -import 'package:html/parser.dart' show parse; - -@Deprecated('Use ReplyItemGrpc instead') -class ReplyItem extends StatelessWidget { - const ReplyItem({ - super.key, - required this.replyItem, - this.replyLevel, - this.showReplyRow = true, - this.replyReply, - this.replyType, - this.needDivider = true, - this.onReply, - this.onDelete, - this.onViewImage, - this.onDismissed, - this.getTag, - this.callback, - required this.onCheckReply, - }); - final ReplyItemModel replyItem; - final String? replyLevel; - final bool? showReplyRow; - final Function? replyReply; - final ReplyType? replyType; - final bool needDivider; - final Function()? onReply; - final Function(dynamic rpid, dynamic frpid)? onDelete; - final VoidCallback? onViewImage; - final ValueChanged? onDismissed; - final Function? getTag; - final Function(List, int)? callback; - final ValueChanged onCheckReply; - - @override - Widget build(BuildContext context) { - return Material( - color: Colors.transparent, - child: InkWell( - // 点击整个评论区 评论详情/回复 - onTap: () { - feedBack(); - replyReply?.call(replyItem, null, null); - }, - onLongPress: () { - feedBack(); - showModalBottomSheet( - context: context, - useSafeArea: true, - isScrollControlled: true, - constraints: BoxConstraints( - maxWidth: min(640, min(Get.width, Get.height)), - ), - builder: (context) { - return morePanel( - context: context, - item: replyItem, - onDelete: (rpid) { - onDelete?.call(rpid, null); - }, - ); - }, - ); - }, - child: Column( - children: [ - if (ModuleAuthorModel.showDynDecorate && - (replyItem.member?.userSailing?.cardbg?['image'] as String?) - ?.isNotEmpty == - true) - Stack( - clipBehavior: Clip.none, - children: [ - Positioned( - top: 8, - right: 12, - child: Stack( - alignment: Alignment.centerRight, - children: [ - CachedNetworkImage( - height: 38, - imageUrl: - replyItem.member?.userSailing?.cardbg?['image'], - ), - if ((replyItem.member?.userSailing?.cardbg?['fan'] - ?['num_desc'] as String?) - ?.isNotEmpty == - true) - Text( - 'NO.\n${replyItem.member?.userSailing?.cardbg?['fan']?['num_desc']}', - style: - (replyItem.member?.userSailing?.cardbg?['fan'] - ?['color'] as String?) - ?.startsWith('#') == - true - ? TextStyle( - fontSize: 8, - fontFamily: 'digital_id_num', - color: Color( - int.parse( - replyItem.member?.userSailing - ?.cardbg?['fan']?['color'] - .replaceFirst('#', '0xFF'), - ), - ), - ) - : null, - ), - ], - ), - ), - _buildAuthorPanel(context), - ], - ) - else - _buildAuthorPanel(context), - if (needDivider) - Divider( - indent: 55, - endIndent: 15, - height: 0.3, - color: Theme.of(context).colorScheme.outline.withOpacity(0.08), - ) - ], - ), - ), - ); - } - - Widget _buildAuthorPanel(context) => Padding( - padding: const EdgeInsets.fromLTRB(12, 14, 8, 5), - child: content(context), - ); - - Widget lfAvtar(BuildContext context) { - return Stack( - clipBehavior: Clip.none, - children: [ - if (ModuleAuthorModel.showDynDecorate && - replyItem.member?.pendant?.image?.isNotEmpty == true) ...[ - Padding( - padding: const EdgeInsets.all(2), - child: NetworkImgLayer( - src: replyItem.member?.avatar, - width: 30, - height: 30, - type: 'avatar', - ), - ), - Positioned( - left: -9, - top: -9, - child: IgnorePointer( - child: CachedNetworkImage( - width: 52, - height: 52, - imageUrl: replyItem.member!.pendant!.image!, - ), - ), - ), - ] else - NetworkImgLayer( - src: replyItem.member?.avatar, - width: 34, - height: 34, - type: 'avatar', - ), - if ((replyItem.member?.vip?['vipStatus'] ?? -1) > 0) - Positioned( - right: 0, - bottom: 0, - child: Container( - decoration: BoxDecoration( - //borderRadius: BorderRadius.circular(7), - shape: BoxShape.circle, - color: Theme.of(context).colorScheme.surface, - ), - child: Image.asset( - 'assets/images/big-vip.png', - height: 14, - semanticLabel: "大会员", - ), - ), - ), - //https://www.bilibili.com/blackboard/activity-whPrHsYJ2.html - if (replyItem.member?.officialVerify?['type'] == 0) - Positioned( - left: 0, - bottom: 0, - child: Container( - decoration: BoxDecoration( - // borderRadius: BorderRadius.circular(8), - shape: BoxShape.circle, - color: Theme.of(context).colorScheme.surface, - ), - child: const Icon( - Icons.offline_bolt, - color: Colors.yellow, - size: 14, - semanticLabel: "认证个人", - ), - ), - ), - if (replyItem.member?.officialVerify?['type'] == 1) - Positioned( - left: 0, - bottom: 0, - child: Container( - decoration: BoxDecoration( - // borderRadius: BorderRadius.circular(8), - shape: BoxShape.circle, - color: Theme.of(context).colorScheme.surface, - ), - child: const Icon( - Icons.offline_bolt, - color: Colors.lightBlueAccent, - size: 14, - semanticLabel: "认证机构", - ), - ), - ), - ], - ); - } - - Widget content(BuildContext context) { - if (replyItem.member == null) return const SizedBox(); - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: [ - /// fix Stack内GestureDetector onTap无效 - GestureDetector( - behavior: HitTestBehavior.opaque, - onTap: () { - feedBack(); - Get.toNamed('/member?mid=${replyItem.mid}'); - }, - child: Row( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisSize: MainAxisSize.min, - children: [ - lfAvtar(context), - const SizedBox(width: 12), - Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - Text( - '${replyItem.member?.uname}', - style: TextStyle( - color: - (replyItem.member?.vip?['vipStatus'] ?? 0) > 0 && - replyItem.member?.vip?['vipType'] == 2 - ? context.vipColor - : Theme.of(context).colorScheme.outline, - fontSize: 13, - ), - ), - const SizedBox(width: 6), - Image.asset( - 'assets/images/lv/lv${replyItem.member?.level}.png', - height: 11, - ), - const SizedBox(width: 6), - if (replyItem.isUp == true) - const PBadge( - text: 'UP', - size: 'small', - stack: 'normal', - fs: 9, - ), - ], - ), - Row( - mainAxisSize: MainAxisSize.min, - children: [ - Text( - Utils.dateFormat(replyItem.ctime), - style: TextStyle( - fontSize: - Theme.of(context).textTheme.labelSmall!.fontSize, - color: Theme.of(context).colorScheme.outline, - ), - ), - if (replyItem.replyControl?.location?.isNotEmpty == true) - Text( - ' • ${replyItem.replyControl!.location!}', - style: TextStyle( - fontSize: Theme.of(context) - .textTheme - .labelSmall! - .fontSize, - color: Theme.of(context).colorScheme.outline), - ), - ], - ) - ], - ), - ], - ), - ), - // title - Padding( - padding: - const EdgeInsets.only(top: 10, left: 45, right: 6, bottom: 4), - child: LayoutBuilder( - builder: (BuildContext context, BoxConstraints constraints) { - String text = replyItem.content?.message ?? ''; - TextStyle style = TextStyle( - height: 1.75, - fontSize: Theme.of(context).textTheme.bodyMedium!.fontSize, - ); - TextPainter? textPainter; - bool? didExceedMaxLines; - if (replyLevel == '1' && GlobalData().replyLengthLimit != 0) { - textPainter = TextPainter( - text: TextSpan(text: text, style: style), - maxLines: GlobalData().replyLengthLimit, - textDirection: Directionality.of(context), - )..layout(maxWidth: constraints.maxWidth); - didExceedMaxLines = textPainter.didExceedMaxLines; - } - return Semantics( - label: text, - child: Text.rich( - style: style, - TextSpan( - children: [ - if (replyItem.isTop == true) ...[ - const WidgetSpan( - alignment: PlaceholderAlignment.top, - child: PBadge( - text: 'TOP', - size: 'small', - stack: 'normal', - type: 'line', - fs: 9, - semanticsLabel: '置顶', - textScaleFactor: 1, - ), - ), - const TextSpan(text: ' '), - ], - buildContent( - context, - replyItem, - replyReply, - null, - textPainter, - didExceedMaxLines, - ), - ], - ), - ), - ); - }, - ), - ), - // 操作区域 - buttonAction(context, replyItem.replyControl), - // 一楼的评论 - if (showReplyRow == true && - (replyItem.replyControl?.isShow == true || - replyItem.replies?.isNotEmpty == true || - replyItem.replyControl?.entryText?.isNotEmpty == true)) - Padding( - padding: const EdgeInsets.only(top: 5, bottom: 12), - child: replyItemRow( - context: context, - replies: replyItem.replies, - replyControl: replyItem.replyControl, - // f_rpid: replyItem.rpid, - replyItem: replyItem, - replyReply: replyReply, - onDelete: (rpid) { - onDelete?.call(rpid, replyItem.rpid); - }, - ), - ), - ], - ); - } - - // 感谢、回复、复制 - Widget buttonAction(BuildContext context, replyControl) { - return Row( - children: [ - const SizedBox(width: 32), - SizedBox( - height: 32, - child: TextButton( - onPressed: () { - feedBack(); - onReply?.call(); - }, - child: Row(children: [ - Icon( - Icons.reply, - size: 18, - color: Theme.of(context).colorScheme.outline.withOpacity(0.8), - ), - const SizedBox(width: 3), - Text( - '回复', - style: TextStyle( - fontSize: Theme.of(context).textTheme.labelMedium!.fontSize, - color: Theme.of(context).colorScheme.outline, - ), - ), - ]), - ), - ), - const SizedBox(width: 2), - if (replyItem.upAction?.like == true) ...[ - SizedBox( - height: 32, - child: TextButton( - onPressed: null, - child: Text( - 'UP主觉得很赞', - style: TextStyle( - color: Theme.of(context).colorScheme.secondary, - fontSize: Theme.of(context).textTheme.labelMedium!.fontSize, - fontWeight: FontWeight.normal, - ), - ), - ), - ), - const SizedBox(width: 2), - ], - if (replyItem.cardLabel?.contains('热评') == true) - Text( - '热评', - style: TextStyle( - color: Theme.of(context).colorScheme.secondary, - fontSize: Theme.of(context).textTheme.labelMedium!.fontSize), - ), - const Spacer(), - ZanButton(replyItem: replyItem, replyType: replyType), - const SizedBox(width: 5) - ], - ); - } - - Widget replyItemRow({ - context, - List? replies, - ReplyControl? replyControl, - required ReplyItemModel replyItem, - replyReply, - onDelete, - }) { - final bool hasExtraRow = replyControl?.isShow == true || - (replyControl?.entryText?.isNotEmpty == true && - replies?.isEmpty == true); - return Container( - margin: const EdgeInsets.only(left: 42, right: 4, top: 0), - child: Material( - color: Theme.of(context).colorScheme.onInverseSurface, - borderRadius: BorderRadius.circular(6), - clipBehavior: Clip.hardEdge, - animationDuration: Duration.zero, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - if (replies?.isNotEmpty == true) - for (int i = 0; i < replies!.length; i++) ...[ - InkWell( - // 一楼点击评论展开评论详情 - onTap: () => replyReply?.call(replyItem, null, null), - onLongPress: () { - feedBack(); - showModalBottomSheet( - context: context, - useSafeArea: true, - isScrollControlled: true, - constraints: BoxConstraints( - maxWidth: min(640, min(Get.width, Get.height)), - ), - builder: (context) { - return morePanel( - context: context, - item: replies[i], - onDelete: onDelete, - ); - }, - ); - }, - child: Container( - width: double.infinity, - padding: EdgeInsets.fromLTRB( - 8, - i == 0 && (hasExtraRow || replies.length > 1) ? 8 : 4, - 8, - i == 0 && (hasExtraRow || replies.length > 1) ? 4 : 6, - ), - child: Semantics( - label: - '${replies[i].member?.uname} ${replies[i].content?.message}', - excludeSemantics: true, - child: Text.rich( - style: TextStyle( - fontSize: Theme.of(context) - .textTheme - .bodyMedium! - .fontSize, - color: Theme.of(context) - .colorScheme - .onSurface - .withOpacity(0.85), - height: 1.6), - overflow: TextOverflow.ellipsis, - maxLines: 2, - TextSpan( - children: [ - TextSpan( - text: '${replies[i].member?.uname}', - style: TextStyle( - color: Theme.of(context).colorScheme.primary, - ), - recognizer: TapGestureRecognizer() - ..onTap = () { - feedBack(); - Get.toNamed( - '/member?mid=${replies[i].member?.mid}'); - }, - ), - if (replies[i].isUp == true) ...[ - const TextSpan(text: ' '), - const WidgetSpan( - alignment: PlaceholderAlignment.middle, - child: PBadge( - text: 'UP', - size: 'small', - stack: 'normal', - fs: 9, - textScaleFactor: 1, - ), - ), - const TextSpan(text: ' '), - ], - TextSpan( - text: replies[i].root == replies[i].parent - ? ': ' - : replies[i].isUp == true - ? '' - : ' '), - buildContent( - context, - replies[i], - replyReply, - replyItem, - null, - null, - ), - ], - ), - ), - ), - ), - ) - ], - if (hasExtraRow) - InkWell( - // 一楼点击【共xx条回复】展开评论详情 - onTap: () => replyReply?.call(replyItem, null, null), - child: Container( - width: double.infinity, - padding: const EdgeInsets.fromLTRB(8, 5, 8, 8), - child: Text.rich( - TextSpan( - style: TextStyle( - fontSize: - Theme.of(context).textTheme.labelMedium!.fontSize, - ), - children: [ - if (replyControl?.upReply == true) - TextSpan( - text: 'UP主等人 ', - style: TextStyle( - color: Theme.of(context) - .colorScheme - .onSurface - .withOpacity(0.85), - )), - TextSpan( - text: replyControl?.entryText, - style: TextStyle( - color: Theme.of(context).colorScheme.primary, - ), - ) - ], - ), - ), - ), - ) - ], - ), - ), - ); - } - - InlineSpan buildContent( - BuildContext context, - replyItem, - replyReply, - fReplyItem, - textPainter, - didExceedMaxLines, - ) { - final String routePath = Get.currentRoute; - bool isVideoPage = routePath.startsWith('/video'); - - // replyItem 当前回复内容 - // replyReply 查看二楼回复(回复详情)回调 - // fReplyItem 父级回复内容,用作二楼回复(回复详情)展示 - final content = replyItem.content; - String message = content.message ?? ''; - final List spanChildren = []; - - if (didExceedMaxLines == true) { - final textSize = textPainter.size; - var position = textPainter.getPositionForOffset( - Offset( - textSize.width, - textSize.height, - ), - ); - final endOffset = textPainter.getOffsetBefore(position.offset); - message = message.substring(0, endOffset); - } - - // 投票 - if (content.vote.isNotEmpty) { - message.splitMapJoin(RegExp(r"\{vote:\d+?\}"), onMatch: (Match match) { - // String matchStr = match[0]!; - spanChildren.add( - TextSpan( - text: '投票: ${content.vote['title']}', - style: TextStyle( - color: Theme.of(context).colorScheme.primary, - ), - recognizer: TapGestureRecognizer() - ..onTap = () => Get.toNamed( - '/webview', - parameters: { - 'url': content.vote['url'], - 'type': 'vote', - 'pageTitle': content.vote['title'], - }, - ), - ), - ); - return ''; - }, onNonMatch: (String str) { - return str; - }); - message = message.replaceAll(RegExp(r"\{vote:\d+?\}"), ""); - } - message = parse(message).body?.text ?? message; - // .replaceAll('&', '&') - // .replaceAll('<', '<') - // .replaceAll('>', '>') - // .replaceAll('"', '"') - // .replaceAll(''', "'") - // .replaceAll(' ', ' '); - // 构建正则表达式 - final List specialTokens = [ - ...content.emote.keys, - ...content.topicsMeta?.keys?.map((e) => '#$e#') ?? [], - ...content.atNameToMid.keys.map((e) => '@$e'), - ]; - List jumpUrlKeysList = content.jumpUrl.keys.map((String e) { - return e; - }).toList(); - specialTokens.sort((a, b) => b.length.compareTo(a.length)); - String patternStr = specialTokens.map(RegExp.escape).join('|'); - if (patternStr.isNotEmpty) { - patternStr += "|"; - } - patternStr += r'(\b(?:\d+[::])?\d+[::]\d+\b)'; - if (jumpUrlKeysList.isNotEmpty) { - patternStr += '|${jumpUrlKeysList.map(RegExp.escape).join('|')}'; - } - patternStr += '|${Constants.urlPattern}'; - final RegExp pattern = RegExp(patternStr); - List matchedStrs = []; - void addPlainTextSpan(str) { - spanChildren.add(TextSpan( - text: str, - )); - // TextSpan( - // - // text: str, - // recognizer: TapGestureRecognizer() - // ..onTap = () => replyReply - // ?.call(replyItem.root == 0 ? replyItem : fReplyItem))))); - } - - late final bool enableWordRe = - GStorage.setting.get(SettingBoxKey.enableWordRe, defaultValue: false); - - // 分割文本并处理每个部分 - message.splitMapJoin( - pattern, - onMatch: (Match match) { - String matchStr = match[0]!; - if (content.emote.containsKey(matchStr)) { - // 处理表情 - final int size = content.emote[matchStr]['meta']['size']; - String imgUrl = content.emote[matchStr]['webp_url'] ?? - content.emote[matchStr]['gif_url'] ?? - content.emote[matchStr]['url']; - spanChildren.add(WidgetSpan( - child: ExcludeSemantics( - child: NetworkImgLayer( - src: imgUrl, - type: 'emote', - width: size * 20, - height: size * 20, - semanticsLabel: matchStr, - )), - )); - } else if (matchStr.startsWith("@") && - content.atNameToMid.containsKey(matchStr.substring(1))) { - // 处理@用户 - final String userName = matchStr.substring(1); - final int userId = content.atNameToMid[userName]; - spanChildren.add( - TextSpan( - text: matchStr, - style: TextStyle( - color: Theme.of(context).colorScheme.primary, - ), - recognizer: TapGestureRecognizer() - ..onTap = () { - Get.toNamed('/member?mid=$userId'); - }, - ), - ); - } else if (RegExp(r'^\b(?:\d+[::])?\d+[::]\d+\b$').hasMatch(matchStr)) { - matchStr = matchStr.replaceAll(':', ':'); - bool isValid = false; - try { - List split = matchStr - .split(':') - .map((item) => int.parse(item)) - .toList() - .reversed - .toList(); - int seek = 0; - for (int i = 0; i < split.length; i++) { - seek += split[i] * pow(60, i).toInt(); - } - int duration = Get.find( - tag: getTag?.call() ?? Get.arguments['heroTag'], - ).data.timeLength ?? - 0; - isValid = seek * 1000 <= duration; - } catch (e) { - debugPrint('failed to validate: $e'); - } - spanChildren.add( - TextSpan( - text: isValid ? ' $matchStr ' : matchStr, - style: isValid && isVideoPage - ? TextStyle( - color: Theme.of(context).colorScheme.primary, - ) - : null, - recognizer: isValid - ? (TapGestureRecognizer() - ..onTap = () { - // 跳转到指定位置 - if (isVideoPage) { - try { - SmartDialog.showToast('跳转至:$matchStr'); - Get.find( - tag: Get.arguments['heroTag']) - .plPlayerController - .seekTo( - Duration(seconds: Utils.duration(matchStr)), - type: 'slider'); - } catch (e) { - SmartDialog.showToast('跳转失败: $e'); - } - } - }) - : null, - ), - ); - } else { - String appUrlSchema = ''; - if (content.jumpUrl[matchStr] != null && - !matchedStrs.contains(matchStr)) { - appUrlSchema = content.jumpUrl[matchStr]['app_url_schema']; - if (appUrlSchema.startsWith('bilibili://search') && !enableWordRe) { - addPlainTextSpan(matchStr); - return ""; - } - spanChildren.addAll( - [ - if (content.jumpUrl[matchStr]?['prefix_icon'] != null) ...[ - WidgetSpan( - child: Image.network( - (content.jumpUrl[matchStr]['prefix_icon'] as String) - .http2https, - height: 19, - color: Theme.of(context).colorScheme.primary, - ), - ) - ], - TextSpan( - text: content.jumpUrl[matchStr]['title'], - style: TextStyle( - color: Theme.of(context).colorScheme.primary, - ), - recognizer: TapGestureRecognizer() - ..onTap = () async { - late final String title = - content.jumpUrl[matchStr]['title']; - if (appUrlSchema == '') { - if (RegExp(r'^(av|bv)', caseSensitive: false) - .hasMatch(matchStr)) { - UrlUtils.matchUrlPush(matchStr, ''); - } else { - RegExpMatch? firstMatch = RegExp( - r'^cv(\d+)$|/read/cv(\d+)|note-app/view\?cvid=(\d+)', - caseSensitive: false) - .firstMatch(matchStr); - String? cvid = firstMatch?.group(1) ?? - firstMatch?.group(2) ?? - firstMatch?.group(3); - if (cvid != null) { - Get.toNamed('/htmlRender', parameters: { - 'url': 'https://www.bilibili.com/read/cv$cvid', - 'title': title, - 'id': 'cv$cvid', - 'dynamicType': 'read' - }); - return; - } - Utils.handleWebview(matchStr); - } - } else { - if (appUrlSchema.startsWith('bilibili://search')) { - Get.toNamed('/searchResult', - parameters: {'keyword': title}); - } else { - Utils.handleWebview(matchStr); - } - } - }, - ) - ], - ); - // 只显示一次 - matchedStrs.add(matchStr); - } else if (matchStr.length > 1 && - content.topicsMeta[matchStr.substring(1, matchStr.length - 1)] != - null) { - spanChildren.add( - TextSpan( - text: matchStr, - style: TextStyle( - color: Theme.of(context).colorScheme.primary, - ), - recognizer: TapGestureRecognizer() - ..onTap = () { - final String topic = - matchStr.substring(1, matchStr.length - 1); - Get.toNamed('/searchResult', - parameters: {'keyword': topic}); - }, - ), - ); - } else if (RegExp(Constants.urlPattern).hasMatch(matchStr)) { - spanChildren.add( - TextSpan( - text: matchStr, - style: TextStyle( - color: Theme.of(context).colorScheme.primary, - ), - recognizer: TapGestureRecognizer() - ..onTap = () { - Utils.handleWebview(matchStr); - }, - ), - ); - } else { - addPlainTextSpan(matchStr); - } - } - return ''; - }, - onNonMatch: (String nonMatchStr) { - addPlainTextSpan(nonMatchStr); - return nonMatchStr; - }, - ); - - if (content.jumpUrl.keys.isNotEmpty) { - List unmatchedItems = content.jumpUrl.keys - .toList() - .where((item) => !content.message.contains(item)) - .toList(); - if (unmatchedItems.isNotEmpty) { - for (int i = 0; i < unmatchedItems.length; i++) { - String patternStr = unmatchedItems[i]; - if (content.jumpUrl?[patternStr]?['extra']?['is_word_search'] == - true && - enableWordRe.not) { - continue; - } - spanChildren.addAll( - [ - if (content.jumpUrl[patternStr]?['prefix_icon'] != null) ...[ - WidgetSpan( - child: Image.network( - (content.jumpUrl[patternStr]['prefix_icon'] as String) - .http2https, - height: 19, - color: Theme.of(context).colorScheme.primary, - ), - ) - ], - TextSpan( - text: content.jumpUrl[patternStr]['title'], - style: TextStyle( - color: Theme.of(context).colorScheme.primary, - ), - recognizer: TapGestureRecognizer() - ..onTap = () { - String? cvid = RegExp(r'note-app/view\?cvid=(\d+)') - .firstMatch(patternStr) - ?.group(1); - if (cvid != null) { - Get.toNamed('/htmlRender', parameters: { - 'url': 'https://www.bilibili.com/read/cv$cvid', - 'title': '', - 'id': 'cv$cvid', - 'dynamicType': 'read' - }); - return; - } - - Utils.handleWebview(patternStr); - }, - ) - ], - ); - } - } - } - - if (didExceedMaxLines == true) { - spanChildren.add( - TextSpan( - text: '\n查看更多', - style: TextStyle( - color: Theme.of(context).colorScheme.primary, - ), - ), - ); - } - - // 图片渲染 - if (content.pictures.isNotEmpty) { - spanChildren.add(const TextSpan(text: '\n')); - spanChildren.add( - WidgetSpan( - child: LayoutBuilder( - builder: (context, constraints) => imageView( - constraints.maxWidth, - (content.pictures as List) - .map( - (item) => ImageModel( - width: item['img_width'], - height: item['img_height'], - url: item['img_src'], - ), - ) - .toList(), - onViewImage: onViewImage, - onDismissed: onDismissed, - callback: callback, - ), - ), - ), - ); - } - - // 笔记链接 - if (content.richText.isNotEmpty) { - spanChildren.add( - TextSpan( - text: ' 笔记', - style: TextStyle( - color: Theme.of(context).colorScheme.primary, - ), - recognizer: TapGestureRecognizer() - ..onTap = () => - Utils.handleWebview(content.richText['note']['click_url']), - ), - ); - } - // spanChildren.add(TextSpan(text: matchMember)); - return TextSpan(children: spanChildren); - } - - Widget morePanel({ - required BuildContext context, - required ReplyItemModel item, - required onDelete, - }) { - Future menuActionHandler(String type) async { - late String message = item.content?.message ?? ''; - switch (type) { - case 'report': - Get.back(); - autoWrapReportDialog( - context, - ReportOptions.commentReport, - (reasonType, reasonDesc, banUid) async { - final res = await Request().post( - '/x/v2/reply/report', - data: { - 'add_blacklist': banUid, - 'csrf': Accounts.main.csrf, - 'gaia_source': 'main_h5', - 'oid': item.oid, - 'platform': 'android', - 'reason': reasonType, - 'rpid': item.rpid, - 'scene': 'main', - 'type': 1, - if (reasonType == 0) 'content': reasonDesc! - }, - options: - Options(contentType: Headers.formUrlEncodedContentType), - ); - if (res.data['code'] == 0) { - onDelete?.call(item.rpid); - } - return res.data as Map; - }, - ); - break; - case 'copyAll': - Get.back(); - Utils.copyText(message); - break; - case 'copyFreedom': - Get.back(); - showDialog( - context: context, - builder: (context) { - return Dialog( - child: Padding( - padding: - const EdgeInsets.symmetric(horizontal: 20, vertical: 16), - child: SelectableText(message), - ), - ); - }, - ); - break; - case 'delete': - Get.back(); - bool? isDelete = await showDialog( - context: context, - builder: (context) { - return AlertDialog( - title: const Text('删除评论(测试)'), - content: Text( - '确定尝试删除这条评论吗?\n\n$message\n\n注:只能删除自己的评论,或自己管理的评论区下的评论'), - actions: [ - TextButton( - onPressed: () { - Get.back(result: false); - }, - child: const Text('取消'), - ), - TextButton( - onPressed: () { - Get.back(result: true); - }, - child: const Text('确定'), - ), - ], - ); - }, - ); - if (isDelete == null || !isDelete) { - return; - } - SmartDialog.showLoading(msg: '删除中...'); - var result = await VideoHttp.replyDel( - type: item.type!, oid: item.oid!, rpid: item.rpid!); - SmartDialog.dismiss(); - if (result['status']) { - SmartDialog.showToast('删除成功'); - onDelete?.call(item.rpid!); - } else { - SmartDialog.showToast('删除失败, ${result["msg"]}'); - } - break; - case 'checkReply': - Get.back(); - onCheckReply(item); - break; - default: - } - } - - int ownerMid = Accounts.main.mid; - Color errorColor = Theme.of(context).colorScheme.error; - - return Padding( - padding: - EdgeInsets.only(bottom: MediaQuery.paddingOf(context).bottom + 20), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - InkWell( - onTap: Get.back, - borderRadius: const BorderRadius.only( - topLeft: Radius.circular(28), - topRight: Radius.circular(28), - ), - child: Container( - height: 35, - padding: const EdgeInsets.only(bottom: 2), - child: Center( - child: Container( - width: 32, - height: 3, - decoration: BoxDecoration( - color: Theme.of(context).colorScheme.outline, - borderRadius: const BorderRadius.all(Radius.circular(3))), - ), - ), - ), - ), - if (ownerMid != 0) ...[ - ListTile( - onTap: () => menuActionHandler('delete'), - minLeadingWidth: 0, - leading: Icon(Icons.delete_outlined, color: errorColor, size: 19), - title: Text('删除', - style: Theme.of(context) - .textTheme - .titleSmall! - .copyWith(color: errorColor)), - ), - ListTile( - onTap: () => menuActionHandler('report'), - minLeadingWidth: 0, - leading: Icon(Icons.error_outline, color: errorColor, size: 19), - title: Text('举报', - style: Theme.of(context) - .textTheme - .titleSmall! - .copyWith(color: errorColor)), - ), - ], - ListTile( - onTap: () => menuActionHandler('copyAll'), - minLeadingWidth: 0, - leading: const Icon(Icons.copy_all_outlined, size: 19), - title: Text('复制全部', style: Theme.of(context).textTheme.titleSmall), - ), - ListTile( - onTap: () => menuActionHandler('copyFreedom'), - minLeadingWidth: 0, - leading: const Icon(Icons.copy_outlined, size: 19), - title: Text('自由复制', style: Theme.of(context).textTheme.titleSmall), - ), - if (item.mid == ownerMid) - ListTile( - onTap: () => menuActionHandler('checkReply'), - minLeadingWidth: 0, - leading: Stack( - alignment: Alignment.center, - children: [ - const Icon(Icons.shield_outlined, size: 19), - const Icon(Icons.reply, size: 12), - ], - ), - title: - Text('检查评论', style: Theme.of(context).textTheme.titleSmall), - ), - ], - ), - ); - } -} diff --git a/lib/pages/video/detail/reply/widgets/zan.dart b/lib/pages/video/detail/reply/widgets/zan.dart deleted file mode 100644 index 6237fcae..00000000 --- a/lib/pages/video/detail/reply/widgets/zan.dart +++ /dev/null @@ -1,153 +0,0 @@ -import 'package:PiliPlus/utils/extension.dart'; -import 'package:PiliPlus/utils/utils.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; -import 'package:font_awesome_flutter/font_awesome_flutter.dart'; -import 'package:PiliPlus/http/reply.dart'; -import 'package:PiliPlus/models/common/reply_type.dart'; -import 'package:PiliPlus/models/video/reply/item.dart'; -import 'package:PiliPlus/utils/feed_back.dart'; - -class ZanButton extends StatefulWidget { - const ZanButton({ - super.key, - this.replyItem, - this.replyType, - }); - - final ReplyItemModel? replyItem; - final ReplyType? replyType; - - @override - State createState() => _ZanButtonState(); -} - -class _ZanButtonState extends State { - Future onHateReply() async { - feedBack(); - // SmartDialog.showLoading(msg: 'piliplus ...'); - final ReplyItemModel replyItem = widget.replyItem!; - final int oid = replyItem.oid!; - final int rpid = replyItem.rpid!; - // 1 已点赞 2 不喜欢 0 未操作 - final int action = replyItem.action != 2 ? 2 : 0; - final res = await ReplyHttp.hateReply( - type: widget.replyType!.index, - action: action == 2 ? 1 : 0, - oid: oid, - rpid: rpid, - ); - // SmartDialog.dismiss(); - if (res['status']) { - SmartDialog.showToast(replyItem.action != 2 ? '点踩成功' : '取消踩'); - if (action == 2) { - if (replyItem.action == 1) { - replyItem.like = replyItem.like! - 1; - } - replyItem.action = 2; - } else { - // replyItem.like = replyItem.like! - 1; - replyItem.action = 0; - } - setState(() {}); - } else { - SmartDialog.showToast(res['msg']); - } - } - - // 评论点赞 - Future onLikeReply() async { - feedBack(); - // SmartDialog.showLoading(msg: 'piliplus ...'); - final ReplyItemModel replyItem = widget.replyItem!; - final int oid = replyItem.oid!; - final int rpid = replyItem.rpid!; - // 1 已点赞 2 不喜欢 0 未操作 - final int action = replyItem.action != 1 ? 1 : 0; - final res = await ReplyHttp.likeReply( - type: widget.replyType!.index, oid: oid, rpid: rpid, action: action); - // SmartDialog.dismiss(); - if (res['status']) { - SmartDialog.showToast(replyItem.action != 1 ? '点赞成功' : '取消赞'); - if (action == 1) { - replyItem.like = replyItem.like! + 1; - replyItem.action = 1; - } else { - replyItem.like = replyItem.like! - 1; - replyItem.action = 0; - } - setState(() {}); - } else { - SmartDialog.showToast(res['msg']); - } - } - - bool isProcessing = false; - void handleState(Future Function() action) async { - if (isProcessing.not) { - isProcessing = true; - await action(); - isProcessing = false; - } - } - - @override - Widget build(BuildContext context) { - final ThemeData t = Theme.of(context); - final Color color = t.colorScheme.outline; - final Color primary = t.colorScheme.primary; - return Row( - mainAxisSize: MainAxisSize.min, - children: [ - SizedBox( - height: 32, - child: TextButton( - onPressed: () => handleState(onHateReply), - child: Icon( - widget.replyItem!.action == 2 - ? FontAwesomeIcons.solidThumbsDown - : FontAwesomeIcons.thumbsDown, - size: 16, - color: widget.replyItem!.action == 2 ? primary : color, - semanticLabel: widget.replyItem!.action == 2 ? '已踩' : '点踩', - ), - ), - ), - SizedBox( - height: 32, - child: TextButton( - onPressed: () => handleState(onLikeReply), - child: Row( - children: [ - Icon( - widget.replyItem!.action == 1 - ? FontAwesomeIcons.solidThumbsUp - : FontAwesomeIcons.thumbsUp, - size: 16, - color: widget.replyItem!.action == 1 ? primary : color, - semanticLabel: widget.replyItem!.action == 1 ? '已赞' : '点赞', - ), - const SizedBox(width: 4), - AnimatedSwitcher( - duration: const Duration(milliseconds: 400), - transitionBuilder: - (Widget child, Animation animation) { - return ScaleTransition(scale: animation, child: child); - }, - child: Text( - Utils.numFormat(widget.replyItem!.like), - key: ValueKey(widget.replyItem!.like!), - style: TextStyle( - color: widget.replyItem!.action == 1 ? primary : color, - fontSize: t.textTheme.labelSmall!.fontSize, - ), - ), - ), - ], - ), - ), - ), - ], - ); - } -} diff --git a/lib/pages/video/detail/widgets/media_list_panel.dart b/lib/pages/video/detail/widgets/media_list_panel.dart index 933e6f64..731d7af0 100644 --- a/lib/pages/video/detail/widgets/media_list_panel.dart +++ b/lib/pages/video/detail/widgets/media_list_panel.dart @@ -235,10 +235,7 @@ class _MediaListPanelState Text( item.upper!.name!, style: TextStyle( - fontSize: Theme.of(context) - .textTheme - .labelMedium! - .fontSize, + fontSize: 12, color: Theme.of(context).colorScheme.outline, ), diff --git a/lib/router/app_pages.dart b/lib/router/app_pages.dart index 5701e60a..d147191a 100644 --- a/lib/router/app_pages.dart +++ b/lib/router/app_pages.dart @@ -1,6 +1,6 @@ import 'package:PiliPlus/pages/fav/view.dart'; -import 'package:PiliPlus/pages/member/new/member_page.dart'; -import 'package:PiliPlus/pages/member/new/widget/edit_profile_page.dart'; +import 'package:PiliPlus/pages/member/member_page.dart'; +import 'package:PiliPlus/pages/member/widget/edit_profile_page.dart'; import 'package:PiliPlus/pages/search_trending/view.dart'; import 'package:PiliPlus/pages/setting/navigation_bar_set.dart'; import 'package:PiliPlus/pages/setting/search_page.dart'; @@ -35,10 +35,8 @@ import '../pages/later/index.dart'; import '../pages/live_room/view.dart'; import '../pages/login/index.dart'; import '../pages/media/index.dart'; -import '../pages/member_archive/index.dart'; import '../pages/member_dynamics/index.dart'; import '../pages/member_search/index.dart'; -import '../pages/member_seasons/index.dart'; import '../pages/msg_feed_top/sys_msg/view.dart'; import '../pages/search/index.dart'; import '../pages/search_result/index.dart'; @@ -152,16 +150,10 @@ class Routes { // 用户动态 CustomGetPage( name: '/memberDynamics', page: () => const MemberDynamicsPage()), - // 用户投稿 - CustomGetPage( - name: '/memberArchive', page: () => const MemberArchivePage()), // 用户最近投币 // CustomGetPage(name: '/memberCoin', page: () => const MemberCoinPage()), // 用户最近喜欢 // CustomGetPage(name: '/memberLike', page: () => const MemberLikePage()), - // 用户专栏 - CustomGetPage( - name: '/memberSeasons', page: () => const MemberSeasonsPage()), // 日志 CustomGetPage(name: '/logs', page: () => const LogsPage()), // 订阅 diff --git a/lib/utils/grid.dart b/lib/utils/grid.dart index 53987f6b..4a135b24 100644 --- a/lib/utils/grid.dart +++ b/lib/utils/grid.dart @@ -1,27 +1,20 @@ import 'dart:math'; +import 'package:PiliPlus/common/constants.dart'; +import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'storage.dart'; class Grid { - static double mediumCardWidth = GStorage.mediumCardWidth; static double smallCardWidth = GStorage.smallCardWidth; - // - // static double calculateActualWidth(BuildContext context, double maxCrossAxisExtent, double crossAxisSpacing, {double? screenWidthOffset}) { - // double screenWidth = MediaQuery.of(context).size.width; - // if (screenWidthOffset != null) { - // screenWidth -= screenWidthOffset; - // } - // if (GStorage.setting.get(SettingBoxKey.useSideBar, defaultValue: false) as bool) { - // screenWidth -= 55; - // } - // int columnCount = ((screenWidth - crossAxisSpacing) / (maxCrossAxisExtent + crossAxisSpacing)).ceil(); - // if (columnCount < 1){ - // columnCount = 1; - // } - // double columnWidth = (screenWidth - crossAxisSpacing) ~/ columnCount - crossAxisSpacing; - // return columnWidth; - // } + + static videoCardHDelegate(context, {double minHeight = 90}) => + SliverGridDelegateWithExtentAndRatio( + mainAxisSpacing: 2, + maxCrossAxisExtent: Grid.smallCardWidth * 2, + childAspectRatio: StyleString.aspectRatio * 2.4, + minHeight: MediaQuery.textScalerOf(context).scale(minHeight), + ); } class SliverGridDelegateWithExtentAndRatio extends SliverGridDelegate { @@ -37,10 +30,14 @@ class SliverGridDelegateWithExtentAndRatio extends SliverGridDelegate { this.crossAxisSpacing = 0.0, this.childAspectRatio = 1.0, this.mainAxisExtent = 0.0, + this.minHeight = 0.0, }) : assert(maxCrossAxisExtent > 0), assert(mainAxisSpacing >= 0), assert(crossAxisSpacing >= 0), - assert(childAspectRatio > 0); + assert(childAspectRatio > 0), + assert(minHeight >= 0); + + final double minHeight; /// The maximum extent of tiles in the cross axis. /// @@ -91,8 +88,8 @@ class SliverGridDelegateWithExtentAndRatio extends SliverGridDelegate { constraints.crossAxisExtent - crossAxisSpacing * (crossAxisCount - 1), ); final double childCrossAxisExtent = usableCrossAxisExtent / crossAxisCount; - final double childMainAxisExtent = - childCrossAxisExtent / childAspectRatio + mainAxisExtent; + final double childMainAxisExtent = max( + minHeight, childCrossAxisExtent / childAspectRatio + mainAxisExtent); return SliverGridRegularTileLayout( crossAxisCount: crossAxisCount, mainAxisStride: childMainAxisExtent + mainAxisSpacing, diff --git a/lib/utils/storage.dart b/lib/utils/storage.dart index bc563622..2f5337f2 100644 --- a/lib/utils/storage.dart +++ b/lib/utils/storage.dart @@ -17,7 +17,7 @@ import 'package:PiliPlus/models/user/danmaku_rule_adapter.dart'; import 'package:PiliPlus/models/video/play/CDN.dart'; import 'package:PiliPlus/models/video/play/quality.dart'; import 'package:PiliPlus/models/video/play/subtitle.dart'; -import 'package:PiliPlus/pages/member/new/controller.dart' show MemberTabType; +import 'package:PiliPlus/pages/member/controller.dart' show MemberTabType; import 'package:PiliPlus/pages/mine/index.dart'; import 'package:PiliPlus/plugin/pl_player/models/bottom_progress_behavior.dart'; import 'package:PiliPlus/plugin/pl_player/models/fullscreen_mode.dart'; @@ -123,9 +123,6 @@ class GStorage { static int get previewQ => setting.get(SettingBoxKey.previewQuality, defaultValue: 100); - static double get mediumCardWidth => - setting.get(SettingBoxKey.mediumCardWidth, defaultValue: 280.0); - static double get smallCardWidth => setting.get(SettingBoxKey.smallCardWidth, defaultValue: 240.0); @@ -807,7 +804,6 @@ class SettingBoxKey { customColor = 'customColor', // 自定义主题色 enableSingleRow = 'enableSingleRow', // 首页单列 displayMode = 'displayMode', - mediumCardWidth = 'mediumCardWidth', // 首页列最大宽度(dp) smallCardWidth = 'smallCardWidth', videoPlayerRemoveSafeArea = 'videoPlayerRemoveSafeArea', // 视频播放器移除安全边距 // videoPlayerShowStatusBarBackgroundColor =