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