Before Width: | Height: | Size: 702 B |
After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 702 B |
After Width: | Height: | Size: 708 B |
After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 948 B |
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 1.0 KiB |
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 118 B After Width: | Height: | Size: 666 B |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 4.2 KiB |
Before Width: | Height: | Size: 606 B After Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 2.1 KiB |
After Width: | Height: | Size: 1.8 KiB |
After Width: | Height: | Size: 848 B |
After Width: | Height: | Size: 876 B |
After Width: | Height: | Size: 2.0 KiB |
After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 4.8 KiB |
After Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 8.0 KiB After Width: | Height: | Size: 2.4 KiB |
After Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 8.0 KiB After Width: | Height: | Size: 2.1 KiB |
Before Width: | Height: | Size: 172 B After Width: | Height: | Size: 766 B |
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 3.5 KiB |
After Width: | Height: | Size: 7.6 KiB |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 4.7 KiB |
Before Width: | Height: | Size: 7.9 KiB After Width: | Height: | Size: 2.0 KiB |
Before Width: | Height: | Size: 400 B |
After Width: | Height: | Size: 798 B |
After Width: | Height: | Size: 762 B |
After Width: | Height: | Size: 602 B |
After Width: | Height: | Size: 614 B |
After Width: | Height: | Size: 780 B |
After Width: | Height: | Size: 704 B |
After Width: | Height: | Size: 928 B |
After Width: | Height: | Size: 788 B |
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 822 B |
After Width: | Height: | Size: 724 B |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 762 B |
Before Width: | Height: | Size: 96 B After Width: | Height: | Size: 600 B |
After Width: | Height: | Size: 782 B |
After Width: | Height: | Size: 870 B |
After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 340 B After Width: | Height: | Size: 890 B |
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 806 B |
@ -0,0 +1,690 @@ |
|||||||
|
import 'dart:io'; |
||||||
|
import 'dart:ui'; |
||||||
|
|
||||||
|
import 'package:emoji_picker_flutter/emoji_picker_flutter.dart'; |
||||||
|
import 'package:flutter/material.dart'; |
||||||
|
import 'package:flutter/rendering.dart'; |
||||||
|
import 'package:flutter/services.dart'; |
||||||
|
import 'package:flutter_screenutil/flutter_screenutil.dart'; |
||||||
|
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; |
||||||
|
import 'package:huixiang/retrofit/retrofit_api.dart'; |
||||||
|
import 'package:huixiang/view_widget/my_appbar.dart'; |
||||||
|
import 'package:flutter/cupertino.dart'; |
||||||
|
import 'package:image_pickers/image_pickers.dart'; |
||||||
|
import '../../community/release_dynamic.dart'; |
||||||
|
import '../../generated/l10n.dart'; |
||||||
|
import '../../utils/font_weight.dart'; |
||||||
|
import 'im_view/on_chat_message.dart'; |
||||||
|
import 'im_view/on_chat_msg_instance.dart'; |
||||||
|
import 'im_view/text_item_container.dart'; |
||||||
|
|
||||||
|
class ChatDetailsPage extends StatefulWidget { |
||||||
|
@override |
||||||
|
State<StatefulWidget> createState() { |
||||||
|
return _ChatDetailsPage(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
class _ChatDetailsPage extends State<ChatDetailsPage> |
||||||
|
with WidgetsBindingObserver |
||||||
|
implements OnChatMessage { |
||||||
|
ApiService apiService; |
||||||
|
List<Medias> mediaPaths = []; |
||||||
|
int selectCount = 9; |
||||||
|
int dynamicType = 0; |
||||||
|
final TextEditingController chatController = TextEditingController(); |
||||||
|
bool emojiShowing = false; |
||||||
|
double keyboard = -1; |
||||||
|
bool needShowSmiley = false; |
||||||
|
bool needHideSmiley = false; |
||||||
|
bool isKeyBoardShow = false; |
||||||
|
bool moreShow = false; |
||||||
|
bool needShowMore = false; |
||||||
|
bool needHideMore = false; |
||||||
|
var commentFocus = FocusNode(); |
||||||
|
String hintText = "请输入消息内容..."; |
||||||
|
final OnChatMessage _tempOnChatMessage = |
||||||
|
OnChatMsgInstance.instance.onChatMessage; |
||||||
|
final ScrollController scrollController = ScrollController(); |
||||||
|
String tex = ""; |
||||||
|
|
||||||
|
@override |
||||||
|
void onMessage(txt) { |
||||||
|
// SmartDialog.showToast("聊天 $txt", alignment: Alignment.center); |
||||||
|
} |
||||||
|
|
||||||
|
@override |
||||||
|
void initState() { |
||||||
|
super.initState(); |
||||||
|
OnChatMsgInstance.instance.onChatMessage = this; |
||||||
|
WidgetsBinding.instance.addObserver(this); |
||||||
|
commentFocus.addListener(_focusNodeListener); |
||||||
|
|
||||||
|
Future.delayed(Duration.zero, () { |
||||||
|
jumpToBottom(); |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
void jumpToBottom(){ |
||||||
|
scrollController.position |
||||||
|
.jumpTo(scrollController.position.maxScrollExtent); |
||||||
|
} |
||||||
|
|
||||||
|
void didChangeMetrics() { |
||||||
|
WidgetsBinding.instance.addPostFrameCallback((_) { |
||||||
|
isKeyBoardShow = MediaQuery.of(context).viewInsets.bottom > 0; |
||||||
|
if (!mounted) return; |
||||||
|
if (MediaQuery.of(context).viewInsets.bottom == 0) { |
||||||
|
if (isKeyBoardShow) { |
||||||
|
FocusScope.of(context).requestFocus(FocusNode()); |
||||||
|
if (mounted) if (!emojiShowing) if (!moreShow) |
||||||
|
setState(() { |
||||||
|
hintText = "请输入消息内容..."; |
||||||
|
isKeyBoardShow = false; |
||||||
|
}); |
||||||
|
} |
||||||
|
} else { |
||||||
|
if (mounted) |
||||||
|
setState(() { |
||||||
|
isKeyBoardShow = true; |
||||||
|
}); |
||||||
|
} |
||||||
|
}); |
||||||
|
if (needShowSmiley && window.viewInsets.bottom <= 0.1) { |
||||||
|
needShowSmiley = false; |
||||||
|
setState(() { |
||||||
|
emojiShowing = true; |
||||||
|
}); |
||||||
|
} |
||||||
|
if (needHideSmiley && window.viewInsets.bottom > 0.1) { |
||||||
|
needHideSmiley = false; |
||||||
|
setState(() { |
||||||
|
emojiShowing = false; |
||||||
|
}); |
||||||
|
} |
||||||
|
if (needShowMore && window.viewInsets.bottom <= 0.1) { |
||||||
|
needShowMore = false; |
||||||
|
setState(() { |
||||||
|
moreShow = true; |
||||||
|
}); |
||||||
|
} |
||||||
|
if (needHideMore && window.viewInsets.bottom > 0.1) { |
||||||
|
needHideMore = false; |
||||||
|
setState(() { |
||||||
|
moreShow = false; |
||||||
|
}); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@override |
||||||
|
void dispose() { |
||||||
|
super.dispose(); |
||||||
|
OnChatMsgInstance.instance.onChatMessage = _tempOnChatMessage; |
||||||
|
WidgetsBinding.instance.removeObserver(this); |
||||||
|
commentFocus.removeListener(_focusNodeListener); |
||||||
|
} |
||||||
|
|
||||||
|
void _focusNodeListener() { |
||||||
|
/*if (_focusNode.hasFocus || _focusNode.consumeKeyboardToken()){ |
||||||
|
setState(() { |
||||||
|
smileyPadGone = true; |
||||||
|
}); |
||||||
|
}*/ |
||||||
|
} |
||||||
|
|
||||||
|
_onTextFieldTap() { |
||||||
|
if (emojiShowing) { |
||||||
|
needHideSmiley = true; |
||||||
|
} |
||||||
|
if (moreShow) { |
||||||
|
needHideMore = true; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
_onSmileyTap() { |
||||||
|
if (!emojiShowing && commentFocus.hasFocus && isKeyBoardShow) { |
||||||
|
needShowSmiley = true; |
||||||
|
commentFocus.unfocus(); |
||||||
|
} else { |
||||||
|
setState(() { |
||||||
|
emojiShowing = !emojiShowing; |
||||||
|
isKeyBoardShow = emojiShowing; |
||||||
|
moreShow = false; |
||||||
|
}); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
_onMoreTap() { |
||||||
|
if (!moreShow && commentFocus.hasFocus && isKeyBoardShow) { |
||||||
|
needShowMore = true; |
||||||
|
commentFocus.unfocus(); |
||||||
|
} else { |
||||||
|
setState(() { |
||||||
|
moreShow = !moreShow; |
||||||
|
isKeyBoardShow = moreShow; |
||||||
|
emojiShowing = false; |
||||||
|
}); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
///图片/视频选择 |
||||||
|
Future getImageOrVideo(GalleryMode galleryMode) async { |
||||||
|
if (selectCount == 0) return; |
||||||
|
List<Media> medias = await ImagePickers.pickerPaths( |
||||||
|
galleryMode: galleryMode, |
||||||
|
selectCount: (galleryMode == GalleryMode.video) ? 1 : selectCount, |
||||||
|
showGif: true, |
||||||
|
showCamera: false, |
||||||
|
compressSize: 500, |
||||||
|
uiConfig: UIConfig( |
||||||
|
uiThemeColor: Color(0xFFFFFFFF), |
||||||
|
), |
||||||
|
cropConfig: CropConfig( |
||||||
|
enableCrop: false, |
||||||
|
width: 200, |
||||||
|
height: 200, |
||||||
|
), |
||||||
|
); |
||||||
|
|
||||||
|
mediaPaths.addAll(medias.map((e) => Medias(e)).toList()); |
||||||
|
selectCount = 9 - mediaPaths.length; |
||||||
|
|
||||||
|
if (mediaPaths.length > 0) { |
||||||
|
if (galleryMode == GalleryMode.image) { |
||||||
|
dynamicType = 1; |
||||||
|
} else { |
||||||
|
dynamicType = 2; |
||||||
|
} |
||||||
|
} |
||||||
|
setState(() {}); |
||||||
|
} |
||||||
|
|
||||||
|
@override |
||||||
|
Widget build(BuildContext context) { |
||||||
|
double h = MediaQuery.of(context).viewInsets.bottom; |
||||||
|
if (h > 0) { |
||||||
|
jumpToBottom(); |
||||||
|
if(keyboard < h){ |
||||||
|
keyboard = h; |
||||||
|
// setState(() {}); |
||||||
|
} |
||||||
|
} |
||||||
|
return Scaffold( |
||||||
|
// resizeToAvoidBottomInset: false, |
||||||
|
backgroundColor: Color(0xFFF9FAF7), |
||||||
|
appBar: MyAppBar( |
||||||
|
title: "哈哈哈哈", |
||||||
|
titleColor: Colors.black, |
||||||
|
titleSize: 18.sp, |
||||||
|
background: Colors.white, |
||||||
|
leading: true, |
||||||
|
leadingColor: Colors.black, |
||||||
|
action: GestureDetector( |
||||||
|
behavior: HitTestBehavior.opaque, |
||||||
|
onTap: () { |
||||||
|
setState(() { |
||||||
|
Navigator.of(context).pushNamed('/router/chat_setting'); |
||||||
|
}); |
||||||
|
}, |
||||||
|
child: Container( |
||||||
|
padding: EdgeInsets.only(top: 3.h, bottom: 16.h), |
||||||
|
alignment: Alignment.center, |
||||||
|
// color: Colors.red, |
||||||
|
child: Icon( |
||||||
|
Icons.more_horiz, |
||||||
|
color: Colors.black, |
||||||
|
size: 30, |
||||||
|
), |
||||||
|
)), |
||||||
|
), |
||||||
|
body: Container( |
||||||
|
child: Column( |
||||||
|
children: [ |
||||||
|
Expanded( |
||||||
|
child: SingleChildScrollView( |
||||||
|
physics: BouncingScrollPhysics(), |
||||||
|
controller: scrollController, |
||||||
|
child: Column( |
||||||
|
children: [ |
||||||
|
GestureDetector( |
||||||
|
behavior: HitTestBehavior.translucent, |
||||||
|
onTap: () { |
||||||
|
setState(() { |
||||||
|
emojiShowing = false; |
||||||
|
isKeyBoardShow = emojiShowing; |
||||||
|
moreShow = false; |
||||||
|
isKeyBoardShow = moreShow; |
||||||
|
FocusScope.of(context).requestFocus(FocusNode()); |
||||||
|
}); |
||||||
|
}, |
||||||
|
child: chatDetailsList()), |
||||||
|
], |
||||||
|
), |
||||||
|
), |
||||||
|
flex: 1, |
||||||
|
), |
||||||
|
input() |
||||||
|
], |
||||||
|
), |
||||||
|
), |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
///聊天列表 |
||||||
|
Widget chatDetailsList() { |
||||||
|
return Container( |
||||||
|
margin: EdgeInsets.only(bottom: 48.h), |
||||||
|
child: ListView.builder( |
||||||
|
itemCount: 10, |
||||||
|
shrinkWrap: true, |
||||||
|
physics: NeverScrollableScrollPhysics(), |
||||||
|
itemBuilder: (context, position) { |
||||||
|
return GestureDetector( |
||||||
|
onTap: () { |
||||||
|
}, |
||||||
|
onLongPress: (){ |
||||||
|
showCustomDialog(context,position); |
||||||
|
}, |
||||||
|
child: chatDetailsItem(), |
||||||
|
); |
||||||
|
}), |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
Widget chatDetailsItem() { |
||||||
|
return Container( |
||||||
|
padding: EdgeInsets.only(top: 32.h,), |
||||||
|
child: Column( |
||||||
|
children: [ |
||||||
|
Text( |
||||||
|
"3月08日 上午 12:10", |
||||||
|
textAlign: TextAlign.center, |
||||||
|
style: TextStyle( |
||||||
|
color: Color(0xFFA29E9E), |
||||||
|
fontSize: 10.sp, |
||||||
|
fontWeight: MyFontWeight.regular, |
||||||
|
), |
||||||
|
), |
||||||
|
Padding( |
||||||
|
padding: EdgeInsets.only(top: 10.h, bottom: 24.h), |
||||||
|
child: Text( |
||||||
|
"在对方未回复或关注你之前,你只能发送一条信息", |
||||||
|
textAlign: TextAlign.center, |
||||||
|
style: TextStyle( |
||||||
|
color: Color(0xFFA29E9E), |
||||||
|
fontSize: 10.sp, |
||||||
|
fontWeight: MyFontWeight.regular, |
||||||
|
), |
||||||
|
), |
||||||
|
), |
||||||
|
SizedBox( |
||||||
|
height: 16.h, |
||||||
|
), |
||||||
|
Padding(padding:EdgeInsets.only(left: 17.w,right: 39.w), |
||||||
|
child: Row( |
||||||
|
children: [ |
||||||
|
// MImage( |
||||||
|
// "", |
||||||
|
// isCircle: true, |
||||||
|
// width: 44, |
||||||
|
// height: 44, |
||||||
|
// fit: BoxFit.cover, |
||||||
|
// errorSrc: "assets/image/default_user.webp", |
||||||
|
// fadeSrc: "assets/image/default_user.webp", |
||||||
|
// ), |
||||||
|
Image.asset( |
||||||
|
"assets/image/fuka_zj.webp", |
||||||
|
height: 44, |
||||||
|
width: 44, |
||||||
|
), |
||||||
|
SizedBox( |
||||||
|
width: 12.w, |
||||||
|
), |
||||||
|
Expanded( |
||||||
|
child: Container( |
||||||
|
decoration: BoxDecoration( |
||||||
|
borderRadius: BorderRadius.circular(6), |
||||||
|
color: Color(0xFFF0FAF4), |
||||||
|
), |
||||||
|
padding: EdgeInsets.symmetric(vertical: 8.h, horizontal: 12.w), |
||||||
|
child:GestureDetector( |
||||||
|
onTap:this.copy(tex), |
||||||
|
child: SelectableText( |
||||||
|
tex = "凭本事买的为啥要给你钱啊伙计", |
||||||
|
textAlign: TextAlign.left, |
||||||
|
style: TextStyle( |
||||||
|
height: 1.2.h, |
||||||
|
color: Colors.black, |
||||||
|
fontSize: 17.sp, |
||||||
|
fontWeight: MyFontWeight.regular, |
||||||
|
), |
||||||
|
), |
||||||
|
) |
||||||
|
)), |
||||||
|
], |
||||||
|
),), |
||||||
|
SizedBox(height: 40.h,), |
||||||
|
Padding(padding:EdgeInsets.only(left:36.w,right: 16.w), |
||||||
|
child: Row( |
||||||
|
children: [ |
||||||
|
Container( |
||||||
|
decoration: BoxDecoration( |
||||||
|
borderRadius: BorderRadius.circular(100), |
||||||
|
color: Color(0xFFFF441A), |
||||||
|
), |
||||||
|
width: 20, |
||||||
|
height: 20, |
||||||
|
alignment: Alignment.center, |
||||||
|
child: Text( |
||||||
|
"!", |
||||||
|
textAlign: TextAlign.left, |
||||||
|
style: TextStyle( |
||||||
|
color: Colors.white, |
||||||
|
fontSize: 17.sp, |
||||||
|
fontWeight: MyFontWeight.regular, |
||||||
|
), |
||||||
|
), |
||||||
|
), |
||||||
|
SizedBox( |
||||||
|
width: 12.w, |
||||||
|
), |
||||||
|
Expanded( |
||||||
|
child: Container( |
||||||
|
decoration: BoxDecoration( |
||||||
|
borderRadius: BorderRadius.circular(6), |
||||||
|
color: Color(0xFF32A060), |
||||||
|
), |
||||||
|
padding: EdgeInsets.symmetric(vertical: 8.h, horizontal: 12.w), |
||||||
|
child: TextItemContainer( |
||||||
|
text: "上次你在我这里买的水果钱是不是忘记付了?一共18块钱做点生意也是真的不容易啊。", |
||||||
|
action: '', |
||||||
|
isMyself: true,), |
||||||
|
)), |
||||||
|
SizedBox( |
||||||
|
width: 12.w, |
||||||
|
), |
||||||
|
// MImage( |
||||||
|
// "", |
||||||
|
// isCircle: true, |
||||||
|
// width: 44, |
||||||
|
// height: 44, |
||||||
|
// fit: BoxFit.cover, |
||||||
|
// errorSrc: "assets/image/default_user.webp", |
||||||
|
// fadeSrc: "assets/image/default_user.webp", |
||||||
|
// ), |
||||||
|
Image.asset( |
||||||
|
"assets/image/fuka_zj.webp", |
||||||
|
height: 44, |
||||||
|
width: 44, |
||||||
|
), |
||||||
|
], |
||||||
|
)), |
||||||
|
Padding( |
||||||
|
padding: EdgeInsets.only(left: 17.w, right: 17.w, top: 24.h), |
||||||
|
child: Text( |
||||||
|
"由于对方没有回复你,你只能发送一条消息,需要对方关注或回复后才能恢复正常聊天", |
||||||
|
textAlign: TextAlign.center, |
||||||
|
style: TextStyle( |
||||||
|
color: Color(0xFFA29E9E), |
||||||
|
fontSize: 10.sp, |
||||||
|
fontWeight: MyFontWeight.regular, |
||||||
|
), |
||||||
|
), |
||||||
|
), |
||||||
|
], |
||||||
|
), |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
///富文本输入框 |
||||||
|
Widget input() { |
||||||
|
return Container( |
||||||
|
color: Colors.white, |
||||||
|
padding: EdgeInsets.only(top: 16.h, bottom: 15.h), |
||||||
|
child: Column( |
||||||
|
children: [ |
||||||
|
Row( |
||||||
|
children: [ |
||||||
|
Expanded( |
||||||
|
flex: 1, |
||||||
|
child: Container( |
||||||
|
margin: EdgeInsets.only( |
||||||
|
left: 20.w, |
||||||
|
), |
||||||
|
decoration: BoxDecoration( |
||||||
|
color: Color(0xFFF0FAF4), |
||||||
|
borderRadius: BorderRadius.circular(6), |
||||||
|
), |
||||||
|
child: Container( |
||||||
|
margin: EdgeInsets.symmetric(horizontal: 12.w), |
||||||
|
alignment: Alignment.topLeft, |
||||||
|
child: TextField( |
||||||
|
textInputAction: TextInputAction.send, |
||||||
|
onTap: () { |
||||||
|
moreShow = false; |
||||||
|
_onTextFieldTap(); |
||||||
|
}, |
||||||
|
onEditingComplete: () { |
||||||
|
var commentText = chatController.text; |
||||||
|
if (commentText.trim() == "") { |
||||||
|
return; |
||||||
|
} |
||||||
|
// widget.queryMemberComment(commentText); |
||||||
|
}, |
||||||
|
maxLines: 8, |
||||||
|
minLines: 1, |
||||||
|
focusNode: commentFocus, |
||||||
|
controller: chatController, |
||||||
|
decoration: InputDecoration( |
||||||
|
border: InputBorder.none, |
||||||
|
hintText: hintText, |
||||||
|
hintStyle: TextStyle( |
||||||
|
fontSize: 14.sp, |
||||||
|
color: Color(0xFF868686), |
||||||
|
), |
||||||
|
), |
||||||
|
), |
||||||
|
), |
||||||
|
), |
||||||
|
), |
||||||
|
GestureDetector( |
||||||
|
behavior: HitTestBehavior.opaque, |
||||||
|
onTap: () { |
||||||
|
_onSmileyTap(); |
||||||
|
Future.delayed(Duration(milliseconds: 500), () { |
||||||
|
jumpToBottom(); |
||||||
|
}); |
||||||
|
}, |
||||||
|
child: Container( |
||||||
|
padding: EdgeInsets.only(left: 15.w, right: 8.w), |
||||||
|
child: Image.asset( |
||||||
|
"assets/image/icon_chat_emo.webp", |
||||||
|
height: 24, |
||||||
|
width: 24, |
||||||
|
)), |
||||||
|
), |
||||||
|
GestureDetector( |
||||||
|
behavior: HitTestBehavior.opaque, |
||||||
|
onTap: () { |
||||||
|
_onMoreTap(); |
||||||
|
|
||||||
|
Future.delayed(Duration(milliseconds: 500), () { |
||||||
|
jumpToBottom(); |
||||||
|
}); |
||||||
|
}, |
||||||
|
child: Container( |
||||||
|
padding: EdgeInsets.only(left: 8.w, right: 19.w), |
||||||
|
child: Image.asset( |
||||||
|
"assets/image/fa_bu.webp", |
||||||
|
height: 24, |
||||||
|
width: 24, |
||||||
|
), |
||||||
|
), |
||||||
|
), |
||||||
|
], |
||||||
|
), |
||||||
|
SizedBox( |
||||||
|
height: 16.h, |
||||||
|
), |
||||||
|
|
||||||
|
///表情 |
||||||
|
Offstage( |
||||||
|
offstage: !emojiShowing, |
||||||
|
child: SizedBox( |
||||||
|
height: keyboard == -1 ? 270 : keyboard, |
||||||
|
width: MediaQuery.of(context).size.width, |
||||||
|
child: EmojiPicker( |
||||||
|
textEditingController: chatController, |
||||||
|
config: Config( |
||||||
|
columns: 7, |
||||||
|
emojiSizeMax: 32 * (Platform.isIOS ? 1.10 : 1.0), |
||||||
|
verticalSpacing: 0, |
||||||
|
horizontalSpacing: 0, |
||||||
|
gridPadding: EdgeInsets.zero, |
||||||
|
initCategory: Category.RECENT, |
||||||
|
bgColor: const Color(0xFFF2F2F2), |
||||||
|
// indicatorColor: Colors.blue, |
||||||
|
iconColor: Colors.grey, |
||||||
|
iconColorSelected: Colors.blue, |
||||||
|
backspaceColor: Colors.blue, |
||||||
|
skinToneDialogBgColor: Colors.white, |
||||||
|
skinToneIndicatorColor: Colors.grey, |
||||||
|
enableSkinTones: true, |
||||||
|
showRecentsTab: true, |
||||||
|
recentsLimit: 28, |
||||||
|
replaceEmojiOnLimitExceed: false, |
||||||
|
noRecents: Text( |
||||||
|
"最近使用", |
||||||
|
style: TextStyle(fontSize: 20, color: Colors.black26), |
||||||
|
textAlign: TextAlign.center, |
||||||
|
), |
||||||
|
loadingIndicator: const SizedBox.shrink(), |
||||||
|
tabIndicatorAnimDuration: Duration(milliseconds: 0), |
||||||
|
categoryIcons: const CategoryIcons(), |
||||||
|
buttonMode: ButtonMode.MATERIAL, |
||||||
|
checkPlatformCompatibility: true, |
||||||
|
), |
||||||
|
)), |
||||||
|
), |
||||||
|
|
||||||
|
///更多 |
||||||
|
Offstage( |
||||||
|
offstage: !moreShow, |
||||||
|
child: Container( |
||||||
|
height: keyboard == -1 ? 270 : keyboard, |
||||||
|
child: Column( |
||||||
|
children: [ |
||||||
|
Container( |
||||||
|
width: double.infinity, |
||||||
|
height: 1.h, |
||||||
|
color: Color(0xFFF7F7F7), |
||||||
|
), |
||||||
|
Row( |
||||||
|
children: [ |
||||||
|
GestureDetector( |
||||||
|
behavior: HitTestBehavior.opaque, |
||||||
|
onTap: () { |
||||||
|
getImageOrVideo(GalleryMode.video); |
||||||
|
}, |
||||||
|
child: Container( |
||||||
|
padding: EdgeInsets.only( |
||||||
|
left: 19.w, right: 16.w, top: 11.h, bottom: 5.h), |
||||||
|
child: Image.asset( |
||||||
|
"assets/image/icon_chat_camera.webp", |
||||||
|
height: 26, |
||||||
|
width: 24, |
||||||
|
), |
||||||
|
), |
||||||
|
), |
||||||
|
GestureDetector( |
||||||
|
behavior: HitTestBehavior.opaque, |
||||||
|
onTap: () { |
||||||
|
getImageOrVideo(GalleryMode.image); |
||||||
|
}, |
||||||
|
child: Container( |
||||||
|
// color: Colors.yellow, |
||||||
|
padding: EdgeInsets.only( |
||||||
|
left: 16.w, right: 16.w, top: 13.h, bottom: 5.h), |
||||||
|
child: Image.asset( |
||||||
|
"assets/image/icon_chat_photo.webp", |
||||||
|
height: 24, |
||||||
|
width: 24, |
||||||
|
), |
||||||
|
), |
||||||
|
), |
||||||
|
], |
||||||
|
) |
||||||
|
], |
||||||
|
), |
||||||
|
), |
||||||
|
) |
||||||
|
], |
||||||
|
), |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
showCustomDialog(BuildContext context,int position ){ |
||||||
|
showDialog( |
||||||
|
context: context, |
||||||
|
builder: (BuildContext context) { |
||||||
|
return new AlertDialog( |
||||||
|
backgroundColor: Color(0xFF2A2A2A), |
||||||
|
elevation: 0, |
||||||
|
contentPadding:EdgeInsets.only(top: 8.h,bottom: 5.h,), |
||||||
|
content: Container( |
||||||
|
height: 40.h, |
||||||
|
// width:20.w, |
||||||
|
alignment: Alignment.center, |
||||||
|
child: Row( |
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween, |
||||||
|
crossAxisAlignment: CrossAxisAlignment.center, |
||||||
|
children: [ |
||||||
|
Column( |
||||||
|
children: [ |
||||||
|
Image.asset( |
||||||
|
"assets/image/icon_chat_copy.webp", |
||||||
|
height:16, |
||||||
|
width: 16, |
||||||
|
), |
||||||
|
Text( |
||||||
|
"复制", |
||||||
|
textAlign: TextAlign.center, |
||||||
|
style: TextStyle( |
||||||
|
color: Colors.white, |
||||||
|
fontSize: 12.sp, |
||||||
|
fontWeight: MyFontWeight.regular, |
||||||
|
), |
||||||
|
), |
||||||
|
], |
||||||
|
), |
||||||
|
Column( |
||||||
|
children: [ |
||||||
|
Image.asset( |
||||||
|
"assets/image/icon_chat_delete.webp", |
||||||
|
height:16, |
||||||
|
width: 16, |
||||||
|
), |
||||||
|
Text( |
||||||
|
S.of(context).shanchu, |
||||||
|
textAlign: TextAlign.center, |
||||||
|
style: TextStyle( |
||||||
|
color: Colors.white, |
||||||
|
fontSize: 12.sp, |
||||||
|
fontWeight: MyFontWeight.regular, |
||||||
|
), |
||||||
|
), |
||||||
|
], |
||||||
|
) |
||||||
|
], |
||||||
|
), |
||||||
|
), |
||||||
|
); |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
/// 复制文本 |
||||||
|
copy(String tex) { |
||||||
|
print(tex); |
||||||
|
Clipboard.setData(ClipboardData(text: tex)); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,107 @@ |
|||||||
|
import 'dart:ui'; |
||||||
|
|
||||||
|
import 'package:flutter/material.dart'; |
||||||
|
import 'package:flutter/rendering.dart'; |
||||||
|
import 'package:flutter/services.dart'; |
||||||
|
import 'package:flutter_screenutil/flutter_screenutil.dart'; |
||||||
|
import 'package:huixiang/retrofit/retrofit_api.dart'; |
||||||
|
import 'package:huixiang/view_widget/my_appbar.dart'; |
||||||
|
import 'package:flutter/cupertino.dart'; |
||||||
|
import '../../generated/l10n.dart'; |
||||||
|
import '../../utils/font_weight.dart'; |
||||||
|
|
||||||
|
class ChatSetting extends StatefulWidget { |
||||||
|
|
||||||
|
@override |
||||||
|
State<StatefulWidget> createState() { |
||||||
|
return _ChatSetting(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
class _ChatSetting extends State<ChatSetting>{ |
||||||
|
ApiService apiService; |
||||||
|
bool topSetting = false; |
||||||
|
|
||||||
|
@override |
||||||
|
void initState() { |
||||||
|
super.initState(); |
||||||
|
} |
||||||
|
|
||||||
|
@override |
||||||
|
Widget build(BuildContext context) { |
||||||
|
return Scaffold( |
||||||
|
backgroundColor: Color(0xFFF9FAF7), |
||||||
|
appBar: MyAppBar( |
||||||
|
title:"聊天设置", |
||||||
|
titleColor: Colors.black, |
||||||
|
titleSize: 18.sp, |
||||||
|
background: Colors.white, |
||||||
|
leading: true, |
||||||
|
leadingColor: Colors.black, |
||||||
|
), |
||||||
|
body: Container( |
||||||
|
child: Column( |
||||||
|
children: [ |
||||||
|
Container( |
||||||
|
color: Colors.white, |
||||||
|
margin: EdgeInsets.symmetric(vertical: 14.h), |
||||||
|
padding: EdgeInsets.symmetric(horizontal: 16.w,vertical: 14.h), |
||||||
|
child: Column( |
||||||
|
children: [ |
||||||
|
Row( |
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween, |
||||||
|
crossAxisAlignment: CrossAxisAlignment.center, |
||||||
|
children: [ |
||||||
|
Text( |
||||||
|
"置顶聊天", |
||||||
|
style: TextStyle( |
||||||
|
color: Color(0xFF353535), |
||||||
|
fontSize:15.sp, |
||||||
|
fontWeight: MyFontWeight.semi_bold, |
||||||
|
), |
||||||
|
), |
||||||
|
CupertinoSwitch( |
||||||
|
value: (topSetting), |
||||||
|
activeColor: Color(0xFF32A060), |
||||||
|
onChanged: (bool value) { |
||||||
|
setState((){ |
||||||
|
topSetting = !topSetting; |
||||||
|
}); |
||||||
|
}, |
||||||
|
), |
||||||
|
], |
||||||
|
), |
||||||
|
SizedBox(height:31.h,), |
||||||
|
Row( |
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween, |
||||||
|
crossAxisAlignment: CrossAxisAlignment.end, |
||||||
|
children: [ |
||||||
|
Text( |
||||||
|
"清空聊天记录", |
||||||
|
style: TextStyle( |
||||||
|
color: Color(0xFF353535), |
||||||
|
fontSize:15.sp, |
||||||
|
fontWeight: MyFontWeight.semi_bold, |
||||||
|
), |
||||||
|
), |
||||||
|
Image.asset( |
||||||
|
"assets/image/icon_right_z.webp", |
||||||
|
height:16, |
||||||
|
width:16, |
||||||
|
color: Colors.black, |
||||||
|
), |
||||||
|
], |
||||||
|
) |
||||||
|
], |
||||||
|
), |
||||||
|
), |
||||||
|
Expanded(child: |
||||||
|
Container( |
||||||
|
color: Colors.white, |
||||||
|
)) |
||||||
|
], |
||||||
|
), |
||||||
|
), |
||||||
|
); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,245 @@ |
|||||||
|
import 'dart:ui'; |
||||||
|
|
||||||
|
import 'package:flutter/material.dart'; |
||||||
|
import 'package:flutter/rendering.dart'; |
||||||
|
import 'package:flutter/services.dart'; |
||||||
|
import 'package:flutter_screenutil/flutter_screenutil.dart'; |
||||||
|
import 'package:huixiang/retrofit/retrofit_api.dart'; |
||||||
|
import 'package:huixiang/view_widget/my_appbar.dart'; |
||||||
|
import 'package:flutter/cupertino.dart'; |
||||||
|
|
||||||
|
import '../../generated/l10n.dart'; |
||||||
|
import '../../retrofit/data/base_data.dart'; |
||||||
|
import '../../utils/font_weight.dart'; |
||||||
|
|
||||||
|
class ContactsShare extends StatefulWidget { |
||||||
|
final Map<String, dynamic> arguments; |
||||||
|
|
||||||
|
ContactsShare({this.arguments}); |
||||||
|
|
||||||
|
@override |
||||||
|
State<StatefulWidget> createState() { |
||||||
|
return _ContactsShare(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
class _ContactsShare extends State<ContactsShare> { |
||||||
|
ApiService apiService; |
||||||
|
final TextEditingController searchController = TextEditingController(); |
||||||
|
int searchIndex = 0; |
||||||
|
|
||||||
|
@override |
||||||
|
void initState() { |
||||||
|
super.initState(); |
||||||
|
} |
||||||
|
|
||||||
|
@override |
||||||
|
Widget build(BuildContext context) { |
||||||
|
return Scaffold( |
||||||
|
backgroundColor: Color(0xFFF9FAF7), |
||||||
|
appBar: MyAppBar( |
||||||
|
background: Color(0xFFFFFFFFF), |
||||||
|
leadingColor: Colors.white, |
||||||
|
title: "私信给", |
||||||
|
titleSize: 18, |
||||||
|
titleColor: Colors.black, |
||||||
|
), |
||||||
|
body: Container( |
||||||
|
margin: EdgeInsets.only(top:14.h), |
||||||
|
color: Colors.white, |
||||||
|
child:SingleChildScrollView( |
||||||
|
physics: BouncingScrollPhysics(), |
||||||
|
child: GestureDetector( |
||||||
|
behavior: HitTestBehavior.translucent, |
||||||
|
onTap: () { |
||||||
|
FocusScope.of(context).requestFocus(FocusNode()); |
||||||
|
}, |
||||||
|
child:Column( |
||||||
|
mainAxisAlignment: MainAxisAlignment.start, |
||||||
|
crossAxisAlignment: CrossAxisAlignment.start, |
||||||
|
children: [ |
||||||
|
contactSearch(), |
||||||
|
Padding( |
||||||
|
padding: EdgeInsets.only(left: 17.w,bottom:24.h), |
||||||
|
child: Text("最近联系(0)", |
||||||
|
style: TextStyle( |
||||||
|
fontSize: 17.sp, |
||||||
|
color: Color(0xFF0D0D0D), |
||||||
|
fontWeight: MyFontWeight.regular, |
||||||
|
)), |
||||||
|
), |
||||||
|
recentList(), |
||||||
|
Padding( |
||||||
|
padding: EdgeInsets.only(left: 17.w,bottom:24.h), |
||||||
|
child: Text("我的关注(0)", |
||||||
|
style: TextStyle( |
||||||
|
fontSize: 17.sp, |
||||||
|
color: Color(0xFF0D0D0D), |
||||||
|
fontWeight: MyFontWeight.regular, |
||||||
|
)), |
||||||
|
), |
||||||
|
mineFollowList(), |
||||||
|
], |
||||||
|
)),) |
||||||
|
), |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
Widget contactSearch() { |
||||||
|
return Container( |
||||||
|
width: double.infinity, |
||||||
|
margin: EdgeInsets.only(left: 16.w, right: 16.w, top: 4.h, bottom: 16.h), |
||||||
|
decoration: BoxDecoration( |
||||||
|
borderRadius: BorderRadius.circular(6.w), |
||||||
|
color: Color(0xFFF9FAF7), |
||||||
|
), |
||||||
|
child: Stack( |
||||||
|
alignment: Alignment.center, |
||||||
|
children: [ |
||||||
|
Row( |
||||||
|
mainAxisAlignment: MainAxisAlignment.center, |
||||||
|
crossAxisAlignment: CrossAxisAlignment.center, |
||||||
|
children: [ |
||||||
|
Image.asset( |
||||||
|
"assets/image/icon_search.webp", |
||||||
|
fit: BoxFit.fill, |
||||||
|
), |
||||||
|
SizedBox( |
||||||
|
width: 4.w, |
||||||
|
), |
||||||
|
Text("搜索", |
||||||
|
style: TextStyle( |
||||||
|
fontSize: 12.sp, |
||||||
|
color: Color(0xFFB3B3B3), |
||||||
|
fontWeight: MyFontWeight.regular, |
||||||
|
)), |
||||||
|
], |
||||||
|
), |
||||||
|
TextField( |
||||||
|
textInputAction: TextInputAction.search, |
||||||
|
enableInteractiveSelection: true, |
||||||
|
onEditingComplete: () { |
||||||
|
|
||||||
|
}, |
||||||
|
controller: searchController, |
||||||
|
cursorHeight: 25.h, |
||||||
|
decoration: InputDecoration( |
||||||
|
contentPadding: EdgeInsets.only(top: 7.h, bottom: 9.h,left:5.w), |
||||||
|
border: InputBorder.none, |
||||||
|
), |
||||||
|
) |
||||||
|
], |
||||||
|
) |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
Widget recentList() { |
||||||
|
return ListView.builder( |
||||||
|
itemCount: 6, |
||||||
|
shrinkWrap: true, |
||||||
|
physics: NeverScrollableScrollPhysics(), |
||||||
|
itemBuilder: (context, position) { |
||||||
|
return GestureDetector( |
||||||
|
onTap: () {}, |
||||||
|
child: recentItem(), |
||||||
|
); |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
Widget recentItem() { |
||||||
|
return Container( |
||||||
|
margin: EdgeInsets.only(bottom: 14.h), |
||||||
|
padding: EdgeInsets.only(left: 16.w,right: 14.w), |
||||||
|
child:Column( |
||||||
|
children: [ |
||||||
|
Row( |
||||||
|
children: [ |
||||||
|
// MImage( |
||||||
|
// "", |
||||||
|
// isCircle: true, |
||||||
|
// width: 44, |
||||||
|
// height: 44, |
||||||
|
// fit: BoxFit.cover, |
||||||
|
// errorSrc: "assets/image/default_user.webp", |
||||||
|
// fadeSrc: "assets/image/default_user.webp", |
||||||
|
// ), |
||||||
|
Image.asset( |
||||||
|
"assets/image/fuka_zj.webp", |
||||||
|
height:44, |
||||||
|
width:44, |
||||||
|
), |
||||||
|
SizedBox(width: 10.w,), |
||||||
|
Text("张五", |
||||||
|
style: TextStyle( |
||||||
|
fontSize: 14.sp, |
||||||
|
color: Color(0xFF1A1A1A), |
||||||
|
fontWeight: MyFontWeight.bold, |
||||||
|
)), |
||||||
|
], |
||||||
|
), |
||||||
|
Container( |
||||||
|
height: 1.h, |
||||||
|
width: double.infinity, |
||||||
|
color: Color(0xFFF7F7F7), |
||||||
|
margin: EdgeInsets.only(left:54.w,top: 10.h), |
||||||
|
) |
||||||
|
], |
||||||
|
) |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
Widget mineFollowList() { |
||||||
|
return ListView.builder( |
||||||
|
itemCount: 3, |
||||||
|
shrinkWrap: true, |
||||||
|
physics: NeverScrollableScrollPhysics(), |
||||||
|
itemBuilder: (context, position) { |
||||||
|
return GestureDetector( |
||||||
|
onTap: () {}, |
||||||
|
child: recentItem(), |
||||||
|
); |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
Widget mineFollowItem() { |
||||||
|
return Container( |
||||||
|
margin: EdgeInsets.only(bottom: 14.h), |
||||||
|
padding: EdgeInsets.only(left: 16.w,right: 14.w), |
||||||
|
child:Column( |
||||||
|
children: [ |
||||||
|
Row( |
||||||
|
children: [ |
||||||
|
// MImage( |
||||||
|
// "", |
||||||
|
// isCircle: true, |
||||||
|
// width: 44, |
||||||
|
// height: 44, |
||||||
|
// fit: BoxFit.cover, |
||||||
|
// errorSrc: "assets/image/default_user.webp", |
||||||
|
// fadeSrc: "assets/image/default_user.webp", |
||||||
|
// ), |
||||||
|
Image.asset( |
||||||
|
"assets/image/fuka_zj.webp", |
||||||
|
height:44, |
||||||
|
width:44, |
||||||
|
), |
||||||
|
SizedBox(width: 10.w,), |
||||||
|
Text("小王", |
||||||
|
style: TextStyle( |
||||||
|
fontSize: 14.sp, |
||||||
|
color: Color(0xFF1A1A1A), |
||||||
|
fontWeight: MyFontWeight.bold, |
||||||
|
)), |
||||||
|
], |
||||||
|
), |
||||||
|
Container( |
||||||
|
height: 1.h, |
||||||
|
width: double.infinity, |
||||||
|
color: Color(0xFFF7F7F7), |
||||||
|
margin: EdgeInsets.only(left:54.w,top: 10.h), |
||||||
|
) |
||||||
|
], |
||||||
|
) |
||||||
|
); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,53 @@ |
|||||||
|
import 'package:extended_text/extended_text.dart'; |
||||||
|
import 'package:flutter/material.dart'; |
||||||
|
|
||||||
|
///emoji/image text |
||||||
|
class EmojiText extends SpecialText { |
||||||
|
static const String flag = "["; |
||||||
|
final int start; |
||||||
|
EmojiText(TextStyle textStyle, {this.start}) |
||||||
|
: super(EmojiText.flag, "]", textStyle); |
||||||
|
|
||||||
|
@override |
||||||
|
InlineSpan finishText() { |
||||||
|
var key = toString(); |
||||||
|
if (EmojiUitl.instance.emojiMap.containsKey(key)) { |
||||||
|
//fontsize id define image height |
||||||
|
//size = 30.0/26.0 * fontSize |
||||||
|
final double size = 20.0; |
||||||
|
|
||||||
|
///fontSize 26 and text height =30.0 |
||||||
|
//final double fontSize = 26.0; |
||||||
|
|
||||||
|
return ImageSpan(AssetImage(EmojiUitl.instance.emojiMap[key]), |
||||||
|
actualText: key, |
||||||
|
imageWidth: size, |
||||||
|
imageHeight: size, |
||||||
|
start: start, |
||||||
|
fit: BoxFit.fill, |
||||||
|
margin: EdgeInsets.only(left: 2.0, right: 2.0)); |
||||||
|
} |
||||||
|
|
||||||
|
return TextSpan(text: toString(), style: textStyle); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
class EmojiUitl { |
||||||
|
final Map<String, String> _emojiMap = new Map<String, String>(); |
||||||
|
|
||||||
|
Map<String, String> get emojiMap => _emojiMap; |
||||||
|
|
||||||
|
final String _emojiFilePath = "assets/images/emoji"; |
||||||
|
|
||||||
|
static EmojiUitl _instance; |
||||||
|
static EmojiUitl get instance { |
||||||
|
if (_instance == null) _instance = new EmojiUitl._(); |
||||||
|
return _instance; |
||||||
|
} |
||||||
|
|
||||||
|
EmojiUitl._() { |
||||||
|
for (int i = 1; i < 100; i++) { |
||||||
|
_emojiMap["[$i]"] = "$_emojiFilePath/sg$i.png"; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,466 @@ |
|||||||
|
import 'package:flutter/material.dart'; |
||||||
|
import 'package:huixiang/message/im/im_view/triangle_painter.dart'; |
||||||
|
|
||||||
|
const double _kMenuScreenPadding = 8.0; |
||||||
|
|
||||||
|
class MagicPop extends StatefulWidget { |
||||||
|
MagicPop({ |
||||||
|
@required this.onValueChanged, |
||||||
|
@required this.actions, |
||||||
|
@required this.child, |
||||||
|
this.pressType = PressType.longPress, |
||||||
|
this.pageMaxChildCount = 5, |
||||||
|
this.backgroundColor = Colors.black, |
||||||
|
this.menuWidth = 250, |
||||||
|
this.menuHeight = 42, |
||||||
|
}) : assert(onValueChanged != null), |
||||||
|
assert(actions != null && actions.length > 0), |
||||||
|
assert(child != null); |
||||||
|
|
||||||
|
final ValueChanged<int> onValueChanged; |
||||||
|
final List<String> actions; |
||||||
|
final Widget child; |
||||||
|
final PressType pressType; // 点击方式 长按 还是单击 |
||||||
|
final int pageMaxChildCount; |
||||||
|
final Color backgroundColor; |
||||||
|
final double menuWidth; |
||||||
|
final double menuHeight; |
||||||
|
|
||||||
|
@override |
||||||
|
_WPopupMenuState createState() => _WPopupMenuState(); |
||||||
|
} |
||||||
|
|
||||||
|
class _WPopupMenuState extends State<MagicPop> { |
||||||
|
@override |
||||||
|
Widget build(BuildContext context) { |
||||||
|
return GestureDetector( |
||||||
|
child: widget.child, |
||||||
|
onTap: () { |
||||||
|
if (widget.pressType == PressType.singleClick) { |
||||||
|
onTap(); |
||||||
|
} |
||||||
|
}, |
||||||
|
onLongPress: () { |
||||||
|
if (widget.pressType == PressType.longPress) { |
||||||
|
onTap(); |
||||||
|
} |
||||||
|
}, |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
void onTap() { |
||||||
|
Navigator.push( |
||||||
|
context, |
||||||
|
_PopupMenuRoute(context, widget.actions, widget.pageMaxChildCount, |
||||||
|
widget.backgroundColor, widget.menuWidth, widget.menuHeight)) |
||||||
|
.then((index) { |
||||||
|
widget.onValueChanged(index); |
||||||
|
}); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
enum PressType { |
||||||
|
// 长按 |
||||||
|
longPress, |
||||||
|
// 单击 |
||||||
|
singleClick, |
||||||
|
} |
||||||
|
|
||||||
|
class _PopupMenuRoute extends PopupRoute { |
||||||
|
final BuildContext btnContext; |
||||||
|
double _height; |
||||||
|
double _width; |
||||||
|
final List<String> actions; |
||||||
|
final int _pageMaxChildCount; |
||||||
|
final Color backgroundColor; |
||||||
|
final double menuWidth; |
||||||
|
final double menuHeight; |
||||||
|
|
||||||
|
_PopupMenuRoute(this.btnContext, this.actions, this._pageMaxChildCount, |
||||||
|
this.backgroundColor, this.menuWidth, this.menuHeight) { |
||||||
|
_height = btnContext.size.height; |
||||||
|
_width = btnContext.size.width; |
||||||
|
} |
||||||
|
|
||||||
|
@override |
||||||
|
Animation<double> createAnimation() { |
||||||
|
return CurvedAnimation( |
||||||
|
parent: super.createAnimation(), |
||||||
|
curve: Curves.linear, |
||||||
|
reverseCurve: const Interval(0.0, 2.0 / 3.0), |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
@override |
||||||
|
Color get barrierColor => null; |
||||||
|
|
||||||
|
@override |
||||||
|
bool get barrierDismissible => true; |
||||||
|
|
||||||
|
@override |
||||||
|
String get barrierLabel => null; |
||||||
|
|
||||||
|
@override |
||||||
|
Widget buildPage(BuildContext context, Animation<double> animation, |
||||||
|
Animation<double> secondaryAnimation) { |
||||||
|
return _MenuPopWidget(this.btnContext, _height, _width, actions, |
||||||
|
_pageMaxChildCount, backgroundColor, menuWidth, menuHeight); |
||||||
|
} |
||||||
|
|
||||||
|
@override |
||||||
|
Duration get transitionDuration => Duration(milliseconds: 300); |
||||||
|
} |
||||||
|
|
||||||
|
class _MenuPopWidget extends StatefulWidget { |
||||||
|
final BuildContext btnContext; |
||||||
|
final double _height; |
||||||
|
final double _width; |
||||||
|
final List<String> actions; |
||||||
|
final int _pageMaxChildCount; |
||||||
|
final Color backgroundColor; |
||||||
|
final double menuWidth; |
||||||
|
final double menuHeight; |
||||||
|
|
||||||
|
_MenuPopWidget( |
||||||
|
this.btnContext, |
||||||
|
this._height, |
||||||
|
this._width, |
||||||
|
this.actions, |
||||||
|
this._pageMaxChildCount, |
||||||
|
this.backgroundColor, |
||||||
|
this.menuWidth, |
||||||
|
this.menuHeight); |
||||||
|
|
||||||
|
@override |
||||||
|
__MenuPopWidgetState createState() => __MenuPopWidgetState(); |
||||||
|
} |
||||||
|
|
||||||
|
class __MenuPopWidgetState extends State<_MenuPopWidget> { |
||||||
|
int _curPage = 0; |
||||||
|
final double _arrowWidth = 40; |
||||||
|
final double _separatorWidth = 1; |
||||||
|
final double _triangleHeight = 10; |
||||||
|
|
||||||
|
RenderBox button; |
||||||
|
RenderBox overlay; |
||||||
|
RelativeRect position; |
||||||
|
|
||||||
|
@override |
||||||
|
void initState() { |
||||||
|
super.initState(); |
||||||
|
button = widget.btnContext.findRenderObject(); |
||||||
|
overlay = Overlay.of(widget.btnContext).context.findRenderObject(); |
||||||
|
position = RelativeRect.fromRect( |
||||||
|
Rect.fromPoints( |
||||||
|
button.localToGlobal(Offset.zero, ancestor: overlay), |
||||||
|
button.localToGlobal(Offset.zero, ancestor: overlay), |
||||||
|
), |
||||||
|
Offset.zero & overlay.size, |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
@override |
||||||
|
Widget build(BuildContext context) { |
||||||
|
// 这里计算出来 当前页的 child 一共有多少个 |
||||||
|
int _curPageChildCount = |
||||||
|
(_curPage + 1) * widget._pageMaxChildCount > widget.actions.length |
||||||
|
? widget.actions.length % widget._pageMaxChildCount |
||||||
|
: widget._pageMaxChildCount; |
||||||
|
|
||||||
|
double _curArrowWidth = 0; |
||||||
|
int _curArrowCount = 0; // 一共几个箭头 |
||||||
|
|
||||||
|
if (widget.actions.length > widget._pageMaxChildCount) { |
||||||
|
// 数据长度大于 widget._pageMaxChildCount |
||||||
|
if (_curPage == 0) { |
||||||
|
// 如果是第一页 |
||||||
|
_curArrowWidth = _arrowWidth; |
||||||
|
_curArrowCount = 1; |
||||||
|
} else { |
||||||
|
// 如果不是第一页 则需要也显示左箭头 |
||||||
|
_curArrowWidth = _arrowWidth * 2; |
||||||
|
_curArrowCount = 2; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
double _curPageWidth = widget.menuWidth + |
||||||
|
(_curPageChildCount - 1 + _curArrowCount) * _separatorWidth + |
||||||
|
_curArrowWidth; |
||||||
|
|
||||||
|
// ignore: unused_element |
||||||
|
Widget view() { |
||||||
|
var isInverted = (position.top + |
||||||
|
(MediaQuery.of(context).size.height - |
||||||
|
position.top - |
||||||
|
position.bottom) / |
||||||
|
2.0 - |
||||||
|
(widget.menuHeight + _triangleHeight)) < |
||||||
|
(widget.menuHeight + _triangleHeight) * 2; |
||||||
|
|
||||||
|
var pain = CustomPaint( |
||||||
|
size: Size(_curPageWidth, _triangleHeight), |
||||||
|
painter: TrianglePainter( |
||||||
|
color: widget.backgroundColor, |
||||||
|
position: position, |
||||||
|
isInverted: true, |
||||||
|
size: button.size), |
||||||
|
); |
||||||
|
|
||||||
|
var row = Row( |
||||||
|
mainAxisSize: MainAxisSize.min, |
||||||
|
children: <Widget>[ |
||||||
|
// 左箭头:判断是否是第一页,如果是第一页则不显示 |
||||||
|
_curPage == 0 |
||||||
|
? Container( |
||||||
|
height: widget.menuHeight, |
||||||
|
) |
||||||
|
: InkWell( |
||||||
|
onTap: () { |
||||||
|
setState(() { |
||||||
|
_curPage--; |
||||||
|
}); |
||||||
|
}, |
||||||
|
child: Container( |
||||||
|
width: _arrowWidth, |
||||||
|
height: widget.menuHeight, |
||||||
|
child: Image.asset( |
||||||
|
'images/left_white.png', |
||||||
|
fit: BoxFit.none, |
||||||
|
), |
||||||
|
), |
||||||
|
), |
||||||
|
// 左箭头:判断是否是第一页,如果是第一页则不显示 |
||||||
|
_curPage == 0 |
||||||
|
? Container( |
||||||
|
height: widget.menuHeight, |
||||||
|
) |
||||||
|
: Container( |
||||||
|
width: 1, |
||||||
|
height: widget.menuHeight, |
||||||
|
color: Colors.grey, |
||||||
|
), |
||||||
|
|
||||||
|
// 中间是ListView |
||||||
|
_buildList(_curPageChildCount, _curPageWidth, _curArrowWidth, |
||||||
|
_curArrowCount), |
||||||
|
|
||||||
|
// 右箭头:判断是否有箭头,如果有就显示,没有就不显示 |
||||||
|
_curArrowCount > 0 |
||||||
|
? Container( |
||||||
|
width: 1, |
||||||
|
color: Colors.grey, |
||||||
|
height: widget.menuHeight, |
||||||
|
) |
||||||
|
: Container( |
||||||
|
height: widget.menuHeight, |
||||||
|
), |
||||||
|
_curArrowCount > 0 |
||||||
|
? InkWell( |
||||||
|
onTap: () { |
||||||
|
if ((_curPage + 1) * widget._pageMaxChildCount < |
||||||
|
widget.actions.length) |
||||||
|
setState(() { |
||||||
|
_curPage++; |
||||||
|
}); |
||||||
|
}, |
||||||
|
child: Container( |
||||||
|
width: _arrowWidth, |
||||||
|
height: widget.menuHeight, |
||||||
|
child: Image.asset( |
||||||
|
(_curPage + 1) * widget._pageMaxChildCount >= |
||||||
|
widget.actions.length |
||||||
|
? 'images/right_gray.png' |
||||||
|
: 'images/right_white.png', |
||||||
|
fit: BoxFit.none, |
||||||
|
), |
||||||
|
), |
||||||
|
) |
||||||
|
: Container( |
||||||
|
height: widget.menuHeight, |
||||||
|
), |
||||||
|
], |
||||||
|
); |
||||||
|
|
||||||
|
return Material( |
||||||
|
color: Colors.transparent, |
||||||
|
child: Column( |
||||||
|
mainAxisSize: MainAxisSize.min, |
||||||
|
children: <Widget>[ |
||||||
|
isInverted ? pain : Container(), |
||||||
|
Expanded( |
||||||
|
child: Stack( |
||||||
|
children: <Widget>[ |
||||||
|
ClipRRect( |
||||||
|
borderRadius: BorderRadius.all(Radius.circular(5)), |
||||||
|
child: Container( |
||||||
|
color: widget.backgroundColor, |
||||||
|
height: widget.menuHeight, |
||||||
|
), |
||||||
|
), |
||||||
|
row, |
||||||
|
], |
||||||
|
), |
||||||
|
), |
||||||
|
isInverted |
||||||
|
? Container() |
||||||
|
: CustomPaint( |
||||||
|
size: Size(_curPageWidth, _triangleHeight), |
||||||
|
painter: TrianglePainter( |
||||||
|
color: widget.backgroundColor, |
||||||
|
position: position, |
||||||
|
size: button.size), |
||||||
|
), |
||||||
|
], |
||||||
|
), |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
return MediaQuery.removePadding( |
||||||
|
context: context, |
||||||
|
removeTop: true, |
||||||
|
removeBottom: true, |
||||||
|
removeLeft: true, |
||||||
|
removeRight: true, |
||||||
|
child: Builder( |
||||||
|
builder: (BuildContext context) { |
||||||
|
return CustomSingleChildLayout( |
||||||
|
// 这里计算偏移量 |
||||||
|
delegate: _PopupMenuRouteLayout( |
||||||
|
position, |
||||||
|
widget.menuHeight + _triangleHeight, |
||||||
|
Directionality.of(widget.btnContext), |
||||||
|
widget._width, |
||||||
|
widget.menuWidth), |
||||||
|
child: SizedBox( |
||||||
|
height: widget.menuHeight + _triangleHeight, |
||||||
|
width: _curPageWidth, |
||||||
|
child: view()), |
||||||
|
); |
||||||
|
}, |
||||||
|
), |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
Widget _buildList(int _curPageChildCount, double _curPageWidth, |
||||||
|
double _curArrowWidth, int _curArrowCount) { |
||||||
|
return ListView.separated( |
||||||
|
shrinkWrap: true, |
||||||
|
physics: NeverScrollableScrollPhysics(), |
||||||
|
scrollDirection: Axis.horizontal, |
||||||
|
itemCount: _curPageChildCount, |
||||||
|
itemBuilder: (BuildContext context, int index) { |
||||||
|
return InkWell( |
||||||
|
onTap: () { |
||||||
|
Navigator.pop( |
||||||
|
context, _curPage * widget._pageMaxChildCount + index); |
||||||
|
}, |
||||||
|
child: SizedBox( |
||||||
|
width: (_curPageWidth - |
||||||
|
_curArrowWidth - |
||||||
|
(_curPageChildCount - 1 + _curArrowCount) * |
||||||
|
_separatorWidth) / |
||||||
|
_curPageChildCount, |
||||||
|
height: widget.menuHeight, |
||||||
|
child: Center( |
||||||
|
child: Text( |
||||||
|
widget.actions[_curPage * widget._pageMaxChildCount + index], |
||||||
|
style: TextStyle(color: Colors.white, fontSize: 16), |
||||||
|
), |
||||||
|
), |
||||||
|
), |
||||||
|
); |
||||||
|
}, |
||||||
|
separatorBuilder: (BuildContext context, int index) { |
||||||
|
return Container( |
||||||
|
width: 1, |
||||||
|
height: widget.menuHeight, |
||||||
|
color: Colors.grey, |
||||||
|
); |
||||||
|
}, |
||||||
|
); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Positioning of the menu on the screen. |
||||||
|
class _PopupMenuRouteLayout extends SingleChildLayoutDelegate { |
||||||
|
_PopupMenuRouteLayout(this.position, this.selectedItemOffset, |
||||||
|
this.textDirection, this.width, this.menuWidth); |
||||||
|
|
||||||
|
// Rectangle of underlying button, relative to the overlay's dimensions. |
||||||
|
final RelativeRect position; |
||||||
|
|
||||||
|
// The distance from the top of the menu to the middle of selected item. |
||||||
|
// |
||||||
|
// This will be null if there's no item to position in this way. |
||||||
|
final double selectedItemOffset; |
||||||
|
|
||||||
|
// Whether to prefer going to the left or to the right. |
||||||
|
final TextDirection textDirection; |
||||||
|
|
||||||
|
final double width; |
||||||
|
final double menuWidth; |
||||||
|
|
||||||
|
// We put the child wherever position specifies, so long as it will fit within |
||||||
|
// the specified parent size padded (inset) by 8. If necessary, we adjust the |
||||||
|
// child's position so that it fits. |
||||||
|
|
||||||
|
@override |
||||||
|
BoxConstraints getConstraintsForChild(BoxConstraints constraints) { |
||||||
|
// The menu can be at most the size of the overlay minus 8.0 pixels in each |
||||||
|
// direction. |
||||||
|
return BoxConstraints.loose(constraints.biggest - |
||||||
|
const Offset(_kMenuScreenPadding * 2.0, _kMenuScreenPadding * 2.0)); |
||||||
|
} |
||||||
|
|
||||||
|
@override |
||||||
|
Offset getPositionForChild(Size size, Size childSize) { |
||||||
|
// size: The size of the overlay. |
||||||
|
// childSize: The size of the menu, when fully open, as determined by |
||||||
|
// getConstraintsForChild. |
||||||
|
|
||||||
|
// Find the ideal vertical position. |
||||||
|
double y; |
||||||
|
if (selectedItemOffset == null) { |
||||||
|
y = position.top; |
||||||
|
} else { |
||||||
|
y = position.top + |
||||||
|
(size.height - position.top - position.bottom) / 2.0 - |
||||||
|
selectedItemOffset; |
||||||
|
} |
||||||
|
|
||||||
|
// Find the ideal horizontal position. |
||||||
|
double x; |
||||||
|
if (position.left > position.right) { |
||||||
|
// Menu button is closer to the right edge, so grow to the left, aligned to the right edge. |
||||||
|
// x = childSize.width - (size.width - position.right); |
||||||
|
x = position.left + width - childSize.width; |
||||||
|
} else if (position.left < position.right) { |
||||||
|
// Menu button is closer to the left edge, so grow to the right, aligned to the left edge. |
||||||
|
if (width > childSize.width) { |
||||||
|
x = position.left + (childSize.width - menuWidth) / 2; |
||||||
|
} else |
||||||
|
x = position.left; |
||||||
|
} else { |
||||||
|
x = position.right - width / 2 - childSize.width / 2; |
||||||
|
} |
||||||
|
// Avoid going outside an area defined as the rectangle 8.0 pixels from the |
||||||
|
// edge of the screen in every direction. |
||||||
|
if (x < _kMenuScreenPadding) |
||||||
|
x = _kMenuScreenPadding; |
||||||
|
else if (x + childSize.width > size.width - _kMenuScreenPadding) |
||||||
|
x = size.width - childSize.width - _kMenuScreenPadding; |
||||||
|
if (y < _kMenuScreenPadding) |
||||||
|
y = _kMenuScreenPadding; |
||||||
|
else if (y + childSize.height > size.height - _kMenuScreenPadding) |
||||||
|
y = size.height - childSize.height; |
||||||
|
else if (y < childSize.height * 2) { |
||||||
|
y = position.top + childSize.height; |
||||||
|
} |
||||||
|
return Offset(x, y); |
||||||
|
} |
||||||
|
|
||||||
|
@override |
||||||
|
bool shouldRelayout(_PopupMenuRouteLayout oldDelegate) { |
||||||
|
return position != oldDelegate.position; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,3 @@ |
|||||||
|
abstract class OnChatMessage{ |
||||||
|
void onMessage(txt); |
||||||
|
} |
@ -0,0 +1,20 @@ |
|||||||
|
import 'on_chat_message.dart'; |
||||||
|
|
||||||
|
class OnChatMsgInstance{ |
||||||
|
factory OnChatMsgInstance() => _getInstance(); |
||||||
|
|
||||||
|
static OnChatMsgInstance get instance => _getInstance(); |
||||||
|
|
||||||
|
static OnChatMsgInstance _instance; |
||||||
|
|
||||||
|
OnChatMessage onChatMessage; |
||||||
|
|
||||||
|
OnChatMsgInstance._internal(); |
||||||
|
|
||||||
|
static OnChatMsgInstance _getInstance(){ |
||||||
|
if(_instance == null){ |
||||||
|
_instance = OnChatMsgInstance._internal(); |
||||||
|
} |
||||||
|
return _instance; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,55 @@ |
|||||||
|
import 'package:extended_text/extended_text.dart'; |
||||||
|
import 'package:flutter/cupertino.dart'; |
||||||
|
import 'package:flutter/material.dart'; |
||||||
|
|
||||||
|
import 'package:flutter/services.dart';import 'package:huixiang/message/im/im_view/text_span_builder.dart'; |
||||||
|
|
||||||
|
import 'magic_pop.dart'; |
||||||
|
|
||||||
|
class TextItemContainer extends StatefulWidget { |
||||||
|
final String text; |
||||||
|
final String action; |
||||||
|
final bool isMyself; |
||||||
|
|
||||||
|
TextItemContainer({this.text, this.action, this.isMyself = true}); |
||||||
|
|
||||||
|
@override |
||||||
|
_TextItemContainerState createState() => _TextItemContainerState(); |
||||||
|
} |
||||||
|
|
||||||
|
class _TextItemContainerState extends State<TextItemContainer> { |
||||||
|
TextSpanBuilder _spanBuilder = TextSpanBuilder(); |
||||||
|
|
||||||
|
@override |
||||||
|
Widget build(BuildContext context) { |
||||||
|
return MagicPop( |
||||||
|
onValueChanged: (int value) { |
||||||
|
switch (value) { |
||||||
|
case 0: |
||||||
|
Clipboard.setData(new ClipboardData(text: widget.text)); |
||||||
|
break; |
||||||
|
case 3: |
||||||
|
break; |
||||||
|
} |
||||||
|
}, |
||||||
|
pressType: PressType.longPress, |
||||||
|
actions: ['复制', '转发', '收藏', '撤回', '删除'], |
||||||
|
child: new Container( |
||||||
|
// width: widget.text.length > 24 ? (MediaQuery.of(context).size.width - 66) - 100 : null, |
||||||
|
// padding: EdgeInsets.all(5.0), |
||||||
|
// decoration: BoxDecoration( |
||||||
|
// color: widget.isMyself ? Color(0xff98E165) : Colors.white, |
||||||
|
// borderRadius: BorderRadius.all(Radius.circular(5.0)), |
||||||
|
// ), |
||||||
|
// margin: EdgeInsets.only(right: 7.0), |
||||||
|
child: ExtendedText( |
||||||
|
widget.text ?? '文字为空', |
||||||
|
maxLines: 99, |
||||||
|
overflow: TextOverflow.ellipsis, |
||||||
|
specialTextSpanBuilder: _spanBuilder, |
||||||
|
style: TextStyle(fontSize: 17,color: Colors.white), |
||||||
|
), |
||||||
|
), |
||||||
|
); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,33 @@ |
|||||||
|
import 'package:extended_text_library/extended_text_library.dart'; |
||||||
|
import 'package:flutter/material.dart'; |
||||||
|
|
||||||
|
import 'emoji_text.dart'; |
||||||
|
|
||||||
|
class TextSpanBuilder extends SpecialTextSpanBuilder { |
||||||
|
final bool showAtBackground; |
||||||
|
|
||||||
|
TextSpanBuilder({ |
||||||
|
this.showAtBackground: false, |
||||||
|
}); |
||||||
|
|
||||||
|
@override |
||||||
|
TextSpan build(String data, {TextStyle textStyle, onTap}) { |
||||||
|
TextSpan result = super.build(data, textStyle: textStyle, onTap: onTap); |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
@override |
||||||
|
SpecialText createSpecialText(String flag, |
||||||
|
{TextStyle textStyle, SpecialTextGestureTapCallback onTap, int index}) { |
||||||
|
if (flag == null || flag == "") return null; |
||||||
|
|
||||||
|
if (isStart(flag, EmojiText.flag)) { |
||||||
|
return EmojiText(textStyle, start: index - (EmojiText.flag.length - 1)); |
||||||
|
} |
||||||
|
return null; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
class SpecialTextStyle { |
||||||
|
TextRange textRange; |
||||||
|
} |
@ -0,0 +1,45 @@ |
|||||||
|
import 'package:flutter/material.dart'; |
||||||
|
|
||||||
|
class TrianglePainter extends CustomPainter { |
||||||
|
Paint _paint; |
||||||
|
final Color color; |
||||||
|
final RelativeRect position; |
||||||
|
final Size size; |
||||||
|
final double radius; |
||||||
|
final bool isInverted; |
||||||
|
final double screenWidth; |
||||||
|
|
||||||
|
TrianglePainter( |
||||||
|
{@required this.color, |
||||||
|
@required this.position, |
||||||
|
@required this.size, |
||||||
|
this.radius = 20, |
||||||
|
this.isInverted = false, |
||||||
|
this.screenWidth}) { |
||||||
|
_paint = Paint() |
||||||
|
..style = PaintingStyle.fill |
||||||
|
..color = color |
||||||
|
..strokeWidth = 10 |
||||||
|
..isAntiAlias = true; |
||||||
|
} |
||||||
|
|
||||||
|
@override |
||||||
|
void paint(Canvas canvas, Size size) { |
||||||
|
var path = Path(); |
||||||
|
path.moveTo(size.width - this.size.width + this.size.width / 1.5, |
||||||
|
isInverted ? 0 : size.height); |
||||||
|
path.lineTo( |
||||||
|
size.width - this.size.width + this.size.width / 1.5 - radius / 3, |
||||||
|
isInverted ? size.height : 0); |
||||||
|
path.lineTo( |
||||||
|
size.width - this.size.width + this.size.width / 1.5 + radius / 3, |
||||||
|
isInverted ? size.height : 0); |
||||||
|
path.close(); |
||||||
|
canvas.drawPath(path, _paint); |
||||||
|
} |
||||||
|
|
||||||
|
@override |
||||||
|
bool shouldRepaint(CustomPainter oldDelegate) { |
||||||
|
return true; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,323 @@ |
|||||||
|
import 'dart:convert'; |
||||||
|
|
||||||
|
import 'package:dio/dio.dart'; |
||||||
|
import 'package:flutter/material.dart'; |
||||||
|
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; |
||||||
|
import 'package:huixiang/generated/l10n.dart'; |
||||||
|
import 'package:huixiang/retrofit/data/base_data.dart'; |
||||||
|
import 'package:huixiang/retrofit/data/message.dart'; |
||||||
|
import 'package:huixiang/retrofit/data/page.dart'; |
||||||
|
import 'package:huixiang/retrofit/retrofit_api.dart'; |
||||||
|
import 'package:huixiang/utils/font_weight.dart'; |
||||||
|
import 'package:huixiang/view_widget/classic_header.dart'; |
||||||
|
import 'package:huixiang/view_widget/custom_image.dart'; |
||||||
|
import 'package:huixiang/view_widget/my_appbar.dart'; |
||||||
|
import 'package:huixiang/view_widget/my_footer.dart'; |
||||||
|
import 'package:huixiang/view_widget/no_data_view.dart'; |
||||||
|
import 'package:huixiang/view_widget/round_button.dart'; |
||||||
|
import 'package:pull_to_refresh/pull_to_refresh.dart'; |
||||||
|
import 'package:shared_preferences/shared_preferences.dart'; |
||||||
|
import 'package:flutter_screenutil/flutter_screenutil.dart'; |
||||||
|
|
||||||
|
class SystemNotice extends StatefulWidget { |
||||||
|
|
||||||
|
@override |
||||||
|
State<StatefulWidget> createState() { |
||||||
|
return _SystemNotice(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
class _SystemNotice extends State<SystemNotice> { |
||||||
|
ApiService apiService; |
||||||
|
int pageNum = 1; |
||||||
|
List<Message> messages = []; |
||||||
|
int msgType = 0; |
||||||
|
|
||||||
|
// String parenId = "0"; |
||||||
|
var commentFocus = FocusNode(); |
||||||
|
String hintText = S.current.liuxianinjingcaidepinglunba; |
||||||
|
bool isKeyBoardShow = false; |
||||||
|
final GlobalKey commentKey = GlobalKey(); |
||||||
|
final GlobalKey inputKey = GlobalKey(); |
||||||
|
final TextEditingController commentTextController = TextEditingController(); |
||||||
|
int indexMsg = 0; |
||||||
|
|
||||||
|
@override |
||||||
|
void initState() { |
||||||
|
super.initState(); |
||||||
|
// msgType = widget.arguments["msgType"]; |
||||||
|
|
||||||
|
SharedPreferences.getInstance().then((value) { |
||||||
|
apiService = |
||||||
|
ApiService(Dio(), token: value.getString("token"), context: context); |
||||||
|
queryMessage(); |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
_refresh() { |
||||||
|
pageNum = 1; |
||||||
|
queryMessage(); |
||||||
|
} |
||||||
|
|
||||||
|
queryMessage() async { |
||||||
|
BaseData<PageInfo<Message>> baseData = await apiService.msgList({ |
||||||
|
"pageNum": pageNum, |
||||||
|
"pageSize": 10, |
||||||
|
"searchKey": "", |
||||||
|
"state": "", |
||||||
|
"typed": "" |
||||||
|
}).catchError((onError) { |
||||||
|
_refreshController.loadFailed(); |
||||||
|
_refreshController.refreshFailed(); |
||||||
|
}); |
||||||
|
|
||||||
|
if (baseData != null && baseData.isSuccess) { |
||||||
|
if (pageNum == 1) { |
||||||
|
messages.clear(); |
||||||
|
} |
||||||
|
List<Message> message = []; |
||||||
|
message.addAll(baseData.data.list); |
||||||
|
message.forEach((element) { |
||||||
|
if (element.typed == 2 || element.typed == 3) { |
||||||
|
messages.add(element); |
||||||
|
} |
||||||
|
}); |
||||||
|
_refreshController.loadComplete(); |
||||||
|
_refreshController.refreshCompleted(); |
||||||
|
if (mounted) setState(() {}); |
||||||
|
if (pageNum * 10 > int.tryParse(baseData.data.total)) { |
||||||
|
_refreshController.loadNoData(); |
||||||
|
} else { |
||||||
|
pageNum += 1; |
||||||
|
} |
||||||
|
} else { |
||||||
|
_refreshController.loadFailed(); |
||||||
|
_refreshController.refreshFailed(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
RefreshController _refreshController = RefreshController(); |
||||||
|
|
||||||
|
@override |
||||||
|
Widget build(BuildContext context) { |
||||||
|
return Scaffold( |
||||||
|
body: SmartRefresher( |
||||||
|
enablePullDown: true, |
||||||
|
enablePullUp: true, |
||||||
|
header: MyHeader(), |
||||||
|
physics: BouncingScrollPhysics(), |
||||||
|
footer: CustomFooter( |
||||||
|
loadStyle: LoadStyle.ShowWhenLoading, |
||||||
|
builder: (BuildContext context, LoadStatus mode) { |
||||||
|
return (messages.length == 0) ? Container() : MyFooter(mode); |
||||||
|
}, |
||||||
|
), |
||||||
|
controller: _refreshController, |
||||||
|
onRefresh: _refresh, |
||||||
|
onLoading: () { |
||||||
|
queryMessage(); |
||||||
|
}, |
||||||
|
child: Container( |
||||||
|
child: SingleChildScrollView( |
||||||
|
physics: BouncingScrollPhysics(), |
||||||
|
child: Container( |
||||||
|
child: Column( |
||||||
|
children: [ |
||||||
|
Container( |
||||||
|
color: Colors.white, |
||||||
|
padding: EdgeInsets.only( |
||||||
|
top: MediaQuery.of(context).padding.top + 10.h, |
||||||
|
bottom: 10.h, |
||||||
|
right: 16.w), |
||||||
|
child: Row( |
||||||
|
children: [ |
||||||
|
GestureDetector( |
||||||
|
behavior: HitTestBehavior.opaque, |
||||||
|
onTap: () { |
||||||
|
Navigator.of(context).pop(); |
||||||
|
}, |
||||||
|
child: Container( |
||||||
|
alignment: Alignment.centerRight, |
||||||
|
margin: EdgeInsets.only( |
||||||
|
left: 12, |
||||||
|
), |
||||||
|
padding: EdgeInsets.all(6), |
||||||
|
child: Icon( |
||||||
|
Icons.arrow_back_ios, |
||||||
|
color: Colors.black, |
||||||
|
size: 24, |
||||||
|
), |
||||||
|
), |
||||||
|
), |
||||||
|
Text( |
||||||
|
"消息通知", |
||||||
|
style: TextStyle( |
||||||
|
color: Colors.black, |
||||||
|
fontSize: 18.sp, |
||||||
|
fontWeight: MyFontWeight.bold, |
||||||
|
), |
||||||
|
), |
||||||
|
], |
||||||
|
), |
||||||
|
), |
||||||
|
buildMessage() |
||||||
|
], |
||||||
|
), |
||||||
|
), |
||||||
|
), |
||||||
|
), |
||||||
|
), |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
Widget buildMessage() { |
||||||
|
return Container( |
||||||
|
color: Colors.white, |
||||||
|
width: double.infinity, |
||||||
|
child: Column( |
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceAround, |
||||||
|
crossAxisAlignment: CrossAxisAlignment.start, |
||||||
|
children: [ |
||||||
|
(messages == null || messages.length == 0) |
||||||
|
? NoDataView( |
||||||
|
src: "assets/image/icon_empty.webp", |
||||||
|
isShowBtn: false, |
||||||
|
text: S.of(context).haimeiyouxiaoxi, |
||||||
|
fontSize: 16.sp, |
||||||
|
margin: EdgeInsets.only(top: 120.h), |
||||||
|
) |
||||||
|
: ListView.builder( |
||||||
|
padding: EdgeInsets.only(top: 16), |
||||||
|
itemCount: messages.length, |
||||||
|
shrinkWrap: true, |
||||||
|
physics: NeverScrollableScrollPhysics(), |
||||||
|
itemBuilder: (context, position) { |
||||||
|
return GestureDetector( |
||||||
|
behavior: HitTestBehavior.opaque, |
||||||
|
onTap: () { |
||||||
|
if (messages[position].typed == 2) |
||||||
|
Navigator.of(context).pushNamed( |
||||||
|
'/router/system_details', |
||||||
|
arguments: {"msgType": 2}); |
||||||
|
else if (messages[position].typed == 3) |
||||||
|
Navigator.of(context).pushNamed( |
||||||
|
'/router/system_details', |
||||||
|
arguments: {"msgType": 3}); |
||||||
|
}, |
||||||
|
child: buildMessageItem(messages[position]), |
||||||
|
); |
||||||
|
}), |
||||||
|
], |
||||||
|
)); |
||||||
|
} |
||||||
|
|
||||||
|
Widget buildMessageItem(Message message) { |
||||||
|
return Container( |
||||||
|
margin: EdgeInsets.only(top: 8.h, bottom: 8.h,left: 16.w,right: 17.w), |
||||||
|
child: Column( |
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween, |
||||||
|
crossAxisAlignment: CrossAxisAlignment.start, |
||||||
|
children: [ |
||||||
|
Row( |
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween, |
||||||
|
crossAxisAlignment: CrossAxisAlignment.start, |
||||||
|
children: [ |
||||||
|
Image.asset( |
||||||
|
(message.typed == 1) |
||||||
|
? "assets/image/icon_order.webp" |
||||||
|
: (message.typed == 2) |
||||||
|
? "assets/image/icon_order.webp" |
||||||
|
: "assets/image/icon_cz.webp", |
||||||
|
width: 24.w, |
||||||
|
height: 24.h, |
||||||
|
), |
||||||
|
SizedBox( |
||||||
|
width: 8.w, |
||||||
|
), |
||||||
|
Expanded( |
||||||
|
child: Column( |
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween, |
||||||
|
crossAxisAlignment: CrossAxisAlignment.start, |
||||||
|
children: [ |
||||||
|
Row( |
||||||
|
children: [ |
||||||
|
Expanded( |
||||||
|
child: Text( |
||||||
|
(message.typed == 1) |
||||||
|
? S.of(context).xitongtongzhi |
||||||
|
: (message.typed == 2) |
||||||
|
? S.of(context).dingdanxiaoxi |
||||||
|
: S.of(context).chongzhixiaoxi, |
||||||
|
style: TextStyle( |
||||||
|
fontSize: 14.sp, |
||||||
|
fontWeight: MyFontWeight.semi_bold, |
||||||
|
color: Color(0xFF060606), |
||||||
|
), |
||||||
|
)), |
||||||
|
Text( |
||||||
|
message.updateTime, |
||||||
|
style: TextStyle( |
||||||
|
fontSize: 10.sp, |
||||||
|
color: Color(0xFFA29E9E), |
||||||
|
), |
||||||
|
), |
||||||
|
], |
||||||
|
), |
||||||
|
SizedBox( |
||||||
|
height: 24.h, |
||||||
|
), |
||||||
|
(message.typed != 3) |
||||||
|
? Row( |
||||||
|
mainAxisAlignment: MainAxisAlignment.center, |
||||||
|
// crossAxisAlignment: CrossAxisAlignment.start, |
||||||
|
children: [ |
||||||
|
Expanded( |
||||||
|
child: Text( |
||||||
|
S.of(context).ninyouyigexindedingdan, |
||||||
|
style: TextStyle( |
||||||
|
fontSize: 12.sp, |
||||||
|
color: Color(0xFF353535), |
||||||
|
), |
||||||
|
), |
||||||
|
), |
||||||
|
Icon( |
||||||
|
Icons.keyboard_arrow_right, |
||||||
|
size: 24, |
||||||
|
), |
||||||
|
], |
||||||
|
) |
||||||
|
: Row( |
||||||
|
mainAxisAlignment: MainAxisAlignment.center, |
||||||
|
crossAxisAlignment: CrossAxisAlignment.end, |
||||||
|
children: [ |
||||||
|
Expanded( |
||||||
|
child: Text( |
||||||
|
message.content, |
||||||
|
style: TextStyle( |
||||||
|
fontSize: 12.sp, |
||||||
|
color: Color(0xFF353535), |
||||||
|
), |
||||||
|
)), |
||||||
|
|
||||||
|
Icon( |
||||||
|
Icons.keyboard_arrow_right, |
||||||
|
size: 24, |
||||||
|
), |
||||||
|
], |
||||||
|
), |
||||||
|
Container( |
||||||
|
margin: EdgeInsets.only(top: 16.h, bottom: 8.h), |
||||||
|
height: 1.h, |
||||||
|
width: double.infinity, |
||||||
|
color: Color(0xFFF7F7F7), |
||||||
|
), |
||||||
|
], |
||||||
|
), |
||||||
|
), |
||||||
|
], |
||||||
|
), |
||||||
|
], |
||||||
|
), |
||||||
|
); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,357 @@ |
|||||||
|
import 'dart:ui'; |
||||||
|
|
||||||
|
import 'package:flutter/material.dart'; |
||||||
|
import 'package:flutter/rendering.dart'; |
||||||
|
import 'package:flutter/services.dart'; |
||||||
|
import 'package:flutter_screenutil/flutter_screenutil.dart'; |
||||||
|
import 'package:huixiang/retrofit/retrofit_api.dart'; |
||||||
|
import 'package:huixiang/view_widget/my_appbar.dart'; |
||||||
|
import 'package:flutter/cupertino.dart'; |
||||||
|
|
||||||
|
import '../../generated/l10n.dart'; |
||||||
|
import '../../retrofit/data/base_data.dart'; |
||||||
|
import '../../utils/font_weight.dart'; |
||||||
|
|
||||||
|
class NoticeSetting extends StatefulWidget { |
||||||
|
@override |
||||||
|
State<StatefulWidget> createState() { |
||||||
|
return _NoticeSetting(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
class _NoticeSetting extends State<NoticeSetting> { |
||||||
|
ApiService apiService; |
||||||
|
bool commentSetting = true; |
||||||
|
bool followSetting = true; |
||||||
|
bool likesSetting = false; |
||||||
|
int index = 0; |
||||||
|
|
||||||
|
@override |
||||||
|
void initState() { |
||||||
|
super.initState(); |
||||||
|
} |
||||||
|
|
||||||
|
@override |
||||||
|
Widget build(BuildContext context) { |
||||||
|
return Scaffold( |
||||||
|
backgroundColor: Color(0xFFF9FAF7), |
||||||
|
appBar: MyAppBar( |
||||||
|
title: "通知设置", |
||||||
|
titleColor: Colors.black, |
||||||
|
titleSize: 18.sp, |
||||||
|
background: Colors.white, |
||||||
|
leading: true, |
||||||
|
leadingColor: Colors.black, |
||||||
|
), |
||||||
|
body: Container( |
||||||
|
color: Color(0xFFF9FAF7), |
||||||
|
child: Column( |
||||||
|
children: [ |
||||||
|
SizedBox( |
||||||
|
height: 12, |
||||||
|
), |
||||||
|
// Container( |
||||||
|
// decoration: BoxDecoration( |
||||||
|
// color: Colors.white, |
||||||
|
// ), |
||||||
|
// padding: EdgeInsets.only( |
||||||
|
// left: 16.w, right: 16.w, top: 14.h, bottom: 16.h), |
||||||
|
// child: Row( |
||||||
|
// children: [ |
||||||
|
// Expanded( |
||||||
|
// child: Text( |
||||||
|
// S.of(context).pinglun, |
||||||
|
// style: TextStyle( |
||||||
|
// fontSize: 15.sp, |
||||||
|
// color: Color(0xFF353535), |
||||||
|
// fontWeight: MyFontWeight.semi_bold, |
||||||
|
// ), |
||||||
|
// )), |
||||||
|
// CupertinoSwitch( |
||||||
|
// value: (commentSetting), |
||||||
|
// activeColor: Color(0xFF32A060), |
||||||
|
// onChanged: (bool value) { |
||||||
|
// setState(() { |
||||||
|
// commentSetting = !commentSetting; |
||||||
|
// }); |
||||||
|
// }, |
||||||
|
// ), |
||||||
|
// ], |
||||||
|
// ), |
||||||
|
// ), |
||||||
|
// Container( |
||||||
|
// decoration: BoxDecoration( |
||||||
|
// color: Colors.white, |
||||||
|
// ), |
||||||
|
// padding: EdgeInsets.only( |
||||||
|
// left: 16.w, right: 16.w, top: 14.h, bottom: 16.h), |
||||||
|
// child: Row( |
||||||
|
// children: [ |
||||||
|
// Expanded( |
||||||
|
// child: Text( |
||||||
|
// S.of(context).guanzhu, |
||||||
|
// style: TextStyle( |
||||||
|
// fontSize: 15.sp, |
||||||
|
// color: Color(0xFF353535), |
||||||
|
// fontWeight: MyFontWeight.semi_bold, |
||||||
|
// ), |
||||||
|
// )), |
||||||
|
// CupertinoSwitch( |
||||||
|
// value: (followSetting), |
||||||
|
// activeColor: Color(0xFF32A060), |
||||||
|
// onChanged: (bool value) { |
||||||
|
// setState(() { |
||||||
|
// followSetting = !followSetting; |
||||||
|
// }); |
||||||
|
// }, |
||||||
|
// ), |
||||||
|
// ], |
||||||
|
// ), |
||||||
|
// ), |
||||||
|
// Container( |
||||||
|
// decoration: BoxDecoration( |
||||||
|
// color: Colors.white, |
||||||
|
// ), |
||||||
|
// padding: EdgeInsets.only( |
||||||
|
// left: 16.w, right: 16.w, top: 14.h, bottom: 16.h), |
||||||
|
// child: Row( |
||||||
|
// children: [ |
||||||
|
// Expanded( |
||||||
|
// child: Text( |
||||||
|
// S.of(context).dianzan, |
||||||
|
// style: TextStyle( |
||||||
|
// fontSize: 15.sp, |
||||||
|
// color: Color(0xFF353535), |
||||||
|
// fontWeight: MyFontWeight.semi_bold, |
||||||
|
// ), |
||||||
|
// )), |
||||||
|
// CupertinoSwitch( |
||||||
|
// value: (likesSetting), |
||||||
|
// activeColor: Color(0xFF32A060), |
||||||
|
// onChanged: (bool value) { |
||||||
|
// setState(() { |
||||||
|
// likesSetting = !likesSetting; |
||||||
|
// }); |
||||||
|
// }, |
||||||
|
// ), |
||||||
|
// ], |
||||||
|
// ), |
||||||
|
// ), |
||||||
|
settingItem(S.of(context).pinglun,commentSetting,(){ |
||||||
|
setState(() { |
||||||
|
commentSetting = !commentSetting; |
||||||
|
}); |
||||||
|
}), |
||||||
|
settingItem(S.of(context).guanzhu,followSetting,(){ |
||||||
|
setState(() { |
||||||
|
followSetting = !followSetting; |
||||||
|
}); |
||||||
|
}), |
||||||
|
settingItem(S.of(context).dianzan,likesSetting,(){ |
||||||
|
setState(() { |
||||||
|
likesSetting = !likesSetting; |
||||||
|
}); |
||||||
|
}), |
||||||
|
SizedBox( |
||||||
|
height: 12, |
||||||
|
), |
||||||
|
Expanded( |
||||||
|
child: Container( |
||||||
|
decoration: BoxDecoration( |
||||||
|
color: Colors.white, |
||||||
|
), |
||||||
|
padding: EdgeInsets.only( |
||||||
|
left: 16.w, right: 16.w, top: 14.h, bottom: 16.h), |
||||||
|
child: Row( |
||||||
|
mainAxisAlignment: MainAxisAlignment.center, |
||||||
|
crossAxisAlignment: CrossAxisAlignment.start, |
||||||
|
children: [ |
||||||
|
Expanded(child: Text( |
||||||
|
"谁可以私信我", |
||||||
|
style: TextStyle( |
||||||
|
fontSize: 15.sp, |
||||||
|
color: Color(0xFF353535), |
||||||
|
fontWeight: MyFontWeight.semi_bold, |
||||||
|
), |
||||||
|
)), |
||||||
|
GestureDetector( |
||||||
|
onTap: (){ |
||||||
|
showAlertDialog(); |
||||||
|
}, |
||||||
|
child: Text( |
||||||
|
index == 0?"默认接收":(index == 1 ? "互关好友": "不接收"), |
||||||
|
style: TextStyle( |
||||||
|
fontSize: 14.sp, |
||||||
|
color: Color(0xFF353535), |
||||||
|
fontWeight: MyFontWeight.regular, |
||||||
|
), |
||||||
|
), |
||||||
|
), |
||||||
|
GestureDetector( |
||||||
|
behavior: HitTestBehavior.opaque, |
||||||
|
onTap: (){ |
||||||
|
showAlertDialog(); |
||||||
|
}, |
||||||
|
child: Image.asset( |
||||||
|
"assets/image/icon_right_z.webp", |
||||||
|
height:16, |
||||||
|
width:16, |
||||||
|
color: Colors.black, |
||||||
|
), |
||||||
|
), |
||||||
|
], |
||||||
|
), |
||||||
|
), |
||||||
|
) |
||||||
|
], |
||||||
|
), |
||||||
|
), |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
Widget settingItem(text, buttonSet,fun) { |
||||||
|
return Container( |
||||||
|
decoration: BoxDecoration( |
||||||
|
color: Colors.white, |
||||||
|
), |
||||||
|
padding: |
||||||
|
EdgeInsets.only(left: 16.w, right: 16.w, top: 14.h, bottom: 16.h), |
||||||
|
child: Row( |
||||||
|
children: [ |
||||||
|
Expanded( |
||||||
|
child: Text( |
||||||
|
text, |
||||||
|
style: TextStyle( |
||||||
|
fontSize: 15.sp, |
||||||
|
color: Color(0xFF353535), |
||||||
|
fontWeight: MyFontWeight.semi_bold, |
||||||
|
), |
||||||
|
)), |
||||||
|
CupertinoSwitch( |
||||||
|
value: (buttonSet), |
||||||
|
activeColor: Color(0xFF32A060), |
||||||
|
onChanged: (bool value) { |
||||||
|
fun(); |
||||||
|
}, |
||||||
|
), |
||||||
|
], |
||||||
|
), |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
///私信接受设置弹窗 |
||||||
|
showAlertDialog() { |
||||||
|
showModalBottomSheet( |
||||||
|
builder: (BuildContext context) { |
||||||
|
return StatefulBuilder(builder: ( |
||||||
|
context, |
||||||
|
state, |
||||||
|
) { |
||||||
|
return WillPopScope( |
||||||
|
///点击背景不收起弹窗; |
||||||
|
// onWillPop: () async => false, |
||||||
|
child: Container( |
||||||
|
width: double.infinity, |
||||||
|
height: 225.h, |
||||||
|
padding: |
||||||
|
EdgeInsets.only(left: 16.w, top:21.h), |
||||||
|
decoration: new BoxDecoration( |
||||||
|
color: Colors.white, |
||||||
|
borderRadius: BorderRadius.only( |
||||||
|
topLeft: Radius.circular(8), |
||||||
|
topRight: Radius.circular(8), |
||||||
|
), |
||||||
|
), |
||||||
|
child: SingleChildScrollView( |
||||||
|
physics: BouncingScrollPhysics(), |
||||||
|
child: Container( |
||||||
|
padding: EdgeInsets.only(right: 18.w), |
||||||
|
width: double.infinity, |
||||||
|
child: Column( |
||||||
|
mainAxisAlignment: MainAxisAlignment.start, |
||||||
|
crossAxisAlignment: CrossAxisAlignment.start, |
||||||
|
children: [ |
||||||
|
GestureDetector( |
||||||
|
behavior: HitTestBehavior.opaque, |
||||||
|
onTap: (){ |
||||||
|
setState((){ |
||||||
|
index = 0; |
||||||
|
Navigator.of(context).pop(); |
||||||
|
}); |
||||||
|
}, |
||||||
|
child:Container( |
||||||
|
width: double.infinity, |
||||||
|
padding: EdgeInsets.only(bottom: 23.h), |
||||||
|
child: Text( |
||||||
|
"默认接收", |
||||||
|
style: TextStyle( |
||||||
|
fontWeight: MyFontWeight.medium, |
||||||
|
fontSize: 16.sp, |
||||||
|
color: Color(0xFF353535), |
||||||
|
), |
||||||
|
), |
||||||
|
), |
||||||
|
), |
||||||
|
Container( |
||||||
|
color: Color(0xFFF7F7F7), |
||||||
|
width: double.infinity, |
||||||
|
height: 1.h, |
||||||
|
), |
||||||
|
GestureDetector( |
||||||
|
behavior: HitTestBehavior.opaque, |
||||||
|
onTap: (){ |
||||||
|
setState((){ |
||||||
|
index = 1; |
||||||
|
Navigator.of(context).pop(); |
||||||
|
}); |
||||||
|
}, |
||||||
|
child:Container( |
||||||
|
width: double.infinity, |
||||||
|
padding: EdgeInsets.only(top: 20.h,bottom: 23.h), |
||||||
|
child: Text( |
||||||
|
"互关好友", |
||||||
|
style: TextStyle( |
||||||
|
fontWeight: MyFontWeight.medium, |
||||||
|
fontSize: 16.sp, |
||||||
|
color: Color(0xFF353535), |
||||||
|
), |
||||||
|
), |
||||||
|
), |
||||||
|
), |
||||||
|
Container( |
||||||
|
color: Color(0xFFF7F7F7), |
||||||
|
width: double.infinity, |
||||||
|
height: 1.h, |
||||||
|
), |
||||||
|
GestureDetector( |
||||||
|
behavior: HitTestBehavior.opaque, |
||||||
|
onTap: (){ |
||||||
|
setState((){ |
||||||
|
index = 2; |
||||||
|
Navigator.of(context).pop(); |
||||||
|
}); |
||||||
|
}, |
||||||
|
child:Container( |
||||||
|
width: double.infinity, |
||||||
|
padding: EdgeInsets.only(top: 20.h), |
||||||
|
child: Text( |
||||||
|
"不接收", |
||||||
|
style: TextStyle( |
||||||
|
fontWeight: MyFontWeight.medium, |
||||||
|
fontSize: 16.sp, |
||||||
|
color: Color(0xFF353535), |
||||||
|
), |
||||||
|
), |
||||||
|
), |
||||||
|
), |
||||||
|
], |
||||||
|
), |
||||||
|
), |
||||||
|
), |
||||||
|
)); |
||||||
|
}); |
||||||
|
}, |
||||||
|
backgroundColor: Colors.transparent, |
||||||
|
context: context); |
||||||
|
} |
||||||
|
} |