|
1 | 1 | import 'dart:async'; |
2 | | -import 'dart:io'; |
3 | 2 | import 'dart:math'; |
4 | 3 |
|
5 | 4 | import 'package:card_swiper/card_swiper.dart'; |
@@ -48,6 +47,7 @@ import '../../Utils/utils.dart'; |
48 | 47 | import '../../Widgets/BottomSheet/bottom_sheet_builder.dart'; |
49 | 48 | import '../../Widgets/Custom/hero_photo_view_screen.dart'; |
50 | 49 | import '../../Widgets/General/EasyRefresh/easy_refresh.dart'; |
| 50 | +import '../../Widgets/Hidable/scroll_to_hide.dart'; |
51 | 51 | import '../../Widgets/Item/item_builder.dart'; |
52 | 52 | import '../../Widgets/Item/loftify_item_builder.dart'; |
53 | 53 | import '../../Widgets/PostItem/general_post_item_builder.dart'; |
@@ -135,6 +135,18 @@ class _PostDetailScreenState extends State<PostDetailScreen> |
135 | 135 | DownloadState downloadState = DownloadState.none; |
136 | 136 | bool isArticle = false; |
137 | 137 | InitPhase _inited = InitPhase.haveNotConnected; |
| 138 | + final ScrollToHideController _scrollToHideController = |
| 139 | + ScrollToHideController(); |
| 140 | + final bool _showPostDetailFloatingOperationBar = |
| 141 | + HiveUtil.getBool(HiveUtil.showPostDetailFloatingOperationBarKey); |
| 142 | + final bool _showPostDetailFloatingOperationBarOnlyInArticle = |
| 143 | + HiveUtil.getBool( |
| 144 | + HiveUtil.showPostDetailFloatingOperationBarOnlyInArticleKey, |
| 145 | + defaultValue: false); |
| 146 | + |
| 147 | + bool get _showBottomBar => |
| 148 | + _showPostDetailFloatingOperationBar && |
| 149 | + (!_showPostDetailFloatingOperationBarOnlyInArticle || isArticle); |
138 | 150 |
|
139 | 151 | @override |
140 | 152 | void initState() { |
@@ -593,6 +605,10 @@ class _PostDetailScreenState extends State<PostDetailScreen> |
593 | 605 | appBar: _buildAppBar(), |
594 | 606 | backgroundColor: MyTheme.getBackground(context), |
595 | 607 | body: _buildBody(), |
| 608 | + extendBody: true, |
| 609 | + bottomNavigationBar: _showBottomBar && _postDetailData != null && _postDetailData!.post != null |
| 610 | + ? _buildFloatingOperationRow() |
| 611 | + : null, |
596 | 612 | ); |
597 | 613 | } |
598 | 614 |
|
@@ -668,16 +684,31 @@ class _PostDetailScreenState extends State<PostDetailScreen> |
668 | 684 | } |
669 | 685 |
|
670 | 686 | _buildMainBody(ScrollPhysics physics) { |
671 | | - return Selector<AppProvider, Size>( |
672 | | - selector: (context, appProvider) => appProvider.windowSize, |
673 | | - builder: (context, windowSize, child) => |
674 | | - windowSize.width > minimumSize.width || |
675 | | - ResponsiveUtil.isLandscapeTablet() |
676 | | - ? ScreenTypeLayout.builder( |
677 | | - mobile: (context) => _buildMobileMainBody(physics), |
678 | | - tablet: (context) => _buildTabletMainBody(), |
679 | | - ) |
680 | | - : _buildMobileMainBody(physics), |
| 687 | + return Stack( |
| 688 | + children: [ |
| 689 | + Selector<AppProvider, Size>( |
| 690 | + selector: (context, appProvider) => appProvider.windowSize, |
| 691 | + builder: (context, windowSize, child) => |
| 692 | + windowSize.width > minimumSize.width || |
| 693 | + ResponsiveUtil.isLandscapeTablet() |
| 694 | + ? ScreenTypeLayout.builder( |
| 695 | + mobile: (context) => _buildMobileMainBody(physics), |
| 696 | + tablet: (context) => _buildTabletMainBody(), |
| 697 | + ) |
| 698 | + : _buildMobileMainBody(physics), |
| 699 | + ), |
| 700 | + if (!_showBottomBar) |
| 701 | + Positioned( |
| 702 | + right: 16, |
| 703 | + bottom: 16, |
| 704 | + child: ScrollToHide( |
| 705 | + controller: _scrollToHideController, |
| 706 | + scrollControllers: [_scrollController], |
| 707 | + hideDirection: AxisDirection.down, |
| 708 | + child: _buildFloatingButtons(), |
| 709 | + ), |
| 710 | + ), |
| 711 | + ], |
681 | 712 | ); |
682 | 713 | } |
683 | 714 |
|
@@ -1045,6 +1076,16 @@ class _PostDetailScreenState extends State<PostDetailScreen> |
1045 | 1076 | ]; |
1046 | 1077 | } |
1047 | 1078 |
|
| 1079 | + jumpToComment() { |
| 1080 | + if (commentKey.currentContext != null) { |
| 1081 | + Scrollable.ensureVisible( |
| 1082 | + commentKey.currentContext!, |
| 1083 | + duration: const Duration(milliseconds: 300), |
| 1084 | + curve: Curves.ease, |
| 1085 | + ); |
| 1086 | + } |
| 1087 | + } |
| 1088 | + |
1048 | 1089 | _buildEggTitle(String tag, String title) { |
1049 | 1090 | return Text.rich( |
1050 | 1091 | TextSpan( |
@@ -2100,6 +2141,127 @@ class _PostDetailScreenState extends State<PostDetailScreen> |
2100 | 2141 | ); |
2101 | 2142 | } |
2102 | 2143 |
|
| 2144 | + _buildFloatingButtons() { |
| 2145 | + return Column( |
| 2146 | + children: [ |
| 2147 | + ItemBuilder.buildShadowIconButton( |
| 2148 | + context: context, |
| 2149 | + icon: const Icon(Icons.comment_bank_outlined), |
| 2150 | + onTap: () { |
| 2151 | + jumpToComment(); |
| 2152 | + }, |
| 2153 | + ), |
| 2154 | + ], |
| 2155 | + ); |
| 2156 | + } |
| 2157 | + |
| 2158 | + Widget _buildFloatingOperationRow() { |
| 2159 | + return ScrollToHide( |
| 2160 | + controller: _scrollToHideController, |
| 2161 | + scrollControllers: [_scrollController], |
| 2162 | + hideDirection: AxisDirection.down, |
| 2163 | + child: Container( |
| 2164 | + height: 64, |
| 2165 | + decoration: BoxDecoration( |
| 2166 | + color: Theme.of(rootContext).canvasColor, |
| 2167 | + border: MyTheme.topBorder, |
| 2168 | + boxShadow: MyTheme.defaultBoxShadow, |
| 2169 | + borderRadius: const BorderRadius.vertical(top: Radius.circular(10)), |
| 2170 | + ), |
| 2171 | + padding: const EdgeInsets.only(left: 6, right: 16, bottom: 8), |
| 2172 | + child: Stack( |
| 2173 | + clipBehavior: Clip.none, |
| 2174 | + children: [ |
| 2175 | + Row( |
| 2176 | + mainAxisSize: MainAxisSize.max, |
| 2177 | + children: [ |
| 2178 | + Stack( |
| 2179 | + children: [ |
| 2180 | + LoftifyItemBuilder.buildLikedLottieButton( |
| 2181 | + context, |
| 2182 | + showCount: true, |
| 2183 | + iconSize: 52, |
| 2184 | + animationController: _likeController, |
| 2185 | + likeCount: |
| 2186 | + _postDetailData!.post!.postCount!.favoriteCount, |
| 2187 | + isLiked: _postDetailData!.liked, |
| 2188 | + onTap: () async { |
| 2189 | + _handleLike(); |
| 2190 | + }, |
| 2191 | + ), |
| 2192 | + Container( |
| 2193 | + margin: const EdgeInsets.only(left: 42), |
| 2194 | + child: LoftifyItemBuilder.buildLottieSharedButton( |
| 2195 | + context, |
| 2196 | + showCount: true, |
| 2197 | + iconSize: 52, |
| 2198 | + shareCount: |
| 2199 | + _postDetailData!.post!.postCount!.shareCount, |
| 2200 | + isShared: _postDetailData!.shared, |
| 2201 | + animationController: _shareController, |
| 2202 | + onTap: () async { |
| 2203 | + _handleRecommend(); |
| 2204 | + }, |
| 2205 | + ), |
| 2206 | + ), |
| 2207 | + ], |
| 2208 | + ), |
| 2209 | + const Spacer(), |
| 2210 | + ], |
| 2211 | + ), |
| 2212 | + Positioned( |
| 2213 | + top: 16, |
| 2214 | + right: 40, |
| 2215 | + child: ItemBuilder.buildIconTextButton( |
| 2216 | + context, |
| 2217 | + text: _postDetailData!.post!.postCount!.responseCount > 0 |
| 2218 | + ? "${_postDetailData!.post!.postCount!.responseCount}" |
| 2219 | + : S.current.comment, |
| 2220 | + icon: const Icon(Icons.comment_bank_outlined, size: 24), |
| 2221 | + direction: Axis.vertical, |
| 2222 | + spacing: 0, |
| 2223 | + style: Theme.of(context).textTheme.labelSmall, |
| 2224 | + onTap: () { |
| 2225 | + jumpToComment(); |
| 2226 | + }, |
| 2227 | + ), |
| 2228 | + ), |
| 2229 | + Positioned( |
| 2230 | + top: 12, |
| 2231 | + right: 0, |
| 2232 | + child: ItemBuilder.buildIconTextButton( |
| 2233 | + context, |
| 2234 | + text: _postDetailData!.subscribedNotNull |
| 2235 | + ? S.current.favorited |
| 2236 | + : S.current.favorite, |
| 2237 | + icon: _postDetailData!.subscribedNotNull |
| 2238 | + ? const Icon(Icons.star_rounded, |
| 2239 | + size: 28, color: Colors.yellow) |
| 2240 | + : const Icon(Icons.star_border_rounded, size: 28), |
| 2241 | + direction: Axis.vertical, |
| 2242 | + spacing: 0, |
| 2243 | + style: Theme.of(context).textTheme.labelSmall, |
| 2244 | + onTap: () { |
| 2245 | + BottomSheetBuilder.showBottomSheet( |
| 2246 | + context, |
| 2247 | + enableDrag: false, |
| 2248 | + (context) => SubscribePostBottomSheet( |
| 2249 | + postId: postId, |
| 2250 | + blogId: blogId, |
| 2251 | + onConfirm: (folderIds) { |
| 2252 | + _handleSubscribe(folderIds); |
| 2253 | + }, |
| 2254 | + ), |
| 2255 | + ); |
| 2256 | + }, |
| 2257 | + ), |
| 2258 | + ), |
| 2259 | + ], |
| 2260 | + ), |
| 2261 | + ), |
| 2262 | + ); |
| 2263 | + } |
| 2264 | + |
2103 | 2265 | Widget _buildComments(List<Comment> comments) { |
2104 | 2266 | return ListView.builder( |
2105 | 2267 | shrinkWrap: true, |
|
0 commit comments