import 'dart:async'; import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.dart'; import 'package:get/get.dart'; import 'package:link/utils/global.dart'; import 'package:link/view/home_social_list.dart'; import '../model/model.dart'; import '../utils/size_fit.dart'; import '../utils/storage.dart'; import '../utils/util.dart'; import 'home_add_link.dart'; class HomeContent extends StatefulWidget { UserBean userBean; Map styles; GlobalKey? _itemkey; GlobalKey? _addLinkkey; List socials; double scale; // ignore: prefer_typing_uninitialized_variables var _openMenu, _share; bool _isPreview = false; HomeContent({ Key? key, required this.userBean, required this.styles, required this.socials, GlobalKey? itemkey, GlobalKey? addLinkkey, required this.scale, var openMenu, var share, bool? isPreview, }) : super(key: key) { if (openMenu != null) { _openMenu = openMenu; } if (share != null) { _share = share; } if (isPreview != null) { _isPreview = isPreview; } if (itemkey != null) { _itemkey = itemkey; } if (addLinkkey != null) { _addLinkkey = addLinkkey; } } @override State createState() => _HomeContentState(); } class _HomeContentState extends State { bool isExpanded = false; bool isMyPage = false; GlobalKey columnKey = GlobalKey(); int bottomStatus = -1; //copyright -1都不显示 0 显示相对布局 1 显示绝对布局 @override void initState() { // TODO: implement initState super.initState(); if (Global().hasLogin && StorageUtil().getJSON('userInfo')['id'] == widget.userBean.id) { isMyPage = true; } // bottomStatus = 0; // if (bottomStatus != -1) { // return; // } Timer(const Duration(milliseconds: 300), () { RenderBox widget = columnKey.currentContext!.findRenderObject() as RenderBox; setState(() { if (widget.size.height >= MediaQuery.of(context).size.height) { bottomStatus = 0; } else { bottomStatus = 1; } }); }); } Widget background() { var background = widget.styles['background']; if (background['type'] == 'single-color') { String strColor = background['color'].substring(1, 9); int value = int.parse(strColor, radix: 16); return Container( color: Color(value), ); } if (background['type'] == 'skew') { double screenHeight = MediaQuery.of(context).size.height; String strTopColor = background['top_color'].substring(1, 9); int topColor = int.parse(strTopColor, radix: 16); String strBottomColor = background['bottom_color'].substring(1, 9); int bottomColor = int.parse(strBottomColor, radix: 16); String strSperateColor = background['seprate_line_color'].substring(1, 9); int sperateColor = int.parse(strSperateColor, radix: 16); double topLeft = double.parse(background['top_left_y']); double topRight = double.parse(background['top_right_y']); if (topLeft == topRight) { return Container( color: Color(topColor), width: 375.px * widget.scale, height: screenHeight * widget.scale, child: Column( children: [ SizedBox( height: topLeft * widget.scale, ), Container( height: screenHeight * widget.scale - topLeft * widget.scale, width: 375.px * widget.scale, decoration: BoxDecoration( color: Color(bottomColor), borderRadius: BorderRadius.only( topLeft: Radius.circular( double.parse(background['top_left_corner']).px * widget.scale), topRight: Radius.circular( double.parse(background['top_right_corner']).px * widget.scale)), // border: Border( // top: BorderSide( // color: Colors.red, // width: double.parse( // background['seprate_line_width']))) )) ], ), ); } return Container( color: Color(topColor), width: 375.px * widget.scale, height: screenHeight * widget.scale, child: Stack(children: [ ClipPath( clipper: SkewCut(topLeft.px * widget.scale, topRight.px * widget.scale), child: Container( // decoration: const BoxDecoration( // gradient: // LinearGradient(colors: [Colors.blue, Colors.pink])), color: Color(bottomColor), width: 375.px * widget.scale, height: screenHeight * widget.scale, ), ), CustomPaint( painter: SkewPaint( topLeft.px * widget.scale, topRight.px * widget.scale, Color(sperateColor), double.parse(background['seprate_line_width']) * widget.scale, widget.scale)) ]), ); } List colors = []; List stops = []; background['colors'].forEach((item) { String strColor = item['color'].substring(1, 9); int value = int.parse(strColor, radix: 16); colors.add(Color(value)); stops.add(item['percent'] * 0.01); }); double corner = double.parse(background['corner']); // double corner = 90; if (corner > 90) { corner = 90; } double beginLeft = corner==0?0:-corner / 45; double beginTop = -1; double endLeft = corner / 45; double endTop = 1.0; if (corner > 45) { beginTop = -(1 - (corner - 45) / 45); endTop = 1 - (corner - 45) / 45; } if (beginLeft < -1) { beginLeft = -1.0; } if (endLeft > 1) { endLeft = 1.0; } return Container( decoration: BoxDecoration( gradient: LinearGradient( begin: Alignment(beginLeft, beginTop), end: Alignment(endLeft, endTop), colors: colors, stops: stops )), ); } Widget topWidget() { return Container( width: 375.px * widget.scale, child: Row( children: [ if (widget._isPreview && widget.scale == 1.0) GestureDetector( onTap: () { Get.back(); }, // onTap: (){Get.to(()=>const EditScreen());print('helo');}, child: Container( height: 72.px, alignment: Alignment.centerLeft, padding: EdgeInsets.only( left: 24.px * widget.scale, right: 24.px * widget.scale), child: Text( '退出预览', style: TextStyle( fontSize: 14.px, color: Util().stringToColor( widget.styles['toolbar']['left_icon']['color']), ), ), ), ), if (!widget._isPreview || (widget._isPreview && widget.scale != 1.0)) GestureDetector( onTap: () { if (StorageUtil().getBool('hasLogin') == null || StorageUtil().getBool('hasLogin') == false) { Get.toNamed('/welcome'); return; } if (!isMyPage) { Get.toNamed('/', parameters: {}, preventDuplicates: false); return; } widget._openMenu(); // Get.toNamed('/detail'); }, // onTap: (){Get.to(()=>const EditScreen());print('helo');}, child: Container( height: 72.px * widget.scale, padding: EdgeInsets.only( left: 24.px * widget.scale, right: 24.px * widget.scale), child: SvgPicture.asset( isMyPage ? 'assets/icons/navi_menu.svg' : 'assets/icons/home.svg', width: 24.px * widget.scale, height: 24.px * widget.scale, color: Util().stringToColor( widget.styles['toolbar']['left_icon']['color']), ), ), ), const Expanded( child: SizedBox( height: 1.0, )), if (isMyPage && !widget._isPreview) GestureDetector( onTap: () { Get.toNamed('/home_preview', parameters: {"style": jsonEncode(widget.styles)}); // Get.toNamed('/', // parameters: {'preview': '1'}, preventDuplicates: false); }, child: Container( margin: EdgeInsets.only(right: 0.px), child: SvgPicture.asset( 'assets/icons/preview.svg', width: 36.px * widget.scale, height: 24.px * widget.scale, color: Util().stringToColor( widget.styles['toolbar']['right_icon']['color']), )), ), GestureDetector( onTap: () { widget._share(); // js.context.callMethod('share',['hi']); }, child: Container( height: 72.px * widget.scale, padding: EdgeInsets.only( left: 24.px * widget.scale, right: 24.px * widget.scale), child: SvgPicture.asset( 'assets/icons/navi_share.svg', width: 24.px * widget.scale, height: 24.px * widget.scale, color: Util().stringToColor( widget.styles['toolbar']['right_icon']['color']), ), ), ) ], ), ); } Widget avatarWidget() { var avatarObj = widget.styles['avatar']; String strColor = ''; if (avatarObj['border_color'] != null && avatarObj['border_color'].length >= 9) { strColor = avatarObj['border_color'].substring(1, 9); } Color borderColor; if (strColor.isEmpty) { borderColor = Colors.transparent; } else { int value = int.parse(strColor, radix: 16); borderColor = Color(value); } AlignmentGeometry alignmentGeometry = Alignment.center; double marginLeft = 0.0; double marginRight = 0.0; if (avatarObj['type'] == 'left') { alignmentGeometry = Alignment.centerLeft; if (!avatarObj['margin_left'].isEmpty) { marginLeft = double.parse(avatarObj['margin_left']); } } else if (avatarObj['type'] == 'right') { alignmentGeometry = Alignment.centerRight; if (!avatarObj['margin_right'].isEmpty) { marginLeft = double.parse(avatarObj['margin_right']); } } return Container( width: 375.px * widget.scale, alignment: alignmentGeometry, margin: EdgeInsets.only( left: marginLeft * widget.scale, right: marginRight * widget.scale, top: double.parse(avatarObj['top']).px * widget.scale), child: ClipRRect( borderRadius: BorderRadius.circular( double.parse(avatarObj['border_radius']).px * widget.scale), child: Container( decoration: BoxDecoration( image: DecorationImage( image: NetworkImage(widget.userBean.avatar), fit: BoxFit.cover), borderRadius: BorderRadius.circular( double.parse(avatarObj['border_radius']).px * widget.scale), border: Border.all( color: borderColor, width: double.parse(avatarObj['border_width']).px * widget.scale), ), width: double.parse(avatarObj['width']).px * widget.scale, height: double.parse(avatarObj['height']).px * widget.scale, // child: Image.network(userBean!.avatar), ), ), ); } Widget nicknameWidget() { var nickObj = widget.styles['nickname']; String strColor = nickObj['color'].substring(1, 9); int value = int.parse(strColor, radix: 16); TextAlign textAlign = TextAlign.center; if (nickObj['type'] == 'left') { textAlign = TextAlign.left; } else if (nickObj['type'] == 'right') { textAlign = TextAlign.right; } FontWeight fontWeight = FontWeight.normal; if (nickObj['font_weight'] == 'bold') { fontWeight = FontWeight.bold; } return Container( width: 375.px * widget.scale, margin: EdgeInsets.only(top: double.parse(nickObj['top']).px * widget.scale), child: Text( widget.userBean.nickname!, textAlign: textAlign, style: TextStyle( color: Color(value), fontSize: double.parse(nickObj['font_size']).px * widget.scale, fontWeight: fontWeight), ), ); } Widget signatureWidget() { var signatureObj = widget.styles['signature']; double left = double.parse(signatureObj['margin_left']).px * widget.scale; double right = double.parse(signatureObj['margin_right']).px * widget.scale; String strColor = signatureObj['color'].substring(1, 9); int value = int.parse(strColor, radix: 16); TextAlign textAlign = TextAlign.center; if (signatureObj['type'] == 'left') { textAlign = TextAlign.left; } else if (signatureObj['type'] == 'right') { textAlign = TextAlign.right; } double height = double.parse(signatureObj['line_height']) / double.parse(signatureObj['font_size']); int lines = int.parse(signatureObj['num_lines']); TextStyle style = TextStyle( color: Color(value), height: height, fontSize: double.parse(signatureObj['font_size']).px * widget.scale); String content = widget.userBean.signature!; bool showExpand = false; String strShow = ''; double width = (375.px - left - right) * widget.scale; double maxHeight = lines * Util().boundingTextSize('1', style, width).height; if (Util().boundingTextSize(content, style, width).height <= maxHeight || isExpanded) { strShow = content; } else { for (int i = 5 * lines; i < content.length; i++) { if (!showExpand && !isExpanded) { String subString = content.substring(0, i) + '...'; if (Util().boundingTextSize(subString, style, width).height > maxHeight) { strShow = content.substring(0, i - 8);// + '...'; showExpand = true; } } } } if (showExpand) { return Container( margin: EdgeInsets.only( top: double.parse(signatureObj['top']), left: left, right: right, ), child: Stack( children: [ Text( strShow, textAlign: textAlign, style: style, ), Positioned( right: 0, bottom: 0, child: GestureDetector( onTap: () { setState(() { isExpanded = true; }); }, child: Container( height: maxHeight / lines, // width: maxHeight / lines, alignment: Alignment.center, child: Text('…更多',style: TextStyle(color: const Color(0x33131314),fontSize: 13.px*widget.scale),) // SvgPicture.asset( // 'assets/icons/arrow_down.svg', // color: // Util().stringToColor(signatureObj['icon']['color']), // width: double.parse(signatureObj['icon']['width']), // height: double.parse(signatureObj['icon']['height']), // ), ), )) ], )); } return Container( margin: EdgeInsets.only( top: double.parse(signatureObj['top']).px * widget.scale, left: left, right: right, ), child: Text( strShow, textAlign: textAlign, // softWrap: true, // overflow: TextOverflow.ellipsis, style: style, // maxLines: lines //, ), ); } Widget locationWidget() { var locationObj = widget.styles['location']; double top = 0.0; if (locationObj['top'] != null) { top = double.parse(locationObj['top']).px * widget.scale; } return Container( alignment: Alignment.center, margin: EdgeInsets.only(top: top), child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Container( height: double.parse(locationObj['height']).px * widget.scale, width: double.parse(locationObj['height']).px * widget.scale, alignment: Alignment.center, child: SvgPicture.asset( widget.userBean.sex == 'MALE' ? 'assets/icons/gender_male.svg' : 'assets/icons/gender_female.svg', width: double.parse(locationObj['gender']['width']).px * widget.scale, height: double.parse(locationObj['gender']['height']).px * widget.scale, color: Util().stringToColor(locationObj['gender']['color']), ), decoration: BoxDecoration( borderRadius: BorderRadius.all(Radius.circular( double.parse(locationObj['height']).px / 2.0 * widget.scale)), border: Border.all( color: Util().stringToColor(locationObj['border_color']), width: double.parse(locationObj['border_width']).px * widget.scale)), ), SizedBox( width: double.parse(locationObj['space_width']).px * widget.scale, ), Container( height: double.parse(locationObj['height']).px * widget.scale, alignment: Alignment.center, padding: EdgeInsets.only( left: double.parse(locationObj['address']['padding_horizontal']) .px * widget.scale, right: double.parse(locationObj['address']['padding_horizontal']) .px * widget.scale), child: Row( children: [ SvgPicture.asset('assets/icons/location.svg', width: double.parse(locationObj['gender']['width']).px * widget.scale, height: double.parse(locationObj['gender']['height']).px * widget.scale, color: Util().stringToColor(locationObj['gender']['color'])), SizedBox( width: 4.px, ), Text( widget.userBean.country! + ' ' + widget.userBean.city!, style: TextStyle( fontSize: double.parse(locationObj['address']['font_size']).px * widget.scale, color: Util() .stringToColor(locationObj['address']['color'])), ) ], ), decoration: BoxDecoration( borderRadius: BorderRadius.all(Radius.circular( double.parse(locationObj['height']).px / 2.0 * widget.scale)), border: Border.all( color: Util().stringToColor(locationObj['border_color']), width: double.parse(locationObj['border_width']).px * widget.scale)), ) ], ), ); } Widget socialWidget() { var socialObj = widget.styles['social_item']; double borderWidth = 0.0; if (socialObj['border_width'] != null) { borderWidth = double.parse(socialObj['border_width']); } return Column(children: [ SizedBox( height: double.parse(socialObj['margin_top']).px * widget.scale, ), if (isMyPage && widget.userBean.socials!.length > 1 && !widget._isPreview) Container( alignment: Alignment.center, width: double.parse(socialObj['width']).px * widget.scale, height: (double.parse(socialObj['height']) + 2 * borderWidth + double.parse((socialObj['space_height'])).px) .px * widget.userBean.socials!.length * widget.scale, child: Theme( data: Theme.of(context).copyWith( canvasColor: Colors.transparent, shadowColor: Colors.transparent, ), child: SocialList( isMyPage: isMyPage, userBean: widget.userBean, socials: widget.socials, styles: widget.styles, itemkey: widget._itemkey, canDrag: true, scale: widget.scale, )), ), if (!isMyPage || widget.userBean.socials!.length < 2 || widget._isPreview) SocialList( isMyPage: isMyPage, userBean: widget.userBean, socials: widget.socials, styles: widget.styles, itemkey: widget._itemkey, canDrag: false, scale: widget.scale, ), if (isMyPage && widget._isPreview == false) GestureDetector( onTap: () { Get.toNamed('/begin_add_first_link', parameters: {'add_more': '1'}); }, child: HomeAddLink( socialObj: socialObj, addLinkkey: widget._addLinkkey, scale: widget.scale, )) ]); } Widget copyrightWidget(bool isPositioned) { double bottom = 20.0; var copyrightObj = widget.styles['copy_right']; if (copyrightObj['bottom'] != null) { bottom = double.parse(copyrightObj['bottom']); } Color color = Colors.black; if (copyrightObj['color'] != null) { color = Util().stringToColor(copyrightObj['color']); } if (!isPositioned) { return Opacity( opacity: bottomStatus == 0 ? 1 : 0, child: Container( alignment: Alignment.center, child: Text( '2022 © LINKBaeBae 链接吧,宝贝!', style: TextStyle(color: color, fontSize: 10.px * widget.scale), ), ), ); } return Positioned( bottom: bottom, left: 0, right: 0, child: Opacity( opacity: bottomStatus == 1 ? 1 : 0, child: Container( alignment: Alignment.center, child: Text( '2022 © LINKBaeBae 链接吧,宝贝!', style: TextStyle(color: color, fontSize: 10.px * widget.scale), ), ), )); } @override Widget build(BuildContext context) { SizeFit.initialize(context); var backObj = widget.styles['background']; return Container( width: 375.px * widget.scale, color: backObj['type'] == 'skew' ? (backObj['top_left_y']==backObj['top_right_y']?Util().stringToColor(backObj['top_color']):Util().stringToColor(backObj['bottom_color'])) : Colors.transparent, child: Stack( children: [ if (backObj['type'] != 'skew') background(), if (backObj['type'] == 'skew') Positioned( left: 0, right: 0, bottom: 0, height: 400.px * widget.scale, child: Container( width: 375.px * widget.scale, height: 400.px * widget.scale, color: (backObj['top_left_y']==backObj['top_right_y']?Util().stringToColor(backObj['bottom_color']):Util().stringToColor(backObj['top_color'])), )), SingleChildScrollView( child: Stack( children: [ if (backObj['type'] == 'skew') background(), Container( // color: backObj['type'] == 'skew' // ? (backObj['top_left_y']==backObj['top_right_y']?Util().stringToColor(backObj['top_color']):Util().stringToColor(backObj['bottom_color'])) // : Colors.transparent, child: Column( key: columnKey, children: [ avatarWidget(), nicknameWidget(), locationWidget(), signatureWidget(), socialWidget(), SizedBox( height: 30.px, ), copyrightWidget(false), SizedBox( height: 30.px, ) ], ), ), ], )), topWidget(), copyrightWidget(true), ], ), ); } } class SkewCut extends CustomClipper { double topLeft; double topRight; SkewCut(this.topLeft, this.topRight); @override Path getClip(Size size) { final path = Path(); // path.lineTo(size.width, 0); // path.lineTo(size.width - 20, size.height); // path.lineTo(0, size.height); path.lineTo(0, 0); path.lineTo(0, topLeft); path.lineTo(size.width, topRight); path.lineTo(size.width, 0); path.close(); return path; } @override bool shouldReclip(covariant CustomClipper oldClipper) { // TODO: implement shouldReclip return false; } } class SkewPaint extends CustomPainter { Paint? myPaint; double topLeft; double topRight; Color lineColor; double lineWidth; double scale; SkewPaint( this.topLeft, this.topRight, this.lineColor, this.lineWidth, this.scale); @override void paint(Canvas canvas, Size size) { myPaint = Paint(); myPaint!.color = lineColor; myPaint!.strokeWidth = lineWidth; canvas.drawLine( Offset(-2.px, topLeft), Offset(379.px * scale, topRight), myPaint!); } @override bool shouldRepaint(covariant CustomPainter oldDelegate) { // TODO: implement shouldRepaint return false; } }