123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631 |
- import 'dart:io';
- import 'dart:math';
- import 'package:cached_network_image/cached_network_image.dart';
- import 'package:flutter/material.dart';
- import 'package:fluttertoast/fluttertoast.dart';
- import 'package:images_picker/images_picker.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/pages/social/gallery_photo_view.dart';
- import 'package:sport/provider/user_model.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/space.dart';
- import 'package:umeng_common_sdk/umeng_common_sdk.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<Media> 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 = "转发帖子";
- }
- UmengCommonSdk.onEvent("social_new_post", {});
- }
- @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 {
- UmengCommonSdk.onEvent("social_new_post_click", {});
- 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 ?? widget.id, postValue, imageList, widget.post?.quoteSubjectId == '0' ? widget.post?.id : widget.post?.quoteSubjectId, widget.url, widget.hash, widget.image)],
- ));
- if (result == true) {
- ToastUtil.show("发布成功");
- await Future.delayed(Duration(seconds: 1));
- // 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, {
- required int currentLength,
- int? maxLength,
- required bool isFocused,
- }) {
- return Align(
- alignment: Alignment.centerLeft,
- child: Padding(
- padding: const EdgeInsets.only(left: 8.0),
- child: Text("$currentLength/$maxLength"),
- ));
- },
- cursorColor: Theme.of(context).colorScheme.secondary,
- 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 ClipRRect(
- borderRadius: BorderRadius.circular(6),
- child: index >= imageList.length
- ? InkWell(
- onTap: () {
- _select();
- },
- child: Image.asset(
- "lib/assets/img/bbs_icon_addimage.png",
- fit: BoxFit.cover,
- ),
- )
- : Container(
- child: Stack(
- children: [
- Image.file(
- File(imageList[index].path),
- fit: BoxFit.cover,
- width: 200,
- height: 200,
- ),
- Align(
- alignment: Alignment.topRight,
- child: GestureDetector(
- onTap: (){
- setState(() {
- imageList.removeAt(index);
- });
- },
- child: Container(
- margin: const EdgeInsets.all(6),
- padding: const EdgeInsets.all(6),
- decoration: BoxDecoration(shape: BoxShape.circle, color: Colors.black.withOpacity(.6)),
- child: Image.asset("lib/assets/img/btn_close_small.png", color: Colors.white,),
- ),
- ))
- ],
- ),
- ),
- );
- })
- : 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(),
- if (widget.forums?.isNotEmpty == true) _postGameLabel(),
- ],
- ),
- ),
- ),
- ),
- );
- }
- Widget _postWidget() {
- Post? post = widget.post?.quoteSubject ?? widget.post;
- if (post == null) return Container();
- 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?.isNotEmpty == true)
- 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>[
- Icon(
- Icons.link,
- size: 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();
- int max = 9 - imageList.length;
- if (max <= 0) {
- Fluttertoast.showToast(msg: "不能再添加了~", backgroundColor: Colors.black, textColor: Colors.white, fontSize: 16.0);
- return;
- }
- try {
- List<Media>? resultList = await ImagesPicker.pick(quality: 0.8, maxSize: 1024, count: 9);
- if (!mounted) return;
- setState(() {
- imageList += resultList ?? [];
- });
- } on Exception catch (e) {
- return;
- }
- }
- 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];
- 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<Media>? 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<Media, photo.Image> upload = {};
- late 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<Media> imageList = [];
- if (widget.imageList?.isNotEmpty == true) {
- imageList.addAll(widget.imageList!);
- }
- if (widget.image != null) {
- imageList.add(Media(size: 0, path: widget.image!));
- }
- debugPrint("post add image ${imageList.map((e) => e.path).toList()}");
- if (imageList.isNotEmpty) {
- for (var i = 0; i < imageList.length; i++) {
- if (_disposed) break;
- Media asset = imageList[i];
- if (upload.containsKey(asset)) continue;
- File file = File(asset.path);
- _msg.value = "上传图片(${i + 1}/${imageList.length})...";
- try {
- var resp = await api.mediaUp4Subject(file, srcType: "image");
- photo.Image? image = resp.data;
- if (image != null) {
- upload[asset] = image;
- debugPrint("post upload image ${image.toJson()}");
- }
- } catch (e, stack) {
- debugPrintStack(stackTrace: stack);
- ToastUtil.show("第${i + 1}张图片检测不通过,请勿使用色情、暴力、广告等的图片");
- Navigator.of(context).pop(false);
- return;
- }
- // 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);
- }
- await Future.delayed(Duration(seconds: 1));
- if (data != null && data.code == 0) {
- for (var i = 0; i < imageList.length; i++) {
- Media asset = imageList[i];
- File file = File(asset.path);
- file.delete();
- }
- 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)),
- )
- ],
- ),
- );
- }
- }
|