first commit
This commit is contained in:
1
moehu/moehu_fontend/lib/widget/.pydio
Normal file
1
moehu/moehu_fontend/lib/widget/.pydio
Normal file
@@ -0,0 +1 @@
|
||||
59007402-c266-46da-982c-7256cce36767
|
||||
59
moehu/moehu_fontend/lib/widget/CellWidget.dart
Normal file
59
moehu/moehu_fontend/lib/widget/CellWidget.dart
Normal file
@@ -0,0 +1,59 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_modular/flutter_modular.dart';
|
||||
import 'package:peach/config/_.dart';
|
||||
import 'package:peach/utils/_.dart';
|
||||
|
||||
/// cell 组件
|
||||
class CellWidget extends StatelessWidget {
|
||||
final Widget leftIcon;
|
||||
final Widget leftText;
|
||||
|
||||
final Widget rightIcon;
|
||||
final Widget rightText;
|
||||
final Function onTap;
|
||||
final double padding;
|
||||
|
||||
CellWidget({
|
||||
this.leftIcon = const Text(""),
|
||||
this.leftText,
|
||||
this.rightIcon = const Icon(Icons.arrow_forward_ios,color: ColorConfig.NoActiveColor,size: 15,),
|
||||
this.rightText = const Text(""),
|
||||
this.onTap,
|
||||
this.padding = 15
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
alignment: Alignment.centerLeft,
|
||||
color: ColorConfig.WhiteBackColor,
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
onTap();
|
||||
},
|
||||
child: Container(
|
||||
padding: EdgeInsets.only(left: Screen.setFontSize(padding),right: Screen.setFontSize(padding)),
|
||||
height: Screen.setHeight(48),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Container(
|
||||
child: Row(
|
||||
children: [
|
||||
leftIcon,
|
||||
SizedBox(width: Screen.setWidth(10),),
|
||||
leftText
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
rightText,
|
||||
SizedBox(width: Screen.setWidth(10),),
|
||||
rightIcon
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
28
moehu/moehu_fontend/lib/widget/CircleTransparentIcon.dart
Normal file
28
moehu/moehu_fontend/lib/widget/CircleTransparentIcon.dart
Normal file
@@ -0,0 +1,28 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:peach/config/Colors.dart';
|
||||
import 'package:peach/config/Index.dart';
|
||||
import 'package:peach/utils/_.dart';
|
||||
|
||||
/*
|
||||
* 圆形背景的icon
|
||||
*/
|
||||
class CircleTransparentIcon extends StatelessWidget {
|
||||
final Widget icon;
|
||||
|
||||
const CircleTransparentIcon({this.icon});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Opacity(
|
||||
opacity: 0.5,
|
||||
child: CircleAvatar(
|
||||
backgroundColor: ColorConfig.BlackBackColor,
|
||||
child: Align(
|
||||
alignment: Alignment.center,
|
||||
child: this.icon,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
59
moehu/moehu_fontend/lib/widget/CommentList.dart
Normal file
59
moehu/moehu_fontend/lib/widget/CommentList.dart
Normal file
@@ -0,0 +1,59 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:peach/entity/CommenListEntity.dart';
|
||||
import 'package:peach/utils/_.dart';
|
||||
import 'package:peach/entity/_.dart';
|
||||
|
||||
import '_.dart';
|
||||
|
||||
/*
|
||||
* 评论样式
|
||||
*/
|
||||
class CommentList extends StatelessWidget {
|
||||
final List<CommenListEntity> comment;
|
||||
final Function reply;
|
||||
|
||||
const CommentList({this.comment, this.reply});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Column(
|
||||
children: [
|
||||
...comment.asMap().keys.map((e) {
|
||||
return view(comment[e]);
|
||||
}).toList(),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget view(CommenListEntity data) {
|
||||
if (data.child.length <= 0) {
|
||||
return CommentWidget(
|
||||
comment: data,
|
||||
reply: () {
|
||||
reply(data.userNickname, data.commentId);
|
||||
});
|
||||
} else {
|
||||
return Column(
|
||||
children: [
|
||||
CommentWidget(
|
||||
comment: data,
|
||||
reply: () {
|
||||
reply(data.userNickname, data.commentId);
|
||||
}),
|
||||
...data.child.asMap().keys.map((e) {
|
||||
return Container(
|
||||
margin: EdgeInsets.only(left: Screen.setWidth(40)),
|
||||
child: CommentWidget(
|
||||
child: data.child[e],
|
||||
userNickname: "@${data.child[e].commentToUsername } ",
|
||||
reply: () {
|
||||
reply(data.child[e].userNickname, data.commentId);
|
||||
}),
|
||||
);
|
||||
}).toList()
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
120
moehu/moehu_fontend/lib/widget/CommentWidget.dart
Normal file
120
moehu/moehu_fontend/lib/widget/CommentWidget.dart
Normal file
@@ -0,0 +1,120 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/gestures.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_modular/flutter_modular.dart';
|
||||
import 'package:peach/config/_.dart';
|
||||
import 'package:peach/entity/CommenListEntity.dart';
|
||||
import 'package:peach/entity/_.dart';
|
||||
import 'package:peach/utils/Screen.dart';
|
||||
import 'package:peach/widget/Panel.dart';
|
||||
|
||||
/*
|
||||
* 评论样式
|
||||
*/
|
||||
class CommentWidget extends StatelessWidget {
|
||||
final Function reply;
|
||||
final CommenListEntity comment;
|
||||
final String userNickname;
|
||||
|
||||
final Child child;
|
||||
|
||||
CommentWidget({this.reply, this.comment, this.child, this.userNickname = ""});
|
||||
|
||||
var data;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
data = comment != null ? comment : child;
|
||||
return Panel(
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
Modular.to.pushNamed("/personal/${comment.userId}");
|
||||
},
|
||||
child: Container(
|
||||
height: Screen.setWidth(35),
|
||||
width: Screen.setWidth(35),
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
image: DecorationImage(
|
||||
image: NetworkImage(data.userHeadImg),
|
||||
fit: BoxFit.fill,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
flex: 1,
|
||||
child: Container(
|
||||
margin: EdgeInsets.only(left: 15),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
data.userNickname,
|
||||
style: TextStyle(fontSize: 14),
|
||||
),
|
||||
Container(
|
||||
margin: EdgeInsets.only(top: 10),
|
||||
child: Text.rich(
|
||||
TextSpan(
|
||||
text: "${userNickname}",
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
color: ColorConfig.ThemeColor,
|
||||
),
|
||||
recognizer: TapGestureRecognizer()
|
||||
..onTap = () {
|
||||
Modular.to.pushNamed("/personal/${data.userId}");
|
||||
},
|
||||
children: [
|
||||
TextSpan(
|
||||
text: data.commentContent,
|
||||
style: TextStyle(
|
||||
color: ColorConfig.TextColor,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
Container(
|
||||
margin: EdgeInsets.only(top: 10),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.baseline,
|
||||
textBaseline: TextBaseline.alphabetic,
|
||||
children: [
|
||||
Container(
|
||||
margin: EdgeInsets.only(right: 10),
|
||||
child: Text(
|
||||
data.commentTime,
|
||||
style: TextStyle(
|
||||
color: ColorConfig.TextColor, fontSize: 13),
|
||||
),
|
||||
),
|
||||
GestureDetector(
|
||||
child: Text(
|
||||
"回复",
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: ColorConfig.ThemeColor,
|
||||
),
|
||||
),
|
||||
onTap: () {
|
||||
reply();
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
56
moehu/moehu_fontend/lib/widget/ContentPositioningLayout.dart
Normal file
56
moehu/moehu_fontend/lib/widget/ContentPositioningLayout.dart
Normal file
@@ -0,0 +1,56 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:peach/config/Colors.dart';
|
||||
import 'package:peach/config/Index.dart';
|
||||
import 'package:peach/utils/_.dart';
|
||||
|
||||
/*
|
||||
* 接受头部和内容,当页面向上滑动时内容部分到达顶部会定位
|
||||
* 并且当到达顶部是会触发回调函数
|
||||
*/
|
||||
class ContentPositioningLayout extends StatelessWidget {
|
||||
final Widget title;
|
||||
final Widget child;
|
||||
final double titleHeight;
|
||||
final double scrollHeight;
|
||||
|
||||
const ContentPositioningLayout(
|
||||
{this.title, this.child, this.titleHeight = 45, this.scrollHeight = 0});
|
||||
|
||||
static Color color = Colors.transparent;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
ScrollController mController = new ScrollController();
|
||||
mController.addListener(() {
|
||||
if (scrollHeight == 0) {
|
||||
return;
|
||||
}
|
||||
if ((scrollHeight.truncate() - mController.offset.truncate()) <= 3) {
|
||||
color = ColorConfig.WhiteBackColor;
|
||||
} else {
|
||||
color = Colors.transparent;
|
||||
}
|
||||
});
|
||||
return Stack(
|
||||
children: <Widget>[
|
||||
Positioned(
|
||||
height: Screen.height(context),
|
||||
child: SingleChildScrollView(
|
||||
physics: BouncingScrollPhysics(),
|
||||
controller: mController,
|
||||
child: this.child,
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
height: Screen.setHeight(this.titleHeight) + Config.top,
|
||||
child: Container(
|
||||
padding: EdgeInsets.only(top: Config.top),
|
||||
decoration: BoxDecoration(color: color),
|
||||
child: this.title,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
39
moehu/moehu_fontend/lib/widget/Empty.dart
Normal file
39
moehu/moehu_fontend/lib/widget/Empty.dart
Normal file
@@ -0,0 +1,39 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:peach/config/Colors.dart';
|
||||
import 'package:peach/utils/_.dart';
|
||||
|
||||
/*
|
||||
* 数据为空时默认展示
|
||||
*/
|
||||
class Empty extends StatelessWidget {
|
||||
final double height;
|
||||
final Widget child;
|
||||
final bool isShow;
|
||||
|
||||
Empty({this.height = 100, this.child = null, this.isShow = false});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
width: Screen.width(context),
|
||||
height: height,
|
||||
child: isShow
|
||||
? Container(
|
||||
padding: EdgeInsets.only(top: 100),
|
||||
alignment: Alignment.center,
|
||||
child: Column(
|
||||
children: [
|
||||
Icon(
|
||||
Icons.drafts,
|
||||
size: 52,
|
||||
color: ColorConfig.TextColor,
|
||||
),
|
||||
Text("暂无数据")
|
||||
],
|
||||
),
|
||||
)
|
||||
: this.child,
|
||||
);
|
||||
}
|
||||
}
|
||||
27
moehu/moehu_fontend/lib/widget/EmptyText.dart
Normal file
27
moehu/moehu_fontend/lib/widget/EmptyText.dart
Normal file
@@ -0,0 +1,27 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:peach/config/Colors.dart';
|
||||
import 'package:peach/utils/_.dart';
|
||||
|
||||
/*
|
||||
* 数据为空时默认展示 text
|
||||
*/
|
||||
class EmptyText extends StatelessWidget {
|
||||
final double height;
|
||||
final String text;
|
||||
|
||||
EmptyText({
|
||||
this.height = 100,
|
||||
this.text = "暂无数据",
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
width: Screen.width(context),
|
||||
height: height,
|
||||
alignment: Alignment.center,
|
||||
child: Text(this.text),
|
||||
);
|
||||
}
|
||||
}
|
||||
53
moehu/moehu_fontend/lib/widget/ExhibitionSearch.dart
Normal file
53
moehu/moehu_fontend/lib/widget/ExhibitionSearch.dart
Normal file
@@ -0,0 +1,53 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:peach/config/Colors.dart';
|
||||
import 'package:peach/utils/_.dart';
|
||||
|
||||
/*
|
||||
* 只做展示作用的 搜索框
|
||||
*/
|
||||
class ExhibitionSearch extends StatelessWidget {
|
||||
final controller = TextEditingController();
|
||||
|
||||
final double height;
|
||||
final Color backgroundColor;
|
||||
|
||||
ExhibitionSearch(
|
||||
{this.height = 28, this.backgroundColor = ColorConfig.WhiteBackColor});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
height: Screen.setHeight(this.height),
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: backgroundColor,
|
||||
borderRadius: BorderRadius.all(Radius.circular(20.0)),
|
||||
),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
verticalDirection: VerticalDirection.up,
|
||||
children: <Widget>[
|
||||
SizedBox(
|
||||
width: 10,
|
||||
),
|
||||
Icon(
|
||||
Icons.search,
|
||||
color: ColorConfig.TextColor,
|
||||
size: 18,
|
||||
),
|
||||
SizedBox(
|
||||
width: 5,
|
||||
),
|
||||
Expanded(
|
||||
child: Text(
|
||||
"搜索动态",
|
||||
style: TextStyle(color: ColorConfig.TextColor, fontSize: 15),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
64
moehu/moehu_fontend/lib/widget/FollowButton.dart
Normal file
64
moehu/moehu_fontend/lib/widget/FollowButton.dart
Normal file
@@ -0,0 +1,64 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:peach/config/_.dart';
|
||||
import 'package:peach/entity/_.dart';
|
||||
import 'package:peach/utils/_.dart';
|
||||
|
||||
/*
|
||||
* 关注按钮样式
|
||||
*/
|
||||
class FollowButton extends StatelessWidget {
|
||||
final bool isCheck;
|
||||
final Function onPressed;
|
||||
|
||||
const FollowButton({this.isCheck, this.onPressed});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return isCheck
|
||||
? ElevatedButton(
|
||||
style: ButtonStyle(
|
||||
backgroundColor: MaterialStateProperty.resolveWith(
|
||||
(states) {
|
||||
//设置按下时的背景颜色
|
||||
if (states.contains(MaterialState.pressed)) {
|
||||
return ColorConfig.AshPlacement;
|
||||
}
|
||||
//默认不使用背景颜色
|
||||
return ColorConfig.AshPlacement;
|
||||
},
|
||||
),
|
||||
elevation: MaterialStateProperty.all(0),
|
||||
),
|
||||
child: Text(
|
||||
"已关注",
|
||||
style: TextStyle(fontSize: 15, letterSpacing: 2,color: ColorConfig.TextColor),
|
||||
),
|
||||
onPressed: () {
|
||||
onPressed();
|
||||
},
|
||||
)
|
||||
: ElevatedButton(
|
||||
style: ButtonStyle(
|
||||
backgroundColor: MaterialStateProperty.resolveWith(
|
||||
(states) {
|
||||
//设置按下时的背景颜色
|
||||
if (states.contains(MaterialState.pressed)) {
|
||||
return ColorConfig.ThemeOtherColor;
|
||||
}
|
||||
//默认不使用背景颜色
|
||||
return ColorConfig.ThemeColor;
|
||||
},
|
||||
),
|
||||
elevation: MaterialStateProperty.all(0),
|
||||
),
|
||||
child: Text(
|
||||
"关注",
|
||||
style: TextStyle(fontSize: 15, letterSpacing: 2, color: ColorConfig.WhiteBackColor),
|
||||
),
|
||||
onPressed: () {
|
||||
onPressed();
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
162
moehu/moehu_fontend/lib/widget/ImagePickerWidget.dart
Normal file
162
moehu/moehu_fontend/lib/widget/ImagePickerWidget.dart
Normal file
@@ -0,0 +1,162 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:image_picker/image_picker.dart';
|
||||
import 'package:peach/config/Colors.dart';
|
||||
import 'package:peach/entity/_.dart';
|
||||
import 'package:peach/utils/_.dart';
|
||||
|
||||
/*
|
||||
* 选择相册或者拍照
|
||||
*/
|
||||
class ImagePickerWidget extends StatelessWidget {
|
||||
final Widget child;
|
||||
final Function onChange;
|
||||
|
||||
const ImagePickerWidget({this.child, this.onChange});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
_showCupertinoActionSheet(context);
|
||||
},
|
||||
child: child,
|
||||
);
|
||||
}
|
||||
|
||||
_showCupertinoActionSheet(BuildContext context) async {
|
||||
var result = await showModalBottomSheet(
|
||||
context: context,
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
|
||||
builder: (context) {
|
||||
return new Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
new ListTile(
|
||||
leading: new Icon(Icons.photo_camera),
|
||||
title: new Text("拍照"),
|
||||
onTap: () async {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
),
|
||||
Divider(height: 1),
|
||||
new ListTile(
|
||||
leading: new Icon(Icons.photo_library),
|
||||
title: new Text("相册"),
|
||||
onTap: () async {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
),
|
||||
Divider(height: 1),
|
||||
Container(
|
||||
height: Screen.setHeight(40),
|
||||
child: Text("取 消", style: TextStyle(color: ColorConfig.ThemeColor,fontSize: Screen.setFontSize(18)),),
|
||||
alignment: Alignment.center,
|
||||
)
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
if (result == 'photograph') {
|
||||
image(ImageSource.camera);
|
||||
} else if (result == 'album') {
|
||||
image(ImageSource.gallery);
|
||||
}
|
||||
}
|
||||
|
||||
Future image(ImageSource type) async {
|
||||
final pickedFile = await ImagePicker().getImage(source: type);
|
||||
if (pickedFile != null) {
|
||||
onChange(ImagePickerEntity(
|
||||
path: File(pickedFile.path), pickedFile: pickedFile));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// import 'dart:io';
|
||||
//
|
||||
// import 'package:flutter/cupertino.dart';
|
||||
// import 'package:flutter/material.dart';
|
||||
// import 'package:image_picker/image_picker.dart';
|
||||
// import 'package:peach/config/Colors.dart';
|
||||
// import 'package:peach/entity/_.dart';
|
||||
//
|
||||
// /*
|
||||
// * 选择相册或者拍照
|
||||
// */
|
||||
// class ImagePickerWidget extends StatelessWidget {
|
||||
// final Widget child;
|
||||
// final Function onChange;
|
||||
//
|
||||
// const ImagePickerWidget({this.child, this.onChange});
|
||||
//
|
||||
// @override
|
||||
// Widget build(BuildContext context) {
|
||||
// return GestureDetector(
|
||||
// onTap: () {
|
||||
// _showCupertinoActionSheet(context);
|
||||
// },
|
||||
// child: child,
|
||||
// );
|
||||
// }
|
||||
//
|
||||
// _showCupertinoActionSheet(BuildContext context) async {
|
||||
// var result = await showCupertinoModalPopup(
|
||||
// context: context,
|
||||
// builder: (context) {
|
||||
// return CupertinoActionSheet(
|
||||
// actions: <Widget>[
|
||||
// CupertinoActionSheetAction(
|
||||
// child: Text(
|
||||
// '拍照',
|
||||
// style: TextStyle(color: ColorConfig.ThemeColor),
|
||||
// ),
|
||||
// onPressed: () {
|
||||
// Navigator.of(context).pop('photograph');
|
||||
// },
|
||||
// isDefaultAction: true,
|
||||
// ),
|
||||
// CupertinoActionSheetAction(
|
||||
// child: Text(
|
||||
// '相册',
|
||||
// style: TextStyle(color: ColorConfig.ThemeColor),
|
||||
// ),
|
||||
// onPressed: () {
|
||||
// Navigator.of(context).pop('album');
|
||||
// },
|
||||
// isDefaultAction: true,
|
||||
// ),
|
||||
// ],
|
||||
// cancelButton: CupertinoActionSheetAction(
|
||||
// child: Text(
|
||||
// '取消',
|
||||
// style: TextStyle(color: ColorConfig.ThemeColor),
|
||||
// ),
|
||||
// onPressed: () {
|
||||
// Navigator.of(context).pop('cancel');
|
||||
// },
|
||||
// ),
|
||||
// );
|
||||
// },
|
||||
// );
|
||||
//
|
||||
// if (result == 'photograph') {
|
||||
// image(ImageSource.camera);
|
||||
// } else if (result == 'album') {
|
||||
// image(ImageSource.gallery);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// Future image(ImageSource type) async {
|
||||
// final pickedFile = await ImagePicker().getImage(source: type);
|
||||
// if (pickedFile != null) {
|
||||
// onChange(ImagePickerEntity(
|
||||
// path: File(pickedFile.path), pickedFile: pickedFile));
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
1
moehu/moehu_fontend/lib/widget/InputWidget/.pydio
Normal file
1
moehu/moehu_fontend/lib/widget/InputWidget/.pydio
Normal file
@@ -0,0 +1 @@
|
||||
317afd6d-ca10-4a61-878f-aadcb5686fda
|
||||
@@ -0,0 +1,35 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'extra_item_container.dart';
|
||||
|
||||
class DefaultExtraWidget extends StatefulWidget {
|
||||
@override
|
||||
_DefaultExtraWidgetState createState() => _DefaultExtraWidgetState();
|
||||
}
|
||||
|
||||
class _DefaultExtraWidgetState extends State<DefaultExtraWidget> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ExtraItemContainer(
|
||||
items: [
|
||||
createitem(),
|
||||
createitem(),
|
||||
createitem(),
|
||||
createitem(),
|
||||
createitem(),
|
||||
createitem(),
|
||||
createitem(),
|
||||
createitem(),
|
||||
createitem(),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
ExtraItem createitem() => DefaultExtraItem(
|
||||
icon: Icon(Icons.add),
|
||||
text: "添加",
|
||||
onPressed: () {
|
||||
print("添加");
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,146 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class ExtraItemContainer extends StatefulWidget {
|
||||
final List<ExtraItem> items;
|
||||
|
||||
const ExtraItemContainer({
|
||||
Key key,
|
||||
this.items,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
_ExtraItemContainerState createState() => _ExtraItemContainerState();
|
||||
}
|
||||
|
||||
class _ExtraItemContainerState extends State<ExtraItemContainer> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final pages = createPages();
|
||||
return PageView(
|
||||
children: pages,
|
||||
);
|
||||
}
|
||||
|
||||
List<Widget> createPages() {
|
||||
final items = widget.items;
|
||||
final hasLastPage = items.length % 8 == 0 ? 0 : 1;
|
||||
final totalPageCount = items.length ~/ 8 + hasLastPage;
|
||||
List<Widget> pages = [];
|
||||
for (var i = 0; i < totalPageCount; i++) {
|
||||
final page = getPage(i);
|
||||
pages.add(page);
|
||||
}
|
||||
return pages;
|
||||
}
|
||||
|
||||
Widget getPage(int page) {
|
||||
List<ExtraItem> extras = [];
|
||||
for (var i = 0; i < widget.items.length; i++) {
|
||||
if (i < page * 8) continue;
|
||||
if (i > (page + 1) * 8 - 1) continue;
|
||||
extras.add(widget.items[i]);
|
||||
}
|
||||
|
||||
List<ExtraItem> itemList1 = [];
|
||||
List<ExtraItem> itemList2 = [];
|
||||
|
||||
for (var i = 0; i < extras.length; i++) {
|
||||
if (i < 4) {
|
||||
itemList1.add(extras[i]);
|
||||
} else {
|
||||
itemList2.add(extras[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (itemList1.length < 4) {
|
||||
final length = itemList1.length;
|
||||
for (var i = 0; i < 4 - length; i++) {
|
||||
itemList1.add(EmptyExtraItem());
|
||||
}
|
||||
}
|
||||
|
||||
if (itemList2.length < 4) {
|
||||
final length = itemList2.length;
|
||||
for (var i = 0; i < 4 - length; i++) {
|
||||
itemList2.add(EmptyExtraItem());
|
||||
}
|
||||
}
|
||||
|
||||
return Column(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
children: <Widget>[
|
||||
for (final item in itemList1)
|
||||
Expanded(
|
||||
child: item.buildItem(),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
for (final item in itemList2)
|
||||
Expanded(
|
||||
child: item.buildItem(),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
abstract class ExtraItem {
|
||||
ExtraItem();
|
||||
|
||||
factory ExtraItem.def({Widget icon, String text, Function onPressed}) {
|
||||
return DefaultExtraItem(
|
||||
icon: icon,
|
||||
text: text,
|
||||
onPressed: onPressed,
|
||||
);
|
||||
}
|
||||
|
||||
Widget buildItem();
|
||||
}
|
||||
|
||||
class DefaultExtraItem extends ExtraItem {
|
||||
final Widget icon;
|
||||
final String text;
|
||||
final Function onPressed;
|
||||
|
||||
DefaultExtraItem({
|
||||
this.icon,
|
||||
this.text,
|
||||
this.onPressed,
|
||||
});
|
||||
|
||||
Widget buildItem() {
|
||||
return InkWell(
|
||||
onTap: onPressed,
|
||||
child: Container(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
icon,
|
||||
Container(
|
||||
height: 10,
|
||||
),
|
||||
Text(text),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class EmptyExtraItem extends ExtraItem {
|
||||
EmptyExtraItem();
|
||||
|
||||
@override
|
||||
Widget buildItem() => Container();
|
||||
}
|
||||
34
moehu/moehu_fontend/lib/widget/InputWidget/image_button.dart
Normal file
34
moehu/moehu_fontend/lib/widget/InputWidget/image_button.dart
Normal file
@@ -0,0 +1,34 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class ImageButton extends StatefulWidget {
|
||||
final ImageProvider image;
|
||||
final Function onPressed;
|
||||
|
||||
const ImageButton({
|
||||
Key key,
|
||||
this.onPressed,
|
||||
this.image,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
_ImageButtonState createState() => _ImageButtonState();
|
||||
}
|
||||
|
||||
class _ImageButtonState extends State<ImageButton> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GestureDetector(
|
||||
onTap: widget.onPressed,
|
||||
child: Container(
|
||||
width: 44,
|
||||
height: 44,
|
||||
alignment: Alignment.center,
|
||||
child: Image(
|
||||
image: widget.image,
|
||||
width: 35,
|
||||
height: 35,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
350
moehu/moehu_fontend/lib/widget/InputWidget/input_widget.dart
Normal file
350
moehu/moehu_fontend/lib/widget/InputWidget/input_widget.dart
Normal file
@@ -0,0 +1,350 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:emojis/emoji.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:peach/config/_.dart';
|
||||
import 'package:peach/event/_.dart';
|
||||
import 'dart:ui' as ui;
|
||||
|
||||
import 'package:peach/utils/Screen.dart';
|
||||
|
||||
typedef void OnSend(String text);
|
||||
|
||||
ChatType _initType = ChatType.text;
|
||||
|
||||
double _softKeyHeight = 324.0;
|
||||
|
||||
class InputWidget extends StatefulWidget {
|
||||
final TextEditingController controller;
|
||||
final Widget extraWidget;
|
||||
final Widget emojiWidget;
|
||||
final Widget voiceWidget;
|
||||
final OnSend onSend;
|
||||
final Function onFocusNode;
|
||||
final String hintText;
|
||||
|
||||
const InputWidget({
|
||||
Key key,
|
||||
@required this.controller,
|
||||
this.extraWidget,
|
||||
this.emojiWidget,
|
||||
this.voiceWidget,
|
||||
this.onSend,
|
||||
this.onFocusNode,
|
||||
this.hintText = "回复",
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
InputWidgetState createState() =>
|
||||
InputWidgetState(this.onSend, this.onFocusNode);
|
||||
}
|
||||
|
||||
class InputWidgetState extends State<InputWidget>
|
||||
with WidgetsBindingObserver, TickerProviderStateMixin {
|
||||
final Function onSend;
|
||||
final Function onFocusNode;
|
||||
String hintText = "回复";
|
||||
|
||||
ChatType currentType = _initType;
|
||||
|
||||
FocusNode focusNode = FocusNode();
|
||||
|
||||
StreamController<String> inputContentStreamController =
|
||||
StreamController.broadcast();
|
||||
|
||||
InputWidgetState(this.onSend, this.onFocusNode);
|
||||
|
||||
Stream<String> get inputContentStream => inputContentStreamController.stream;
|
||||
|
||||
AnimationController _bottomHeightController;
|
||||
|
||||
double maxHeight = 90;
|
||||
|
||||
List<Emoji> emList = Emoji.all().take(100).toList();
|
||||
|
||||
Color butColor = ColorConfig.TextColor;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
onFocusNode(focusNode);
|
||||
WidgetsBinding.instance.addObserver(this);
|
||||
focusNode.addListener(onFocus);
|
||||
widget.controller.addListener(_onInputChange);
|
||||
_bottomHeightController = AnimationController(
|
||||
vsync: this,
|
||||
duration: Duration(
|
||||
milliseconds: 250,
|
||||
),
|
||||
);
|
||||
|
||||
Config.eventBus.on<ClasshHntTextEvent>().listen((event) {
|
||||
if (event.text != "") {
|
||||
hintText = event.text;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// bool checkShowSendButton(String text) {
|
||||
// if (currentType == ChatType.voice) {
|
||||
// return false;
|
||||
// }
|
||||
// if (text.trim().isNotEmpty) {
|
||||
// return true;
|
||||
// }
|
||||
// return false;
|
||||
// }
|
||||
|
||||
@override
|
||||
void didChangeMetrics() {
|
||||
final mediaQueryData = MediaQueryData.fromWindow(ui.window);
|
||||
final keyHeight = mediaQueryData?.viewInsets?.bottom;
|
||||
if (keyHeight != 0) {
|
||||
_softKeyHeight = keyHeight;
|
||||
// updateState(ChatType.text);
|
||||
} else {
|
||||
// setState(() {});
|
||||
}
|
||||
}
|
||||
|
||||
void onFocus() {
|
||||
if (focusNode.hasFocus) {
|
||||
updateState(ChatType.text);
|
||||
}
|
||||
}
|
||||
|
||||
void _onInputChange() {
|
||||
inputContentStreamController.add(widget.controller.text);
|
||||
if (widget.controller.text.length > 0) {
|
||||
butColor = ColorConfig.ThemeColor;
|
||||
} else {
|
||||
butColor = ColorConfig.TextColor;
|
||||
}
|
||||
setState(() {});
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_bottomHeightController.dispose();
|
||||
inputContentStreamController.close();
|
||||
widget.controller.removeListener(_onInputChange);
|
||||
focusNode.removeListener(onFocus);
|
||||
focusNode.dispose();
|
||||
WidgetsBinding.instance.removeObserver(this);
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ConstrainedBox(
|
||||
constraints: BoxConstraints(maxHeight: 390),
|
||||
child: Container(
|
||||
height: maxHeight,
|
||||
// decoration: BoxDecoration(
|
||||
// border: Border(
|
||||
// top: BorderSide(color: ColorConfig.LineColor, width: 1),
|
||||
// ),
|
||||
// ),
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
buildInputButton(),
|
||||
Container(
|
||||
margin: EdgeInsets.only(bottom: 20),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
buildEmojiButton(),
|
||||
buildRightButton(),
|
||||
],
|
||||
),
|
||||
),
|
||||
// Divider(),
|
||||
_buildBottomContainer(child: _buildBottomItems())
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget buildRightButton() {
|
||||
return ConstrainedBox(
|
||||
constraints: BoxConstraints(
|
||||
maxHeight: 25,
|
||||
),
|
||||
child: IconButton(
|
||||
splashColor: Colors.transparent,
|
||||
highlightColor: Colors.transparent,
|
||||
iconSize: 32,
|
||||
color: butColor,
|
||||
enableFeedback: true,
|
||||
padding: EdgeInsets.only(top: 0),
|
||||
icon: Icon(Icons.send),
|
||||
onPressed: () {
|
||||
if (widget.controller.text.length <= 0) return;
|
||||
this.onSend(widget.controller.text);
|
||||
widget.controller.text = "";
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget buildEmojiButton() {
|
||||
return ConstrainedBox(
|
||||
constraints: BoxConstraints(
|
||||
maxHeight: 25,
|
||||
),
|
||||
child: IconButton(
|
||||
splashColor: Colors.transparent,
|
||||
highlightColor: Colors.transparent,
|
||||
iconSize: 32,
|
||||
color: ColorConfig.TextColor,
|
||||
padding: EdgeInsets.only(top: 0),
|
||||
icon: currentType != ChatType.emoji
|
||||
? Icon(Icons.mood)
|
||||
: Icon(Icons.keyboard),
|
||||
onPressed: () {
|
||||
if (currentType != ChatType.emoji) {
|
||||
updateState(ChatType.emoji);
|
||||
} else {
|
||||
updateState(ChatType.text);
|
||||
}
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget buildInputButton() {
|
||||
final inputButton = TextField(
|
||||
focusNode: focusNode,
|
||||
controller: widget.controller,
|
||||
cursorHeight: 20,
|
||||
decoration: InputDecoration(
|
||||
isDense: true,
|
||||
hintText: hintText,
|
||||
fillColor: Colors.white,
|
||||
border: OutlineInputBorder(borderSide: BorderSide.none),
|
||||
),
|
||||
);
|
||||
|
||||
return Container(
|
||||
height: Screen.setHeight(35),
|
||||
padding: EdgeInsets.only(top: 15),
|
||||
child: ConstrainedBox(
|
||||
constraints: BoxConstraints(
|
||||
maxHeight: 25,
|
||||
),
|
||||
child: inputButton,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void changeBottomHeight(final double height) {
|
||||
if (height > 0) {
|
||||
_bottomHeightController.animateTo(1);
|
||||
} else {
|
||||
_bottomHeightController.animateBack(0);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> updateState(ChatType type) async {
|
||||
if (type == ChatType.text || type == ChatType.voice) {
|
||||
_initType = type;
|
||||
}
|
||||
if (type == currentType) {
|
||||
return;
|
||||
}
|
||||
this.currentType = type;
|
||||
ChangeChatTypeNotification(type).dispatch(context);
|
||||
|
||||
if (type != ChatType.text) {
|
||||
hideSoftKey();
|
||||
setState(() {
|
||||
maxHeight = 390;
|
||||
});
|
||||
} else {
|
||||
showSoftKey();
|
||||
setState(() {
|
||||
maxHeight = 90;
|
||||
});
|
||||
}
|
||||
|
||||
if (type == ChatType.emoji || type == ChatType.extra) {
|
||||
// _currentOtherHeight = _softKeyHeight;
|
||||
changeBottomHeight(1);
|
||||
} else {
|
||||
changeBottomHeight(0);
|
||||
// _currentOtherHeight = 0;
|
||||
}
|
||||
|
||||
setState(() {});
|
||||
}
|
||||
|
||||
void showSoftKey() {
|
||||
FocusScope.of(context).requestFocus(focusNode);
|
||||
}
|
||||
|
||||
void hideSoftKey() {
|
||||
focusNode.unfocus();
|
||||
}
|
||||
|
||||
Widget _buildBottomContainer({Widget child}) {
|
||||
return SizeTransition(
|
||||
sizeFactor: _bottomHeightController,
|
||||
child: Container(
|
||||
child: child,
|
||||
height: 300,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildBottomItems() {
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
border: Border(top: BorderSide(width: 1, color: ColorConfig.LineColor)),
|
||||
),
|
||||
child: MediaQuery.removePadding(
|
||||
context: context,
|
||||
removeTop: true,
|
||||
removeBottom: true,
|
||||
child: GridView(
|
||||
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
|
||||
crossAxisCount: 7,
|
||||
),
|
||||
children: [
|
||||
...emList.asMap().keys.map(
|
||||
(e) {
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
widget.controller.text += emList[e].toString();
|
||||
},
|
||||
child: Container(
|
||||
alignment: Alignment.center,
|
||||
child: Text(
|
||||
"${emList[e]}",
|
||||
style: TextStyle(
|
||||
fontSize: 24,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
).toList(),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
enum ChatType {
|
||||
text,
|
||||
voice,
|
||||
emoji,
|
||||
extra,
|
||||
}
|
||||
|
||||
class ChangeChatTypeNotification extends Notification {
|
||||
final ChatType type;
|
||||
|
||||
ChangeChatTypeNotification(this.type);
|
||||
}
|
||||
18
moehu/moehu_fontend/lib/widget/Line.dart
Normal file
18
moehu/moehu_fontend/lib/widget/Line.dart
Normal file
@@ -0,0 +1,18 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:peach/config/Colors.dart';
|
||||
import 'package:peach/utils/Screen.dart';
|
||||
|
||||
/*
|
||||
* 大部分布局的左右上下宽高都是固定的所以单独抽一个面板组件
|
||||
*/
|
||||
class Line extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
height: 8,
|
||||
width: Screen.width(context),
|
||||
color: ColorConfig.LineColor,
|
||||
);
|
||||
}
|
||||
}
|
||||
44
moehu/moehu_fontend/lib/widget/Loading.dart
Normal file
44
moehu/moehu_fontend/lib/widget/Loading.dart
Normal file
@@ -0,0 +1,44 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:peach/config/Colors.dart';
|
||||
import 'package:peach/utils/Screen.dart';
|
||||
|
||||
/*
|
||||
* 加载动画
|
||||
*/
|
||||
class Loading extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
height: Screen.height(context),
|
||||
width: Screen.width(context),
|
||||
color: ColorConfig.WhiteBackColor,
|
||||
child: Center(
|
||||
child: Container(
|
||||
padding: EdgeInsets.all(20.0),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.black87, borderRadius: BorderRadius.circular(4.0)),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
CircularProgressIndicator(),
|
||||
Container(
|
||||
padding: EdgeInsets.fromLTRB(10.0, 10.0, 10.0, 0),
|
||||
child: Text(
|
||||
"加载中~",
|
||||
style: TextStyle(
|
||||
color: ColorConfig.TextColor,
|
||||
fontSize: 16.0,
|
||||
decoration: TextDecoration.none,
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
113
moehu/moehu_fontend/lib/widget/MyInput.dart
Normal file
113
moehu/moehu_fontend/lib/widget/MyInput.dart
Normal file
@@ -0,0 +1,113 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:peach/config/_.dart';
|
||||
import 'package:peach/utils/_.dart';
|
||||
|
||||
class MyInput extends StatefulWidget {
|
||||
final String hintText;
|
||||
|
||||
const MyInput({this.hintText});
|
||||
|
||||
@override
|
||||
_MyInput createState() => _MyInput(hintText: hintText);
|
||||
}
|
||||
|
||||
/*
|
||||
* 评论输入框
|
||||
*/
|
||||
class _MyInput extends State {
|
||||
FocusNode focusNode = FocusNode();
|
||||
TextEditingController textFieldcontroller;
|
||||
ChatType currentType = ChatType.text;
|
||||
final String hintText;
|
||||
|
||||
double height = 70;
|
||||
|
||||
_MyInput({this.hintText = "君观之有言否?"}) {
|
||||
focusNode.addListener(onFocus);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
height: Screen.setHeight(height),
|
||||
decoration: BoxDecoration(
|
||||
border: Border(
|
||||
top: BorderSide(color: ColorConfig.LineColor, width: 1),
|
||||
),
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
buildInputButton(),
|
||||
buildEmojiButton(),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget buildInputButton() {
|
||||
return Container(
|
||||
height: Screen.setHeight(35),
|
||||
padding: EdgeInsets.only(top: 15),
|
||||
child: TextField(
|
||||
focusNode: focusNode,
|
||||
controller: textFieldcontroller,
|
||||
cursorHeight: 20,
|
||||
decoration: InputDecoration(
|
||||
hintText: hintText,
|
||||
fillColor: Colors.white,
|
||||
border: OutlineInputBorder(borderSide: BorderSide.none),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget buildEmojiButton() {
|
||||
return ConstrainedBox(
|
||||
constraints: BoxConstraints(
|
||||
maxHeight: 25,
|
||||
),
|
||||
child: IconButton(
|
||||
splashColor: Colors.transparent,
|
||||
highlightColor: Colors.transparent,
|
||||
iconSize: 32,
|
||||
color: ColorConfig.TextColor,
|
||||
padding: EdgeInsets.only(top: 0),
|
||||
icon: currentType != ChatType.emoji
|
||||
? Icon(Icons.mood)
|
||||
: Icon(Icons.keyboard),
|
||||
onPressed: () {
|
||||
if (currentType != ChatType.emoji) {
|
||||
updateState(ChatType.emoji);
|
||||
} else {
|
||||
updateState(ChatType.text);
|
||||
}
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
onFocus() {
|
||||
// print("${focusNode.hasFocus}88888");
|
||||
// height = 200;
|
||||
}
|
||||
|
||||
updateState(ChatType type) {
|
||||
if (type == ChatType.text) {
|
||||
height = 70;
|
||||
FocusScope.of(context).requestFocus(focusNode);
|
||||
} else {
|
||||
height = 200;
|
||||
focusNode.unfocus();
|
||||
}
|
||||
print(height);
|
||||
setState(() {
|
||||
currentType = type;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
enum ChatType {
|
||||
text,
|
||||
emoji,
|
||||
}
|
||||
21
moehu/moehu_fontend/lib/widget/PageAnimation.dart
Normal file
21
moehu/moehu_fontend/lib/widget/PageAnimation.dart
Normal file
@@ -0,0 +1,21 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:peach/config/Colors.dart';
|
||||
import 'package:peach/utils/Screen.dart';
|
||||
|
||||
/*
|
||||
* 组件加载时的动画
|
||||
*/
|
||||
class PageAnimation extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
height: Screen.height(context),
|
||||
width: Screen.width(context),
|
||||
child: CupertinoActivityIndicator(
|
||||
radius: 10,
|
||||
),
|
||||
color: ColorConfig.WhiteBackColor,
|
||||
);
|
||||
}
|
||||
}
|
||||
25
moehu/moehu_fontend/lib/widget/Panel.dart
Normal file
25
moehu/moehu_fontend/lib/widget/Panel.dart
Normal file
@@ -0,0 +1,25 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:peach/utils/Screen.dart';
|
||||
|
||||
/*
|
||||
* 大部分布局的左右上下宽高都是固定的所以单独抽一个面板组件
|
||||
*/
|
||||
class Panel extends StatelessWidget {
|
||||
final double top;
|
||||
final double bottom;
|
||||
final Widget child;
|
||||
|
||||
const Panel({this.child, this.top = 10.0, this.bottom = 10.0});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
width: Screen.width(context),
|
||||
child: Padding(
|
||||
padding: EdgeInsets.only(
|
||||
left: 10, right: 10, top: this.top, bottom: this.bottom),
|
||||
child: this.child),
|
||||
);
|
||||
}
|
||||
}
|
||||
210
moehu/moehu_fontend/lib/widget/PersonalpTitle.dart
Normal file
210
moehu/moehu_fontend/lib/widget/PersonalpTitle.dart
Normal file
@@ -0,0 +1,210 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_modular/flutter_modular.dart';
|
||||
import 'package:peach/config/Colors.dart';
|
||||
import 'package:peach/utils/_.dart';
|
||||
import 'package:peach/widget/TextLimitDisplay.dart';
|
||||
import 'package:peach/widget/_.dart';
|
||||
|
||||
/*
|
||||
* 头像和粉丝内容等
|
||||
*/
|
||||
class PersonalpTitle extends StatelessWidget {
|
||||
final double headImgHeight;
|
||||
final bool isEditing;
|
||||
final bool isText;
|
||||
final Function onExpand;
|
||||
final double textHeight;
|
||||
// 是否是本人空间 true 是
|
||||
final bool isOpenFollow;
|
||||
// 是否已经关注 true 是
|
||||
final bool isFollow;
|
||||
final Function opusFollowUser;
|
||||
|
||||
// 头像
|
||||
final String imgHead;
|
||||
final String nickname;
|
||||
final String autograph;
|
||||
final int fansNums;
|
||||
final int satisfiedNums;
|
||||
final int followNums;
|
||||
|
||||
final int userId;
|
||||
|
||||
PersonalpTitle({
|
||||
this.headImgHeight = 58,
|
||||
this.isEditing = false,
|
||||
this.onExpand,
|
||||
this.isText = false,
|
||||
this.textHeight = 20,
|
||||
this.imgHead = '',
|
||||
this.nickname = '',
|
||||
this.autograph = '',
|
||||
this.fansNums = 0,
|
||||
this.satisfiedNums = 0,
|
||||
this.followNums = 0,
|
||||
this.isOpenFollow = false,
|
||||
this.isFollow = false,
|
||||
this.opusFollowUser,
|
||||
this.userId = 0,
|
||||
});
|
||||
|
||||
GlobalKey txtKey = GlobalKey();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Column(
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: [
|
||||
Container(
|
||||
margin: EdgeInsets.only(right: Screen.setWidth(40)),
|
||||
child: ClipOval(
|
||||
child: Image.network(
|
||||
imgHead,
|
||||
width: Screen.setWidth(this.headImgHeight),
|
||||
height: Screen.setWidth(this.headImgHeight),
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
)),
|
||||
Expanded(
|
||||
flex: 1,
|
||||
child: Column(
|
||||
children: [
|
||||
Container(
|
||||
width: 160,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
Modular.to.pushNamed("/fans/${userId}");
|
||||
},
|
||||
child: Column(
|
||||
children: [
|
||||
Text(fansNums.toString(),
|
||||
style: TextStyle(fontSize: 16)),
|
||||
Text(
|
||||
"粉丝",
|
||||
style: TextStyle(
|
||||
color: ColorConfig.TextColor,
|
||||
fontSize: 14,
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
Modular.to.pushNamed("/follow/${userId}");
|
||||
},
|
||||
child: Column(
|
||||
children: [
|
||||
Text(followNums.toString(),
|
||||
style: TextStyle(fontSize: 16)),
|
||||
Text(
|
||||
"关注",
|
||||
style: TextStyle(
|
||||
color: ColorConfig.TextColor,
|
||||
fontSize: 14,
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
Column(
|
||||
children: [
|
||||
Text(satisfiedNums.toString(),
|
||||
style: TextStyle(fontSize: 16)),
|
||||
Text(
|
||||
"获赞",
|
||||
style: TextStyle(
|
||||
color: ColorConfig.TextColor,
|
||||
fontSize: 14,
|
||||
),
|
||||
)
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
this.isEditing
|
||||
? Container(
|
||||
width: Screen.setWidth(240),
|
||||
margin: EdgeInsets.only(top: Screen.setFontSize(5)),
|
||||
child: isOpenFollow
|
||||
? FollowButton(
|
||||
isCheck: isFollow,
|
||||
onPressed: () {
|
||||
opusFollowUser();
|
||||
})
|
||||
: ElevatedButton(
|
||||
style: ButtonStyle(backgroundColor:
|
||||
MaterialStateProperty.resolveWith(
|
||||
(states) {
|
||||
//设置按下时的背景颜色
|
||||
if (states
|
||||
.contains(MaterialState.pressed)) {
|
||||
return ColorConfig.ThemeOtherColor;
|
||||
}
|
||||
//默认不使用背景颜色
|
||||
return ColorConfig.ThemeColor;
|
||||
})),
|
||||
child: Text("编辑资料",
|
||||
style: TextStyle(fontSize: Screen.setFontSize(18))),
|
||||
onPressed: () {
|
||||
Navigator.of(context)
|
||||
.pushNamed("/editMaterials");
|
||||
},
|
||||
),
|
||||
)
|
||||
: Container()
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
var keyContext = txtKey.currentContext;
|
||||
if (keyContext != null) {
|
||||
final txtBox = keyContext.findRenderObject() as RenderBox;
|
||||
print(
|
||||
'height ${txtBox.size.height} and width ${txtBox.size.width}');
|
||||
}
|
||||
},
|
||||
child: Container(
|
||||
margin: EdgeInsets.only(top: Screen.setHeight(10)),
|
||||
child: Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Text(
|
||||
nickname,
|
||||
style: TextStyle(
|
||||
color: ColorConfig.ThemeColor,
|
||||
fontSize: 16,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Container(
|
||||
margin: EdgeInsets.only(top: Screen.setHeight(10)),
|
||||
child: Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Text(
|
||||
autograph,
|
||||
style: TextStyle(
|
||||
color: ColorConfig.TextColor,
|
||||
fontSize: 14,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
62
moehu/moehu_fontend/lib/widget/RoutineShowDialog.dart
Normal file
62
moehu/moehu_fontend/lib/widget/RoutineShowDialog.dart
Normal file
@@ -0,0 +1,62 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:peach/config/_.dart';
|
||||
|
||||
/*
|
||||
* 底部弹出操作栏
|
||||
*/
|
||||
class RoutineShowDialog {
|
||||
static itemShowDialog(BuildContext context) {
|
||||
showCupertinoModalPopup(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return CupertinoActionSheet(
|
||||
actions: <Widget>[
|
||||
CupertinoActionSheetAction(
|
||||
child: Text(
|
||||
'复制链接',
|
||||
style: TextStyle(
|
||||
color: ColorConfig.ThemeColor,
|
||||
fontSize: 16,
|
||||
),
|
||||
),
|
||||
onPressed: () {},
|
||||
isDefaultAction: true,
|
||||
),
|
||||
CupertinoActionSheetAction(
|
||||
child: Text(
|
||||
'分享',
|
||||
style: TextStyle(
|
||||
color: ColorConfig.ThemeColor,
|
||||
fontSize: 16,
|
||||
),
|
||||
),
|
||||
onPressed: () {},
|
||||
isDefaultAction: true,
|
||||
),
|
||||
CupertinoActionSheetAction(
|
||||
child: Text(
|
||||
'举报',
|
||||
style: TextStyle(
|
||||
color: ColorConfig.ThemeColor,
|
||||
fontSize: 16,
|
||||
),
|
||||
),
|
||||
onPressed: () {},
|
||||
isDefaultAction: true,
|
||||
),
|
||||
CupertinoActionSheetAction(
|
||||
child: Text(
|
||||
'取消',
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
),
|
||||
),
|
||||
onPressed: () {},
|
||||
isDestructiveAction: true,
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
347
moehu/moehu_fontend/lib/widget/TextLimitDisplay.dart
Normal file
347
moehu/moehu_fontend/lib/widget/TextLimitDisplay.dart
Normal file
@@ -0,0 +1,347 @@
|
||||
import 'dart:math' show max;
|
||||
import 'dart:ui' show LineMetrics;
|
||||
|
||||
import 'package:flutter/gestures.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
/// 在文本超出指定行数之后,会显示 展开/收起 按钮的文本展示组件
|
||||
///
|
||||
/// 用例1: 常规使用
|
||||
/// TextLimitDisplay(
|
||||
/// text: '一大段文字...',
|
||||
/// minLines: 2,
|
||||
/// textStyle: TextStyle(color: Colors.blue),
|
||||
/// )
|
||||
///
|
||||
/// 用例2:特性化使用-比如 一段文字结尾显示的是 编辑,而点击编辑按钮之后要做一些事, 且显示样式不变
|
||||
/// TextLimitDisplay(
|
||||
/// text: '一大段文字...',
|
||||
/// minLines: 2, // 这两个长度也要设置一致
|
||||
/// maxLines: 2,
|
||||
/// isAlwaysDisplay: true, // 按钮始终显示
|
||||
/// textStyle: TextStyle(color: Colors.blue),
|
||||
/// shrinkText: '编辑', // 这两个文本文字要设置成一样的
|
||||
/// expandText: '编辑',
|
||||
/// onShrink: onEdit, // 两个点击事件也要传递同样的事件
|
||||
/// onExpand: onEdit,
|
||||
/// )
|
||||
class TextLimitDisplay extends StatefulWidget {
|
||||
final String text;
|
||||
|
||||
/// 最少展示几行-在收起的状态下展示几行
|
||||
final int minLines;
|
||||
|
||||
/// 最多展示几行-在展开的状态下展示几行,
|
||||
/// 默认最多支持显示99行,要显示更多的行数需要手动传入
|
||||
final int maxLines;
|
||||
|
||||
/// 文字整体样式
|
||||
final TextStyle textStyle;
|
||||
|
||||
/// 收起、展开文字颜色
|
||||
final Color keyColor;
|
||||
|
||||
/// 收起状态下按钮文字
|
||||
final String shrinkText;
|
||||
|
||||
/// 展开状态下的按钮文字
|
||||
final String expandText;
|
||||
|
||||
/// 当点击收起的时候
|
||||
final Function onShrink;
|
||||
|
||||
/// 当点击展开的时候
|
||||
final Function onExpand;
|
||||
|
||||
/// 结尾按钮是否始终处于显示状态
|
||||
final bool isAlwaysDisplay;
|
||||
|
||||
/// 展开按钮的widget,会替换文字
|
||||
final Icon expandIcon;
|
||||
|
||||
/// 收起按钮的widget, 会替换文字
|
||||
final Icon shrinkIcon;
|
||||
|
||||
final bool isExpand;
|
||||
|
||||
const TextLimitDisplay({
|
||||
Key key,
|
||||
this.text = '',
|
||||
this.minLines,
|
||||
this.textStyle,
|
||||
this.maxLines,
|
||||
this.keyColor = const Color(0xFF5396FD),
|
||||
this.shrinkText = '展开',
|
||||
this.expandText = '收起',
|
||||
this.onShrink,
|
||||
this.onExpand,
|
||||
this.isAlwaysDisplay = false,
|
||||
this.expandIcon,
|
||||
this.shrinkIcon,
|
||||
this.isExpand = false,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
_TextLimitDisplayState createState() => _TextLimitDisplayState();
|
||||
}
|
||||
|
||||
class _TextLimitDisplayState extends State<TextLimitDisplay> {
|
||||
final GlobalKey _key = GlobalKey();
|
||||
|
||||
bool _isExpand = false;
|
||||
|
||||
bool _isOver = false;
|
||||
|
||||
String _shrinkText;
|
||||
|
||||
String _expandText;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
init();
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_key.currentState?.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
void didUpdateWidget(TextLimitDisplay oldWidget) {
|
||||
super.didUpdateWidget(oldWidget);
|
||||
if (widget.text.compareTo(oldWidget.text) != 0) {
|
||||
init();
|
||||
}
|
||||
}
|
||||
|
||||
void init() {
|
||||
_shrinkText = widget.text;
|
||||
_expandText = widget.text;
|
||||
_isExpand = widget.isExpand;
|
||||
if (widget.minLines != null && widget.minLines > 0) {
|
||||
initValue();
|
||||
}
|
||||
}
|
||||
|
||||
String get _activeText => _isExpand ? _expandBtnText : _shrinkBtnText;
|
||||
|
||||
String get _showText => _isExpand ? _expandText : _shrinkText;
|
||||
|
||||
int get _minLines => _isExpand ? _maxLines : widget.minLines;
|
||||
|
||||
int get _maxLines => widget.maxLines ?? 99;
|
||||
|
||||
bool _isOverflow(List metrics, int len) => metrics.length > len;
|
||||
|
||||
String get _shrinkBtnText => ' ${widget.shrinkText}';
|
||||
|
||||
String get _expandBtnText => ' ${widget.expandText}';
|
||||
|
||||
TextStyle get _textStyle =>
|
||||
DefaultTextStyle.of(context).style.merge(widget.textStyle);
|
||||
|
||||
Icon _icon(bool isExpand) => isExpand ? widget.shrinkIcon : widget.expandIcon;
|
||||
|
||||
void initValue() {
|
||||
// TODO: 暂时还剩一个问题是这种延时处理的方式无法保证文本组件一定渲染完成了
|
||||
Future.delayed(Duration(), () {
|
||||
// 如果没有渲染完成那么这里就会报错,无法获取到size
|
||||
List<LineMetrics> lineMetrics;
|
||||
try {
|
||||
lineMetrics = _paintText(widget.text);
|
||||
} catch (_) {
|
||||
lineMetrics = List.generate(
|
||||
max(99, widget.maxLines ?? 99),
|
||||
(index) => null,
|
||||
);
|
||||
}
|
||||
setState(() {
|
||||
_isOver = _isOverflow(lineMetrics, widget.minLines);
|
||||
if (_isOver) {
|
||||
_shrinkText =
|
||||
_calcShrinkText(lineMetrics, widget.minLines, _shrinkBtnText);
|
||||
_expandText = _calcShrinkText(
|
||||
lineMetrics,
|
||||
_maxLines,
|
||||
_expandBtnText,
|
||||
isExpand: true,
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
List<LineMetrics> _paintText(String text, {double maxWidth}) {
|
||||
final textPainter = TextPainter(
|
||||
textDirection: TextDirection.ltr,
|
||||
text: TextSpan(text: text, style: _textStyle),
|
||||
);
|
||||
if (maxWidth != null) {
|
||||
textPainter.layout(minWidth: maxWidth, maxWidth: maxWidth);
|
||||
} else {
|
||||
final textWidth = _key.currentContext.size.width;
|
||||
textPainter.layout(minWidth: textWidth, maxWidth: textWidth);
|
||||
}
|
||||
|
||||
return textPainter.computeLineMetrics();
|
||||
}
|
||||
|
||||
bool _lenEquals(String text, int len) => _paintText(text).length == len;
|
||||
|
||||
void _tapRecognizer() {
|
||||
setState(() => _isExpand = !_isExpand);
|
||||
if (_isExpand) {
|
||||
(widget.onShrink ?? () => {})();
|
||||
} else {
|
||||
(widget.onExpand ?? () => {})();
|
||||
}
|
||||
}
|
||||
|
||||
String _getOverflowedText(
|
||||
String shrinkText, {
|
||||
String trailingText = '',
|
||||
int limitLen = 0,
|
||||
}) {
|
||||
int textLen = widget.text.length;
|
||||
int step = 1;
|
||||
int count = 0;
|
||||
while (!_lenEquals('$shrinkText$trailingText', limitLen + 1)) {
|
||||
if (shrinkText.length + step > textLen) {
|
||||
count++;
|
||||
if (count > 10) {
|
||||
// 死循环检测处理
|
||||
break;
|
||||
}
|
||||
if (step < 1) {
|
||||
break;
|
||||
} else {
|
||||
step = step ~/ 2;
|
||||
}
|
||||
} else {
|
||||
shrinkText = widget.text.substring(0, shrinkText.length + step);
|
||||
step += 4;
|
||||
}
|
||||
}
|
||||
return shrinkText;
|
||||
}
|
||||
|
||||
/// 获取大于指定宽度的_文本
|
||||
String _getSpeWidthText(double width) {
|
||||
String result = '_';
|
||||
while (!_isOverflow(_paintText(result, maxWidth: width), 1)) {
|
||||
result += '_';
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
String _calcShrinkText(
|
||||
List<LineMetrics> lineMetrics,
|
||||
int len,
|
||||
String trailingBtnText, {
|
||||
bool isExpand = false,
|
||||
}) {
|
||||
// 如果限制的最大行数超过了实际渲染出来的最大行数,说明根据不会出现溢出的情况
|
||||
if (len > lineMetrics.length) return widget.text;
|
||||
|
||||
final String spacerText = _isOverflow(lineMetrics, len) ? '...' : '';
|
||||
|
||||
String trailingText;
|
||||
|
||||
if (_icon(isExpand) != null) {
|
||||
trailingText =
|
||||
'$spacerText${_getSpeWidthText(_icon(isExpand).size ?? IconTheme.of(context).size)}';
|
||||
} else {
|
||||
trailingText = '$spacerText$trailingBtnText';
|
||||
}
|
||||
// 计算出n行文本大致的字数,根据字数从原文本截取相应的字符串
|
||||
// double nTextLength = min(len, lineMetrics.length) *
|
||||
// _key.currentContext.size.width /
|
||||
// _textStyle.fontSize;
|
||||
// String shrinkText = widget.text.substring(0, nTextLength.toInt());
|
||||
// 暂时不能从这里计算长度,当文字带有换行的时候会出问题
|
||||
String shrinkText = '';
|
||||
// 下面加上结尾字符不一定会换行,因为字体不是等宽字体
|
||||
// 所以需要先确定溢出才开始倒算
|
||||
shrinkText = _getOverflowedText(
|
||||
shrinkText,
|
||||
trailingText: trailingText,
|
||||
limitLen: len,
|
||||
);
|
||||
// 这个时候这些文字加上结尾附加文字一定是会换行的
|
||||
// 所以一直判断如果文字换行的行数大于传入的指定行数,那么就从文字末尾减去一个字符
|
||||
// 再继续判断,直到文本行数等于传入的指定行数为止
|
||||
// 使用runes计算,避免表情在某些位置报错
|
||||
final shrinkTextRunnes = shrinkText.runes.toList();
|
||||
int offset = 0;
|
||||
while (!_lenEquals('$shrinkText$trailingText', len)) {
|
||||
if (shrinkTextRunnes.length - offset > 0) {
|
||||
// shrinkText = shrinkText.substring(0, shrinkText.length - 1);
|
||||
offset++;
|
||||
shrinkText = String.fromCharCodes(
|
||||
shrinkTextRunnes.sublist(0, shrinkTextRunnes.length - offset));
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return '$shrinkText$spacerText';
|
||||
}
|
||||
|
||||
InlineSpan _trailingBtn() {
|
||||
if (_icon(_isExpand) != null) {
|
||||
return WidgetSpan(
|
||||
child: InkWell(
|
||||
focusColor: Colors.transparent,
|
||||
highlightColor: Colors.transparent,
|
||||
hoverColor: Colors.transparent,
|
||||
splashColor: Colors.transparent,
|
||||
onTap: _tapRecognizer,
|
||||
child: _icon(_isExpand),
|
||||
),
|
||||
style: _textStyle.copyWith(color: widget.keyColor),
|
||||
);
|
||||
}
|
||||
return TextSpan(
|
||||
text: _activeText,
|
||||
style: _textStyle.copyWith(color: widget.keyColor),
|
||||
recognizer: TapGestureRecognizer()..onTap = _tapRecognizer,
|
||||
);
|
||||
}
|
||||
|
||||
Widget _handleText() {
|
||||
return Stack(
|
||||
children: [
|
||||
Text.rich(
|
||||
TextSpan(
|
||||
text: _showText,
|
||||
children: [
|
||||
if (_isOver || widget.isAlwaysDisplay) _trailingBtn(),
|
||||
],
|
||||
),
|
||||
key: _key,
|
||||
maxLines: _minLines,
|
||||
softWrap: true,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: _textStyle,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _dispatch() {
|
||||
if (widget.minLines != null && widget.minLines > 0) {
|
||||
return _handleText();
|
||||
}
|
||||
return Text(
|
||||
widget.text,
|
||||
maxLines: widget.minLines,
|
||||
style: _textStyle,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return _dispatch();
|
||||
}
|
||||
}
|
||||
59
moehu/moehu_fontend/lib/widget/TopicView.dart
Normal file
59
moehu/moehu_fontend/lib/widget/TopicView.dart
Normal file
@@ -0,0 +1,59 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_modular/flutter_modular.dart';
|
||||
import 'package:peach/config/Colors.dart';
|
||||
import 'package:peach/entity/_.dart';
|
||||
|
||||
/*
|
||||
* 话题展示
|
||||
*/
|
||||
class TopicView extends StatelessWidget {
|
||||
final Function onTap;
|
||||
|
||||
final List<Tags> tag;
|
||||
|
||||
final bool edit;
|
||||
|
||||
const TopicView({this.tag, this.onTap, this.edit = false});
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Wrap(
|
||||
runSpacing: 3,
|
||||
crossAxisAlignment: WrapCrossAlignment.center,
|
||||
children: [
|
||||
...tag.map((e) {
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
Modular.to.pushNamed("/indexResultsList/${e.tagsTitle}/${2}");
|
||||
},
|
||||
child: Container(
|
||||
margin: EdgeInsets.only(right: 10),
|
||||
child: Text(
|
||||
"#${e.tagsTitle}",
|
||||
style: TextStyle(
|
||||
color: ColorConfig.ThemeColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}).toList(),
|
||||
edit
|
||||
? GestureDetector(
|
||||
onTap: () {
|
||||
onTap();
|
||||
},
|
||||
child: Container(
|
||||
margin: EdgeInsets.only(right: 10),
|
||||
child: Text(
|
||||
"编辑",
|
||||
style: TextStyle(
|
||||
color: ColorConfig.ThemeColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
: Container()
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
1
moehu/moehu_fontend/lib/widget/WaterfallFlow/.pydio
Normal file
1
moehu/moehu_fontend/lib/widget/WaterfallFlow/.pydio
Normal file
@@ -0,0 +1 @@
|
||||
508f6717-b2ff-4096-b80e-91c006bbd44d
|
||||
@@ -0,0 +1,80 @@
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
|
||||
import 'TileWidget.dart';
|
||||
|
||||
class StaggeredGridViewPage extends StatelessWidget {
|
||||
const StaggeredGridViewPage.count({
|
||||
@required this.title,
|
||||
@required this.crossAxisCount,
|
||||
@required this.tiles,
|
||||
this.mainAxisSpacing: 4.0,
|
||||
this.crossAxisSpacing: 4.0,
|
||||
}) : _staggeredGridViewMode = _StaggeredGridViewMode.count,
|
||||
maxCrossAxisExtent = null;
|
||||
|
||||
const StaggeredGridViewPage.extent({
|
||||
@required this.title,
|
||||
@required this.maxCrossAxisExtent,
|
||||
@required this.tiles,
|
||||
this.mainAxisSpacing: 4.0,
|
||||
this.crossAxisSpacing: 4.0,
|
||||
}) : _staggeredGridViewMode = _StaggeredGridViewMode.extent,
|
||||
crossAxisCount = null;
|
||||
|
||||
static const EdgeInsetsGeometry padding =
|
||||
const EdgeInsets.symmetric(horizontal: 4.0);
|
||||
|
||||
final String title;
|
||||
final List<StaggeredTile> tiles;
|
||||
final int crossAxisCount;
|
||||
final double mainAxisSpacing;
|
||||
final double crossAxisSpacing;
|
||||
final double maxCrossAxisExtent;
|
||||
final _StaggeredGridViewMode _staggeredGridViewMode;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return new Scaffold(
|
||||
body: new Padding(
|
||||
padding: const EdgeInsets.only(top: 4.0),
|
||||
child: _buildStaggeredGridView(context)));
|
||||
}
|
||||
|
||||
Widget _buildStaggeredGridView(BuildContext context) {
|
||||
switch (_staggeredGridViewMode) {
|
||||
case _StaggeredGridViewMode.count:
|
||||
return new StaggeredGridView.countBuilder(
|
||||
crossAxisCount: crossAxisCount,
|
||||
itemCount: tiles.length,
|
||||
itemBuilder: _getChild,
|
||||
mainAxisSpacing: mainAxisSpacing,
|
||||
crossAxisSpacing: crossAxisSpacing,
|
||||
padding: padding,
|
||||
staggeredTileBuilder: _getStaggeredTile,
|
||||
);
|
||||
default:
|
||||
return new StaggeredGridView.extentBuilder(
|
||||
maxCrossAxisExtent: maxCrossAxisExtent,
|
||||
itemCount: tiles.length,
|
||||
itemBuilder: _getChild,
|
||||
mainAxisSpacing: mainAxisSpacing,
|
||||
crossAxisSpacing: crossAxisSpacing,
|
||||
padding: padding,
|
||||
staggeredTileBuilder: _getStaggeredTile,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
StaggeredTile _getStaggeredTile(int i) {
|
||||
return i >= tiles.length ? null : tiles[i];
|
||||
}
|
||||
|
||||
TileWidget _getChild(BuildContext context, int index) {
|
||||
return new TileWidget(
|
||||
key: new ObjectKey(index), index: index, backgroundColor: Colors.green);
|
||||
}
|
||||
}
|
||||
|
||||
enum _StaggeredGridViewMode { count, extent }
|
||||
24
moehu/moehu_fontend/lib/widget/WaterfallFlow/TileWidget.dart
Normal file
24
moehu/moehu_fontend/lib/widget/WaterfallFlow/TileWidget.dart
Normal file
@@ -0,0 +1,24 @@
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
class TileWidget extends StatelessWidget {
|
||||
const TileWidget(
|
||||
{Key key, @required this.index, this.backgroundColor: Colors.green})
|
||||
: super(key: key);
|
||||
|
||||
final int index;
|
||||
final Color backgroundColor;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return new Container(
|
||||
color: this.backgroundColor,
|
||||
child: new Center(
|
||||
child: new CircleAvatar(
|
||||
backgroundColor: Colors.white,
|
||||
child: new Text('$index+1'),
|
||||
)),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
|
||||
|
||||
import 'StaggeredGridViewPage.dart';
|
||||
|
||||
const List<StaggeredTile> _tiles = const <StaggeredTile>[
|
||||
const StaggeredTile.count(2, 2),
|
||||
const StaggeredTile.count(1, 1),
|
||||
const StaggeredTile.count(1, 2),
|
||||
const StaggeredTile.count(1, 1),
|
||||
const StaggeredTile.count(4, 1),
|
||||
const StaggeredTile.count(4, 2),
|
||||
const StaggeredTile.count(1, 1),
|
||||
const StaggeredTile.count(1, 1),
|
||||
const StaggeredTile.count(1, 1),
|
||||
const StaggeredTile.count(1, 1),
|
||||
const StaggeredTile.count(1, 4),
|
||||
const StaggeredTile.count(1, 3),
|
||||
const StaggeredTile.count(1, 2),
|
||||
const StaggeredTile.count(1, 1),
|
||||
const StaggeredTile.count(1, 1),
|
||||
const StaggeredTile.count(1, 1),
|
||||
const StaggeredTile.count(1, 1),
|
||||
const StaggeredTile.count(1, 1),
|
||||
const StaggeredTile.count(1, 1),
|
||||
const StaggeredTile.count(1, 1),
|
||||
];
|
||||
|
||||
class SpannableCountCountPage extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return const StaggeredGridViewPage.count(
|
||||
title: 'Spannable (Count, Count)', crossAxisCount: 2, tiles: _tiles);
|
||||
}
|
||||
}
|
||||
116
moehu/moehu_fontend/lib/widget/WorkDataView.dart
Normal file
116
moehu/moehu_fontend/lib/widget/WorkDataView.dart
Normal file
@@ -0,0 +1,116 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:peach/config/Colors.dart';
|
||||
import 'package:peach/entity/_.dart';
|
||||
import 'package:peach/utils/_.dart';
|
||||
|
||||
/*
|
||||
* 作品的数据展示 点赞 评论 浏览
|
||||
*/
|
||||
class WorkDataView extends StatelessWidget {
|
||||
final MainAxisAlignment mainAxisAlignment;
|
||||
final OpusOpusInfoEntityData infoData;
|
||||
final bool isUpvote;
|
||||
final Function onUpvote;
|
||||
final bool isCollectionOpus;
|
||||
final Function onOpusCollectionOpus;
|
||||
|
||||
const WorkDataView({
|
||||
this.mainAxisAlignment = MainAxisAlignment.center,
|
||||
this.infoData,
|
||||
this.isUpvote = false,
|
||||
this.onUpvote,
|
||||
this.isCollectionOpus = false,
|
||||
this.onOpusCollectionOpus,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Align(
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
flex: 1,
|
||||
child: TextButton(
|
||||
onPressed: () {
|
||||
onUpvote();
|
||||
},
|
||||
child: Row(
|
||||
mainAxisAlignment: this.mainAxisAlignment,
|
||||
children: [
|
||||
Icon(
|
||||
Icons.thumb_up,
|
||||
size: 18,
|
||||
color: isUpvote
|
||||
? ColorConfig.ThemeColor
|
||||
: ColorConfig.TextColor,
|
||||
),
|
||||
SizedBox(
|
||||
width: 5,
|
||||
),
|
||||
Text(
|
||||
infoData.opusSatisfied.toString(),
|
||||
style: TextStyle(
|
||||
color: ColorConfig.TextColor,
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
flex: 1,
|
||||
child: TextButton(
|
||||
onPressed: () {
|
||||
onOpusCollectionOpus();
|
||||
},
|
||||
child: Row(
|
||||
mainAxisAlignment: this.mainAxisAlignment,
|
||||
children: [
|
||||
Icon(
|
||||
Icons.favorite,
|
||||
size: 18,
|
||||
color: isCollectionOpus
|
||||
? ColorConfig.ThemeColor
|
||||
: ColorConfig.TextColor,
|
||||
),
|
||||
SizedBox(
|
||||
width: 5,
|
||||
),
|
||||
Text(
|
||||
infoData.opusCollection.toString(),
|
||||
style: TextStyle(
|
||||
color: ColorConfig.TextColor,
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
flex: 1,
|
||||
child: Row(
|
||||
mainAxisAlignment: this.mainAxisAlignment,
|
||||
children: [
|
||||
Icon(
|
||||
Icons.visibility,
|
||||
size: 18,
|
||||
color: ColorConfig.TextColor,
|
||||
),
|
||||
SizedBox(
|
||||
width: 5,
|
||||
),
|
||||
Text(
|
||||
infoData.opusSee.toString(),
|
||||
style: TextStyle(
|
||||
color: ColorConfig.TextColor,
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
20
moehu/moehu_fontend/lib/widget/_.dart
Normal file
20
moehu/moehu_fontend/lib/widget/_.dart
Normal file
@@ -0,0 +1,20 @@
|
||||
library widget;
|
||||
|
||||
export 'ExhibitionSearch.dart';
|
||||
export 'Panel.dart';
|
||||
export 'PersonalpTitle.dart';
|
||||
export 'Line.dart';
|
||||
export 'ContentPositioningLayout.dart';
|
||||
export 'CircleTransparentIcon.dart';
|
||||
export 'TopicView.dart';
|
||||
export 'WorkDataView.dart';
|
||||
export 'CommentWidget.dart';
|
||||
export 'CommentList.dart';
|
||||
export 'ImagePickerWidget.dart';
|
||||
export 'FollowButton.dart';
|
||||
export 'PageAnimation.dart';
|
||||
export 'TextLimitDisplay.dart';
|
||||
export 'MyInput.dart';
|
||||
export 'RoutineShowDialog.dart';
|
||||
export 'Loading.dart';
|
||||
export 'EmptyText.dart';
|
||||
Reference in New Issue
Block a user