import 'dart:async'; import 'dart:convert'; import 'dart:math'; import 'dart:typed_data'; import 'package:event_bus/event_bus.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.dart'; import 'package:link/model/model.dart'; import 'package:link/utils/api.dart'; import 'package:link/utils/global.dart'; import 'package:link/utils/storage.dart'; import 'package:link/utils/util.dart'; import 'package:link/view/home_add_link.dart'; import 'package:link/view/home_content.dart'; import 'package:link/view/share.dart'; import 'package:link/view/home_social_list.dart'; import 'package:url_launcher/url_launcher.dart'; import '../constants.dart'; import '../utils/http_utils.dart'; import '../utils/size_fit.dart'; import 'package:get/get.dart'; import 'package:screenshot/screenshot.dart'; import 'component/link_btn.dart'; import 'component/menu.dart'; import 'component/toast.dart'; import 'component/top_container.dart'; import 'guide.dart'; import 'package:dio/dio.dart'; import 'package:dio/dio.dart' as adio; import 'dart:js' as js; class IndexScreen extends StatefulWidget { const IndexScreen({Key? key}) : super(key: key); @override State createState() => _IndexScreenState(); } class _IndexScreenState extends State with RouteAware, SingleTickerProviderStateMixin { ScreenshotController screenshotController = ScreenshotController(); double alpha = 0.0; late AnimationController controller; late Animation animation; Uint8List? byteData; Uint8List? qrcodeData; Widget? demoWidget; UserBean? userBean; Map? styles; bool showMenu = false; bool isMyPage = false; GlobalKey addLinkkey = GlobalKey(); GlobalKey itemkey = GlobalKey(); bool showGuide = false; Offset itemOffset = const Offset(0, 0); Offset guideOffset = const Offset(0, 0); int guideStep = 0; String uid = ''; bool showGuideLink = false; bool showGuideMore = false; bool showGuideDrag = false; bool showWelcome = false; List socials = []; @override void initState() { // TODO: implement initState super.initState(); if (Global().eventBus == null) { Global().eventBus = EventBus(); } checkToken(); controller = AnimationController( vsync: this, duration: const Duration(milliseconds: 100)); animation = Tween(begin: 0.0, end: 1.0) .animate(CurvedAnimation(parent: controller, curve: Curves.easeOut)); controller.addListener(() { setState(() {}); }); // getUserInfo(); Map data = Get.parameters; if (data.isNotEmpty) { if (data['u'] != null) { uid = data['u']; Global().uid = uid; if (StorageUtil().getJSON('userInfo')!=null && StorageUtil().getJSON('userInfo')['id'] == uid) { isMyPage = true; } } if (data['code']!=null){ Global().code = data['code']; } } else { if (Global().hasLogin) { isMyPage = true; } } getUserInfo(); if (isMyPage) { Util().setPageTitle('我的主页'); getQRCode(); } // getQRCode(); } Future getQRCode() async { Dio dio = Dio(); // 注意:这里使用bytes dio.options.responseType = ResponseType.bytes; // 如果headers有东西,则添加 Map headers = { 'Authorization': 'Bearer ${Global().token}' }; dio.options.headers = headers; try { String url = 'https://h5.link.dev.liveplus.fun/?u=' + uid; String path = Api.baseUrl + Api.qr + '?data=$url'; adio.Response response = await dio.get(path); final Uint8List bytes = consolidateHttpClientResponseBytes(response.data); setState(() { qrcodeData = bytes; }); } catch (e) { return await null; } } consolidateHttpClientResponseBytes(List data) { final List> chunks = >[]; int contentLength = 0; chunks.add(data); contentLength += data.length; final Uint8List bytes = Uint8List(contentLength); int offset = 0; for (List chunk in chunks) { bytes.setRange(offset, offset + chunk.length, chunk); offset += chunk.length; } return bytes; } Future checkToken() async { if (Global().token.isNotEmpty){ var data = await HttpUtils.get(Api.token,params: {'token':Global().token}); if (data['success']==false){ Get.toNamed('/login'); return; } } var jsonUserStep0 = StorageUtil().getJSON('tempUser0'); if (jsonUserStep0!=null){ Get.toNamed('/edit_nick_info'); return; } var jsonUserStep1 = StorageUtil().getJSON('tempUser1'); if (jsonUserStep1!=null){ Get.toNamed('/edit_base_info'); return; } var jsonLink0 = StorageUtil().getJSON('tempGuideLink0'); if (jsonLink0!=null){ Get.toNamed('/begin_add_first_link'); return; } var jsonLink1 = StorageUtil().getJSON('tempGuideLink1'); if (jsonLink1!=null){ Get.toNamed('/add_link', parameters: {'social': jsonEncode(jsonLink1['social'])}); return; } var json = StorageUtil().getJSON('tempLink'); if (json != null) { Get.toNamed('/add_link', parameters: {'social': jsonEncode(json['social']), 'add_more': '1'}); return; } } getSize() { if (!isMyPage) { return; } if (showGuideLink || showGuideMore || showGuideDrag) { Offset offset; if (userBean!.socials!.isEmpty) { offset = Offset.zero; } else { RenderBox widget = itemkey.currentContext!.findRenderObject() as RenderBox; offset = widget.localToGlobal(Offset.zero); } if (addLinkkey.currentContext==null){ return; } RenderBox widget2 = addLinkkey.currentContext!.findRenderObject() as RenderBox; setState(() { showGuide = true; itemOffset = offset; guideOffset = widget2.localToGlobal(Offset.zero); }); } } @override void dispose() { // TODO: implement dispose controller.dispose(); super.dispose(); } @override void didChangeDependencies() { // TODO: implement didChangeDependencies super.didChangeDependencies(); Global().routeObserver!.subscribe(this, ModalRoute.of(context)!); } @override void didPopNext() { // TODO: implement didPopNext getUserInfo(); super.didPopNext(); } Future getUserInfo() async { Map data; Map styleObj; if (uid.isNotEmpty && (StorageUtil().getJSON('userInfo')==null||StorageUtil().getJSON('userInfo')['id'] != uid)) { data = await HttpUtils.get('users/$uid/info'); styleObj = await HttpUtils.get('users/$uid/styles'); } else { data = await HttpUtils.get(Api.userSocials); styleObj = await HttpUtils.get(Api.userStyles); uid = data['id']; Global().uid = uid; } var data2 = await HttpUtils.get(Api.socials); // print(data.toString()); if (data2['data'] is List) { setState(() { userBean = UserBean.fromJson(data); Global().userBean = userBean; styles = styleObj; socials = data2['data']; Global().socials = socials; }); } else { setState(() { userBean = UserBean.fromJson(data); Global().userBean = userBean; styles = styleObj; }); } Global().themeId = data['theme_style_id']; if (Global().hasLogin) { Map data2 = await HttpUtils.get(Api.frontData, params: {'code': 'guide_first_link'}); Map data3 = await HttpUtils.get(Api.frontData, params: {'code': 'guide_more'}); Map data4 = await HttpUtils.get(Api.frontData, params: {'code': 'guide_drag'}); var newData = await HttpUtils.get(Api.frontDatas,params: {'codes':"guide_first_link,guide_more,guide_drag"}); Timer(const Duration(seconds: 1), () { getSize(); }); setState(() { if (data2['value'].length == 0 && data3['value'].length == 0 && data4['value'].length == 0) { showWelcome = true; guideStep = 0; } else { guideStep = 1; } if (userBean!.socials!.isEmpty) { if (data2['value'].length == 0) { showGuideLink = true; } } else if (userBean!.socials!.length == 1) { if (data3['value'].length == 0) { showGuideMore = true; } } else if (userBean!.socials!.length > 1) { if (data4['value'].length == 0) { showGuideDrag = true; } } }); } if (!isMyPage) { Util().setPageTitle(userBean!.nickname!); } getQRCode(); } Future updateGuideData(var data) async { await HttpUtils.post(Api.frontData, data: data); } openMenu() { setState(() { showMenu = true; }); controller.forward(); } closeMenu() { controller.reverse(); Timer(const Duration(milliseconds: 300), () { setState(() { showMenu = false; }); }); } lauchURL(url) async { // js.context.callMethod('aaa',['hisss']); if (await canLaunch(url)) { await launch(url); } } Widget guideItem() { String title = '开始探索 2/4'; String content = '这是我刚添加的第1个链接,点击跳转查看;如需调整,仍可继续编辑'; if (guideStep == 2) { title = '开始探索 3/4'; content = '添加更多链接,让世界更好地了解我!'; } else if (guideStep == 3) { title = '开始探索 4/4'; content = '这里汇集了更多主题风格,快去探索并装点我的主页吧!未来将会支持个性化样式,敬请期待~'; } else if (guideStep == 4) { title = '完成'; content = '预览主页效果,所见即是我确认后,分享至会话或群聊,是时候让世界认识我了!'; } if (guideStep == 3) { return Stack( children: [ Positioned(left: 0, width: 120.px, top: 0, bottom: 0, child: Menu()), Container( margin: EdgeInsets.only(left: 80.px, top: 15.px), child: Row( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( padding: EdgeInsets.only(left: 8.px), child: GuideTip(content: content, direction: 2, width: 258.px), ), Container( margin: EdgeInsets.only(top: 90.px), // alignment: Alignment.centerLeft, transform: Matrix4.translationValues(-20.px - 258.px, 0, 0), child: Transform.rotate( angle: pi / 2.0, child: Image.asset( 'assets/images/arrow_corner.png', width: 28.px, height: 14.px, )), ) // Positioned( // left: 0, // top: 0, // bottom: 0, // child: Container( // alignment: Alignment.centerLeft, // transform: Matrix4.translationValues(-12.px-258.px, 0, 0), // child: Transform.rotate( // angle: pi / 2.0, // child: Image.asset( // 'assets/images/arrow_corner.png', // width: 28.px, // height: 14.px, // )), // )) ], ), ), Column( children: [ Expanded(child: Container()), LinkButton( title: title, btnWidth: 172.px, disable: false, isBlack: false, callback: () { setState(() { guideStep = guideStep + 1; if (guideStep > 4) { showGuide = false; } // showGuide = false; }); }), SizedBox( height: 64.px, ) ], ) ], ); } if (guideStep == 4) { return Container( width: 375.px, color: Colors.transparent, child: Column( children: [ Container( width: 375.px, height: 72.px, decoration: const BoxDecoration( gradient: LinearGradient( begin: Alignment.centerLeft, end: Alignment.centerRight, colors: [ Color(0x00FFF700), Color(0x00FFF700), Color(0xFFFFF700), ], stops: [ 0, 0.25, 1 ]), ), ), Container( width: 375.px, height: 300.px, transform: Matrix4.translationValues(0, -20.px, 0), child: Stack( children: [ Positioned( top: 13.5.px, right: 8.px, child: GuideTip(content: content, direction: 2, width: 276.px), ), Positioned( right: 60.px, child: Transform.rotate( angle: pi, child: Image.asset( 'assets/images/arrow_corner.png', width: 28.px, height: 14.px, // color: const Color(0xFF0000FF), ) // SvgPicture.asset( // 'assets/icons/arrow_corner.svg', // width: 28.px, // height: 14.px, // color: const Color(0xFF0000FF), // ) )) ], ), ), Expanded(child: Container()), LinkButton( title: title, btnWidth: 172.px, disable: false, isBlack: false, callback: () { setState(() { guideStep = guideStep + 1; if (guideStep > 4) { showGuide = false; showGuideMore = false; updateGuideData({"code": "guide_more", "value": "1"}); } // showGuide = false; }); }), SizedBox( height: 64.px, ) ], ), ); } if (showGuide) { return Container( color: Colors.transparent, child: Column( children: [ Container( height: guideStep == 1 ? itemOffset.dy : guideOffset.dy, alignment: Alignment.bottomCenter, child: Column( children: [ Expanded(child: Container()), GuideTip(content: content, direction: 2, width: 316.px), Image.asset( 'assets/images/arrow_corner.png', width: 28.px, height: 14.px, ) // SvgPicture.asset( // 'assets/icons/arrow_corner.svg', // width: 28.px, // height: 14.px, // color: const Color(0xFF0000FF), // ) ], ), ), if (guideStep == 1) SocialList( userBean: userBean!, styles: styles!, itemkey: itemkey, isMyPage: isMyPage, socials: socials, canDrag: false, scale: 1.0, ), if (guideStep == 2) HomeAddLink( socialObj: styles!['social_item'], addLinkkey: addLinkkey, scale: 1.0, ), Expanded(child: Container()), LinkButton( title: title, btnWidth: 172.px, disable: false, isBlack: false, callback: () { setState(() { guideStep = guideStep + 1; if (guideStep > 4) { showGuide = false; showGuideMore = false; updateGuideData({"code": "guide_more", "value": "1"}); } // showGuide = false; }); }), SizedBox( height: 64.px, ) ], ), ); } return Container(); } Widget guideAddLink() { if (showGuide) { return Container( color: Colors.transparent, child: Column( children: [ Container( height: guideOffset.dy, alignment: Alignment.bottomCenter, child: Column( children: [ Expanded(child: Container()), GuideTip( content: '快去添加我的第1个链接,让世界认识我!添加后解锁「切换主题」、「预览&分享」等更多功能', direction: 2, width: 316.px), Image.asset( 'assets/images/arrow_corner.png', width: 28.px, height: 14.px, // color: const Color(0xFF0000FF), ) ], ), ), // addLinkWidget(disable: true), HomeAddLink( socialObj: styles!['social_item'], addLinkkey: addLinkkey, disable: true, scale: 1.0, ), Expanded(child: Container()), LinkButton( title: '完成', btnWidth: 172.px, disable: false, isBlack: false, callback: () { setState(() { showGuide = false; showGuideLink = false; updateGuideData({"code": "guide_first_link", "value": "1"}); }); }), SizedBox( height: 64.px, ) ], ), ); } return Container(); } guideDrag() { return Container( color: Colors.transparent, child: Column( children: [ Container( height: guideStep == 1 ? itemOffset.dy : guideOffset.dy, alignment: Alignment.bottomCenter, child: Column( children: [ Expanded(child: Container()), GuideTip(content: '长按激活,上下拖拽调整排序', direction: 2, width: 316.px), // SvgPicture.asset( // 'assets/icons/arrow_corner.svg', // width: 28.px, // height: 14.px, // color: const Color(0xFF0000FF), // ) Image.asset( 'assets/images/arrow_corner.png', width: 28.px, height: 14.px, ) ], ), ), if (guideStep == 1) SocialList( userBean: userBean!, styles: styles!, itemkey: itemkey, isMyPage: isMyPage, socials: socials, canDrag: false, scale: 1.0, ), Expanded(child: Container()), LinkButton( title: '完成', btnWidth: 172.px, disable: false, isBlack: false, callback: () { setState(() { showGuide = false; showGuideDrag = false; updateGuideData({"code": "guide_drag", "value": "1"}); // showGuide = false; }); }), SizedBox( height: 64.px, ) ], ), ); } test() { String title = '开始探索 2/4'; String content = '这是我刚添加的第1个链接,点击跳转查看;如需调整,仍可继续编辑'; return Positioned( left: 0, right: 0, top: 0, bottom: 0, child: Container( color: const Color(0xBF000000), child: Stack( children: [ Positioned( left: 0, width: 120.px, top: 0, bottom: 0, child: Menu()), Container( margin: EdgeInsets.only(left: 80.px, top: 15.px), child: Stack( children: [ Container( padding: EdgeInsets.only(left: 8.px), child: GuideTip( content: content, direction: 2, width: 260.px), ), Positioned( left: 0, top: 0, bottom: 0, child: Container( alignment: Alignment.centerLeft, transform: Matrix4.translationValues(-12.px, 0, 0), child: Transform.rotate( angle: pi / 2.0, child: Image.asset( 'assets/images/arrow_corner.png', width: 28.px, height: 14.px, )), )) ], )), Column( children: [ Expanded(child: Container()), LinkButton( title: title, btnWidth: 172.px, disable: false, isBlack: false, callback: () { setState(() { guideStep = guideStep + 1; if (guideStep > 4) { showGuide = false; } // showGuide = false; }); }), SizedBox( height: 64.px, ) ], ) ], ), )); } guideContent() { return Positioned( left: 0, right: 0, top: 0, bottom: 0, child: Container( color: guideStep == 0 ? Colors.transparent : const Color(0xBF000000), // color: const Color(0xBF000000), child: Stack( children: [ if (guideStep == 0) IndexWelcome( close: () { setState(() { guideStep = 1; }); }, ), if (guideStep != 0 && showGuideMore) guideItem(), if (guideStep != 0 && showGuideLink) guideAddLink(), if (guideStep != 0 && showGuideDrag) guideDrag(), // guideItem() // guideAddLink() // Container( // width: 375.px, // height: 72.px, // decoration: const BoxDecoration( // gradient: LinearGradient( // begin: Alignment.centerLeft, // end: Alignment.centerRight, // colors: [ // Color(0x00FFF700), // Color(0x00FFF700), // Color(0xFFFFF700), // ], // stops: [0,0.25,1] // ), // ), // ), ], ), )); } tapShare() { // width: MediaQuery.of(context).size.width, // height: MediaQuery.of(context).size.height, // js.context.callMethod('capture', [0, 0, MediaQuery.of(context).size.width, MediaQuery.of(context).size.height]); // final canvas = html.CanvasElement(width: 300, height: 300); // var context = canvas.context2D; // context.draw...(); // do whatever drawing you need // final blob = await canvas.toBlob('image/jpeg', 0.8); screenshotController.capture().then((value) { Toast().showText('长按图片识别或保存', context: context); setState(() { byteData = value as Uint8List; }); showDialog( context: context, barrierDismissible: false, barrierColor: const Color(0xBF000000), useSafeArea: false, builder: (BuildContext context) { return Share(byteData: value as Uint8List); }); }).catchError((error) { Toast().showText(error.toString(), context: context); }); } content() { return Material( child: Stack( children: [ Opacity( opacity: 0.01, child: Screenshot( controller: screenshotController, child: Stack(children: [ HomeContent( userBean: userBean!, styles: styles!, socials: socials, scale: 1.0, isPreview: true, ), Positioned( left: 0, right: 0, bottom: 0, height: 200.px, child: Container( padding: EdgeInsets.only(top: 30.px), decoration: const BoxDecoration( gradient: LinearGradient( begin: Alignment.topCenter, end: Alignment.bottomCenter, colors: [ Color(0x00000000), Color(0x33000000), Color(0xFF131314), Color(0xFF131314) ], stops: [ 0, 0.18, 0.51, 1 ])), child: Row( children: [ SizedBox( width: 32.px, ), Column( children: [ if (qrcodeData != null) Image.memory( qrcodeData!, width: 100.px, height: 100.px, // color: Colors.pink, ), SizedBox( height: 8.px, ), Text( '长按识别二维码\n进入我的LinkBaeBae主页', textAlign: TextAlign.center, style: TextStyle( color: Colors.white, fontSize: 10.px), ) ], ), SizedBox( width: 38.px, ), Container( margin: EdgeInsets.only(top: 40.px), child: Image.asset( 'assets/images/logo.png', width: 155.px, fit: BoxFit.cover, ), ), ], ), )) ])), ), HomeContent( userBean: userBean!, styles: styles!, socials: socials, itemkey: itemkey, addLinkkey: addLinkkey, scale: 1.0, share: () { tapShare(); }, openMenu: () { openMenu(); }, ), // Container( // width: MediaQuery.of(context).size.width * 0.3, // height: MediaQuery.of(context).size.height * 0.3, // child: HomeContent( // userBean: userBean!, // styles: styles!, // socials: socials, // itemkey: itemkey1, // addLinkkey: addLinkkey1, // scale: 0.3, // ), // ), // copyrightWidget(), if (showMenu) Positioned( child: Opacity( opacity: animation.value, child: Container( color: const Color(0xBF000000), ), )), if (showMenu) Positioned( left: 0, right: 0, top: 0, bottom: 0, child: Container( color: Colors.transparent, width: 375.px, transform: Matrix4.translationValues( -220.px + animation.value * 220.px, 0, 0), child: Row( children: [ Menu( isEnable: true, closeMenu: () { closeMenu(); }, ), Expanded( child: GestureDetector( onTap: () { closeMenu(); }, child: Container( color: Colors.transparent, )), ) // child: Expanded(child: SizedBox(width: 1,)), // ) ], ), )), if (showGuide) guideContent(), // test(), if (showGuide && guideStep == 4) Row( children: [ const Expanded( child: SizedBox( height: 1.0, )), if (isMyPage) GestureDetector( child: Container( margin: EdgeInsets.only(right: 0.px), child: SvgPicture.asset( 'assets/icons/preview.svg', width: 36.px, height: 24.px, color: Util().stringToColor( styles!['toolbar']['right_icon']['color']), )), ), GestureDetector( child: Container( height: 72.px, padding: EdgeInsets.only(left: 24.px, right: 24.px), child: SvgPicture.asset( 'assets/icons/navi_share.svg', width: 24.px, height: 24.px, color: Util().stringToColor( styles!['toolbar']['right_icon']['color']), ), ), ) ], ), ], )); } @override Widget build(BuildContext context) { SizeFit.initialize(context); if (styles == null) { return Container(); } return Material( child: TopContainer( child:content())); // return content(); // return Screenshot(controller: screenshotController, child: content()); } }