diff --git a/lib/pages/dynamics/controller.dart b/lib/pages/dynamics/controller.dart index 1d0af54b..42647f3f 100644 --- a/lib/pages/dynamics/controller.dart +++ b/lib/pages/dynamics/controller.dart @@ -9,6 +9,7 @@ import 'package:pilipala/models/common/dynamics_type.dart'; import 'package:pilipala/models/dynamics/result.dart'; import 'package:pilipala/models/dynamics/up.dart'; import 'package:pilipala/models/live/item.dart'; +import 'package:pilipala/utils/feed_back.dart'; class DynamicsController extends GetxController { int page = 1; @@ -78,6 +79,7 @@ class DynamicsController extends GetxController { } pushDetail(item, floor, {action = 'all'}) async { + feedBack(); if (action == 'comment') { Get.toNamed('/dynamicDetail', arguments: {'item': item, 'floor': floor, 'action': action}); diff --git a/lib/pages/dynamics/view.dart b/lib/pages/dynamics/view.dart index 9330679d..0577fa29 100644 --- a/lib/pages/dynamics/view.dart +++ b/lib/pages/dynamics/view.dart @@ -8,6 +8,7 @@ import 'package:pilipala/common/widgets/http_error.dart'; import 'package:pilipala/common/widgets/network_img_layer.dart'; import 'package:pilipala/models/dynamics/result.dart'; import 'package:pilipala/pages/mine/index.dart'; +import 'package:pilipala/utils/feed_back.dart'; import 'package:pilipala/utils/storage.dart'; import 'controller.dart'; @@ -143,6 +144,7 @@ class _DynamicsPageState extends State duration: const Duration(milliseconds: 300), curve: Curves.easeInOut, onValueChanged: (v) { + feedBack(); _dynamicsController.onSelectType(v); }, ), @@ -155,7 +157,8 @@ class _DynamicsPageState extends State bottom: 0, child: IconButton( padding: EdgeInsets.zero, - onPressed: () => _dynamicsController.resetSearch(), + onPressed: () => + {feedBack(), _dynamicsController.resetSearch()}, icon: const Icon(Icons.history, size: 21), ), ), @@ -167,15 +170,18 @@ class _DynamicsPageState extends State alignment: Alignment.center, child: user.get(UserBoxKey.userLogin) ?? false ? GestureDetector( - onTap: () => showModalBottomSheet( - context: context, - builder: (_) => const SizedBox( - height: 450, - child: MinePage(), - ), - clipBehavior: Clip.hardEdge, - isScrollControlled: true, - ), + onTap: () { + feedBack(); + showModalBottomSheet( + context: context, + builder: (_) => const SizedBox( + height: 450, + child: MinePage(), + ), + clipBehavior: Clip.hardEdge, + isScrollControlled: true, + ); + }, child: NetworkImgLayer( type: 'avatar', width: 30, @@ -184,15 +190,18 @@ class _DynamicsPageState extends State ), ) : IconButton( - onPressed: () => showModalBottomSheet( - context: context, - builder: (_) => const SizedBox( - height: 450, - child: MinePage(), - ), - clipBehavior: Clip.hardEdge, - isScrollControlled: true, - ), + onPressed: () { + feedBack(); + showModalBottomSheet( + context: context, + builder: (_) => const SizedBox( + height: 450, + child: MinePage(), + ), + clipBehavior: Clip.hardEdge, + isScrollControlled: true, + ); + }, icon: const Icon(CupertinoIcons.person, size: 22), ), ), diff --git a/lib/pages/dynamics/widgets/action_panel.dart b/lib/pages/dynamics/widgets/action_panel.dart index d601c025..34b7f6af 100644 --- a/lib/pages/dynamics/widgets/action_panel.dart +++ b/lib/pages/dynamics/widgets/action_panel.dart @@ -6,6 +6,7 @@ import 'package:get/get.dart'; import 'package:pilipala/http/dynamics.dart'; import 'package:pilipala/models/dynamics/result.dart'; import 'package:pilipala/pages/dynamics/index.dart'; +import 'package:pilipala/utils/feed_back.dart'; class ActionPanel extends StatefulWidget { const ActionPanel({ @@ -31,6 +32,7 @@ class _ActionPanelState extends State { // 动态点赞 onLikeDynamic() async { + feedBack(); var item = widget.item!; String dynamicId = item.idStr!; // 1 已点赞 2 不喜欢 0 未操作 diff --git a/lib/pages/dynamics/widgets/author_panel.dart b/lib/pages/dynamics/widgets/author_panel.dart index a1b67a92..0e2e51dc 100644 --- a/lib/pages/dynamics/widgets/author_panel.dart +++ b/lib/pages/dynamics/widgets/author_panel.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:pilipala/common/widgets/network_img_layer.dart'; +import 'package:pilipala/utils/feed_back.dart'; import 'package:pilipala/utils/utils.dart'; Widget author(item, context) { @@ -10,12 +11,16 @@ Widget author(item, context) { child: Row( children: [ GestureDetector( - onTap: () => Get.toNamed( + onTap: () { + feedBack(); + Get.toNamed( '/member?mid=${item.modules.moduleAuthor.mid}', arguments: { 'face': item.modules.moduleAuthor.face, 'heroTag': heroTag - }), + }, + ); + }, child: Hero( tag: heroTag, child: NetworkImgLayer( diff --git a/lib/pages/dynamics/widgets/up_panel.dart b/lib/pages/dynamics/widgets/up_panel.dart index f6147de3..e1054ba0 100644 --- a/lib/pages/dynamics/widgets/up_panel.dart +++ b/lib/pages/dynamics/widgets/up_panel.dart @@ -5,6 +5,7 @@ import 'package:pilipala/common/widgets/network_img_layer.dart'; import 'package:pilipala/models/dynamics/up.dart'; import 'package:pilipala/models/live/item.dart'; import 'package:pilipala/pages/dynamics/controller.dart'; +import 'package:pilipala/utils/feed_back.dart'; import 'package:pilipala/utils/storage.dart'; import 'package:pilipala/utils/utils.dart'; @@ -81,7 +82,7 @@ class _UpPanelState extends State { ), Material( child: InkWell( - onTap: () => Get.toNamed('/follow'), + onTap: () => {feedBack(), Get.toNamed('/follow')}, child: Container( height: 100, padding: const EdgeInsets.only(left: 10, right: 10), @@ -111,6 +112,7 @@ class _UpPanelState extends State { bool isCurrent = currentMid == data.mid || currentMid == -1; return InkWell( onTap: () { + feedBack(); if (data.type == 'up') { currentMid = data.mid; Get.find().mid.value = data.mid; @@ -149,6 +151,7 @@ class _UpPanelState extends State { } }, onLongPress: () { + feedBack(); String heroTag = Utils.makeHeroTag(data.mid); Get.toNamed('/member?mid=${data.mid}', arguments: {'face': data.face, 'heroTag': heroTag}); diff --git a/lib/pages/follow/widgets/follow_item.dart b/lib/pages/follow/widgets/follow_item.dart index 301b3e84..e9ee6e2e 100644 --- a/lib/pages/follow/widgets/follow_item.dart +++ b/lib/pages/follow/widgets/follow_item.dart @@ -1,13 +1,17 @@ import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:pilipala/common/widgets/network_img_layer.dart'; +import 'package:pilipala/utils/feed_back.dart'; import 'package:pilipala/utils/utils.dart'; Widget followItem({item}) { String heroTag = Utils.makeHeroTag(item!.mid); return ListTile( - onTap: () => Get.toNamed('/member?mid=${item.mid}', - arguments: {'face': item.face, 'heroTag': heroTag}), + onTap: () { + feedBack(); + Get.toNamed('/member?mid=${item.mid}', + arguments: {'face': item.face, 'heroTag': heroTag}); + }, leading: Hero( tag: heroTag, child: NetworkImgLayer( diff --git a/lib/pages/home/view.dart b/lib/pages/home/view.dart index 3a265c84..8230246b 100644 --- a/lib/pages/home/view.dart +++ b/lib/pages/home/view.dart @@ -4,6 +4,7 @@ import 'package:get/get.dart'; import 'package:pilipala/pages/hot/index.dart'; import 'package:pilipala/pages/live/index.dart'; import 'package:pilipala/pages/rcmd/index.dart'; +import 'package:pilipala/utils/feed_back.dart'; import './controller.dart'; class HomePage extends StatefulWidget { @@ -92,7 +93,8 @@ class _HomePageState extends State dividerColor: Colors.transparent, unselectedLabelColor: Theme.of(context).colorScheme.outline, - onTap: (value) => {_homeController.initialIndex = value}, + onTap: (value) => + {feedBack(), _homeController.initialIndex = value}, ), ), ), @@ -103,6 +105,7 @@ class _HomePageState extends State tag: 'searchTag', child: IconButton( onPressed: () { + feedBack(); Get.toNamed('/search'); }, icon: const Icon(CupertinoIcons.search, size: 21), diff --git a/lib/pages/main/view.dart b/lib/pages/main/view.dart index 2eab8f24..73823270 100644 --- a/lib/pages/main/view.dart +++ b/lib/pages/main/view.dart @@ -3,6 +3,7 @@ import 'package:get/get.dart'; import 'package:hive/hive.dart'; import 'package:pilipala/pages/dynamics/index.dart'; import 'package:pilipala/pages/home/index.dart'; +import 'package:pilipala/utils/feed_back.dart'; import 'package:pilipala/utils/storage.dart'; import './controller.dart'; @@ -44,6 +45,7 @@ class _MainAppState extends State with SingleTickerProviderStateMixin { } void setIndex(int value) async { + feedBack(); if (selectedIndex != value) { selectedIndex = value; _animationController!.reverse().then((_) { diff --git a/lib/pages/setting/controller.dart b/lib/pages/setting/controller.dart index 47819593..2a394587 100644 --- a/lib/pages/setting/controller.dart +++ b/lib/pages/setting/controller.dart @@ -2,17 +2,22 @@ import 'package:get/get.dart'; import 'package:hive/hive.dart'; import 'package:pilipala/http/init.dart'; import 'package:pilipala/pages/mine/controller.dart'; +import 'package:pilipala/utils/feed_back.dart'; import 'package:pilipala/utils/storage.dart'; class SettingController extends GetxController { Box user = GStrorage.user; RxBool userLogin = false.obs; Box userInfoCache = GStrorage.userInfo; + Box setting = GStrorage.setting; + RxBool feedBackEnable = false.obs; @override void onInit() { super.onInit(); userLogin.value = user.get(UserBoxKey.userLogin) ?? false; + feedBackEnable.value = + setting.get(SettingBoxKey.feedBackEnable, defaultValue: false); } loginOut() async { @@ -21,4 +26,11 @@ class SettingController extends GetxController { userLogin.value = user.get(UserBoxKey.userLogin) ?? false; userInfoCache.put('userInfoCache', null); } + + // 开启关闭震动反馈 + onOpenFeedBack() { + feedBack(); + feedBackEnable.value = !feedBackEnable.value; + setting.put(SettingBoxKey.feedBackEnable, feedBackEnable.value); + } } diff --git a/lib/pages/setting/view.dart b/lib/pages/setting/view.dart index a36b5527..155eec2a 100644 --- a/lib/pages/setting/view.dart +++ b/lib/pages/setting/view.dart @@ -7,6 +7,10 @@ class SettingPage extends StatelessWidget { @override Widget build(BuildContext context) { + TextStyle subTitleStyle = Theme.of(context) + .textTheme + .labelMedium! + .copyWith(color: Theme.of(context).colorScheme.outline); final SettingController settingController = Get.put(SettingController()); return Scaffold( appBar: AppBar( @@ -14,6 +18,28 @@ class SettingPage extends StatelessWidget { ), body: Column( children: [ + Obx( + () => ListTile( + enableFeedback: true, + onTap: () => settingController.onOpenFeedBack(), + title: const Text('震动反馈'), + subtitle: Text('请确定手机设置中已开启震动反馈', style: subTitleStyle), + trailing: Transform.scale( + scale: 0.8, + child: Switch( + thumbIcon: MaterialStateProperty.resolveWith( + (Set states) { + if (states.isNotEmpty && + states.first == MaterialState.selected) { + return const Icon(Icons.done); + } + return null; // All other states will use the default thumbIcon. + }), + value: settingController.feedBackEnable.value, + onChanged: (value) => settingController.onOpenFeedBack()), + ), + ), + ), Obx( () => Visibility( visible: settingController.userLogin.value, diff --git a/lib/pages/video/detail/introduction/controller.dart b/lib/pages/video/detail/introduction/controller.dart index bb208b3b..c6cb792b 100644 --- a/lib/pages/video/detail/introduction/controller.dart +++ b/lib/pages/video/detail/introduction/controller.dart @@ -8,6 +8,7 @@ import 'package:pilipala/http/video.dart'; import 'package:pilipala/models/user/fav_folder.dart'; import 'package:pilipala/models/video_detail_res.dart'; import 'package:pilipala/pages/video/detail/controller.dart'; +import 'package:pilipala/utils/feed_back.dart'; import 'package:pilipala/utils/id_utils.dart'; import 'package:pilipala/utils/storage.dart'; import 'package:share_plus/share_plus.dart'; @@ -303,6 +304,7 @@ class VideoIntroController extends GetxController { // 选择文件夹 onChoose(bool checkValue, int index) { + feedBack(); List datalist = favFolderData.value.list!; for (var i = 0; i < datalist.length; i++) { if (i == index) { @@ -327,6 +329,7 @@ class VideoIntroController extends GetxController { // 关注/取关up Future actionRelationMod() async { + feedBack(); if (user.get(UserBoxKey.userMid) == null) { SmartDialog.showToast('账号未登录'); return; diff --git a/lib/pages/video/detail/introduction/view.dart b/lib/pages/video/detail/introduction/view.dart index 682bfda0..247cf114 100644 --- a/lib/pages/video/detail/introduction/view.dart +++ b/lib/pages/video/detail/introduction/view.dart @@ -12,6 +12,7 @@ import 'package:pilipala/common/widgets/stat/danmu.dart'; import 'package:pilipala/common/widgets/stat/view.dart'; import 'package:pilipala/models/video_detail_res.dart'; import 'package:pilipala/pages/video/detail/introduction/controller.dart'; +import 'package:pilipala/utils/feed_back.dart'; import 'package:pilipala/utils/storage.dart'; import 'package:pilipala/utils/utils.dart'; @@ -125,6 +126,7 @@ class _VideoInfoState extends State with TickerProviderStateMixin { // 视频介绍 showIntroDetail() { + feedBack(); showBottomSheet( context: context, enableDrag: true, @@ -245,6 +247,7 @@ class _VideoInfoState extends State with TickerProviderStateMixin { ], GestureDetector( onTap: () { + feedBack(); int mid = !widget.loadingStatus ? widget.videoDetail!.owner!.mid : videoItem['owner'].mid; diff --git a/lib/pages/video/detail/introduction/widgets/action_row_item.dart b/lib/pages/video/detail/introduction/widgets/action_row_item.dart index 254d7bcd..5b940e0b 100644 --- a/lib/pages/video/detail/introduction/widgets/action_row_item.dart +++ b/lib/pages/video/detail/introduction/widgets/action_row_item.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:pilipala/utils/feed_back.dart'; class ActionRowItem extends StatelessWidget { final Icon? icon; @@ -27,7 +28,10 @@ class ActionRowItem extends StatelessWidget { borderRadius: const BorderRadius.all(Radius.circular(30)), clipBehavior: Clip.hardEdge, child: InkWell( - onTap: () => onTap!(), + onTap: () => { + feedBack(), + onTap!(), + }, child: Padding( padding: const EdgeInsets.fromLTRB(13, 6.5, 15, 6.3), child: Row( diff --git a/lib/pages/video/detail/introduction/widgets/fav_panel.dart b/lib/pages/video/detail/introduction/widgets/fav_panel.dart index b640242d..44502b0e 100644 --- a/lib/pages/video/detail/introduction/widgets/fav_panel.dart +++ b/lib/pages/video/detail/introduction/widgets/fav_panel.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:hive/hive.dart'; import 'package:pilipala/common/widgets/http_error.dart'; +import 'package:pilipala/utils/feed_back.dart'; import 'package:pilipala/utils/storage.dart'; class FavPanel extends StatefulWidget { @@ -43,6 +44,7 @@ class _FavPanelState extends State { actions: [ TextButton( onPressed: () async { + feedBack(); await widget.ctr!.actionFavVideo(); }, child: const Text('完成'), diff --git a/lib/pages/video/detail/introduction/widgets/menu_row.dart b/lib/pages/video/detail/introduction/widgets/menu_row.dart index 4a9aef35..7832d7be 100644 --- a/lib/pages/video/detail/introduction/widgets/menu_row.dart +++ b/lib/pages/video/detail/introduction/widgets/menu_row.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:pilipala/utils/feed_back.dart'; class MenuRow extends StatelessWidget { final bool? loadingStatus; @@ -62,7 +63,10 @@ class MenuRow extends StatelessWidget { borderRadius: const BorderRadius.all(Radius.circular(30)), clipBehavior: Clip.hardEdge, child: InkWell( - onTap: () => onTap!(), + onTap: () => { + feedBack(), + onTap!(), + }, child: Container( padding: const EdgeInsets.fromLTRB(13, 5.5, 13, 5.5), decoration: BoxDecoration( diff --git a/lib/pages/video/detail/reply/controller.dart b/lib/pages/video/detail/reply/controller.dart index 76fb8be6..09a910fe 100644 --- a/lib/pages/video/detail/reply/controller.dart +++ b/lib/pages/video/detail/reply/controller.dart @@ -4,6 +4,7 @@ import 'package:pilipala/http/reply.dart'; import 'package:pilipala/models/common/reply_sort_type.dart'; import 'package:pilipala/models/common/reply_type.dart'; import 'package:pilipala/models/video/reply/item.dart'; +import 'package:pilipala/utils/feed_back.dart'; class VideoReplyController extends GetxController { VideoReplyController( @@ -83,6 +84,7 @@ class VideoReplyController extends GetxController { // 排序搜索评论 queryBySort() { + feedBack(); switch (sortType) { case ReplySortType.time: sortType = ReplySortType.like; diff --git a/lib/pages/video/detail/reply/view.dart b/lib/pages/video/detail/reply/view.dart index b2521473..80c6fedf 100644 --- a/lib/pages/video/detail/reply/view.dart +++ b/lib/pages/video/detail/reply/view.dart @@ -8,6 +8,7 @@ import 'package:pilipala/common/widgets/http_error.dart'; import 'package:pilipala/models/common/reply_type.dart'; import 'package:pilipala/pages/video/detail/index.dart'; import 'package:pilipala/pages/video/detail/replyNew/index.dart'; +import 'package:pilipala/utils/feed_back.dart'; import 'package:pilipala/utils/id_utils.dart'; import 'controller.dart'; import 'widgets/reply_item.dart'; @@ -262,6 +263,7 @@ class _VideoReplyPanelState extends State child: FloatingActionButton( heroTag: null, onPressed: () { + feedBack(); showModalBottomSheet( context: context, isScrollControlled: true, diff --git a/lib/pages/video/detail/reply/widgets/reply_item.dart b/lib/pages/video/detail/reply/widgets/reply_item.dart index d32d296d..23ca4208 100644 --- a/lib/pages/video/detail/reply/widgets/reply_item.dart +++ b/lib/pages/video/detail/reply/widgets/reply_item.dart @@ -7,6 +7,7 @@ import 'package:pilipala/models/common/reply_type.dart'; import 'package:pilipala/models/video/reply/item.dart'; import 'package:pilipala/pages/video/detail/controller.dart'; import 'package:pilipala/pages/video/detail/replyNew/index.dart'; +import 'package:pilipala/utils/feed_back.dart'; import 'package:pilipala/utils/utils.dart'; import 'zan.dart'; @@ -86,6 +87,7 @@ class ReplyItem extends StatelessWidget { // 头像、昵称 GestureDetector( onTap: () { + feedBack(); Get.toNamed('/member?mid=${replyItem!.mid}', arguments: { 'face': replyItem!.member!.avatar!, 'heroTag': heroTag @@ -259,6 +261,7 @@ class ReplyItem extends StatelessWidget { .labelMedium! .copyWith(color: Theme.of(context).colorScheme.outline)), onPressed: () { + feedBack(); showModalBottomSheet( context: context, isScrollControlled: true, @@ -348,6 +351,7 @@ class ReplyItemRow extends StatelessWidget { ), recognizer: TapGestureRecognizer() ..onTap = () { + feedBack(); String heroTag = Utils.makeHeroTag(replies![i].member.mid); Get.toNamed( diff --git a/lib/pages/video/detail/reply/widgets/zan.dart b/lib/pages/video/detail/reply/widgets/zan.dart index bc08e839..da0c1378 100644 --- a/lib/pages/video/detail/reply/widgets/zan.dart +++ b/lib/pages/video/detail/reply/widgets/zan.dart @@ -4,6 +4,7 @@ import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:pilipala/http/reply.dart'; import 'package:pilipala/models/common/reply_type.dart'; import 'package:pilipala/models/video/reply/item.dart'; +import 'package:pilipala/utils/feed_back.dart'; class ZanButton extends StatefulWidget { const ZanButton({ @@ -22,6 +23,7 @@ class ZanButton extends StatefulWidget { class _ZanButtonState extends State { // 评论点赞 onLikeReply() async { + feedBack(); SmartDialog.showLoading(msg: 'pilipala ...'); ReplyItemModel replyItem = widget.replyItem!; int oid = replyItem.oid!; diff --git a/lib/pages/video/detail/replyNew/view.dart b/lib/pages/video/detail/replyNew/view.dart index 45131110..122cc652 100644 --- a/lib/pages/video/detail/replyNew/view.dart +++ b/lib/pages/video/detail/replyNew/view.dart @@ -6,6 +6,7 @@ import 'package:hive/hive.dart'; import 'package:pilipala/http/video.dart'; import 'package:pilipala/models/common/reply_type.dart'; import 'package:pilipala/models/video/reply/item.dart'; +import 'package:pilipala/utils/feed_back.dart'; import 'package:pilipala/utils/storage.dart'; class VideoReplyNewDialog extends StatefulWidget { @@ -68,6 +69,7 @@ class _VideoReplyNewDialogState extends State } Future submitReplyAdd() async { + feedBack(); String message = _replyContentController.text; var result = await VideoHttp.replyAdd( type: widget.replyType ?? ReplyType.video, diff --git a/lib/utils/feed_back.dart b/lib/utils/feed_back.dart new file mode 100644 index 00000000..cb3a693c --- /dev/null +++ b/lib/utils/feed_back.dart @@ -0,0 +1,12 @@ +import 'package:flutter/services.dart'; +import 'package:hive/hive.dart'; +import 'package:pilipala/utils/storage.dart'; + +Box setting = GStrorage.setting; +void feedBack() { + // 设置中是否开启 + bool enable = setting.get(SettingBoxKey.feedBackEnable, defaultValue: false); + if (enable) { + HapticFeedback.lightImpact(); + } +} diff --git a/lib/utils/storage.dart b/lib/utils/storage.dart index bfff55d6..36bd6bec 100644 --- a/lib/utils/storage.dart +++ b/lib/utils/storage.dart @@ -13,6 +13,7 @@ class GStrorage { static late final Box hotKeyword; static late final Box historyword; static late final Box localCache; + static late final Box setting; static Future init() async { final dir = await getApplicationDocumentsDirectory(); @@ -27,6 +28,8 @@ class GStrorage { userInfo = await Hive.openBox('userInfo'); // 本地缓存 localCache = await Hive.openBox('localCache'); + // 设置 + setting = await Hive.openBox('setting'); } static regAdapter() { @@ -61,6 +64,7 @@ class UserBoxKey { class SettingBoxKey { static const String themeMode = 'themeMode'; + static const String feedBackEnable = 'feedBackEnable'; } class LocalCacheKey {