Merge pull request #6 from guozhigq/alpha

Alpha
This commit is contained in:
Infinite
2023-07-26 15:50:00 +08:00
committed by GitHub
27 changed files with 331 additions and 196 deletions

View File

@ -0,0 +1,24 @@
import 'package:flutter/material.dart';
class CustomToast extends StatelessWidget {
final String msg;
const CustomToast({Key? key, required this.msg}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
margin:
EdgeInsets.only(bottom: MediaQuery.of(context).padding.bottom + 20),
padding: const EdgeInsets.symmetric(horizontal: 17, vertical: 10),
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.primaryContainer.withOpacity(0.8),
borderRadius: BorderRadius.circular(20),
),
child: Text(msg,
style: Theme.of(context)
.textTheme
.labelMedium!
.copyWith(color: Theme.of(context).colorScheme.primary)),
);
}
}

View File

@ -24,7 +24,7 @@ class StatDanMu extends StatelessWidget {
size: 14, size: 14,
color: color, color: color,
), ),
const SizedBox(width: 3), const SizedBox(width: 2),
Text( Text(
Utils.numFormat(danmu!), Utils.numFormat(danmu!),
style: TextStyle( style: TextStyle(

View File

@ -24,7 +24,7 @@ class StatView extends StatelessWidget {
size: 13, size: 13,
color: color, color: color,
), ),
const SizedBox(width: 3), const SizedBox(width: 2),
Text( Text(
Utils.numFormat(view!), Utils.numFormat(view!),
style: TextStyle( style: TextStyle(

View File

@ -4,6 +4,7 @@ import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:dynamic_color/dynamic_color.dart'; import 'package:dynamic_color/dynamic_color.dart';
import 'package:pilipala/common/widgets/custom_toast.dart';
import 'package:pilipala/http/init.dart'; import 'package:pilipala/http/init.dart';
import 'package:pilipala/pages/search/index.dart'; import 'package:pilipala/pages/search/index.dart';
import 'package:pilipala/pages/video/detail/index.dart'; import 'package:pilipala/pages/video/detail/index.dart';
@ -61,7 +62,9 @@ class MyApp extends StatelessWidget {
fallbackLocale: const Locale("zh", "CN"), fallbackLocale: const Locale("zh", "CN"),
getPages: Routes.getPages, getPages: Routes.getPages,
home: const MainApp(), home: const MainApp(),
builder: FlutterSmartDialog.init(), builder: FlutterSmartDialog.init(
toastBuilder: (String msg) => CustomToast(msg: msg),
),
navigatorObservers: [ navigatorObservers: [
VideoDetailPage.routeObserver, VideoDetailPage.routeObserver,
SearchPage.routeObserver SearchPage.routeObserver

View File

@ -9,6 +9,7 @@ import 'package:pilipala/models/common/dynamics_type.dart';
import 'package:pilipala/models/dynamics/result.dart'; import 'package:pilipala/models/dynamics/result.dart';
import 'package:pilipala/models/dynamics/up.dart'; import 'package:pilipala/models/dynamics/up.dart';
import 'package:pilipala/models/live/item.dart'; import 'package:pilipala/models/live/item.dart';
import 'package:pilipala/utils/feed_back.dart';
class DynamicsController extends GetxController { class DynamicsController extends GetxController {
int page = 1; int page = 1;
@ -78,6 +79,7 @@ class DynamicsController extends GetxController {
} }
pushDetail(item, floor, {action = 'all'}) async { pushDetail(item, floor, {action = 'all'}) async {
feedBack();
if (action == 'comment') { if (action == 'comment') {
Get.toNamed('/dynamicDetail', Get.toNamed('/dynamicDetail',
arguments: {'item': item, 'floor': floor, 'action': action}); arguments: {'item': item, 'floor': floor, 'action': action});

View File

@ -8,6 +8,7 @@ import 'package:pilipala/common/widgets/http_error.dart';
import 'package:pilipala/common/widgets/network_img_layer.dart'; import 'package:pilipala/common/widgets/network_img_layer.dart';
import 'package:pilipala/models/dynamics/result.dart'; import 'package:pilipala/models/dynamics/result.dart';
import 'package:pilipala/pages/mine/index.dart'; import 'package:pilipala/pages/mine/index.dart';
import 'package:pilipala/utils/feed_back.dart';
import 'package:pilipala/utils/storage.dart'; import 'package:pilipala/utils/storage.dart';
import 'controller.dart'; import 'controller.dart';
@ -143,6 +144,7 @@ class _DynamicsPageState extends State<DynamicsPage>
duration: const Duration(milliseconds: 300), duration: const Duration(milliseconds: 300),
curve: Curves.easeInOut, curve: Curves.easeInOut,
onValueChanged: (v) { onValueChanged: (v) {
feedBack();
_dynamicsController.onSelectType(v); _dynamicsController.onSelectType(v);
}, },
), ),
@ -155,7 +157,8 @@ class _DynamicsPageState extends State<DynamicsPage>
bottom: 0, bottom: 0,
child: IconButton( child: IconButton(
padding: EdgeInsets.zero, padding: EdgeInsets.zero,
onPressed: () => _dynamicsController.resetSearch(), onPressed: () =>
{feedBack(), _dynamicsController.resetSearch()},
icon: const Icon(Icons.history, size: 21), icon: const Icon(Icons.history, size: 21),
), ),
), ),
@ -167,7 +170,9 @@ class _DynamicsPageState extends State<DynamicsPage>
alignment: Alignment.center, alignment: Alignment.center,
child: user.get(UserBoxKey.userLogin) ?? false child: user.get(UserBoxKey.userLogin) ?? false
? GestureDetector( ? GestureDetector(
onTap: () => showModalBottomSheet( onTap: () {
feedBack();
showModalBottomSheet(
context: context, context: context,
builder: (_) => const SizedBox( builder: (_) => const SizedBox(
height: 450, height: 450,
@ -175,7 +180,8 @@ class _DynamicsPageState extends State<DynamicsPage>
), ),
clipBehavior: Clip.hardEdge, clipBehavior: Clip.hardEdge,
isScrollControlled: true, isScrollControlled: true,
), );
},
child: NetworkImgLayer( child: NetworkImgLayer(
type: 'avatar', type: 'avatar',
width: 30, width: 30,
@ -184,7 +190,9 @@ class _DynamicsPageState extends State<DynamicsPage>
), ),
) )
: IconButton( : IconButton(
onPressed: () => showModalBottomSheet( onPressed: () {
feedBack();
showModalBottomSheet(
context: context, context: context,
builder: (_) => const SizedBox( builder: (_) => const SizedBox(
height: 450, height: 450,
@ -192,7 +200,8 @@ class _DynamicsPageState extends State<DynamicsPage>
), ),
clipBehavior: Clip.hardEdge, clipBehavior: Clip.hardEdge,
isScrollControlled: true, isScrollControlled: true,
), );
},
icon: const Icon(CupertinoIcons.person, size: 22), icon: const Icon(CupertinoIcons.person, size: 22),
), ),
), ),

View File

@ -6,6 +6,7 @@ import 'package:get/get.dart';
import 'package:pilipala/http/dynamics.dart'; import 'package:pilipala/http/dynamics.dart';
import 'package:pilipala/models/dynamics/result.dart'; import 'package:pilipala/models/dynamics/result.dart';
import 'package:pilipala/pages/dynamics/index.dart'; import 'package:pilipala/pages/dynamics/index.dart';
import 'package:pilipala/utils/feed_back.dart';
class ActionPanel extends StatefulWidget { class ActionPanel extends StatefulWidget {
const ActionPanel({ const ActionPanel({
@ -31,6 +32,7 @@ class _ActionPanelState extends State<ActionPanel> {
// 动态点赞 // 动态点赞
onLikeDynamic() async { onLikeDynamic() async {
feedBack();
var item = widget.item!; var item = widget.item!;
String dynamicId = item.idStr!; String dynamicId = item.idStr!;
// 1 已点赞 2 不喜欢 0 未操作 // 1 已点赞 2 不喜欢 0 未操作

View File

@ -1,6 +1,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:pilipala/common/widgets/network_img_layer.dart'; import 'package:pilipala/common/widgets/network_img_layer.dart';
import 'package:pilipala/utils/feed_back.dart';
import 'package:pilipala/utils/utils.dart'; import 'package:pilipala/utils/utils.dart';
Widget author(item, context) { Widget author(item, context) {
@ -10,12 +11,16 @@ Widget author(item, context) {
child: Row( child: Row(
children: [ children: [
GestureDetector( GestureDetector(
onTap: () => Get.toNamed( onTap: () {
feedBack();
Get.toNamed(
'/member?mid=${item.modules.moduleAuthor.mid}', '/member?mid=${item.modules.moduleAuthor.mid}',
arguments: { arguments: {
'face': item.modules.moduleAuthor.face, 'face': item.modules.moduleAuthor.face,
'heroTag': heroTag 'heroTag': heroTag
}), },
);
},
child: Hero( child: Hero(
tag: heroTag, tag: heroTag,
child: NetworkImgLayer( child: NetworkImgLayer(

View File

@ -5,6 +5,7 @@ import 'package:pilipala/common/widgets/network_img_layer.dart';
import 'package:pilipala/models/dynamics/up.dart'; import 'package:pilipala/models/dynamics/up.dart';
import 'package:pilipala/models/live/item.dart'; import 'package:pilipala/models/live/item.dart';
import 'package:pilipala/pages/dynamics/controller.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/storage.dart';
import 'package:pilipala/utils/utils.dart'; import 'package:pilipala/utils/utils.dart';
@ -81,7 +82,7 @@ class _UpPanelState extends State<UpPanel> {
), ),
Material( Material(
child: InkWell( child: InkWell(
onTap: () => Get.toNamed('/follow'), onTap: () => {feedBack(), Get.toNamed('/follow')},
child: Container( child: Container(
height: 100, height: 100,
padding: const EdgeInsets.only(left: 10, right: 10), padding: const EdgeInsets.only(left: 10, right: 10),
@ -111,6 +112,7 @@ class _UpPanelState extends State<UpPanel> {
bool isCurrent = currentMid == data.mid || currentMid == -1; bool isCurrent = currentMid == data.mid || currentMid == -1;
return InkWell( return InkWell(
onTap: () { onTap: () {
feedBack();
if (data.type == 'up') { if (data.type == 'up') {
currentMid = data.mid; currentMid = data.mid;
Get.find<DynamicsController>().mid.value = data.mid; Get.find<DynamicsController>().mid.value = data.mid;
@ -149,6 +151,7 @@ class _UpPanelState extends State<UpPanel> {
} }
}, },
onLongPress: () { onLongPress: () {
feedBack();
String heroTag = Utils.makeHeroTag(data.mid); String heroTag = Utils.makeHeroTag(data.mid);
Get.toNamed('/member?mid=${data.mid}', Get.toNamed('/member?mid=${data.mid}',
arguments: {'face': data.face, 'heroTag': heroTag}); arguments: {'face': data.face, 'heroTag': heroTag});

View File

@ -1,13 +1,17 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:pilipala/common/widgets/network_img_layer.dart'; import 'package:pilipala/common/widgets/network_img_layer.dart';
import 'package:pilipala/utils/feed_back.dart';
import 'package:pilipala/utils/utils.dart'; import 'package:pilipala/utils/utils.dart';
Widget followItem({item}) { Widget followItem({item}) {
String heroTag = Utils.makeHeroTag(item!.mid); String heroTag = Utils.makeHeroTag(item!.mid);
return ListTile( return ListTile(
onTap: () => Get.toNamed('/member?mid=${item.mid}', onTap: () {
arguments: {'face': item.face, 'heroTag': heroTag}), feedBack();
Get.toNamed('/member?mid=${item.mid}',
arguments: {'face': item.face, 'heroTag': heroTag});
},
leading: Hero( leading: Hero(
tag: heroTag, tag: heroTag,
child: NetworkImgLayer( child: NetworkImgLayer(
@ -19,6 +23,8 @@ Widget followItem({item}) {
), ),
title: Text( title: Text(
item.uname, item.uname,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: const TextStyle(fontSize: 14), style: const TextStyle(fontSize: 14),
), ),
subtitle: Text( subtitle: Text(

View File

@ -4,6 +4,7 @@ import 'package:get/get.dart';
import 'package:pilipala/pages/hot/index.dart'; import 'package:pilipala/pages/hot/index.dart';
import 'package:pilipala/pages/live/index.dart'; import 'package:pilipala/pages/live/index.dart';
import 'package:pilipala/pages/rcmd/index.dart'; import 'package:pilipala/pages/rcmd/index.dart';
import 'package:pilipala/utils/feed_back.dart';
import './controller.dart'; import './controller.dart';
class HomePage extends StatefulWidget { class HomePage extends StatefulWidget {
@ -92,7 +93,8 @@ class _HomePageState extends State<HomePage>
dividerColor: Colors.transparent, dividerColor: Colors.transparent,
unselectedLabelColor: unselectedLabelColor:
Theme.of(context).colorScheme.outline, Theme.of(context).colorScheme.outline,
onTap: (value) => {_homeController.initialIndex = value}, onTap: (value) =>
{feedBack(), _homeController.initialIndex = value},
), ),
), ),
), ),
@ -103,6 +105,7 @@ class _HomePageState extends State<HomePage>
tag: 'searchTag', tag: 'searchTag',
child: IconButton( child: IconButton(
onPressed: () { onPressed: () {
feedBack();
Get.toNamed('/search'); Get.toNamed('/search');
}, },
icon: const Icon(CupertinoIcons.search, size: 21), icon: const Icon(CupertinoIcons.search, size: 21),

View File

@ -3,6 +3,7 @@ import 'package:get/get.dart';
import 'package:hive/hive.dart'; import 'package:hive/hive.dart';
import 'package:pilipala/pages/dynamics/index.dart'; import 'package:pilipala/pages/dynamics/index.dart';
import 'package:pilipala/pages/home/index.dart'; import 'package:pilipala/pages/home/index.dart';
import 'package:pilipala/utils/feed_back.dart';
import 'package:pilipala/utils/storage.dart'; import 'package:pilipala/utils/storage.dart';
import './controller.dart'; import './controller.dart';
@ -44,6 +45,7 @@ class _MainAppState extends State<MainApp> with SingleTickerProviderStateMixin {
} }
void setIndex(int value) async { void setIndex(int value) async {
feedBack();
if (selectedIndex != value) { if (selectedIndex != value) {
selectedIndex = value; selectedIndex = value;
_animationController!.reverse().then((_) { _animationController!.reverse().then((_) {

View File

@ -108,16 +108,19 @@ class _MemberPageState extends State<MemberPage>
const SizedBox(height: 14), const SizedBox(height: 14),
Row( Row(
children: [ children: [
Text( Expanded(
child: Text(
_memberController _memberController
.memberInfo.value.name!, .memberInfo.value.name!,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: Theme.of(context) style: Theme.of(context)
.textTheme .textTheme
.bodyLarge! .bodyLarge!
.copyWith( .copyWith(
fontWeight: fontWeight:
FontWeight.bold), FontWeight.bold),
), )),
const SizedBox(width: 2), const SizedBox(width: 2),
if (_memberController if (_memberController
.memberInfo.value.sex == .memberInfo.value.sex ==

View File

@ -2,17 +2,22 @@ import 'package:get/get.dart';
import 'package:hive/hive.dart'; import 'package:hive/hive.dart';
import 'package:pilipala/http/init.dart'; import 'package:pilipala/http/init.dart';
import 'package:pilipala/pages/mine/controller.dart'; import 'package:pilipala/pages/mine/controller.dart';
import 'package:pilipala/utils/feed_back.dart';
import 'package:pilipala/utils/storage.dart'; import 'package:pilipala/utils/storage.dart';
class SettingController extends GetxController { class SettingController extends GetxController {
Box user = GStrorage.user; Box user = GStrorage.user;
RxBool userLogin = false.obs; RxBool userLogin = false.obs;
Box userInfoCache = GStrorage.userInfo; Box userInfoCache = GStrorage.userInfo;
Box setting = GStrorage.setting;
RxBool feedBackEnable = false.obs;
@override @override
void onInit() { void onInit() {
super.onInit(); super.onInit();
userLogin.value = user.get(UserBoxKey.userLogin) ?? false; userLogin.value = user.get(UserBoxKey.userLogin) ?? false;
feedBackEnable.value =
setting.get(SettingBoxKey.feedBackEnable, defaultValue: false);
} }
loginOut() async { loginOut() async {
@ -21,4 +26,11 @@ class SettingController extends GetxController {
userLogin.value = user.get(UserBoxKey.userLogin) ?? false; userLogin.value = user.get(UserBoxKey.userLogin) ?? false;
userInfoCache.put('userInfoCache', null); userInfoCache.put('userInfoCache', null);
} }
// 开启关闭震动反馈
onOpenFeedBack() {
feedBack();
feedBackEnable.value = !feedBackEnable.value;
setting.put(SettingBoxKey.feedBackEnable, feedBackEnable.value);
}
} }

View File

@ -7,6 +7,10 @@ class SettingPage extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
TextStyle subTitleStyle = Theme.of(context)
.textTheme
.labelMedium!
.copyWith(color: Theme.of(context).colorScheme.outline);
final SettingController settingController = Get.put(SettingController()); final SettingController settingController = Get.put(SettingController());
return Scaffold( return Scaffold(
appBar: AppBar( appBar: AppBar(
@ -14,6 +18,28 @@ class SettingPage extends StatelessWidget {
), ),
body: Column( body: Column(
children: [ 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<Icon?>(
(Set<MaterialState> 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( Obx(
() => Visibility( () => Visibility(
visible: settingController.userLogin.value, visible: settingController.userLogin.value,

View File

@ -8,6 +8,7 @@ import 'package:pilipala/http/video.dart';
import 'package:pilipala/models/user/fav_folder.dart'; import 'package:pilipala/models/user/fav_folder.dart';
import 'package:pilipala/models/video_detail_res.dart'; import 'package:pilipala/models/video_detail_res.dart';
import 'package:pilipala/pages/video/detail/controller.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/id_utils.dart';
import 'package:pilipala/utils/storage.dart'; import 'package:pilipala/utils/storage.dart';
import 'package:share_plus/share_plus.dart'; import 'package:share_plus/share_plus.dart';
@ -303,6 +304,7 @@ class VideoIntroController extends GetxController {
// 选择文件夹 // 选择文件夹
onChoose(bool checkValue, int index) { onChoose(bool checkValue, int index) {
feedBack();
List<FavFolderItemData> datalist = favFolderData.value.list!; List<FavFolderItemData> datalist = favFolderData.value.list!;
for (var i = 0; i < datalist.length; i++) { for (var i = 0; i < datalist.length; i++) {
if (i == index) { if (i == index) {
@ -327,6 +329,7 @@ class VideoIntroController extends GetxController {
// 关注/取关up // 关注/取关up
Future actionRelationMod() async { Future actionRelationMod() async {
feedBack();
if (user.get(UserBoxKey.userMid) == null) { if (user.get(UserBoxKey.userMid) == null) {
SmartDialog.showToast('账号未登录'); SmartDialog.showToast('账号未登录');
return; return;

View File

@ -12,6 +12,7 @@ import 'package:pilipala/common/widgets/stat/danmu.dart';
import 'package:pilipala/common/widgets/stat/view.dart'; import 'package:pilipala/common/widgets/stat/view.dart';
import 'package:pilipala/models/video_detail_res.dart'; import 'package:pilipala/models/video_detail_res.dart';
import 'package:pilipala/pages/video/detail/introduction/controller.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/storage.dart';
import 'package:pilipala/utils/utils.dart'; import 'package:pilipala/utils/utils.dart';
@ -107,6 +108,7 @@ class _VideoInfoState extends State<VideoInfo> with TickerProviderStateMixin {
sheetHeight = localCache.get('sheetHeight'); sheetHeight = localCache.get('sheetHeight');
} }
// 收藏
showFavBottomSheet() { showFavBottomSheet() {
if (videoIntroController.user.get(UserBoxKey.userMid) == null) { if (videoIntroController.user.get(UserBoxKey.userMid) == null) {
SmartDialog.showToast('账号未登录'); SmartDialog.showToast('账号未登录');
@ -122,8 +124,21 @@ class _VideoInfoState extends State<VideoInfo> with TickerProviderStateMixin {
); );
} }
// 视频介绍
showIntroDetail() {
feedBack();
showBottomSheet(
context: context,
enableDrag: true,
builder: (BuildContext context) {
return IntroDetail(videoDetail: widget.videoDetail!);
},
);
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
ThemeData t = Theme.of(context);
return SliverPadding( return SliverPadding(
padding: const EdgeInsets.only( padding: const EdgeInsets.only(
left: StyleString.safeSpace, right: StyleString.safeSpace, top: 13), left: StyleString.safeSpace, right: StyleString.safeSpace, top: 13),
@ -133,15 +148,7 @@ class _VideoInfoState extends State<VideoInfo> with TickerProviderStateMixin {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
GestureDetector( GestureDetector(
onTap: () { onTap: () => showIntroDetail(),
showBottomSheet(
context: context,
enableDrag: true,
builder: (BuildContext context) {
return IntroDetail(videoDetail: widget.videoDetail!);
},
);
},
child: Row( child: Row(
children: [ children: [
Expanded( Expanded(
@ -168,9 +175,7 @@ class _VideoInfoState extends State<VideoInfo> with TickerProviderStateMixin {
MaterialStateProperty.all(EdgeInsets.zero), MaterialStateProperty.all(EdgeInsets.zero),
backgroundColor: backgroundColor:
MaterialStateProperty.resolveWith((states) { MaterialStateProperty.resolveWith((states) {
return Theme.of(context) return t.highlightColor.withOpacity(0.2);
.highlightColor
.withOpacity(0.2);
}), }),
), ),
onPressed: () { onPressed: () {
@ -189,12 +194,12 @@ class _VideoInfoState extends State<VideoInfo> with TickerProviderStateMixin {
], ],
), ),
), ),
const SizedBox(height: 6), GestureDetector(
Row( onTap: () => showIntroDetail(),
child: Row(
children: [ children: [
const SizedBox(width: 2),
StatView( StatView(
theme: 'black', theme: 'gray',
view: !widget.loadingStatus view: !widget.loadingStatus
? widget.videoDetail!.stat!.view ? widget.videoDetail!.stat!.view
: videoItem['stat'].view, : videoItem['stat'].view,
@ -202,7 +207,7 @@ class _VideoInfoState extends State<VideoInfo> with TickerProviderStateMixin {
), ),
const SizedBox(width: 10), const SizedBox(width: 10),
StatDanMu( StatDanMu(
theme: 'black', theme: 'gray',
danmu: !widget.loadingStatus danmu: !widget.loadingStatus
? widget.videoDetail!.stat!.danmaku ? widget.videoDetail!.stat!.danmaku
: videoItem['stat'].danmaku, : videoItem['stat'].danmaku,
@ -215,14 +220,18 @@ class _VideoInfoState extends State<VideoInfo> with TickerProviderStateMixin {
? widget.videoDetail!.pubdate ? widget.videoDetail!.pubdate
: videoItem['pubdate'], : videoItem['pubdate'],
formatType: 'detail'), formatType: 'detail'),
style: const TextStyle(fontSize: 12), style: TextStyle(
fontSize: 12,
color: t.colorScheme.outline,
),
), ),
], ],
), ),
),
const SizedBox(height: 6),
// 点赞收藏转发 // 点赞收藏转发
Padding( SingleChildScrollView(
padding: const EdgeInsets.only(top: 15), padding: const EdgeInsets.only(top: 7, bottom: 7),
child: SingleChildScrollView(
scrollDirection: Axis.horizontal, scrollDirection: Axis.horizontal,
child: actionRow( child: actionRow(
context, context,
@ -230,20 +239,15 @@ class _VideoInfoState extends State<VideoInfo> with TickerProviderStateMixin {
videoDetailCtr, videoDetailCtr,
), ),
), ),
),
// 合集 // 合集
if (!widget.loadingStatus && if (!widget.loadingStatus &&
widget.videoDetail!.ugcSeason != null) ...[ widget.videoDetail!.ugcSeason != null) ...[
seasonPanel(widget.videoDetail!.ugcSeason!, seasonPanel(widget.videoDetail!.ugcSeason!,
widget.videoDetail!.pages!.first.cid, sheetHeight) widget.videoDetail!.pages!.first.cid, sheetHeight)
], ],
// Divider(
// height: 26,
// color: Theme.of(context).dividerColor.withOpacity(0.1),
// ),
const SizedBox(height: 20),
GestureDetector( GestureDetector(
onTap: () { onTap: () {
feedBack();
int mid = !widget.loadingStatus int mid = !widget.loadingStatus
? widget.videoDetail!.owner!.mid ? widget.videoDetail!.owner!.mid
: videoItem['owner'].mid; : videoItem['owner'].mid;
@ -255,9 +259,11 @@ class _VideoInfoState extends State<VideoInfo> with TickerProviderStateMixin {
'heroTag': (mid + 99).toString() 'heroTag': (mid + 99).toString()
}); });
}, },
child: Padding(
padding: const EdgeInsets.only(
top: 12, bottom: 12, left: 4, right: 4),
child: Row( child: Row(
children: [ children: [
const SizedBox(width: 5),
NetworkImgLayer( NetworkImgLayer(
type: 'avatar', type: 'avatar',
src: !widget.loadingStatus src: !widget.loadingStatus
@ -278,15 +284,12 @@ class _VideoInfoState extends State<VideoInfo> with TickerProviderStateMixin {
const SizedBox(width: 10), const SizedBox(width: 10),
Text( Text(
widget.loadingStatus widget.loadingStatus
? '- 粉丝' ? '-'
: Utils.numFormat( : Utils.numFormat(videoIntroController
videoIntroController.userStat['follower']), .userStat['follower']),
style: TextStyle( style: TextStyle(
fontSize: Theme.of(context) fontSize: t.textTheme.labelSmall!.fontSize,
.textTheme color: t.colorScheme.outline),
.labelSmall!
.fontSize,
color: Theme.of(context).colorScheme.outline),
), ),
const Spacer(), const Spacer(),
AnimatedOpacity( AnimatedOpacity(
@ -295,7 +298,8 @@ class _VideoInfoState extends State<VideoInfo> with TickerProviderStateMixin {
child: SizedBox( child: SizedBox(
height: 32, height: 32,
child: Obx( child: Obx(
() => videoIntroController.followStatus.isNotEmpty () => videoIntroController
.followStatus.isNotEmpty
? TextButton( ? TextButton(
onPressed: () => videoIntroController onPressed: () => videoIntroController
.actionRelationMod(), .actionRelationMod(),
@ -303,24 +307,20 @@ class _VideoInfoState extends State<VideoInfo> with TickerProviderStateMixin {
padding: const EdgeInsets.only( padding: const EdgeInsets.only(
left: 8, right: 8), left: 8, right: 8),
foregroundColor: foregroundColor:
videoIntroController.followStatus[ videoIntroController
.followStatus[
'attribute'] != 'attribute'] !=
0 0
? Theme.of(context) ? t.colorScheme.outline
.colorScheme : t.colorScheme.onPrimary,
.outline
: Theme.of(context)
.colorScheme
.onPrimary,
backgroundColor: backgroundColor:
videoIntroController.followStatus[ videoIntroController
.followStatus[
'attribute'] != 'attribute'] !=
0 0
? Theme.of(context) ? t.colorScheme
.colorScheme
.onInverseSurface .onInverseSurface
: Theme.of(context) : t.colorScheme
.colorScheme
.primary, // 设置按钮背景色 .primary, // 设置按钮背景色
), ),
child: Text( child: Text(
@ -330,10 +330,8 @@ class _VideoInfoState extends State<VideoInfo> with TickerProviderStateMixin {
? '已关注' ? '已关注'
: '关注', : '关注',
style: TextStyle( style: TextStyle(
fontSize: Theme.of(context) fontSize: t.textTheme
.textTheme .labelMedium!.fontSize),
.labelMedium!
.fontSize),
), ),
) )
: ElevatedButton( : ElevatedButton(
@ -344,15 +342,9 @@ class _VideoInfoState extends State<VideoInfo> with TickerProviderStateMixin {
), ),
), ),
), ),
const SizedBox(width: 4)
], ],
), ),
), )),
const SizedBox(height: 12),
// Divider(
// height: 12,
// color: Theme.of(context).dividerColor.withOpacity(0.1),
// ),
], ],
) )
: const SizedBox( : const SizedBox(

View File

@ -1,4 +1,5 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:pilipala/utils/feed_back.dart';
class ActionRowItem extends StatelessWidget { class ActionRowItem extends StatelessWidget {
final Icon? icon; final Icon? icon;
@ -27,7 +28,10 @@ class ActionRowItem extends StatelessWidget {
borderRadius: const BorderRadius.all(Radius.circular(30)), borderRadius: const BorderRadius.all(Radius.circular(30)),
clipBehavior: Clip.hardEdge, clipBehavior: Clip.hardEdge,
child: InkWell( child: InkWell(
onTap: () => onTap!(), onTap: () => {
feedBack(),
onTap!(),
},
child: Padding( child: Padding(
padding: const EdgeInsets.fromLTRB(13, 6.5, 15, 6.3), padding: const EdgeInsets.fromLTRB(13, 6.5, 15, 6.3),
child: Row( child: Row(

View File

@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:hive/hive.dart'; import 'package:hive/hive.dart';
import 'package:pilipala/common/widgets/http_error.dart'; import 'package:pilipala/common/widgets/http_error.dart';
import 'package:pilipala/utils/feed_back.dart';
import 'package:pilipala/utils/storage.dart'; import 'package:pilipala/utils/storage.dart';
class FavPanel extends StatefulWidget { class FavPanel extends StatefulWidget {
@ -43,6 +44,7 @@ class _FavPanelState extends State<FavPanel> {
actions: [ actions: [
TextButton( TextButton(
onPressed: () async { onPressed: () async {
feedBack();
await widget.ctr!.actionFavVideo(); await widget.ctr!.actionFavVideo();
}, },
child: const Text('完成'), child: const Text('完成'),

View File

@ -1,4 +1,5 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:pilipala/utils/feed_back.dart';
class MenuRow extends StatelessWidget { class MenuRow extends StatelessWidget {
final bool? loadingStatus; final bool? loadingStatus;
@ -62,7 +63,10 @@ class MenuRow extends StatelessWidget {
borderRadius: const BorderRadius.all(Radius.circular(30)), borderRadius: const BorderRadius.all(Radius.circular(30)),
clipBehavior: Clip.hardEdge, clipBehavior: Clip.hardEdge,
child: InkWell( child: InkWell(
onTap: () => onTap!(), onTap: () => {
feedBack(),
onTap!(),
},
child: Container( child: Container(
padding: const EdgeInsets.fromLTRB(13, 5.5, 13, 5.5), padding: const EdgeInsets.fromLTRB(13, 5.5, 13, 5.5),
decoration: BoxDecoration( decoration: BoxDecoration(

View File

@ -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_sort_type.dart';
import 'package:pilipala/models/common/reply_type.dart'; import 'package:pilipala/models/common/reply_type.dart';
import 'package:pilipala/models/video/reply/item.dart'; import 'package:pilipala/models/video/reply/item.dart';
import 'package:pilipala/utils/feed_back.dart';
class VideoReplyController extends GetxController { class VideoReplyController extends GetxController {
VideoReplyController( VideoReplyController(
@ -83,6 +84,7 @@ class VideoReplyController extends GetxController {
// 排序搜索评论 // 排序搜索评论
queryBySort() { queryBySort() {
feedBack();
switch (sortType) { switch (sortType) {
case ReplySortType.time: case ReplySortType.time:
sortType = ReplySortType.like; sortType = ReplySortType.like;

View File

@ -8,6 +8,7 @@ import 'package:pilipala/common/widgets/http_error.dart';
import 'package:pilipala/models/common/reply_type.dart'; import 'package:pilipala/models/common/reply_type.dart';
import 'package:pilipala/pages/video/detail/index.dart'; import 'package:pilipala/pages/video/detail/index.dart';
import 'package:pilipala/pages/video/detail/replyNew/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 'package:pilipala/utils/id_utils.dart';
import 'controller.dart'; import 'controller.dart';
import 'widgets/reply_item.dart'; import 'widgets/reply_item.dart';
@ -262,6 +263,7 @@ class _VideoReplyPanelState extends State<VideoReplyPanel>
child: FloatingActionButton( child: FloatingActionButton(
heroTag: null, heroTag: null,
onPressed: () { onPressed: () {
feedBack();
showModalBottomSheet( showModalBottomSheet(
context: context, context: context,
isScrollControlled: true, isScrollControlled: true,

View File

@ -7,6 +7,7 @@ import 'package:pilipala/models/common/reply_type.dart';
import 'package:pilipala/models/video/reply/item.dart'; import 'package:pilipala/models/video/reply/item.dart';
import 'package:pilipala/pages/video/detail/controller.dart'; import 'package:pilipala/pages/video/detail/controller.dart';
import 'package:pilipala/pages/video/detail/replyNew/index.dart'; import 'package:pilipala/pages/video/detail/replyNew/index.dart';
import 'package:pilipala/utils/feed_back.dart';
import 'package:pilipala/utils/utils.dart'; import 'package:pilipala/utils/utils.dart';
import 'zan.dart'; import 'zan.dart';
@ -86,6 +87,7 @@ class ReplyItem extends StatelessWidget {
// 头像、昵称 // 头像、昵称
GestureDetector( GestureDetector(
onTap: () { onTap: () {
feedBack();
Get.toNamed('/member?mid=${replyItem!.mid}', arguments: { Get.toNamed('/member?mid=${replyItem!.mid}', arguments: {
'face': replyItem!.member!.avatar!, 'face': replyItem!.member!.avatar!,
'heroTag': heroTag 'heroTag': heroTag
@ -259,6 +261,7 @@ class ReplyItem extends StatelessWidget {
.labelMedium! .labelMedium!
.copyWith(color: Theme.of(context).colorScheme.outline)), .copyWith(color: Theme.of(context).colorScheme.outline)),
onPressed: () { onPressed: () {
feedBack();
showModalBottomSheet( showModalBottomSheet(
context: context, context: context,
isScrollControlled: true, isScrollControlled: true,
@ -348,6 +351,7 @@ class ReplyItemRow extends StatelessWidget {
), ),
recognizer: TapGestureRecognizer() recognizer: TapGestureRecognizer()
..onTap = () { ..onTap = () {
feedBack();
String heroTag = String heroTag =
Utils.makeHeroTag(replies![i].member.mid); Utils.makeHeroTag(replies![i].member.mid);
Get.toNamed( Get.toNamed(

View File

@ -4,6 +4,7 @@ import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:pilipala/http/reply.dart'; import 'package:pilipala/http/reply.dart';
import 'package:pilipala/models/common/reply_type.dart'; import 'package:pilipala/models/common/reply_type.dart';
import 'package:pilipala/models/video/reply/item.dart'; import 'package:pilipala/models/video/reply/item.dart';
import 'package:pilipala/utils/feed_back.dart';
class ZanButton extends StatefulWidget { class ZanButton extends StatefulWidget {
const ZanButton({ const ZanButton({
@ -22,6 +23,8 @@ class ZanButton extends StatefulWidget {
class _ZanButtonState extends State<ZanButton> { class _ZanButtonState extends State<ZanButton> {
// 评论点赞 // 评论点赞
onLikeReply() async { onLikeReply() async {
feedBack();
SmartDialog.showLoading(msg: 'pilipala ...');
ReplyItemModel replyItem = widget.replyItem!; ReplyItemModel replyItem = widget.replyItem!;
int oid = replyItem.oid!; int oid = replyItem.oid!;
int rpid = replyItem.rpid!; int rpid = replyItem.rpid!;
@ -29,8 +32,9 @@ class _ZanButtonState extends State<ZanButton> {
int action = replyItem.action == 0 ? 1 : 0; int action = replyItem.action == 0 ? 1 : 0;
var res = await ReplyHttp.likeReply( var res = await ReplyHttp.likeReply(
type: widget.replyType!.index, oid: oid, rpid: rpid, action: action); type: widget.replyType!.index, oid: oid, rpid: rpid, action: action);
SmartDialog.dismiss();
if (res['status']) { if (res['status']) {
SmartDialog.showToast(replyItem.action == 0 ? '点赞成功' : '取消赞'); SmartDialog.showToast(replyItem.action == 0 ? '点赞成功 👍' : '取消赞 💔');
if (action == 1) { if (action == 1) {
replyItem.like = replyItem.like! + 1; replyItem.like = replyItem.like! + 1;
replyItem.action = 1; replyItem.action = 1;

View File

@ -6,6 +6,7 @@ import 'package:hive/hive.dart';
import 'package:pilipala/http/video.dart'; import 'package:pilipala/http/video.dart';
import 'package:pilipala/models/common/reply_type.dart'; import 'package:pilipala/models/common/reply_type.dart';
import 'package:pilipala/models/video/reply/item.dart'; import 'package:pilipala/models/video/reply/item.dart';
import 'package:pilipala/utils/feed_back.dart';
import 'package:pilipala/utils/storage.dart'; import 'package:pilipala/utils/storage.dart';
class VideoReplyNewDialog extends StatefulWidget { class VideoReplyNewDialog extends StatefulWidget {
@ -68,6 +69,7 @@ class _VideoReplyNewDialogState extends State<VideoReplyNewDialog>
} }
Future submitReplyAdd() async { Future submitReplyAdd() async {
feedBack();
String message = _replyContentController.text; String message = _replyContentController.text;
var result = await VideoHttp.replyAdd( var result = await VideoHttp.replyAdd(
type: widget.replyType ?? ReplyType.video, type: widget.replyType ?? ReplyType.video,

12
lib/utils/feed_back.dart Normal file
View File

@ -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();
}
}

View File

@ -13,6 +13,7 @@ class GStrorage {
static late final Box hotKeyword; static late final Box hotKeyword;
static late final Box historyword; static late final Box historyword;
static late final Box localCache; static late final Box localCache;
static late final Box setting;
static Future<void> init() async { static Future<void> init() async {
final dir = await getApplicationDocumentsDirectory(); final dir = await getApplicationDocumentsDirectory();
@ -27,6 +28,8 @@ class GStrorage {
userInfo = await Hive.openBox('userInfo'); userInfo = await Hive.openBox('userInfo');
// 本地缓存 // 本地缓存
localCache = await Hive.openBox('localCache'); localCache = await Hive.openBox('localCache');
// 设置
setting = await Hive.openBox('setting');
} }
static regAdapter() { static regAdapter() {
@ -61,6 +64,7 @@ class UserBoxKey {
class SettingBoxKey { class SettingBoxKey {
static const String themeMode = 'themeMode'; static const String themeMode = 'themeMode';
static const String feedBackEnable = 'feedBackEnable';
} }
class LocalCacheKey { class LocalCacheKey {