Compare commits
10 Commits
feature-fo
...
feature-fa
Author | SHA1 | Date | |
---|---|---|---|
5bf7b69d79 | |||
d57f84a1d7 | |||
32b2f0ceff | |||
bae871cfa1 | |||
d95fe9fe14 | |||
eb006e4c55 | |||
cb88d0c9ae | |||
3efad736ae | |||
42ad959155 | |||
cdf800c49f |
@ -24,11 +24,13 @@ class _FavDetailPageState extends State<FavDetailPage> {
|
||||
Get.put(FavDetailController());
|
||||
late StreamController<bool> titleStreamC; // a
|
||||
Future? _futureBuilderFuture;
|
||||
late String mediaId;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_futureBuilderFuture = _favDetailController.queryUserFavFolderDetail();
|
||||
mediaId = Get.parameters['mediaId']!;
|
||||
titleStreamC = StreamController<bool>();
|
||||
_controller.addListener(
|
||||
() {
|
||||
@ -94,8 +96,8 @@ class _FavDetailPageState extends State<FavDetailPage> {
|
||||
),
|
||||
actions: [
|
||||
IconButton(
|
||||
onPressed: () => Get.toNamed(
|
||||
'/favSearch?searchType=0&mediaId=${Get.parameters['mediaId']!}'),
|
||||
onPressed: () =>
|
||||
Get.toNamed('/favSearch?searchType=0&mediaId=$mediaId'),
|
||||
icon: const Icon(Icons.search_outlined),
|
||||
),
|
||||
// IconButton(
|
||||
|
@ -15,9 +15,14 @@ import '../../../common/widgets/badge.dart';
|
||||
class FavVideoCardH extends StatelessWidget {
|
||||
final dynamic videoItem;
|
||||
final Function? callFn;
|
||||
final int? searchType;
|
||||
|
||||
const FavVideoCardH({Key? key, required this.videoItem, this.callFn})
|
||||
: super(key: key);
|
||||
const FavVideoCardH({
|
||||
Key? key,
|
||||
required this.videoItem,
|
||||
this.callFn,
|
||||
this.searchType,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@ -107,7 +112,11 @@ class FavVideoCardH extends StatelessWidget {
|
||||
},
|
||||
),
|
||||
),
|
||||
VideoContent(videoItem: videoItem, callFn: callFn)
|
||||
VideoContent(
|
||||
videoItem: videoItem,
|
||||
callFn: callFn,
|
||||
searchType: searchType,
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
@ -123,7 +132,13 @@ class FavVideoCardH extends StatelessWidget {
|
||||
class VideoContent extends StatelessWidget {
|
||||
final dynamic videoItem;
|
||||
final Function? callFn;
|
||||
const VideoContent({super.key, required this.videoItem, this.callFn});
|
||||
final int? searchType;
|
||||
const VideoContent({
|
||||
super.key,
|
||||
required this.videoItem,
|
||||
this.callFn,
|
||||
this.searchType,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@ -189,48 +204,51 @@ class VideoContent extends StatelessWidget {
|
||||
),
|
||||
],
|
||||
),
|
||||
Positioned(
|
||||
right: 0,
|
||||
bottom: -4,
|
||||
child: IconButton(
|
||||
style: ButtonStyle(
|
||||
padding: MaterialStateProperty.all(EdgeInsets.zero),
|
||||
),
|
||||
onPressed: () {
|
||||
showDialog(
|
||||
context: Get.context!,
|
||||
builder: (context) {
|
||||
return AlertDialog(
|
||||
title: const Text('提示'),
|
||||
content: const Text('要取消收藏吗?'),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Get.back(),
|
||||
child: Text(
|
||||
'取消',
|
||||
style: TextStyle(
|
||||
color:
|
||||
Theme.of(context).colorScheme.outline),
|
||||
)),
|
||||
TextButton(
|
||||
onPressed: () async {
|
||||
await callFn!();
|
||||
Get.back();
|
||||
},
|
||||
child: const Text('确定取消'),
|
||||
)
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
icon: Icon(
|
||||
Icons.clear_outlined,
|
||||
color: Theme.of(context).colorScheme.outline,
|
||||
size: 18,
|
||||
),
|
||||
),
|
||||
),
|
||||
searchType != 1
|
||||
? Positioned(
|
||||
right: 0,
|
||||
bottom: -4,
|
||||
child: IconButton(
|
||||
style: ButtonStyle(
|
||||
padding: MaterialStateProperty.all(EdgeInsets.zero),
|
||||
),
|
||||
onPressed: () {
|
||||
showDialog(
|
||||
context: Get.context!,
|
||||
builder: (context) {
|
||||
return AlertDialog(
|
||||
title: const Text('提示'),
|
||||
content: const Text('要取消收藏吗?'),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Get.back(),
|
||||
child: Text(
|
||||
'取消',
|
||||
style: TextStyle(
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.outline),
|
||||
)),
|
||||
TextButton(
|
||||
onPressed: () async {
|
||||
await callFn!();
|
||||
Get.back();
|
||||
},
|
||||
child: const Text('确定取消'),
|
||||
)
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
icon: Icon(
|
||||
Icons.clear_outlined,
|
||||
color: Theme.of(context).colorScheme.outline,
|
||||
size: 18,
|
||||
),
|
||||
),
|
||||
)
|
||||
: const SizedBox(),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
@ -1,8 +1,11 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:pilipala/http/user.dart';
|
||||
import 'package:pilipala/models/user/fav_detail.dart';
|
||||
|
||||
import '../../http/video.dart';
|
||||
|
||||
class FavSearchController extends GetxController {
|
||||
final ScrollController scrollController = ScrollController();
|
||||
Rx<TextEditingController> controller = TextEditingController().obs;
|
||||
@ -72,4 +75,21 @@ class FavSearchController extends GetxController {
|
||||
if (!hasMore) return;
|
||||
searchFav(type: 'onLoad');
|
||||
}
|
||||
|
||||
onCancelFav(int id) async {
|
||||
var result = await VideoHttp.favVideo(
|
||||
aid: id, addIds: '', delIds: mediaId.toString());
|
||||
if (result['status']) {
|
||||
if (result['data']['prompt']) {
|
||||
List dataList = favList;
|
||||
for (var i in dataList) {
|
||||
if (i.id == id) {
|
||||
dataList.remove(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
SmartDialog.showToast('取消收藏');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -8,9 +8,7 @@ import 'package:pilipala/pages/fav_detail/widget/fav_video_card.dart';
|
||||
import 'controller.dart';
|
||||
|
||||
class FavSearchPage extends StatefulWidget {
|
||||
final int? sourceType;
|
||||
final int? mediaId;
|
||||
const FavSearchPage({super.key, this.sourceType, this.mediaId});
|
||||
const FavSearchPage({super.key});
|
||||
|
||||
@override
|
||||
State<FavSearchPage> createState() => _FavSearchPageState();
|
||||
@ -19,11 +17,12 @@ class FavSearchPage extends StatefulWidget {
|
||||
class _FavSearchPageState extends State<FavSearchPage> {
|
||||
final FavSearchController _favSearchCtr = Get.put(FavSearchController());
|
||||
late ScrollController scrollController;
|
||||
late int searchType;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
||||
searchType = int.parse(Get.parameters['searchType']!);
|
||||
scrollController = _favSearchCtr.scrollController;
|
||||
scrollController.addListener(
|
||||
() {
|
||||
@ -100,7 +99,11 @@ class _FavSearchPageState extends State<FavSearchPage> {
|
||||
} else {
|
||||
return FavVideoCardH(
|
||||
videoItem: _favSearchCtr.favList[index],
|
||||
callFn: () => null,
|
||||
searchType: searchType,
|
||||
callFn: () => searchType != 1
|
||||
? _favSearchCtr
|
||||
.onCancelFav(_favSearchCtr.favList[index].id!)
|
||||
: {},
|
||||
);
|
||||
}
|
||||
},
|
||||
|
@ -3,7 +3,6 @@ import 'package:pilipala/http/constants.dart';
|
||||
import 'package:pilipala/http/live.dart';
|
||||
import 'package:pilipala/models/live/room_info.dart';
|
||||
import 'package:pilipala/plugin/pl_player/index.dart';
|
||||
|
||||
import '../../models/live/room_info_h5.dart';
|
||||
|
||||
class LiveRoomController extends GetxController {
|
||||
@ -16,13 +15,6 @@ class LiveRoomController extends GetxController {
|
||||
RxBool volumeOff = false.obs;
|
||||
PlPlayerController plPlayerController =
|
||||
PlPlayerController.getInstance(videoType: 'live');
|
||||
|
||||
// MeeduPlayerController meeduPlayerController = MeeduPlayerController(
|
||||
// colorTheme: Theme.of(Get.context!).colorScheme.primary,
|
||||
// pipEnabled: true,
|
||||
// controlsStyle: ControlsStyle.live,
|
||||
// enabledButtons: const EnabledButtons(pip: true),
|
||||
// );
|
||||
Rx<RoomInfoH5Model> roomInfoH5 = RoomInfoH5Model().obs;
|
||||
|
||||
@override
|
||||
@ -39,8 +31,6 @@ class LiveRoomController extends GetxController {
|
||||
cover = liveItem.cover;
|
||||
}
|
||||
}
|
||||
queryLiveInfo();
|
||||
queryLiveInfoH5();
|
||||
}
|
||||
|
||||
playerInit(source) async {
|
||||
|
@ -29,22 +29,18 @@ class _LiveRoomPageState extends State<LiveRoomPage> {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
plPlayerController = _liveRoomController.plPlayerController;
|
||||
plPlayerController!.onPlayerStatusChanged.listen(
|
||||
(PlayerStatus status) {
|
||||
if (status == PlayerStatus.playing) {
|
||||
isShowCover = false;
|
||||
setState(() {});
|
||||
}
|
||||
},
|
||||
);
|
||||
if (Platform.isAndroid) {
|
||||
floating = Floating();
|
||||
}
|
||||
_futureBuilder = _liveRoomController.queryLiveInfoH5();
|
||||
videoSourceInit();
|
||||
_futureBuilderFuture = _liveRoomController.queryLiveInfo();
|
||||
}
|
||||
|
||||
Future<void> videoSourceInit() async {
|
||||
_futureBuilder = _liveRoomController.queryLiveInfoH5();
|
||||
plPlayerController = _liveRoomController.plPlayerController;
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
plPlayerController!.dispose();
|
||||
|
@ -105,7 +105,7 @@ class _MemberPageState extends State<MemberPage>
|
||||
actions: [
|
||||
IconButton(
|
||||
onPressed: () => Get.toNamed(
|
||||
'/memberSearch?mid=${Get.parameters['mid']}&uname=${_memberController.memberInfo.value.name!}'),
|
||||
'/memberSearch?mid=$mid&uname=${_memberController.memberInfo.value.name!}'),
|
||||
icon: const Icon(Icons.search_outlined),
|
||||
),
|
||||
PopupMenuButton(
|
||||
|
@ -1,5 +1,6 @@
|
||||
import 'package:flutter/gestures.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
@ -46,6 +47,17 @@ class ReplyItem extends StatelessWidget {
|
||||
replyReply!(replyItem);
|
||||
}
|
||||
},
|
||||
onLongPress: () {
|
||||
feedBack();
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
useRootNavigator: true,
|
||||
isScrollControlled: true,
|
||||
builder: (context) {
|
||||
return MorePanel(item: replyItem);
|
||||
},
|
||||
);
|
||||
},
|
||||
child: Column(
|
||||
children: [
|
||||
Padding(
|
||||
@ -121,98 +133,6 @@ class ReplyItem extends StatelessWidget {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
// 头像、昵称
|
||||
// SizedBox(
|
||||
// width: double.infinity,
|
||||
// child: Stack(
|
||||
// children: [
|
||||
// GestureDetector(
|
||||
// behavior: HitTestBehavior.opaque,
|
||||
// onTap: () {
|
||||
// feedBack();
|
||||
// Get.toNamed('/member?mid=${replyItem!.mid}', arguments: {
|
||||
// 'face': replyItem!.member!.avatar!,
|
||||
// 'heroTag': heroTag
|
||||
// });
|
||||
// },
|
||||
// child: Row(
|
||||
// crossAxisAlignment: CrossAxisAlignment.center,
|
||||
// mainAxisSize: MainAxisSize.min,
|
||||
// children: <Widget>[
|
||||
// lfAvtar(context, heroTag),
|
||||
// const SizedBox(width: 12),
|
||||
// Text(
|
||||
// replyItem!.member!.uname!,
|
||||
// style: TextStyle(
|
||||
// color: replyItem!.member!.vip!['vipStatus'] > 0
|
||||
// ? const Color.fromARGB(255, 251, 100, 163)
|
||||
// : 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!)
|
||||
// const PBadge(
|
||||
// text: 'UP',
|
||||
// size: 'small',
|
||||
// stack: 'normal',
|
||||
// fs: 9,
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
// Positioned(
|
||||
// top: 0,
|
||||
// left: 0,
|
||||
// right: 0,
|
||||
// child: Container(
|
||||
// width: double.infinity,
|
||||
// height: 45,
|
||||
// decoration: BoxDecoration(
|
||||
// image: replyItem!.member!.userSailing!.cardbg != null
|
||||
// ? DecorationImage(
|
||||
// alignment: Alignment.centerRight,
|
||||
// fit: BoxFit.fitHeight,
|
||||
// image: NetworkImage(
|
||||
// replyItem!.member!.userSailing!.cardbg!['image'],
|
||||
// ),
|
||||
// )
|
||||
// : null,
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// if (replyItem!.member!.userSailing!.cardbg != null &&
|
||||
// replyItem!.member!.userSailing!.cardbg!['fan']['number'] > 0)
|
||||
// Positioned(
|
||||
// top: 10,
|
||||
// left: Get.size.width / 7 * 5.8,
|
||||
// child: DefaultTextStyle(
|
||||
// style: TextStyle(
|
||||
// fontFamily: 'fansCard',
|
||||
// fontSize: 9,
|
||||
// color: Theme.of(context).colorScheme.primary,
|
||||
// ),
|
||||
// child: Column(
|
||||
// crossAxisAlignment: CrossAxisAlignment.start,
|
||||
// mainAxisAlignment: MainAxisAlignment.center,
|
||||
// children: [
|
||||
// const Text('NO.'),
|
||||
// Text(
|
||||
// replyItem!.member!.userSailing!.cardbg!['fan']
|
||||
// ['num_desc'],
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
/// fix Stack内GestureDetector onTap无效
|
||||
GestureDetector(
|
||||
behavior: HitTestBehavior.opaque,
|
||||
@ -289,30 +209,26 @@ class ReplyItem extends StatelessWidget {
|
||||
// title
|
||||
Container(
|
||||
margin: const EdgeInsets.only(top: 10, left: 45, right: 6, bottom: 4),
|
||||
child: SelectableRegion(
|
||||
focusNode: FocusNode(),
|
||||
selectionControls: MaterialTextSelectionControls(),
|
||||
child: Text.rich(
|
||||
style: const TextStyle(height: 1.75),
|
||||
maxLines:
|
||||
replyItem!.content!.isText! && replyLevel == '1' ? 3 : 999,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
TextSpan(
|
||||
children: [
|
||||
if (replyItem!.isTop!)
|
||||
const WidgetSpan(
|
||||
alignment: PlaceholderAlignment.top,
|
||||
child: PBadge(
|
||||
text: 'TOP',
|
||||
size: 'small',
|
||||
stack: 'normal',
|
||||
type: 'line',
|
||||
fs: 9,
|
||||
),
|
||||
child: Text.rich(
|
||||
style: const TextStyle(height: 1.75),
|
||||
maxLines:
|
||||
replyItem!.content!.isText! && replyLevel == '1' ? 3 : 999,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
TextSpan(
|
||||
children: [
|
||||
if (replyItem!.isTop!)
|
||||
const WidgetSpan(
|
||||
alignment: PlaceholderAlignment.top,
|
||||
child: PBadge(
|
||||
text: 'TOP',
|
||||
size: 'small',
|
||||
stack: 'normal',
|
||||
type: 'line',
|
||||
fs: 9,
|
||||
),
|
||||
buildContent(context, replyItem!, replyReply, null),
|
||||
],
|
||||
),
|
||||
),
|
||||
buildContent(context, replyItem!, replyReply, null),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -445,6 +361,17 @@ class ReplyItemRow extends StatelessWidget {
|
||||
InkWell(
|
||||
// 一楼点击评论展开评论详情
|
||||
onTap: () => replyReply!(replyItem),
|
||||
onLongPress: () {
|
||||
feedBack();
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
useRootNavigator: true,
|
||||
isScrollControlled: true,
|
||||
builder: (context) {
|
||||
return MorePanel(item: replies![i]);
|
||||
},
|
||||
);
|
||||
},
|
||||
child: Container(
|
||||
width: double.infinity,
|
||||
padding: EdgeInsets.fromLTRB(
|
||||
@ -636,8 +563,8 @@ InlineSpan buildContent(
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
} else if (RegExp(r'^\b(?:\d+[::])?[0-5]?[0-9][::][0-5]?[0-9]\b$').hasMatch(matchStr)) {
|
||||
} else if (RegExp(r'^\b(?:\d+[::])?[0-5]?[0-9][::][0-5]?[0-9]\b$')
|
||||
.hasMatch(matchStr)) {
|
||||
matchStr = matchStr.replaceAll(':', ':');
|
||||
spanChilds.add(
|
||||
TextSpan(
|
||||
@ -955,3 +882,100 @@ InlineSpan buildContent(
|
||||
// spanChilds.add(TextSpan(text: matchMember));
|
||||
return TextSpan(children: spanChilds);
|
||||
}
|
||||
|
||||
class MorePanel extends StatelessWidget {
|
||||
final dynamic item;
|
||||
const MorePanel({super.key, required this.item});
|
||||
|
||||
Future<dynamic> menuActionHandler(String type) async {
|
||||
String message = item.content.message ?? item.content;
|
||||
switch (type) {
|
||||
case 'copyAll':
|
||||
await Clipboard.setData(ClipboardData(text: message));
|
||||
SmartDialog.showToast('已复制');
|
||||
Get.back();
|
||||
break;
|
||||
case 'copyFreedom':
|
||||
Get.back();
|
||||
showDialog(
|
||||
context: Get.context!,
|
||||
builder: (context) {
|
||||
return AlertDialog(
|
||||
title: const Text('自由复制'),
|
||||
content: SelectableText(message),
|
||||
);
|
||||
},
|
||||
);
|
||||
break;
|
||||
// case 'block':
|
||||
// SmartDialog.showToast('加入黑名单');
|
||||
// break;
|
||||
// case 'report':
|
||||
// SmartDialog.showToast('举报');
|
||||
// break;
|
||||
// case 'delete':
|
||||
// SmartDialog.showToast('删除');
|
||||
// break;
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
Color errorColor = Theme.of(context).colorScheme.error;
|
||||
return Container(
|
||||
padding: EdgeInsets.only(bottom: MediaQuery.of(context).padding.bottom),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
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.outline,
|
||||
borderRadius: const BorderRadius.all(Radius.circular(3))),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
ListTile(
|
||||
onTap: () async => await menuActionHandler('copyAll'),
|
||||
minLeadingWidth: 0,
|
||||
leading: const Icon(Icons.copy_all_outlined, size: 19),
|
||||
title: Text('复制全部', style: Theme.of(context).textTheme.titleSmall),
|
||||
),
|
||||
ListTile(
|
||||
onTap: () async => await menuActionHandler('copyFreedom'),
|
||||
minLeadingWidth: 0,
|
||||
leading: const Icon(Icons.copy_outlined, size: 19),
|
||||
title: Text('自由复制', style: Theme.of(context).textTheme.titleSmall),
|
||||
),
|
||||
// ListTile(
|
||||
// onTap: () async => await menuActionHandler('block'),
|
||||
// minLeadingWidth: 0,
|
||||
// leading: Icon(Icons.block_outlined, color: errorColor),
|
||||
// title: Text('加入黑名单', style: TextStyle(color: errorColor)),
|
||||
// ),
|
||||
// ListTile(
|
||||
// onTap: () async => await menuActionHandler('report'),
|
||||
// minLeadingWidth: 0,
|
||||
// leading: Icon(Icons.report_outlined, color: errorColor),
|
||||
// title: Text('举报', style: TextStyle(color: errorColor)),
|
||||
// ),
|
||||
// ListTile(
|
||||
// onTap: () async => await menuActionHandler('del'),
|
||||
// minLeadingWidth: 0,
|
||||
// leading: Icon(Icons.delete_outline, color: errorColor),
|
||||
// title: Text('删除', style: TextStyle(color: errorColor)),
|
||||
// ),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -438,7 +438,7 @@ class _HeaderControlState extends State<HeaderControl> {
|
||||
}),
|
||||
actions: <Widget>[
|
||||
TextButton(
|
||||
onPressed: () => SmartDialog.dismiss(),
|
||||
onPressed: () => Get.back(),
|
||||
child: Text(
|
||||
'取消',
|
||||
style: TextStyle(color: Theme.of(context).colorScheme.outline),
|
||||
|
Reference in New Issue
Block a user