123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637 |
- import 'dart:io';
- import 'dart:math';
- import 'package:cached_network_image/cached_network_image.dart';
- import 'package:flutter/cupertino.dart';
- import 'package:flutter/material.dart';
- import 'package:flutter/services.dart';
- import 'package:multi_image_picker/multi_image_picker.dart';
- import 'package:path_provider/path_provider.dart';
- import 'package:provider/provider.dart';
- import 'package:sport/bean/forum.dart';
- import 'package:sport/bean/image.dart' as photo;
- import 'package:sport/bean/post.dart';
- import 'package:sport/bean/user.dart';
- import 'package:sport/pages/social/gallery_photo_view.dart';
- import 'package:sport/pages/social/social_detail_page.dart';
- import 'package:sport/provider/user_model.dart';
- import 'package:sport/router/navigator_util.dart';
- import 'package:sport/services/api/inject_api.dart';
- import 'package:sport/utils/toast.dart';
- import 'package:sport/widgets/appbar.dart';
- import 'package:sport/widgets/button_primary.dart';
- import 'package:sport/widgets/dialog/alert_dialog.dart';
- import 'package:sport/widgets/dialog/bindphone_dialog.dart';
- import 'package:sport/widgets/label.dart';
- import 'package:sport/widgets/space.dart';
- import 'chat_page.dart';
- class PostPage extends StatefulWidget {
- final String id; // 论坛Id
- final Forum forum; // 论坛实例
- final Post post; // 帖子 转发的情况下
- final String url; // url 转发的情况下
- final String hash; // 转发的情况下
- final String image; // 转发的情况下
- final List<Forum> forums; // 主要是获取 forums 名字 分享好像拿不到这个东西...
- const PostPage(this.id, {this.post, this.forum,this.url,this.hash,this.image,this.forums});
- @override
- State<StatefulWidget> createState() => _PageState();
- }
- class _PageState extends State<PostPage> {
- List<Asset> imageList = [];
- TextEditingController _controller;
- ValueNotifier<String> _valueNotifier = ValueNotifier("");
- FocusNode _focusNode;
- ValueNotifier<int> labelIndex = ValueNotifier(0);
- Forum selectLabel;
- @override
- void initState() {
- super.initState();
- _focusNode = FocusNode();
- _controller = TextEditingController()..addListener(() {});
- //...
- if(widget.post != null) {
- _controller.text = "转发帖子";
- _valueNotifier.value ="转发帖子";
- }
- }
- @override
- void dispose() {
- super.dispose();
- _controller?.dispose();
- _focusNode?.dispose();
- _valueNotifier?.dispose();
- PaintingBinding.instance.imageCache.clear();
- }
- @override
- Widget build(BuildContext context) {
- return Scaffold(
- backgroundColor: Colors.white,
- appBar: AppBar(
- leading: buildBackButton(context),
- title: Row(
- mainAxisAlignment: MainAxisAlignment.spaceBetween,
- children: <Widget>[
- Text(""),
- PrimaryButton(
- width: 65,
- height: 35,
- content: "发布",
- callback: () async {
- if (await showBindPhoneDialog(context) != true) {
- return ;
- }
- // if(widget.forum != null) {
- // NavigatorUtil.pushAndRemoveUntil(context, (context) => SocialDetailPage(widget.forum, index: 2), RouteSettings(name: "forum"));
- // }else {
- // Navigator.of(context).pop(true);
- // }
- _focusNode?.unfocus();
- String postValue = _valueNotifier.value.trim();
- if (postValue == "") {
- ToastUtil.show("不能发布空白内容喔!");
- return;
- }
- if (await showDialog(
- context: context,
- builder: (context) => CustomAlertDialog(title: '是否确认发布', ok: () => Navigator.of(context).pop(true)),
- ) !=
- true) {
- return;
- }
- bool result = await showDialog(
- context: context,
- barrierDismissible: false,
- builder: (context) => SimpleDialog(
- children: <Widget>[
- PostAction(selectLabel?.forumId == null? '':selectLabel.forumId, postValue, imageList, widget.post?.quoteSubjectId == '0' ? widget.post?.id : widget.post?.quoteSubjectId,widget.url,widget.hash,widget.image)
- ],
- ));
- if (result == true) {
- ToastUtil.show("发布成功");
- // if(widget.forum != null) {
- // NavigatorUtil.pushAndRemoveUntil(context, (context) => SocialDetailPage(widget.forum, index: 2), RouteSettings(name: "forum"));
- // }else {
- Navigator.of(context).pop(true);
- // }
- } else {
- // ToastUtil.show("已取消发布");
- }
- },
- )
- ],
- ),
- ),
- body: SingleChildScrollView(
- child: Padding(
- padding: const EdgeInsets.symmetric(horizontal: 12.0),
- child: Form(
- onWillPop: () async {
- if (_valueNotifier.value.isNotEmpty || imageList.isNotEmpty) {
- bool result = await showDialog(
- context: context,
- barrierDismissible: false,
- builder: (context) {
- return CustomAlertDialog(
- title: '确认关闭吗?',
- ok: () {
- Navigator.of(context).pop(true);
- },
- );
- }) ??
- false;
- return result;
- }
- return true;
- },
- child: Column(
- children: <Widget>[
- TextFormField(
- focusNode: _focusNode,
- controller: _controller,
- keyboardType: TextInputType.multiline,
- maxLines: 8,
- maxLength: 500,
- style: TextStyle(fontSize: 16),
- strutStyle: StrutStyle(forceStrutHeight: true, height: 1.4),
- onChanged: (v) {
- _valueNotifier.value = v;
- if (_valueNotifier.value.length == 500) {
- ToastUtil.show("文字数量已达上限");
- }
- },
- buildCounter: (
- BuildContext context, {
- int currentLength,
- int maxLength,
- bool isFocused,
- }) {
- return Align(alignment: Alignment.centerLeft, child: Padding(
- padding: const EdgeInsets.only(left:8.0),
- child: Text("$currentLength/$maxLength"),
- ));
- },
- decoration: InputDecoration(hintText: widget.post == null ? '发表你的看法...' : "", border: InputBorder.none,
- contentPadding: EdgeInsets.symmetric(horizontal: 6),
- hintStyle: TextStyle(color: Color(0xff999999))),
- ),
- Space(
- height: 16,
- ),
- widget.post == null? widget.url != null ? _postLink() : widget.image != null ? _postSharePoster(widget.image) :GridView.builder(
- padding: EdgeInsets.zero,
- shrinkWrap: true,
- physics: NeverScrollableScrollPhysics(),
- itemCount: imageList.length + (imageList.length < 9 ? 1 : 0),
- gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3, crossAxisSpacing: 12.0, mainAxisSpacing: 12.0),
- itemBuilder: (context, index) {
- return InkWell(
- onTap: () => _select(),
- child: ClipRRect(
- borderRadius: BorderRadius.circular(6),
- child: index >= imageList.length
- ? Image.asset(
- "lib/assets/img/bbs_icon_addimage.png",
- fit: BoxFit.cover,
- )
- : AssetThumb(
- asset: imageList[index],
- quality: 50,
- width: 200,
- height: 200,
- ),
- ),
- );
- })
- : Container(
- padding: EdgeInsets.all(11.0),
- width: double.infinity,
- decoration: BoxDecoration(
- shape: BoxShape.rectangle, borderRadius: BorderRadius.all(Radius.circular(10)), color: Theme.of(context).scaffoldBackgroundColor),
- child: _postWidget(),
- ),
- // if(widget.url != null)
- // _postLink(),
- Space(height: 21.0,),
- Divider(),
- _postGameLabel(),
- ],
- ),
- ),
- ),
- ),
- );
- }
- Widget _postWidget() {
- Post post = widget.post.quoteSubject ?? widget.post;
- double width = MediaQuery.of(context).size.width - 24 - 22;
- return Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: <Widget>[
- RichText(
- maxLines: 3,
- overflow: TextOverflow.ellipsis,
- text: TextSpan(style: Theme.of(context).textTheme.subtitle1.copyWith(fontSize: 16), children: <InlineSpan>[
- TextSpan(text: '${post.nickname}:', style: Theme.of(context).textTheme.subtitle1.copyWith(color: Theme.of(context).accentColor)),
- TextSpan(text: '${post.content}', style: Theme.of(context).textTheme.subtitle1),
- ]),
- ),
- if (post.images.length > 0)
- GridView.count(
- physics: new NeverScrollableScrollPhysics(),
- shrinkWrap: true,
- padding: EdgeInsets.only(top: 15),
- childAspectRatio: post.images.length == 1 ? max(16 / 10, post.images[0].getImageAspectRatio()) : 1,
- crossAxisSpacing: 10.0,
- crossAxisCount: min(3, post.images.length),
- children: post.images
- .asMap()
- .keys
- .take(min(3, post.images.length))
- .map((i) => GestureDetector(
- onTap: () => open(context, i, post.images),
- child: i < 2
- ? post.images.length == 1
- ? Row(
- mainAxisSize: MainAxisSize.min,
- children: <Widget>[
- ClipRRect(
- borderRadius: BorderRadius.circular(6),
- child: Stack(
- children: <Widget>[
- CachedNetworkImage(
- alignment: Alignment.centerLeft,
- imageUrl: post.images[i].thumbnail,
- fit: BoxFit.cover,
- width: post.images[i].getWidth(width),
- ),
- if (post.images[i].isLongImage())
- Positioned(
- bottom: 4,
- right: 4,
- child: Container(
- padding: EdgeInsets.symmetric(horizontal: 8, vertical: 2),
- decoration:
- BoxDecoration(color: Colors.black.withOpacity(.8), borderRadius: BorderRadius.all(Radius.circular(20))),
- child: Text(
- "长图",
- style: Theme.of(context).textTheme.bodyText1.copyWith(color: Colors.white),
- ),
- ),
- )
- ],
- ))
- ],
- )
- : ClipRRect(
- borderRadius: BorderRadius.circular(6),
- child: CachedNetworkImage(alignment: Alignment.centerLeft, imageUrl: post.images[i].thumbnail, fit: BoxFit.cover))
- : ClipRRect(
- borderRadius: BorderRadius.circular(6),
- child: Stack(
- fit: StackFit.expand,
- children: <Widget>[
- CachedNetworkImage(
- imageUrl: post.images[i].thumbnail,
- fit: BoxFit.cover,
- ),
- if (post.images.length - 3 > 0)
- Container(
- color: Color(0x80000000),
- child: Center(
- child: Text(
- "+${post.images.length - 3}",
- style: TextStyle(color: Colors.white, fontSize: 16),
- ),
- ),
- )
- ],
- ))))
- .toList()),
- if(post.quoteData != null)
- _postLink(),
- ],
- );
- }
- Widget _postLink(){
- return Container(
- padding: EdgeInsets.all(12.0),
- color: Colors.white,
- child: Row(
- crossAxisAlignment: CrossAxisAlignment.start,
- mainAxisSize: MainAxisSize.max,
- children: <Widget>[
- CachedNetworkImage(
- imageUrl: avatarList[4],
- width: 60.0,
- height: 60.0,
- ),
- Space(
- width: 5.0,
- ),
- Expanded(
- child: RichText(
- maxLines: 3,
- overflow: TextOverflow.ellipsis,
- text: TextSpan(style: Theme.of(context).textTheme.subtitle1.copyWith(fontSize: 16), children: <InlineSpan>[
- TextSpan(text: '${Provider.of<UserModel>(context).user.name}:', style: Theme.of(context).textTheme.subtitle1.copyWith(color: Theme.of(context).accentColor)),
- TextSpan(text: '分享了他的运动记录,快来围观吧~', style: Theme.of(context).textTheme.subtitle1),
- ]),
- ),
- ),]),
- );
- }
- Widget _postSharePoster(String image){
- return Row(
- mainAxisAlignment: MainAxisAlignment.start,
- children: <Widget>[
- Container(
- constraints: BoxConstraints(
- maxWidth: 100,
- maxHeight: 200,
- ),
- child: ClipRRect(
- borderRadius: BorderRadius.circular(6),
- child:Image.file(
- File(image),
- fit: BoxFit.cover,
- )
- ),
- )
- ],
- );
- }
- void _select() async {
- _focusNode?.unfocus();
- List<Asset> resultList;
- String error;
- // int max = 9 - imageList.length;
- // if (max <= 0) {
- // Fluttertoast.showToast(msg: "不能再添加了~", backgroundColor: Colors.black, textColor: Colors.white, fontSize: 16.0);
- // return;
- // }
- try {
- resultList = await MultiImagePicker.pickImages(
- maxImages: 9,
- selectedAssets: imageList,
- materialOptions: MaterialOptions(
- actionBarTitle: "选择图片",
- allViewTitle: "选择图片",
- useDetailsView: true,
- startInAllView: true,
- selectionLimitReachedText: "不能选择更多了~",
- ),
- cupertinoOptions: CupertinoOptions(
- selectionFillColor: "#ff11ab",
- selectionTextColor: "#ffffff",
- selectionCharacter: "✓",
- ));
- } on Exception catch (e) {
- error = e.toString();
- }
- // If the widget was removed from the tree while the asynchronous platform
- // message was in flight, we want to discard the reply rather than calling
- // setState to update our non-existent appearance.
- if (!mounted) return;
- if (resultList == null || resultList.isEmpty) return;
- setState(() {
- imageList = resultList;
- });
- }
- Widget _labelItem(String title){
- if(title == null) return Container();
- return Container(
- padding: EdgeInsets.symmetric(vertical: 6.0,horizontal: 16.0),
- decoration: BoxDecoration(border: Border.all(color: Theme.of(context).accentColor), borderRadius: BorderRadius.all(Radius.circular(44.0))),
- child: Row(
- crossAxisAlignment: CrossAxisAlignment.center,
- children: <Widget>[
- Text(title,style: TextStyle(color: Theme.of(context).accentColor,fontSize: 12.0),strutStyle: StrutStyle(forceStrutHeight: true),),
- Space(width: 5.0,),
- Image.asset("lib/assets/img/btn_close_yellow.png",width: 7.0,height: 7.0,)
- ],
- ),
- );
- }
- Widget _postGameLabel(){
- return Row(
- mainAxisAlignment: MainAxisAlignment.spaceBetween,
- children: <Widget>[
- InkWell(
- child: selectLabel != null ? _labelItem(selectLabel.gameName) : Container(),
- onTap: (){
- selectLabel = new Forum();
- setState(() {});
- },
- ),
- InkWell(
- child: Container(
- height: 34.0,
- child: Row(
- // crossAxisAlignment: CrossAxisAlignment.center,
- children: <Widget>[
- Text("添加游戏标签",style: TextStyle(fontSize: 12.0,color: Color(0xff666666)),),
- Divider(height: 2.0,),
- Space(
- width: 4.0,
- ),
- Image.asset("lib/assets/img/btn_arrow_bottom.png")
- ],
- ),
- ),
- onTap: () async {
- bool flag = await showDialog(context: context,builder: (context) => CustomAlertDialog(title: "添加游戏标签",
- isLine: true,
- ok: () => Navigator.of(context).pop(true),
- child: Container(
- padding: EdgeInsets.only(left: 20.0),
- width: double.infinity,
- child: ValueListenableBuilder(
- valueListenable: labelIndex,
- builder: (context,index,child) => Wrap(
- runSpacing: 12.0,
- spacing: 8.0,
- children: widget.forums.asMap()
- .entries
- .map((e) => _buildDrawerButtonItem(
- e.value, e.key, labelIndex))
- .toList()
- ),
- ),
- ),));
- // print("${labelIndex}==========================================");
- if(flag){
- selectLabel = widget.forums[labelIndex.value];
- print("${selectLabel.toJson()}-----------------------------------");
- setState(() {});
- }
- },
- ),
- ],
- );
- }
- Widget _buildDrawerButtonItem(
- Forum data, int index, ValueNotifier<int> targetIndex) {
- return InkWell(
- child: Container(
- decoration: BoxDecoration(
- color: index == targetIndex.value
- ? Theme.of(context).accentColor
- : Colors.white,
- borderRadius: BorderRadius.all(Radius.circular(20.0)),
- border: Border.all(
- color: index == targetIndex.value
- ? Colors.white
- : Theme.of(context).dividerTheme.color)),
- padding: EdgeInsets.symmetric(vertical: 8.0, horizontal: 20.0),
- child: Text(
- data.gameName,
- strutStyle: StrutStyle(forceStrutHeight: true),
- style: TextStyle(
- fontSize: 14.0,
- color: index == targetIndex.value
- ? Colors.white
- : Color(0xff999999)),
- ),
- ),
- onTap: () {
- labelIndex.value = index;
- },
- );
- }
- }
- class PostAction extends StatefulWidget {
- final String forumId;
- final String content;
- final List<Asset> imageList;
- final String quoteSubjectId;
- final String url;
- final String hash;
- final String image;
- const PostAction(this.forumId, this.content, this.imageList, this.quoteSubjectId,this.url,this.hash,this.image);
- @override
- State<StatefulWidget> createState() => PostActionState();
- }
- class PostActionState extends State<PostAction> with InjectApi {
- final Map<Asset, photo.Image> upload = {};
- ValueNotifier<String> _msg;
- bool _disposed = false;
- @override
- void initState() {
- super.initState();
- _disposed = false;
- _msg = ValueNotifier<String>("请稍候...");
- WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
- post();
- });
- }
- @override
- void dispose() {
- _disposed = true;
- _msg?.dispose();
- super.dispose();
- }
- void post() async {
- List<Asset> imageList = [];
- if(widget.imageList?.isNotEmpty == true){
- imageList.addAll(widget.imageList);
- }
- if(widget.image != null){
- imageList.add(Asset(Uri.file(widget.image).toString() ,"", 0, 0));
- }
- if (imageList != null && imageList.isNotEmpty) {
- Directory tempDir = await getTemporaryDirectory();
- Directory directory = new Directory('${tempDir.path}/upload');
- if (!directory.existsSync()) {
- directory.createSync();
- print('文档初始化成功,文件保存路径为 ${directory.path}');
- }
- for (var i = 0; i < imageList.length; i++) {
- if (_disposed) break;
- Asset asset = imageList[i];
- if (upload.containsKey(asset)) continue;
- ByteData byteData = await asset.getByteData(quality: 85);
- File file = File('${directory.path}/${DateTime.now().millisecondsSinceEpoch}_$i.jpg');
- List<int> bytes = byteData.buffer.asUint8List().toList();
- print('临时文件 ${file.path} ${bytes.length}');
- file.writeAsBytesSync(bytes);
- _msg.value = "上传图片(${i + 1}/${imageList.length})...";
- var resp = await api.mediaUp4Subject(file, srcType: "image");
- photo.Image image = resp.data;
- file.delete();
- upload[asset] = image;
- // await Future.delayed(Duration(seconds: 3));
- }
- }
- _msg.value = "发布中...";
- // await Future.delayed(Duration(seconds: 3));
- if (_disposed) return;
- var data;
- // 这里我也没办法知道它之前的名字叫什么吧...
- if(widget.url != null){
- data =
- await api.postForum(widget.forumId, widget.content, images: upload.values.map((e) => e.id).toList().join(","), quoteSubjectId: widget.quoteSubjectId,
- quoteData: '{"username":{"value":"${Provider.of<UserModel>(context,listen: false).user.name}","from":"user#${Provider.of<UserModel>(context,listen: false).user.id}"},"url":{"value":"${widget.url}"},"hash":{"value":"${widget.hash}"}}');
- }else{
- data =
- await api.postForum(widget.forumId, widget.content, images: upload.values.map((e) => e.id).toList().join(","), quoteSubjectId: widget.quoteSubjectId);
- }
- if (data != null && data.code == 0) {
- Navigator.of(context).pop(true);
- } else {
- Navigator.of(context).pop(false);
- }
- }
- @override
- Widget build(BuildContext context) {
- return Padding(
- padding: const EdgeInsets.symmetric(vertical: 16),
- child: Column(
- children: <Widget>[
- CircularProgressIndicator(),
- Padding(
- padding: const EdgeInsets.only(top: 15),
- child: ValueListenableBuilder(valueListenable: _msg, builder: (BuildContext context, String value, Widget child) => Text(value)),
- )
- ],
- ),
- );
- }
- }
|