Commit c2c14ef7d02aa7407d58186316a55cfd8de698ba

Authored by weixin_45529955
1 parent 845ac3e5

微信分享登录&&预订表下载预览&&评论列表视频封面展示播放&&版本更新&&店铺门头照片裁剪

Showing 100 changed files with 2688 additions and 174 deletions

Too many changes to show.

To preserve performance only 100 of 100+ files are displayed.

@@ -4,6 +4,8 @@ import 'package:fluwx/fluwx.dart'; @@ -4,6 +4,8 @@ import 'package:fluwx/fluwx.dart';
4 class Constant { 4 class Constant {
5 static const int status_success = 200; //服务器返回成功 5 static const int status_success = 200; //服务器返回成功
6 6
  7 + static const String ohos_app_id = '6917567548342276009'; //服务器返回成功
  8 +
7 /** 9 /**
8 * 10 *
9 * 打包注意事项 !!!!!!!! ****************苹果 看看导出预订数据**************** 11 * 打包注意事项 !!!!!!!! ****************苹果 看看导出预订数据****************
1 -  
2 import 'dart:convert'; 1 import 'dart:convert';
3 2
4 -  
5 import 'package:common_utils/common_utils.dart'; 3 import 'package:common_utils/common_utils.dart';
6 4
7 class CommentsModel { 5 class CommentsModel {
@@ -212,21 +210,22 @@ class CommentsImageModel { @@ -212,21 +210,22 @@ class CommentsImageModel {
212 ImageAve? imageAve; 210 ImageAve? imageAve;
213 String? url; 211 String? url;
214 String? avinfo; 212 String? avinfo;
215 -  
216 -  
217 - CommentsImageModel(  
218 - {this.key,  
219 - this.bucket,  
220 - this.mimeType,  
221 - this.fsize,  
222 - this.exif,  
223 - this.imageInfo,  
224 - this.imageAve,  
225 - this.url,  
226 - this.avinfo,  
227 - });  
228 -  
229 - CommentsImageModel.fromJson(Map<String, dynamic> json) { 213 +
  214 + String? filePath;
  215 +
  216 + CommentsImageModel({
  217 + this.key,
  218 + this.bucket,
  219 + this.mimeType,
  220 + this.fsize,
  221 + this.exif,
  222 + this.imageInfo,
  223 + this.imageAve,
  224 + this.url,
  225 + this.avinfo,
  226 + });
  227 +
  228 + CommentsImageModel.fromJson(Map<String, dynamic> json) {
230 key = json['key']; 229 key = json['key'];
231 bucket = json['bucket']; 230 bucket = json['bucket'];
232 mimeType = json['mimeType']; 231 mimeType = json['mimeType'];
@@ -241,8 +240,6 @@ class CommentsImageModel { @@ -241,8 +240,6 @@ class CommentsImageModel {
241 url = json['url']; 240 url = json['url'];
242 avinfo = json['avinfo'] == null ? null : jsonEncode(json['avinfo']); 241 avinfo = json['avinfo'] == null ? null : jsonEncode(json['avinfo']);
243 print(avinfo); 242 print(avinfo);
244 -  
245 -  
246 } 243 }
247 244
248 Map<String, dynamic> toJson() { 245 Map<String, dynamic> toJson() {
@@ -542,6 +542,9 @@ class _MapChoicePointPageState extends State<MapChoicePointPage> { @@ -542,6 +542,9 @@ class _MapChoicePointPageState extends State<MapChoicePointPage> {
542 list.add(new PoiModel(title.toString(), cityStr, latLng)); 542 list.add(new PoiModel(title.toString(), cityStr, latLng));
543 } 543 }
544 544
  545 +
  546 + print(list);
  547 +
545 setState(() { 548 setState(() {
546 // isloading = false; 549 // isloading = false;
547 }); 550 });
@@ -30,6 +30,10 @@ import 'dart:collection'; @@ -30,6 +30,10 @@ import 'dart:collection';
30 // import 'package:open_file/open_file.dart'; 30 // import 'package:open_file/open_file.dart';
31 // import 'package:flutter_downloader/flutter_downloader.dart'; 31 // import 'package:flutter_downloader/flutter_downloader.dart';
32 32
  33 +/**
  34 + * 我的-----帮助与反馈页面 ----- 目前已经功能已经屏蔽
  35 + */
  36 +
33 class WebPage extends StatefulWidget { 37 class WebPage extends StatefulWidget {
34 final String? title; 38 final String? title;
35 final String? url; 39 final String? url;
1 -  
2 import 'dart:async'; 1 import 'dart:async';
3 import 'dart:io'; 2 import 'dart:io';
4 import 'dart:ui'; 3 import 'dart:ui';
@@ -10,6 +9,7 @@ import 'package:flutter/rendering.dart'; @@ -10,6 +9,7 @@ import 'package:flutter/rendering.dart';
10 import 'package:one_key/models/comments_label_model.dart'; 9 import 'package:one_key/models/comments_label_model.dart';
11 import 'package:one_key/models/comments_model.dart'; 10 import 'package:one_key/models/comments_model.dart';
12 import 'package:one_key/pages/my/comment_manage/input_buttom_widget.dart'; 11 import 'package:one_key/pages/my/comment_manage/input_buttom_widget.dart';
  12 +import 'package:one_key/pages/my/comment_manage/ohos_video_page.dart';
13 import 'package:one_key/pages/my/comment_manage/pop_route.dart'; 13 import 'package:one_key/pages/my/comment_manage/pop_route.dart';
14 import 'package:one_key/pages/my/comment_manage/video_page.dart'; 14 import 'package:one_key/pages/my/comment_manage/video_page.dart';
15 import 'package:one_key/provider/user_model.dart'; 15 import 'package:one_key/provider/user_model.dart';
@@ -36,6 +36,11 @@ import '../../online_check/photo_view_wiget.dart'; @@ -36,6 +36,11 @@ import '../../online_check/photo_view_wiget.dart';
36 // import 'package:cached_video_player/cached_video_player.dart'; 36 // import 'package:cached_video_player/cached_video_player.dart';
37 import 'package:video_thumbnail/video_thumbnail.dart'; 37 import 'package:video_thumbnail/video_thumbnail.dart';
38 38
  39 +import 'package:path_provider_platform_interface/path_provider_platform_interface.dart';
  40 +import 'package:dio/dio.dart';
  41 +
  42 +// import 'package:flutter_downloader/flutter_downloader.dart';
  43 +
39 /** 44 /**
40 * 评价管理 45 * 评价管理
41 */ 46 */
@@ -60,7 +65,8 @@ class _CommentManageHomePageState extends State<CommentManageHomePage> { @@ -60,7 +65,8 @@ class _CommentManageHomePageState extends State<CommentManageHomePage> {
60 65
61 starTextMap = {'1': '差', '2': '有点差', '3': '一般', '4': '满意', '5': '非常满意'}; 66 starTextMap = {'1': '差', '2': '有点差', '3': '一般', '4': '满意', '5': '非常满意'};
62 67
63 - WidgetsBinding.instance.addPostFrameCallback((_) { 68 + WidgetsBinding.instance.addPostFrameCallback((_) async {
  69 + // await FlutterDownloader.initialize(debug: true, ignoreSsl: true);
64 _getSellerComments(isShowLoading: false); 70 _getSellerComments(isShowLoading: false);
65 // _getCountCommentLabel(isShowLoading: false); 71 // _getCountCommentLabel(isShowLoading: false);
66 }); 72 });
@@ -111,7 +117,7 @@ class _CommentManageHomePageState extends State<CommentManageHomePage> { @@ -111,7 +117,7 @@ class _CommentManageHomePageState extends State<CommentManageHomePage> {
111 }; 117 };
112 118
113 bool success = await commentManageProvider.setComment(context, pramas, 119 bool success = await commentManageProvider.setComment(context, pramas,
114 - isShowLoading: isShowLoading) ; 120 + isShowLoading: isShowLoading);
115 if (success) { 121 if (success) {
116 //成功 刷新列表 122 //成功 刷新列表
117 _getSellerComments(isShowLoading: false); 123 _getSellerComments(isShowLoading: false);
@@ -180,24 +186,97 @@ class _CommentManageHomePageState extends State<CommentManageHomePage> { @@ -180,24 +186,97 @@ class _CommentManageHomePageState extends State<CommentManageHomePage> {
180 // return data; 186 // return data;
181 // } 187 // }
182 188
183 - Future<String?>? getThumbnailFile( 189 + Future<String?>? getThumbnailFile(
184 List<CommentsImageModel> imags, int index) async { 190 List<CommentsImageModel> imags, int index) async {
185 - final fileName = await VideoThumbnail.thumbnailFile(  
186 - video: imags[index].url!,  
187 - thumbnailPath: (await getTemporaryDirectory()).path,  
188 - // imageFormat: ImageFormat.WEBP,  
189 - // maxHeight:  
190 - // 64, // specify the height of the thumbnail, let the width auto-scaled to keep the source aspect ratio  
191 - quality: 100, 191 + String? thumbnailPath;
  192 +
  193 + if (Platform.isAndroid || Platform.isIOS) {
  194 + thumbnailPath = (await getTemporaryDirectory()).path;
  195 + try {
  196 + final fileName = await VideoThumbnail.thumbnailFile(
  197 + video: imags[index].url!,
  198 + thumbnailPath: thumbnailPath,
  199 + // imageFormat: ImageFormat.WEBP,
  200 + // maxHeight:
  201 + // 64, // specify the height of the thumbnail, let the width auto-scaled to keep the source aspect ratio
  202 + quality: 100,
  203 + );
  204 + print(fileName);
  205 +
  206 + return fileName;
  207 + } catch (e) {
  208 + print(e);
  209 + }
  210 + } else if (Platform.isOhos) {
  211 + // final PathProviderPlatform provider = PathProviderPlatform.instance;
  212 +
  213 + // thumbnailPath = await provider.getExternalStoragePath();
  214 + // Directory? downloadsDir = await getTemporaryDirectory();
  215 + thumbnailPath = (await getTemporaryDirectory()).path;
  216 + // getTemporaryDirectory().then((d) => thumbnailPath = d.path);
  217 + print(thumbnailPath);
  218 +
  219 + String fileName = Utils.extractFileNameFromUrl(imags[index].url!);
  220 + print("File Name: $fileName"); // 输出:File Name: file.txt
  221 +//鸿蒙,flutter侧下载视频到缓存,然后使用video_thumbnail 插件从鸿蒙设备本地缓存读取文件并获取第一帧图片
  222 + String thumbnailPathVideo = await downloadVideo(
  223 + imags[index].url!, thumbnailPath + '/' + fileName);
  224 + try {
  225 + final fileName = await VideoThumbnail.thumbnailFile(
  226 + video: thumbnailPathVideo,
  227 + thumbnailPath: thumbnailPath,
  228 + // imageFormat: ImageFormat.WEBP,
  229 + // maxHeight:
  230 + // 64, // specify the height of the thumbnail, let the width auto-scaled to keep the source aspect ratio
  231 + quality: 100,
  232 + );
  233 + imags[index].filePath = fileName;
  234 + print(fileName);
  235 + return fileName;
  236 + } catch (e) {
  237 + print(e);
  238 + }
  239 + }
  240 +
  241 + return null;
  242 + }
  243 +
  244 + Future<String> downloadVideo(String url, String savePath) async {
  245 + var dio = Dio();
  246 + var response = await dio.get(
  247 + url,
  248 + options: Options(responseType: ResponseType.bytes),
192 ); 249 );
193 - return fileName; 250 +
  251 + final file = File(savePath);
  252 + File tempFile = await file.writeAsBytes(response.data); // 将字节写入文件
  253 + return tempFile.path;
194 } 254 }
195 255
  256 + // Future<void> _requestDownload(String url) async {
  257 + //ohos不需要请求权限,路径直接返回image
  258 + // String _localPath = 'Image';
  259 +
  260 + // try {
  261 + // String? taskId = await FlutterDownloader.enqueue(
  262 + // url: url,
  263 + // headers: {'auth': 'test_for_sql_encoding'},
  264 + // savedDir: _localPath,
  265 + // saveInPublicStorage: false,
  266 + // );
  267 +
  268 + // print(taskId);
  269 + // } catch (e) {
  270 + // print(e);
  271 + // }
  272 +
  273 + // 下载结束后把缓存地址给鸿蒙原生回传
  274 + // }
  275 +
196 /// 九宫格 276 /// 九宫格
197 Widget _getGridImg(List<CommentsImageModel> imags) { 277 Widget _getGridImg(List<CommentsImageModel> imags) {
198 imags.removeWhere((element) => element.url == null || element.url == ''); 278 imags.removeWhere((element) => element.url == null || element.url == '');
199 279
200 -  
201 return GridView.builder( 280 return GridView.builder(
202 controller: controller, 281 controller: controller,
203 padding: EdgeInsets.symmetric(vertical: w(7)), 282 padding: EdgeInsets.symmetric(vertical: w(7)),
@@ -214,7 +293,7 @@ class _CommentManageHomePageState extends State<CommentManageHomePage> { @@ -214,7 +293,7 @@ class _CommentManageHomePageState extends State<CommentManageHomePage> {
214 crossAxisSpacing: w(7), 293 crossAxisSpacing: w(7),
215 //子组件宽高长度比例 294 //子组件宽高长度比例
216 childAspectRatio: 1.0), 295 childAspectRatio: 1.0),
217 - itemBuilder: (BuildContext context, int index){ 296 + itemBuilder: (BuildContext context, int index) {
218 if (imags[index].avinfo != null && 297 if (imags[index].avinfo != null &&
219 imags[index].avinfo != 'false' && 298 imags[index].avinfo != 'false' &&
220 imags[index].avinfo != '0') { 299 imags[index].avinfo != '0') {
@@ -238,12 +317,21 @@ class _CommentManageHomePageState extends State<CommentManageHomePage> { @@ -238,12 +317,21 @@ class _CommentManageHomePageState extends State<CommentManageHomePage> {
238 if (snapshot.hasData) { 317 if (snapshot.hasData) {
239 return InkWell( 318 return InkWell(
240 onTap: () { 319 onTap: () {
241 - Navigator.push(  
242 - context,  
243 - PopRoute(  
244 - child: VideoPage(  
245 - url: imags[index].url,  
246 - ))); 320 + if (Platform.isIOS || Platform.isAndroid) {
  321 + Navigator.push(
  322 + context,
  323 + PopRoute(
  324 + child: VideoPage(
  325 + url: imags[index].url,
  326 + )));
  327 + } else {
  328 + Navigator.push(
  329 + context,
  330 + PopRoute(
  331 + child: BumbleBeeRemoteVideo(
  332 + imags[index].url ?? '',imags[index].filePath
  333 + )));
  334 + }
247 }, 335 },
248 child: Stack(alignment: Alignment.center, children: [ 336 child: Stack(alignment: Alignment.center, children: [
249 ClipRRect( 337 ClipRRect(
  1 +import 'dart:io';
  2 +
  3 +import 'package:flutter/cupertino.dart';
  4 +import 'package:flutter/material.dart';
  5 +import 'package:flutter_screenutil/flutter_screenutil.dart';
  6 +import 'package:one_key/res/colors.dart';
  7 +import 'package:one_key/utils/screen_util.dart';
  8 +import 'package:video_player/video_player.dart';
  9 +
  10 +import '../../../widgets/system_app_bar.dart';
  11 +
  12 +class BumbleBeeRemoteVideo extends StatefulWidget {
  13 + const BumbleBeeRemoteVideo(this.url, this.filePath);
  14 + final String? filePath;
  15 +
  16 + final String url;
  17 +
  18 + @override
  19 + BumbleBeeRemoteVideoState createState() => BumbleBeeRemoteVideoState();
  20 +}
  21 +
  22 +class BumbleBeeRemoteVideoState extends State<BumbleBeeRemoteVideo> {
  23 + late VideoPlayerController _controller;
  24 +
  25 + // Future<ClosedCaptionFile> _loadCaptions() async {
  26 + // final String fileContents = await DefaultAssetBundle.of(context)
  27 + // .loadString('assets/bumble_bee_captions.vtt');
  28 + // return WebVTTCaptionFile(
  29 + // fileContents); // For vtt files, use WebVTTCaptionFile
  30 + // }
  31 +
  32 + @override
  33 + void initState() {
  34 + super.initState();
  35 + _controller = VideoPlayerController.networkUrl(
  36 + Uri.parse(widget.url),
  37 + // Uri.parse(
  38 + // 'https://flutter.github.io/assets-for-api-docs/assets/videos/bee.mp4'),
  39 + // closedCaptionFile: _loadCaptions(),
  40 + videoPlayerOptions: VideoPlayerOptions(mixWithOthers: true),
  41 + // viewType: widget.viewType,
  42 + );
  43 +
  44 + _controller.addListener(() {
  45 + setState(() {});
  46 + });
  47 + _controller.setLooping(true);
  48 + _controller.initialize();
  49 +
  50 + // _controller.initialize().then((_) {
  51 + // // 确保添加了这一行,以便在初始化完成后执行操作
  52 + // setState(() {});
  53 + // });
  54 + }
  55 +
  56 + @override
  57 + void dispose() {
  58 + _controller.dispose();
  59 + super.dispose();
  60 + }
  61 +
  62 + @override
  63 + Widget build(BuildContext context) {
  64 + return Scaffold(
  65 + appBar: SystemAppBar("评价管理"),
  66 + body: Container(
  67 + child: _controller.value.isInitialized
  68 + ? Center(
  69 + child: Stack(
  70 + alignment: Alignment.bottomCenter,
  71 + children: <Widget>[
  72 + VideoPlayer(_controller),
  73 +
  74 + // widget.filePath != null
  75 + // ? Image.file(
  76 + // File(widget.filePath!),
  77 + // fit: BoxFit.contain,
  78 + // width: ScreenUtil().screenWidth,
  79 + // height: ScreenUtil().screenHeight,
  80 + // )
  81 + // : SizedBox(),
  82 + // ClosedCaption(text: _controller.value.caption.text),
  83 + _ControlsOverlay(controller: _controller),
  84 + VideoProgressIndicator(
  85 + _controller,
  86 + allowScrubbing: true,
  87 + colors: VideoProgressColors(
  88 + playedColor: MyColours.color_438E93,
  89 + bufferedColor: Colors.black,
  90 + backgroundColor: Colors.black),
  91 + ),
  92 + ],
  93 + ),
  94 + // AspectRatio(
  95 + // aspectRatio: _controller.value.aspectRatio,
  96 + // child:
  97 + // ),
  98 + // Material(
  99 + // child: SingleChildScrollView(
  100 + // child: Column(
  101 + // children: <Widget>[
  102 +
  103 + // // // Container(padding: const EdgeInsets.only(top: 20.0)),
  104 + // // // const Text('With remote mp4'),
  105 + // // Container(
  106 + // // // padding: const EdgeInsets.all(20),
  107 + // // child:
  108 + // // ),
  109 + // ],
  110 + // ),
  111 + // ))
  112 + )
  113 + : Container(
  114 + width: ScreenUtil().screenWidth,
  115 + height: ScreenUtil().screenHeight,
  116 + color: MyColours.color_000000,
  117 + child: SizedBox(
  118 + width: ScreenUtil().setWidth(80),
  119 + height: ScreenUtil().setWidth(80),
  120 + child: Center(
  121 + child: CircularProgressIndicator(
  122 + color: Colors.white,
  123 + ),
  124 + )),
  125 + ),
  126 + ));
  127 + }
  128 +}
  129 +
  130 +class _ControlsOverlay extends StatelessWidget {
  131 + const _ControlsOverlay({required this.controller});
  132 +
  133 + // static const List<Duration> _exampleCaptionOffsets = <Duration>[
  134 + // Duration(seconds: -10),
  135 + // Duration(seconds: -3),
  136 + // Duration(seconds: -1, milliseconds: -500),
  137 + // Duration(milliseconds: -250),
  138 + // Duration.zero,
  139 + // Duration(milliseconds: 250),
  140 + // Duration(seconds: 1, milliseconds: 500),
  141 + // Duration(seconds: 3),
  142 + // Duration(seconds: 10),
  143 + // ];
  144 + // static const List<double> _examplePlaybackRates = <double>[
  145 + // 0.25,
  146 + // 0.5,
  147 + // 1.0,
  148 + // 1.5,
  149 + // 2.0,
  150 + // 3.0,
  151 + // 5.0,
  152 + // 10.0,
  153 + // ];
  154 +
  155 + final VideoPlayerController controller;
  156 +
  157 + @override
  158 + Widget build(BuildContext context) {
  159 + return Stack(
  160 + children: <Widget>[
  161 + AnimatedSwitcher(
  162 + duration: const Duration(milliseconds: 50),
  163 + reverseDuration: const Duration(milliseconds: 200),
  164 + child: controller.value.isPlaying
  165 + ? const SizedBox.shrink()
  166 + : const ColoredBox(
  167 + color: Colors.black26,
  168 + child: Center(
  169 + child: Icon(
  170 + Icons.play_arrow,
  171 + color: Colors.white,
  172 + size: 50,
  173 + semanticLabel: 'Play',
  174 + ),
  175 + ),
  176 + ),
  177 + ),
  178 + GestureDetector(
  179 + onTap: () {
  180 + controller.value.isPlaying ? controller.pause() : controller.play();
  181 + },
  182 + ),
  183 + // Align(
  184 + // alignment: Alignment.topLeft,
  185 + // child: PopupMenuButton<Duration>(
  186 + // initialValue: controller.value.captionOffset,
  187 + // tooltip: 'Caption Offset',
  188 + // onSelected: (Duration delay) {
  189 + // controller.setCaptionOffset(delay);
  190 + // },
  191 + // itemBuilder: (BuildContext context) {
  192 + // return <PopupMenuItem<Duration>>[
  193 + // for (final Duration offsetDuration in _exampleCaptionOffsets)
  194 + // PopupMenuItem<Duration>(
  195 + // value: offsetDuration,
  196 + // child: Text('${offsetDuration.inMilliseconds}ms'),
  197 + // )
  198 + // ];
  199 + // },
  200 + // child: Padding(
  201 + // padding: const EdgeInsets.symmetric(
  202 + // // Using less vertical padding as the text is also longer
  203 + // // horizontally, so it feels like it would need more spacing
  204 + // // horizontally (matching the aspect ratio of the video).
  205 + // vertical: 12,
  206 + // horizontal: 16,
  207 + // ),
  208 + // child: Text('${controller.value.captionOffset.inMilliseconds}ms'),
  209 + // ),
  210 + // ),
  211 + // ),
  212 + // Align(
  213 + // alignment: Alignment.topRight,
  214 + // child: PopupMenuButton<double>(
  215 + // initialValue: controller.value.playbackSpeed,
  216 + // tooltip: 'Playback speed',
  217 + // onSelected: (double speed) {
  218 + // controller.setPlaybackSpeed(speed);
  219 + // },
  220 + // itemBuilder: (BuildContext context) {
  221 + // return <PopupMenuItem<double>>[
  222 + // for (final double speed in _examplePlaybackRates)
  223 + // PopupMenuItem<double>(
  224 + // value: speed,
  225 + // child: Text('${speed}x'),
  226 + // )
  227 + // ];
  228 + // },
  229 + // child: Padding(
  230 + // padding: const EdgeInsets.symmetric(
  231 + // // Using less vertical padding as the text is also longer
  232 + // // horizontally, so it feels like it would need more spacing
  233 + // // horizontally (matching the aspect ratio of the video).
  234 + // vertical: 12,
  235 + // horizontal: 16,
  236 + // ),
  237 + // child: Text('${controller.value.playbackSpeed}x'),
  238 + // ),
  239 + // ),
  240 + // ),
  241 + ],
  242 + );
  243 + }
  244 +}
@@ -2,9 +2,9 @@ import 'dart:async'; @@ -2,9 +2,9 @@ import 'dart:async';
2 import 'dart:io'; 2 import 'dart:io';
3 3
4 import 'package:common_utils/common_utils.dart'; 4 import 'package:common_utils/common_utils.dart';
5 -// import 'package:device_info/device_info.dart'; 5 +import 'package:device_info/device_info.dart';
6 6
7 -import 'package:device_info_plus/device_info_plus.dart'; 7 +// import 'package:device_info_plus/device_info_plus.dart';
8 8
9 // import 'package:device_info_plus/device_info_plus.dart'; 9 // import 'package:device_info_plus/device_info_plus.dart';
10 10
@@ -39,6 +39,11 @@ import 'package:excel/excel.dart' as excelUtil; @@ -39,6 +39,11 @@ import 'package:excel/excel.dart' as excelUtil;
39 39
40 import '../../../../widgets/loading.dart'; 40 import '../../../../widgets/loading.dart';
41 41
  42 +import 'package:path_provider_platform_interface/path_provider_platform_interface.dart';
  43 +// import 'package:flutter_document_picker/flutter_document_picker.dart';
  44 +// import 'package:file_document_saver/file_document_saver.dart';
  45 +import 'package:save_file/save_file.dart';
  46 +
42 // import 'package:open_file_plus/open_file_plus.dart'; 47 // import 'package:open_file_plus/open_file_plus.dart';
43 // import 'package:flutter_filereader/flutter_filereader.dart'; 48 // import 'package:flutter_filereader/flutter_filereader.dart';
44 49
@@ -103,6 +108,20 @@ class _ExportBookDataPageState extends State<ExportBookDataPage> { @@ -103,6 +108,20 @@ class _ExportBookDataPageState extends State<ExportBookDataPage> {
103 108
104 externalStorageDirPath = 109 externalStorageDirPath =
105 externalStorageDirPath.replaceFirst("Library/Caches", "Documents"); 110 externalStorageDirPath.replaceFirst("Library/Caches", "Documents");
  111 + } else if (Platform.isOhos) {
  112 + final PathProviderPlatform provider = PathProviderPlatform.instance;
  113 +
  114 + String? externalStorageDirPath1 = await provider.getExternalStoragePath();
  115 +// Directory? downloadsDir =await getApplicationDocumentsDirectory();
  116 + // Directory? downloadsDir = await getTemporaryDirectory();
  117 + // getDownloadsDirectory();
  118 + // getApplicationDocumentsDirectory();
  119 + // getDownloadsDirectory();
  120 + // provider.getTemporaryPath(); cache
  121 + // String? externalStorageDirPath1 = downloadsDir.path;
  122 + // ;
  123 + print(externalStorageDirPath1);
  124 + return externalStorageDirPath1;
106 } 125 }
107 return externalStorageDirPath; 126 return externalStorageDirPath;
108 } 127 }
@@ -110,33 +129,7 @@ class _ExportBookDataPageState extends State<ExportBookDataPage> { @@ -110,33 +129,7 @@ class _ExportBookDataPageState extends State<ExportBookDataPage> {
110 Future<bool> _checkPermission() async { 129 Future<bool> _checkPermission() async {
111 if (Platform.isIOS) { 130 if (Platform.isIOS) {
112 return true; 131 return true;
113 - }  
114 -  
115 - if (Platform.isOhos) {  
116 - // DeviceInfoPlugin deviceInfoPlugin = DeviceInfoPlugin();  
117 - // Map<String, dynamic> _deviceData = (await deviceInfoPlugin.ohosInfo).data;  
118 - // print(_deviceData);  
119 -  
120 - var status = await Permission.storage.status;  
121 - if (!status.isGranted) {  
122 - var result = await Permission.storage.request();  
123 - if (result.isGranted) {  
124 - // 权限被用户允许  
125 - print('Permission granted');  
126 - return true;  
127 - } else {  
128 - // 权限被用户拒绝  
129 - print('Permission denied');  
130 - return false;  
131 - }  
132 - } else {  
133 - // 权限已经授权  
134 - print('Permission already granted');  
135 - return true;  
136 - }  
137 - }  
138 -  
139 - if (Platform.isAndroid) { 132 + } else if (Platform.isAndroid) {
140 final info = await DeviceInfoPlugin().androidInfo; 133 final info = await DeviceInfoPlugin().androidInfo;
141 134
142 if (info.version.sdkInt >= 33) { 135 if (info.version.sdkInt >= 33) {
@@ -183,7 +176,30 @@ class _ExportBookDataPageState extends State<ExportBookDataPage> { @@ -183,7 +176,30 @@ class _ExportBookDataPageState extends State<ExportBookDataPage> {
183 } 176 }
184 return result == PermissionStatus.granted; 177 return result == PermissionStatus.granted;
185 } 178 }
  179 + } else if (Platform.isOhos) {
  180 + // return true;
  181 + // DeviceInfoPlugin deviceInfoPlugin = DeviceInfoPlugin();
  182 + // Map<String, dynamic> _deviceData = (await deviceInfoPlugin.ohosInfo).data;
  183 + // print(_deviceData);
  184 + var status = await Permission.photos.status;
  185 + if (!status.isGranted) {
  186 + var result = await Permission.photos.request();
  187 + if (result.isGranted) {
  188 + // 权限被用户允许
  189 + print('Permission granted');
  190 + return true;
  191 + } else {
  192 + // 权限被用户拒绝
  193 + print('Permission denied');
  194 + return false;
  195 + }
  196 + } else {
  197 + // 权限已经授权
  198 + print('Permission already granted');
  199 + return true;
  200 + }
186 } 201 }
  202 +
187 // manageExternalStorage 203 // manageExternalStorage
188 throw StateError('unknown platform'); 204 throw StateError('unknown platform');
189 } 205 }
@@ -280,6 +296,26 @@ class _ExportBookDataPageState extends State<ExportBookDataPage> { @@ -280,6 +296,26 @@ class _ExportBookDataPageState extends State<ExportBookDataPage> {
280 return data; 296 return data;
281 } 297 }
282 298
  299 + _openOHOSFile(String? filePath) async {
  300 + // OpenFilex.open 需要传入有权限访问的文件地址才能访问,比如应用沙箱路径下的文件
  301 + // 这里使用了其它三方库来自定义选取文件做功能展示
  302 + var _openResult = 'Unknown';
  303 + // String? path = await FlutterDocumentPicker.openDocument();
  304 + if (filePath != null) {
  305 + // String filePath = "file://com.crazecoder.openfile.example$path";
  306 + final result = await OpenFilex.open(
  307 + filePath);
  308 +
  309 + _openResult = "type=${result.type} message=${result.message}";
  310 + } else {
  311 + // setState(() {
  312 + _openResult = "User canceled the picker";
  313 + // });
  314 + }
  315 +
  316 + print(_openResult);
  317 + }
  318 +
283 void _download() async { 319 void _download() async {
284 Loading.showLoading( 320 Loading.showLoading(
285 context, 321 context,
@@ -378,7 +414,7 @@ class _ExportBookDataPageState extends State<ExportBookDataPage> { @@ -378,7 +414,7 @@ class _ExportBookDataPageState extends State<ExportBookDataPage> {
378 String timetemp = 414 String timetemp =
379 ((DateTime.now().millisecondsSinceEpoch / 1000).floor()).toString(); 415 ((DateTime.now().millisecondsSinceEpoch / 1000).floor()).toString();
380 String sunfix = '.xlsx'; 416 String sunfix = '.xlsx';
381 - 417 +
382 // String sunfix = '.xls'; 418 // String sunfix = '.xls';
383 // String fileName = "/${sellername}${starttime}至${endtime}.xlsx"; 419 // String fileName = "/${sellername}${starttime}至${endtime}.xlsx";
384 String fileName = nameS + timetemp + sunfix; 420 String fileName = nameS + timetemp + sunfix;
@@ -388,14 +424,41 @@ class _ExportBookDataPageState extends State<ExportBookDataPage> { @@ -388,14 +424,41 @@ class _ExportBookDataPageState extends State<ExportBookDataPage> {
388 String filePath = _localPath! + '${fileName}'; 424 String filePath = _localPath! + '${fileName}';
389 425
390 if (fileBytes != null) { 426 if (fileBytes != null) {
391 - File file = File(filePath)  
392 - ..createSync(recursive: true)  
393 - ..writeAsBytesSync(fileBytes);  
394 - try {  
395 - File file1 = await file.copy('/storage/emulated/0/Download${fileName}');  
396 - // Utils.showToast('文件已保存到${file1.path}');  
397 - } catch (e) {  
398 - // Utils.showToast('保存失败!'); 427 + String? resultPath ;
  428 + if (Platform.isIOS || Platform.isAndroid) {
  429 + File file = File(filePath)
  430 + ..createSync(recursive: true)
  431 + ..writeAsBytesSync(fileBytes);
  432 + try {
  433 + File file1 =
  434 + await file.copy('/storage/emulated/0/Download${fileName}');
  435 + // Utils.showToast('文件已保存到${file1.path}');
  436 + } catch (e) {
  437 + // Utils.showToast('保存失败!');
  438 + }
  439 + } else if (Platform.isOhos) {
  440 + File file = File(filePath)
  441 + ..createSync(recursive: true)
  442 + ..writeAsBytesSync(fileBytes);
  443 +
  444 + try {
  445 + final _saveFilePlugin = SaveFile();
  446 + resultPath = await _saveFilePlugin.saveFile(file.path,'${sellername}${starttime}至${endtime}_${timetemp}');
  447 + print(resultPath);
  448 + } catch (e) {
  449 + print(e);
  450 + }
  451 +
  452 + // try {
  453 + // File file1 = await file
  454 + // .copy('/storage/media/100/local/files/Documents${fileName}');
  455 + // } catch (e) {
  456 + // print(e);
  457 + // }
  458 + // 把当前存储目录的文件复制到文件管理器的文档目录里
  459 +// String downloadUri = FileManager.getUri(FileManager.DIRECTORY_DOWNLOADS);
  460 +// File file = new File(downloadUri + "/filename.txt");
  461 +// file.writeString('content');
399 } 462 }
400 463
401 Loading.hideLoading(context); 464 Loading.hideLoading(context);
@@ -409,20 +472,27 @@ class _ExportBookDataPageState extends State<ExportBookDataPage> { @@ -409,20 +472,27 @@ class _ExportBookDataPageState extends State<ExportBookDataPage> {
409 progress = null; 472 progress = null;
410 setState(() {}); 473 setState(() {});
411 }, rCallback: () async { 474 }, rCallback: () async {
412 - // final result =  
413 - // await OpenFilex.open(filePath, type: 'application/vnd.ms-excel');  
414 - final result = await OpenFilex.open(filePath,  
415 - type:  
416 - 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');  
417 - print(result.type);  
418 - if (result.type == ResultType.noAppToOpen) {  
419 - Utils.showToast('没有应用可以打开');  
420 - } else if (result.type == ResultType.fileNotFound) {  
421 - Utils.showToast('找不到文件');  
422 - } else if (result.type == ResultType.permissionDenied) {  
423 - Utils.showToast('没有相关权限');  
424 - } else if (result.type == ResultType.permissionDenied) {  
425 - Utils.showToast('发生未知错误'); 475 + if (Platform.isAndroid || Platform.isIOS) {
  476 + // final result =
  477 + // await OpenFilex.open(filePath, type: 'application/vnd.ms-excel');
  478 + final result = await OpenFilex.open(filePath,
  479 + type:
  480 + 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
  481 + print(result.type);
  482 + if (result.type == ResultType.noAppToOpen) {
  483 + Utils.showToast('没有应用可以打开');
  484 + } else if (result.type == ResultType.fileNotFound) {
  485 + Utils.showToast('找不到文件');
  486 + } else if (result.type == ResultType.permissionDenied) {
  487 + Utils.showToast('没有相关权限');
  488 + } else if (result.type == ResultType.permissionDenied) {
  489 + Utils.showToast('发生未知错误');
  490 + }
  491 + } else if (Platform.isOhos) {
  492 +
  493 +
  494 + _openOHOSFile(filePath);
  495 + // _openOHOSFile(resultPath);
426 } 496 }
427 }); 497 });
428 } else { 498 } else {
@@ -648,16 +718,16 @@ class _ExportBookDataPageState extends State<ExportBookDataPage> { @@ -648,16 +718,16 @@ class _ExportBookDataPageState extends State<ExportBookDataPage> {
648 } 718 }
649 } 719 }
650 } else { 720 } else {
651 - // String title = Platform.isAndroid ? '存储' : '相册'; 721 + String title = Platform.isIOS ? '相册' : Platform.isAndroid ?'存储':'图片和视频';
652 722
653 // //用户选择不在弹出权限提示框 723 // //用户选择不在弹出权限提示框
654 // print('never'); 724 // print('never');
655 // // Navigator.pop(context); 725 // // Navigator.pop(context);
656 - // DialogUtil.openAlertDialog(context, '未获得${title}权限',  
657 - // "请在手机的权限管理里,将${title}权限开启", '去设置', 340.0, onTap: () {  
658 - // openSetting();  
659 - // Navigator.pop(context, '');  
660 - // }); 726 + DialogUtil.openAlertDialog(context, '未获得${title}权限',
  727 + "请在手机的权限管理里,将${title}权限开启", '去设置', 340.0, onTap: () {
  728 + openSetting();
  729 + Navigator.pop(context, '');
  730 + });
661 } 731 }
662 }, 732 },
663 ) 733 )
@@ -6,6 +6,7 @@ import 'package:flutter_app_update/azhon_app_update.dart'; @@ -6,6 +6,7 @@ import 'package:flutter_app_update/azhon_app_update.dart';
6 // import 'package:flutter_ex_widget/ex_text.dart'; 6 // import 'package:flutter_ex_widget/ex_text.dart';
7 import 'package:flutter_screenutil/flutter_screenutil.dart'; 7 import 'package:flutter_screenutil/flutter_screenutil.dart';
8 import 'package:fluwx/fluwx.dart'; 8 import 'package:fluwx/fluwx.dart';
  9 +import 'package:install_plugin/install_plugin.dart';
9 import 'package:one_key/constant/state.dart'; 10 import 'package:one_key/constant/state.dart';
10 import 'package:one_key/models/sms_info.dart'; 11 import 'package:one_key/models/sms_info.dart';
11 import 'package:one_key/models/store_info.dart'; 12 import 'package:one_key/models/store_info.dart';
@@ -1775,7 +1776,7 @@ class MyPageState extends State<MyPage> with WidgetsBindingObserver { @@ -1775,7 +1776,7 @@ class MyPageState extends State<MyPage> with WidgetsBindingObserver {
1775 )), 1776 )),
1776 VEmptyView(48), 1777 VEmptyView(48),
1777 InkWell( 1778 InkWell(
1778 - onTap: () { 1779 + onTap: () async {
1779 UserModel usermodel = 1780 UserModel usermodel =
1780 Provider.of<UserModel>(context, 1781 Provider.of<UserModel>(context,
1781 listen: false); 1782 listen: false);
@@ -869,7 +869,6 @@ class _StoreBaseInfoPageState extends State<StoreBaseInfoPage> { @@ -869,7 +869,6 @@ class _StoreBaseInfoPageState extends State<StoreBaseInfoPage> {
869 Uint8List newImg = (await Utils.testFromFileComporessList( 869 Uint8List newImg = (await Utils.testFromFileComporessList(
870 context, afterImg, 870 context, afterImg,
871 needResize: true))!; 871 needResize: true))!;
872 -  
873 print(Utils.size(newImg.length)); 872 print(Utils.size(newImg.length));
874 if (newImg != null) { 873 if (newImg != null) {
875 String? path = await Utils.saveImage(newImg); 874 String? path = await Utils.saveImage(newImg);
@@ -1930,7 +1929,8 @@ class _StoreBaseInfoPageState extends State<StoreBaseInfoPage> { @@ -1930,7 +1929,8 @@ class _StoreBaseInfoPageState extends State<StoreBaseInfoPage> {
1930 FocusScope.of(context).requestFocus( 1929 FocusScope.of(context).requestFocus(
1931 FocusNode()); //点击空白处隐藏键盘 1930 FocusNode()); //点击空白处隐藏键盘
1932 }, 1931 },
1933 - keyboardType: TextInputType.numberWithOptions(), 1932 + keyboardType:
  1933 + TextInputType.numberWithOptions(),
1934 ), 1934 ),
1935 )), 1935 )),
1936 HEmptyView(20), 1936 HEmptyView(20),
@@ -2016,7 +2016,8 @@ class _StoreBaseInfoPageState extends State<StoreBaseInfoPage> { @@ -2016,7 +2016,8 @@ class _StoreBaseInfoPageState extends State<StoreBaseInfoPage> {
2016 .requestFocus( 2016 .requestFocus(
2017 FocusNode()); //点击空白处隐藏键盘 2017 FocusNode()); //点击空白处隐藏键盘
2018 }, 2018 },
2019 - keyboardType: TextInputType.numberWithOptions(), 2019 + keyboardType: TextInputType
  2020 + .numberWithOptions(),
2020 ), 2021 ),
2021 )), 2022 )),
2022 HEmptyView(20), 2023 HEmptyView(20),
@@ -1719,9 +1719,17 @@ class MyPageSimState extends State<MyPageSim> with WidgetsBindingObserver { @@ -1719,9 +1719,17 @@ class MyPageSimState extends State<MyPageSim> with WidgetsBindingObserver {
1719 VEmptyView(48), 1719 VEmptyView(48),
1720 InkWell( 1720 InkWell(
1721 onTap: () { 1721 onTap: () {
  1722 +
  1723 + UpdateModelMy updateModel =
  1724 + new UpdateModelMy();
  1725 +
  1726 + updateModel.showUpdateDialog(
  1727 + context,Version());
  1728 +
1722 UserModel usermodel = 1729 UserModel usermodel =
1723 Provider.of<UserModel>(context, 1730 Provider.of<UserModel>(context,
1724 listen: false); 1731 listen: false);
  1732 +
1725 if (usermodel.downLoading) { 1733 if (usermodel.downLoading) {
1726 Utils.showToast("正在后台下载新版本…"); 1734 Utils.showToast("正在后台下载新版本…");
1727 return; 1735 return;
@@ -20,11 +20,13 @@ import 'package:one_key/utils/misc.dart'; @@ -20,11 +20,13 @@ import 'package:one_key/utils/misc.dart';
20 import 'package:one_key/utils/utils.dart'; 20 import 'package:one_key/utils/utils.dart';
21 import 'package:one_key/widgets/MyDivider.dart'; 21 import 'package:one_key/widgets/MyDivider.dart';
22 import 'package:one_key/widgets/v_empty_view.dart'; 22 import 'package:one_key/widgets/v_empty_view.dart';
  23 +// import 'package:package_info/package_info.dart';
23 import 'package:path_provider/path_provider.dart'; 24 import 'package:path_provider/path_provider.dart';
24 import 'package:permission_handler/permission_handler.dart'; 25 import 'package:permission_handler/permission_handler.dart';
25 import 'package:provider/provider.dart'; 26 import 'package:provider/provider.dart';
26 import 'package:flutter_app_update/azhon_app_update.dart'; 27 import 'package:flutter_app_update/azhon_app_update.dart';
27 import 'package:flutter_app_update/update_model.dart'; 28 import 'package:flutter_app_update/update_model.dart';
  29 +import 'package:url_launcher/url_launcher.dart';
28 30
29 import '../app.dart'; 31 import '../app.dart';
30 import '../utils/dialog_util.dart'; 32 import '../utils/dialog_util.dart';
@@ -32,6 +34,8 @@ import 'package:device_utils_my/device_utils_my.dart'; @@ -32,6 +34,8 @@ import 'package:device_utils_my/device_utils_my.dart';
32 34
33 import '../widgets/fixed_text.dart'; 35 import '../widgets/fixed_text.dart';
34 36
  37 +import 'package:package_info_plus/package_info_plus.dart';
  38 +
35 typedef VeisonCallback = void Function(Version value); 39 typedef VeisonCallback = void Function(Version value);
36 40
37 class UpdateModelMy { 41 class UpdateModelMy {
@@ -105,15 +109,22 @@ class UpdateModelMy { @@ -105,15 +109,22 @@ class UpdateModelMy {
105 //检查更新 109 //检查更新
106 checkUpdate(BuildContext context, VeisonCallback callback, 110 checkUpdate(BuildContext context, VeisonCallback callback,
107 {showToast = true}) async { 111 {showToast = true}) async {
108 - String deviceId = await Utils.getUUID()??''; //鸿蒙获取uuid代码测试 112 + String deviceId = await Utils.getUUID() ?? ''; //鸿蒙获取uuid代码测试
109 UserModel userModel = Provider.of<UserModel>(context, listen: false); 113 UserModel userModel = Provider.of<UserModel>(context, listen: false);
110 - int versionCode = await AzhonAppUpdate.getVersionCode; 114 + String versionCode = '';
  115 + if (Platform.isIOS || Platform.isAndroid) {
  116 + versionCode = (await AzhonAppUpdate.getVersionCode).toString();
  117 + } else if (Platform.isOhos) {
  118 + final info = await PackageInfo.fromPlatform();
  119 + // String version = info.version; // 1.0.0
  120 + versionCode = info.buildNumber; //1
  121 + }
111 String make = "3"; 122 String make = "3";
112 if (Platform.isIOS) make = "4"; 123 if (Platform.isIOS) make = "4";
113 Map<String, String?> params = { 124 Map<String, String?> params = {
114 "deviceId": deviceId, 125 "deviceId": deviceId,
115 "sid": userModel.user!.sellerid, 126 "sid": userModel.user!.sellerid,
116 - "versionCode": versionCode.toString(), 127 + "versionCode": versionCode,
117 "flag": "4", 128 "flag": "4",
118 "make": make, //3 android 4 ios 129 "make": make, //3 android 4 ios
119 }; 130 };
@@ -124,7 +135,7 @@ class UpdateModelMy { @@ -124,7 +135,7 @@ class UpdateModelMy {
124 if (baseResp != null && baseResp.code == Constant.status_success) { 135 if (baseResp != null && baseResp.code == Constant.status_success) {
125 LogUtil.v(baseResp.data); 136 LogUtil.v(baseResp.data);
126 Map<String, dynamic> dataMap = baseResp.data![0]; 137 Map<String, dynamic> dataMap = baseResp.data![0];
127 - if (int.parse(dataMap["version"].toString()) > versionCode) { 138 + if (int.parse(dataMap["version"].toString()) > int.parse(versionCode)) {
128 Version version = Version.fromJson({ 139 Version version = Version.fromJson({
129 "name": dataMap["name"].toString(), 140 "name": dataMap["name"].toString(),
130 "version": dataMap["version"].toString(), 141 "version": dataMap["version"].toString(),
@@ -166,6 +177,22 @@ class UpdateModelMy { @@ -166,6 +177,22 @@ class UpdateModelMy {
166 } 177 }
167 } 178 }
168 179
  180 + Future<void> launchHarmonyAppStore(String appId) async {
  181 + final urls = [
  182 + 'harmony://appstore/$appId', // 鸿蒙原生Scheme
  183 + 'https://appgallery.huawei.com/app/$appId', // 网页版
  184 + ];
  185 +
  186 + for (final url in urls) {
  187 + if (await canLaunch(url)) {
  188 + await launch(url);
  189 + return;
  190 + }
  191 + }
  192 + // 所有方案都失败时打开默认应用商店主页
  193 + await launch('https://appgallery.huawei.com');
  194 + }
  195 +
169 //版本更新弹框 196 //版本更新弹框
170 showUpdateDialog(BuildContext pageContext, Version? version) { 197 showUpdateDialog(BuildContext pageContext, Version? version) {
171 showDialog( 198 showDialog(
@@ -243,10 +270,12 @@ class UpdateModelMy { @@ -243,10 +270,12 @@ class UpdateModelMy {
243 // tryOtaUpdate(version.file_url); 270 // tryOtaUpdate(version.file_url);
244 simpleUse(false, version.file_url); 271 simpleUse(false, version.file_url);
245 Navigator.of(context).pop(); 272 Navigator.of(context).pop();
246 - } else { 273 + } else if (Platform.isIOS) {
247 Navigator.of(context).pop(); 274 Navigator.of(context).pop();
248 InstallPlugin.gotoAppStore( 275 InstallPlugin.gotoAppStore(
249 "itms-apps://itunes.apple.com/WebObjects/MZStore.woa/wa/viewSoftware?id=1510697490"); 276 "itms-apps://itunes.apple.com/WebObjects/MZStore.woa/wa/viewSoftware?id=1510697490");
  277 + } else if (Platform.isOhos) {
  278 + launchHarmonyAppStore(Constant.ohos_app_id);
250 } 279 }
251 }, 280 },
252 child: FixedText( 281 child: FixedText(
@@ -12,7 +12,7 @@ class MyColours { @@ -12,7 +12,7 @@ class MyColours {
12 static const Color color_FBF6F1 = Color(0xFFFBF6F1); 12 static const Color color_FBF6F1 = Color(0xFFFBF6F1);
13 static const Color color_4D4E50 = Color(0xFF4D4E50); 13 static const Color color_4D4E50 = Color(0xFF4D4E50);
14 static const Color color_00715F = Color(0xFF00715F); 14 static const Color color_00715F = Color(0xFF00715F);
15 - static const Color color_80D9D9D9 = Color(0x80D9D9D9); 15 + static const Color color_80D9D9D9 = Color.fromARGB(128, 12, 3, 3);
16 static const Color color_42A5FF = Color(0xFF42A5FF); 16 static const Color color_42A5FF = Color(0xFF42A5FF);
17 static const Color color_4C8DAD = Color(0xFF4C8DAD); 17 static const Color color_4C8DAD = Color(0xFF4C8DAD);
18 static const Color color_4D0C0F0E = Color(0x4D0C0F0E); 18 static const Color color_4D0C0F0E = Color(0x4D0C0F0E);
  1 +import 'package:flutter/material.dart';
  2 +import 'package:image_cropper/image_cropper.dart';
  3 +
  4 +class CropImageUtils {
  5 + static cropImage(BuildContext context, String path) async {
  6 + final croppedFile = await ImageCropper().cropImage(
  7 + sourcePath: path,
  8 + compressFormat: ImageCompressFormat.jpg,
  9 + compressQuality: 100,
  10 + uiSettings: [
  11 + AndroidUiSettings(
  12 + // backgroundColor: Colors.red,
  13 + // toolbarTitle: 'Cropper',
  14 + // toolbarColor: Colors.deepOrange,
  15 + // toolbarWidgetColor: Colors.white,
  16 + // initAspectRatio: CropAspectRatioPreset.ratio5x4,
  17 + cropStyle: CropStyle.rectangle,
  18 + aspectRatioPresets: [CropAspectRatioPreset.ratio5x4],
  19 + hideBottomControls: true,
  20 + lockAspectRatio: true),
  21 + IOSUiSettings(
  22 + // title: 'Cropper',
  23 + // rotateButtonsHidden: true,
  24 + // rotateClockwiseButtonHidden: true,
  25 + cropStyle: CropStyle.rectangle,
  26 + aspectRatioPresets: [CropAspectRatioPreset.ratio5x4],
  27 + resetAspectRatioEnabled: false,
  28 + doneButtonTitle: '确定',
  29 + cancelButtonTitle: '取消',
  30 + aspectRatioLockEnabled: true),
  31 + // AndroidUiSettings(
  32 + // toolbarTitle: '裁剪',
  33 + // toolbarColor: Colors.white,
  34 + // toolbarWidgetColor: Colors.white,
  35 + // initAspectRatio: CropAspectRatioPreset.square,
  36 + // lockAspectRatio: false,
  37 + // aspectRatioPresets: [
  38 + // // CropAspectRatioPreset.original,
  39 + // // CropAspectRatioPreset.square,
  40 + // CropAspectRatioPreset.ratio5x4,
  41 + // // CropAspectRatioPresetCustom(),
  42 + // ],
  43 + // ),
  44 + // IOSUiSettings(
  45 + // title: '裁剪',
  46 + // aspectRatioPresets: [
  47 + // // CropAspectRatioPreset.original,
  48 + // // CropAspectRatioPreset.square,
  49 + // CropAspectRatioPreset.ratio5x4,
  50 + // // CropAspectRatioPresetCustom(),
  51 + // ],
  52 + // ),
  53 + WebUiSettings(
  54 + context: context,
  55 + presentStyle: WebPresentStyle.dialog,
  56 + size: const CropperSize(
  57 + width: 500,
  58 + height:400,
  59 + ),
  60 + ),
  61 + ],
  62 + );
  63 +
  64 + return croppedFile;
  65 + }
  66 +}
  67 +
  68 +// class CropAspectRatioPresetCustom implements CropAspectRatioPresetData {
  69 +// @override
  70 +// (int, int)? get data => (5, 4);
  71 +
  72 +// @override
  73 +// String get name => '5x4';
  74 +// }
1 -  
2 import 'dart:async'; 1 import 'dart:async';
3 import 'dart:io'; 2 import 'dart:io';
4 3
@@ -10,14 +9,28 @@ import 'package:permission_handler/permission_handler.dart'; @@ -10,14 +9,28 @@ import 'package:permission_handler/permission_handler.dart';
10 import '../app.dart'; 9 import '../app.dart';
11 10
12 FutureOr<bool> checkPermissionStorage() async { 11 FutureOr<bool> checkPermissionStorage() async {
13 - var status = await Permission.storage.status;  
14 - if (!status.isGranted) {  
15 - status = await Permission.storage.request();  
16 - if (status.isGranted) { 12 + if (Platform.isIOS || Platform.isAndroid) {
  13 + var status = await Permission.storage.status;
  14 + if (!status.isGranted) {
  15 + status = await Permission.storage.request();
  16 + if (status.isGranted) {
  17 + return true;
  18 + }
  19 + } else {
17 return true; 20 return true;
18 } 21 }
19 - } else {  
20 - return true; 22 + return false;
  23 + } else if (Platform.isOhos) {
  24 + var status = await Permission.photos.status;
  25 + if (!status.isGranted) {
  26 + status = await Permission.photos.request();
  27 + if (status.isGranted) {
  28 + return true;
  29 + }
  30 + } else {
  31 + return true;
  32 + }
  33 + return false;
21 } 34 }
22 return false; 35 return false;
23 } 36 }
@@ -40,7 +53,7 @@ FutureOr<bool> checkPermission(Permission permissionGroup) async { @@ -40,7 +53,7 @@ FutureOr<bool> checkPermission(Permission permissionGroup) async {
40 } 53 }
41 } 54 }
42 55
43 -FutureOr<bool> requestPermission( Permission permissionGroup) async { 56 +FutureOr<bool> requestPermission(Permission permissionGroup) async {
44 //全局提示权限使用目的 57 //全局提示权限使用目的
45 if (Platform.isAndroid) { 58 if (Platform.isAndroid) {
46 //全局提示权限使用目的 59 //全局提示权限使用目的
@@ -68,13 +81,13 @@ FutureOr<bool> requestPermission( Permission permissionGroup) async { @@ -68,13 +81,13 @@ FutureOr<bool> requestPermission( Permission permissionGroup) async {
68 } 81 }
69 82
70 final permissions = await [permissionGroup].request(); 83 final permissions = await [permissionGroup].request();
71 - if(App.isShowDes){  
72 - //全局提示权限使用目的 84 + if (App.isShowDes) {
  85 + //全局提示权限使用目的
73 BuildContext context = App.navigatorKey.currentState!.overlay!.context; 86 BuildContext context = App.navigatorKey.currentState!.overlay!.context;
74 - if (Navigator.canPop(context)) {  
75 - Navigator.pop(context);  
76 - }  
77 - } 87 + if (Navigator.canPop(context)) {
  88 + Navigator.pop(context);
  89 + }
  90 + }
78 if (await permissionGroup.request().isGranted) { 91 if (await permissionGroup.request().isGranted) {
79 print(true); 92 print(true);
80 // Either the permission was already granted before or the user just granted it. 93 // Either the permission was already granted before or the user just granted it.
@@ -6,8 +6,6 @@ @@ -6,8 +6,6 @@
6 * @Description: 截图工具,生成截图,保存到相册或者保存本地cash文件夹返回文件路径(供分享使用) 6 * @Description: 截图工具,生成截图,保存到相册或者保存本地cash文件夹返回文件路径(供分享使用)
7 */ 7 */
8 8
9 -  
10 -  
11 import 'dart:io'; 9 import 'dart:io';
12 import 'dart:typed_data'; 10 import 'dart:typed_data';
13 import 'dart:async'; 11 import 'dart:async';
@@ -45,9 +43,17 @@ class RepaintBoundaryUtils { @@ -45,9 +43,17 @@ class RepaintBoundaryUtils {
45 bool isDirExist = await Directory(applicationDir.path).exists(); 43 bool isDirExist = await Directory(applicationDir.path).exists();
46 if (!isDirExist) Directory(applicationDir.path).create(); 44 if (!isDirExist) Directory(applicationDir.path).create();
47 // 直接保存,返回的就是保存后的文件 45 // 直接保存,返回的就是保存后的文件
48 - File saveFile = await File(  
49 - applicationDir.path + "${DateTime.now().toIso8601String()}.jpg")  
50 - .writeAsBytes(pngBytes); 46 + File saveFile;
  47 + if (Platform.isOhos) {
  48 + // 直接保存,返回的就是保存后的文件
  49 + saveFile = await File(
  50 + applicationDir.path + "/${DateTime.now().toIso8601String()}.jpg")
  51 + .writeAsBytes(pngBytes);
  52 + } else {
  53 + saveFile = await File(
  54 + applicationDir.path + "${DateTime.now().toIso8601String()}.jpg")
  55 + .writeAsBytes(pngBytes);
  56 + }
51 filePath = saveFile.path; 57 filePath = saveFile.path;
52 // if (Platform.isAndroid) { 58 // if (Platform.isAndroid) {
53 // // 如果是Android 的话,直接使用image_gallery_saver就可以了 59 // // 如果是Android 的话,直接使用image_gallery_saver就可以了
@@ -24,6 +24,7 @@ import 'package:fluwx/fluwx.dart'; @@ -24,6 +24,7 @@ import 'package:fluwx/fluwx.dart';
24 import 'package:one_key/provider/my_model.dart'; 24 import 'package:one_key/provider/my_model.dart';
25 import 'package:one_key/provider/user_model.dart'; 25 import 'package:one_key/provider/user_model.dart';
26 import 'package:one_key/res/colors.dart'; 26 import 'package:one_key/res/colors.dart';
  27 +import 'package:one_key/utils/crop_image_utils.dart';
27 import 'package:one_key/utils/dialog_util.dart'; 28 import 'package:one_key/utils/dialog_util.dart';
28 import 'package:one_key/utils/lunar_calendar.dart'; 29 import 'package:one_key/utils/lunar_calendar.dart';
29 import 'package:one_key/utils/misc.dart'; 30 import 'package:one_key/utils/misc.dart';
@@ -31,7 +32,7 @@ import 'package:one_key/route/navigator_util.dart'; @@ -31,7 +32,7 @@ import 'package:one_key/route/navigator_util.dart';
31 import 'package:one_key/utils/screen_util.dart'; 32 import 'package:one_key/utils/screen_util.dart';
32 import 'package:one_key/utils/wx_sdk.dart'; 33 import 'package:one_key/utils/wx_sdk.dart';
33 import 'package:one_key/widgets/loading.dart'; 34 import 'package:one_key/widgets/loading.dart';
34 -import 'package:package_info/package_info.dart'; 35 +
35 // import 'package:package_info_plus/package_info_plus.dart'; 36 // import 'package:package_info_plus/package_info_plus.dart';
36 import 'package:permission_handler/permission_handler.dart'; 37 import 'package:permission_handler/permission_handler.dart';
37 import 'package:provider/provider.dart'; 38 import 'package:provider/provider.dart';
@@ -54,10 +55,24 @@ import '../models/recharge_list_model.dart'; @@ -54,10 +55,24 @@ import '../models/recharge_list_model.dart';
54 // import 'dart:typed_data'; 55 // import 'dart:typed_data';
55 import 'dart:typed_data'; 56 import 'dart:typed_data';
56 // import 'package:image/image.dart' as Img; 57 // import 'package:image/image.dart' as Img;
  58 +import 'package:path/path.dart' as p; // 导入path包
  59 +import 'package:flutter_udid/flutter_udid.dart';
  60 +// import 'package:package_info/package_info.dart';
  61 +import 'package:package_info_plus/package_info_plus.dart';
57 62
58 typedef BookTimeSetCallback = void Function(bool needChange); 63 typedef BookTimeSetCallback = void Function(bool needChange);
59 64
60 class Utils { 65 class Utils {
  66 + static String extractFileNameFromUrl(String url) {
  67 + try {
  68 + Uri uri = Uri.parse(url);
  69 + return p.basename(uri.path); // 使用basename函数提取文件名
  70 + } catch (e) {
  71 + print("Error parsing URL: $e");
  72 + return ""; // 或者返回null或抛出异常,根据你的需求处理错误情况
  73 + }
  74 + }
  75 +
61 static bool isBeforeToday(DateTime dateToCompare) { 76 static bool isBeforeToday(DateTime dateToCompare) {
62 DateTime today = DateTime.now(); 77 DateTime today = DateTime.now();
63 // 只比较年、月、日部分,忽略时间部分 78 // 只比较年、月、日部分,忽略时间部分
@@ -1714,7 +1729,7 @@ class Utils { @@ -1714,7 +1729,7 @@ class Utils {
1714 NavigatorUtil.goWebviewPage(context); 1729 NavigatorUtil.goWebviewPage(context);
1715 } 1730 }
1716 1731
1717 - //获取应用版本昊 1732 + //获取应用版本h号
1718 static getCurrVersion() async { 1733 static getCurrVersion() async {
1719 PackageInfo packageInfo = await PackageInfo.fromPlatform(); 1734 PackageInfo packageInfo = await PackageInfo.fromPlatform();
1720 String version = packageInfo.version; 1735 String version = packageInfo.version;
@@ -1726,16 +1741,27 @@ class Utils { @@ -1726,16 +1741,27 @@ class Utils {
1726 PackageInfo packageInfo = await PackageInfo.fromPlatform(); 1741 PackageInfo packageInfo = await PackageInfo.fromPlatform();
1727 return int.parse(packageInfo.buildNumber); 1742 return int.parse(packageInfo.buildNumber);
1728 } 1743 }
1729 - //获取唯一标识 1744 +
  1745 + //获取唯一标识
1730 static Future<String> getUUID() async { 1746 static Future<String> getUUID() async {
1731 DeviceInfoPlugin deviceInfoPlugin = DeviceInfoPlugin(); 1747 DeviceInfoPlugin deviceInfoPlugin = DeviceInfoPlugin();
1732 if (Platform.isAndroid) { 1748 if (Platform.isAndroid) {
1733 AndroidDeviceInfo androidDeviceInfo = await deviceInfoPlugin.androidInfo; 1749 AndroidDeviceInfo androidDeviceInfo = await deviceInfoPlugin.androidInfo;
1734 return androidDeviceInfo.androidId; 1750 return androidDeviceInfo.androidId;
1735 - } else { 1751 + } else if (Platform.isIOS) {
1736 IosDeviceInfo iosDeviceInfo = await deviceInfoPlugin.iosInfo; 1752 IosDeviceInfo iosDeviceInfo = await deviceInfoPlugin.iosInfo;
1737 return iosDeviceInfo.identifierForVendor; 1753 return iosDeviceInfo.identifierForVendor;
  1754 + } else if (Platform.isOhos) {
  1755 + String udid;
  1756 + try {
  1757 + udid = await FlutterUdid.udid;
  1758 + } on PlatformException {
  1759 + udid = 'Failed to get UDID.';
  1760 + }
  1761 +
  1762 + return udid;
1738 } 1763 }
  1764 + return '';
1739 } 1765 }
1740 1766
1741 //获取唯一标识 1767 //获取唯一标识
@@ -1749,7 +1775,7 @@ class Utils { @@ -1749,7 +1775,7 @@ class Utils {
1749 // IosDeviceInfo iosDeviceInfo = await deviceInfoPlugin.iosInfo; 1775 // IosDeviceInfo iosDeviceInfo = await deviceInfoPlugin.iosInfo;
1750 // return iosDeviceInfo.identifierForVendor; 1776 // return iosDeviceInfo.identifierForVendor;
1751 // } else { 1777 // } else {
1752 - 1778 +
1753 // OhosDeviceInfo ohosDeviceInfo = await deviceInfoPlugin.ohosInfo; 1779 // OhosDeviceInfo ohosDeviceInfo = await deviceInfoPlugin.ohosInfo;
1754 // return ohosDeviceInfo.udid; 1780 // return ohosDeviceInfo.udid;
1755 // } 1781 // }
@@ -1791,7 +1817,7 @@ class Utils { @@ -1791,7 +1817,7 @@ class Utils {
1791 Uint8List? result = list; 1817 Uint8List? result = list;
1792 Uint8List? resultnew; 1818 Uint8List? resultnew;
1793 if (needResize) { 1819 if (needResize) {
1794 - result = (await resizeImage(list)) ?? null; //重置图片尺寸,裁剪5:4尺寸 1820 + result = (await resizeImage(list, context)) ?? null; //重置图片尺寸,裁剪5:4尺寸
1795 if (result == null) { 1821 if (result == null) {
1796 //取消重置尺寸 1822 //取消重置尺寸
1797 Loading.hideLoading(context); 1823 Loading.hideLoading(context);
@@ -1956,7 +1982,8 @@ class Utils { @@ -1956,7 +1982,8 @@ class Utils {
1956 } 1982 }
1957 1983
1958 //裁剪图片,改变图片大小 1984 //裁剪图片,改变图片大小
1959 - static Future<Uint8List?> resizeImage(Uint8List data) async { 1985 + static Future<Uint8List?> resizeImage(
  1986 + Uint8List data, BuildContext context) async {
1960 /** 1987 /**
1961 1988
1962 //image插件改变图片尺寸 copyCrop、copyResize 两个方法 1989 //image插件改变图片尺寸 copyCrop、copyResize 两个方法
@@ -1987,44 +2014,59 @@ class Utils { @@ -1987,44 +2014,59 @@ class Utils {
1987 // Uint8List afterImg = data; 2014 // Uint8List afterImg = data;
1988 Uint8List? afterImg; 2015 Uint8List? afterImg;
1989 if (imgPath != null) { 2016 if (imgPath != null) {
1990 - final croppedImage = await ImageCropper().cropImage(  
1991 - sourcePath: imgPath,  
1992 - //  
1993 - compressQuality: 100,  
1994 - compressFormat: ImageCompressFormat.jpg,  
1995 - //  
1996 - aspectRatio: const CropAspectRatio(ratioX: 5, ratioY: 4),  
1997 - uiSettings: [  
1998 - AndroidUiSettings(  
1999 - // backgroundColor: Colors.red,  
2000 - // toolbarTitle: 'Cropper',  
2001 - // toolbarColor: Colors.deepOrange,  
2002 - // toolbarWidgetColor: Colors.white,  
2003 - // initAspectRatio: CropAspectRatioPreset.ratio5x4,  
2004 - cropStyle: CropStyle.rectangle,  
2005 - aspectRatioPresets: [CropAspectRatioPreset.ratio5x4],  
2006 - hideBottomControls: true,  
2007 - lockAspectRatio: true),  
2008 - IOSUiSettings(  
2009 - // title: 'Cropper',  
2010 - // rotateButtonsHidden: true,  
2011 - // rotateClockwiseButtonHidden: true,  
2012 - cropStyle: CropStyle.rectangle,  
2013 - aspectRatioPresets: [CropAspectRatioPreset.ratio5x4],  
2014 - resetAspectRatioEnabled: false,  
2015 - doneButtonTitle: '确定',  
2016 - cancelButtonTitle: '取消',  
2017 - aspectRatioLockEnabled: true),  
2018 - // WebUiSettings(  
2019 - // context: context,  
2020 - // ),  
2021 - ],  
2022 - );  
2023 - print(croppedImage);  
2024 - if (croppedImage != null) {  
2025 - File yourFile = File(croppedImage.path);  
2026 -  
2027 - afterImg = await yourFile.readAsBytes(); 2017 + if (Platform.isIOS || Platform.isAndroid) {
  2018 + final croppedImage = await ImageCropper().cropImage(
  2019 + sourcePath: imgPath,
  2020 + //
  2021 + compressQuality: 100,
  2022 + compressFormat: ImageCompressFormat.jpg,
  2023 + //
  2024 + aspectRatio: const CropAspectRatio(ratioX: 5, ratioY: 4),
  2025 + uiSettings: [
  2026 + AndroidUiSettings(
  2027 + // backgroundColor: Colors.red,
  2028 + // toolbarTitle: 'Cropper',
  2029 + // toolbarColor: Colors.deepOrange,
  2030 + // toolbarWidgetColor: Colors.white,
  2031 + // initAspectRatio: CropAspectRatioPreset.ratio5x4,
  2032 + cropStyle: CropStyle.rectangle,
  2033 + aspectRatioPresets: [CropAspectRatioPreset.ratio5x4],
  2034 + hideBottomControls: true,
  2035 + lockAspectRatio: true),
  2036 + IOSUiSettings(
  2037 + // title: 'Cropper',
  2038 + // rotateButtonsHidden: true,
  2039 + // rotateClockwiseButtonHidden: true,
  2040 + cropStyle: CropStyle.rectangle,
  2041 + aspectRatioPresets: [CropAspectRatioPreset.ratio5x4],
  2042 + resetAspectRatioEnabled: false,
  2043 + doneButtonTitle: '确定',
  2044 + cancelButtonTitle: '取消',
  2045 + aspectRatioLockEnabled: true),
  2046 + // WebUiSettings(
  2047 + // context: context,
  2048 + // ),
  2049 + ],
  2050 + );
  2051 + print(croppedImage);
  2052 + if (croppedImage != null) {
  2053 + File yourFile = File(croppedImage.path);
  2054 +
  2055 + afterImg = await yourFile.readAsBytes();
  2056 + }
  2057 + } else if (Platform.isOhos) {
  2058 +// 该插件需要构造一个CropWidget组件来实现裁剪功能,该插件使用方式和其他端相比有差异
  2059 + //鸿蒙需要创建一个widget
  2060 +
  2061 + final croppedImage = await CropImageUtils.cropImage(context, imgPath);
  2062 + print(croppedImage);
  2063 + if (croppedImage != null) {
  2064 + File yourFile = File(croppedImage.path);
  2065 +
  2066 + afterImg = await yourFile.readAsBytes();
  2067 + }
  2068 + } else {
  2069 + return null;
2028 } 2070 }
2029 } 2071 }
2030 2072
@@ -3596,7 +3638,8 @@ class Utils { @@ -3596,7 +3638,8 @@ class Utils {
3596 3638
3597 return isSuccess; 3639 return isSuccess;
3598 } 3640 }
3599 - //检查网络连接 3641 +
  3642 + //检查网络连接
3600 static Future<bool> checkConnectiviy() async { 3643 static Future<bool> checkConnectiviy() async {
3601 var connectivityResult = await (new Connectivity().checkConnectivity()); 3644 var connectivityResult = await (new Connectivity().checkConnectivity());
3602 if (connectivityResult == ConnectivityResult.mobile) { 3645 if (connectivityResult == ConnectivityResult.mobile) {
@@ -3605,7 +3648,7 @@ class Utils { @@ -3605,7 +3648,7 @@ class Utils {
3605 } else if (connectivityResult == ConnectivityResult.wifi) { 3648 } else if (connectivityResult == ConnectivityResult.wifi) {
3606 // I am connected to a wifi network. 3649 // I am connected to a wifi network.
3607 return true; 3650 return true;
3608 - }else if(connectivityResult == ConnectivityResult.ethernet){ 3651 + } else if (connectivityResult == ConnectivityResult.ethernet) {
3609 return true; 3652 return true;
3610 } 3653 }
3611 return false; 3654 return false;
@@ -3623,7 +3666,7 @@ class Utils { @@ -3623,7 +3666,7 @@ class Utils {
3623 // return true; 3666 // return true;
3624 // } 3667 // }
3625 // } 3668 // }
3626 - 3669 +
3627 // return false; 3670 // return false;
3628 // } 3671 // }
3629 3672
  1 +# Miscellaneous
  2 +*.class
  3 +*.log
  4 +*.pyc
  5 +*.swp
  6 +.DS_Store
  7 +.atom/
  8 +.buildlog/
  9 +.history
  10 +.svn/
  11 +migrate_working_dir/
  12 +
  13 +# IntelliJ related
  14 +*.iml
  15 +*.ipr
  16 +*.iws
  17 +.idea/
  18 +
  19 +# The .vscode folder contains launch configuration and tasks you configure in
  20 +# VS Code which you may wish to be included in version control, so this line
  21 +# is commented out by default.
  22 +#.vscode/
  23 +
  24 +# Flutter/Dart/Pub related
  25 +# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock.
  26 +/pubspec.lock
  27 +**/doc/api/
  28 +.dart_tool/
  29 +build/
  1 +# This file tracks properties of this Flutter project.
  2 +# Used by Flutter tool to assess capabilities and perform upgrades etc.
  3 +#
  4 +# This file should be version controlled and should not be manually edited.
  5 +
  6 +version:
  7 + revision: "c4a66f77d0e5047ddf5a1bd353fd3ee9cbfeafcd"
  8 + channel: "[user-branch]"
  9 +
  10 +project_type: plugin
  11 +
  12 +# Tracks metadata for the flutter migrate command
  13 +migration:
  14 + platforms:
  15 + - platform: root
  16 + create_revision: c4a66f77d0e5047ddf5a1bd353fd3ee9cbfeafcd
  17 + base_revision: c4a66f77d0e5047ddf5a1bd353fd3ee9cbfeafcd
  18 + - platform: android
  19 + create_revision: c4a66f77d0e5047ddf5a1bd353fd3ee9cbfeafcd
  20 + base_revision: c4a66f77d0e5047ddf5a1bd353fd3ee9cbfeafcd
  21 + - platform: ios
  22 + create_revision: c4a66f77d0e5047ddf5a1bd353fd3ee9cbfeafcd
  23 + base_revision: c4a66f77d0e5047ddf5a1bd353fd3ee9cbfeafcd
  24 + - platform: ohos
  25 + create_revision: c4a66f77d0e5047ddf5a1bd353fd3ee9cbfeafcd
  26 + base_revision: c4a66f77d0e5047ddf5a1bd353fd3ee9cbfeafcd
  27 +
  28 + # User provided section
  29 +
  30 + # List of Local paths (relative to this file) that should be
  31 + # ignored by the migrate tool.
  32 + #
  33 + # Files that are not part of the templates will be ignored by default.
  34 + unmanaged_files:
  35 + - 'lib/main.dart'
  36 + - 'ios/Runner.xcodeproj/project.pbxproj'
  1 +## 0.0.1
  2 +
  3 +* TODO: Describe initial release.
  1 +TODO: Add your license here.
  1 +# file_document_saver
  2 +
  3 +A new Flutter plugin project.
  4 +
  5 +## Getting Started
  6 +
  7 +This project is a starting point for a Flutter
  8 +[plug-in package](https://flutter.dev/developing-packages/),
  9 +a specialized package that includes platform-specific implementation code for
  10 +Android and/or iOS.
  11 +
  12 +For help getting started with Flutter development, view the
  13 +[online documentation](https://flutter.dev/docs), which offers tutorials,
  14 +samples, guidance on mobile development, and a full API reference.
  15 +
  1 +include: package:flutter_lints/flutter.yaml
  2 +
  3 +# Additional information about this file can be found at
  4 +# https://dart.dev/guides/language/analysis-options
  1 +*.iml
  2 +.gradle
  3 +/local.properties
  4 +/.idea/workspace.xml
  5 +/.idea/libraries
  6 +.DS_Store
  7 +/build
  8 +/captures
  9 +.cxx
  1 +group = "com.example.file_document_saver"
  2 +version = "1.0-SNAPSHOT"
  3 +
  4 +buildscript {
  5 + ext.kotlin_version = "1.7.10"
  6 + repositories {
  7 + google()
  8 + mavenCentral()
  9 + }
  10 +
  11 + dependencies {
  12 + classpath("com.android.tools.build:gradle:7.3.0")
  13 + classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version")
  14 + }
  15 +}
  16 +
  17 +allprojects {
  18 + repositories {
  19 + google()
  20 + mavenCentral()
  21 + }
  22 +}
  23 +
  24 +apply plugin: "com.android.library"
  25 +apply plugin: "kotlin-android"
  26 +
  27 +android {
  28 + if (project.android.hasProperty("namespace")) {
  29 + namespace = "com.example.file_document_saver"
  30 + }
  31 +
  32 + compileSdk = 34
  33 +
  34 + compileOptions {
  35 + sourceCompatibility = JavaVersion.VERSION_1_8
  36 + targetCompatibility = JavaVersion.VERSION_1_8
  37 + }
  38 +
  39 + kotlinOptions {
  40 + jvmTarget = "1.8"
  41 + }
  42 +
  43 + sourceSets {
  44 + main.java.srcDirs += "src/main/kotlin"
  45 + test.java.srcDirs += "src/test/kotlin"
  46 + }
  47 +
  48 + defaultConfig {
  49 + minSdk = 21
  50 + }
  51 +
  52 + dependencies {
  53 + testImplementation("org.jetbrains.kotlin:kotlin-test")
  54 + testImplementation("org.mockito:mockito-core:5.0.0")
  55 + }
  56 +
  57 + testOptions {
  58 + unitTests.all {
  59 + useJUnitPlatform()
  60 +
  61 + testLogging {
  62 + events "passed", "skipped", "failed", "standardOut", "standardError"
  63 + outputs.upToDateWhen {false}
  64 + showStandardStreams = true
  65 + }
  66 + }
  67 + }
  68 +}
  1 +rootProject.name = 'file_document_saver'
  1 +<manifest xmlns:android="http://schemas.android.com/apk/res/android"
  2 + package="com.example.file_document_saver">
  3 +</manifest>
  1 +package com.example.file_document_saver
  2 +
  3 +import androidx.annotation.NonNull
  4 +
  5 +import io.flutter.embedding.engine.plugins.FlutterPlugin
  6 +import io.flutter.plugin.common.MethodCall
  7 +import io.flutter.plugin.common.MethodChannel
  8 +import io.flutter.plugin.common.MethodChannel.MethodCallHandler
  9 +import io.flutter.plugin.common.MethodChannel.Result
  10 +
  11 +/** FileDocumentSaverPlugin */
  12 +class FileDocumentSaverPlugin: FlutterPlugin, MethodCallHandler {
  13 + /// The MethodChannel that will the communication between Flutter and native Android
  14 + ///
  15 + /// This local reference serves to register the plugin with the Flutter Engine and unregister it
  16 + /// when the Flutter Engine is detached from the Activity
  17 + private lateinit var channel : MethodChannel
  18 +
  19 + override fun onAttachedToEngine(flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
  20 + channel = MethodChannel(flutterPluginBinding.binaryMessenger, "file_document_saver")
  21 + channel.setMethodCallHandler(this)
  22 + }
  23 +
  24 + override fun onMethodCall(call: MethodCall, result: Result) {
  25 + if (call.method == "getPlatformVersion") {
  26 + result.success("Android ${android.os.Build.VERSION.RELEASE}")
  27 + } else {
  28 + result.notImplemented()
  29 + }
  30 + }
  31 +
  32 + override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) {
  33 + channel.setMethodCallHandler(null)
  34 + }
  35 +}
  1 +package com.example.file_document_saver
  2 +
  3 +import io.flutter.plugin.common.MethodCall
  4 +import io.flutter.plugin.common.MethodChannel
  5 +import kotlin.test.Test
  6 +import org.mockito.Mockito
  7 +
  8 +/*
  9 + * This demonstrates a simple unit test of the Kotlin portion of this plugin's implementation.
  10 + *
  11 + * Once you have built the plugin's example app, you can run these tests from the command
  12 + * line by running `./gradlew testDebugUnitTest` in the `example/android/` directory, or
  13 + * you can run them directly from IDEs that support JUnit such as Android Studio.
  14 + */
  15 +
  16 +internal class FileDocumentSaverPluginTest {
  17 + @Test
  18 + fun onMethodCall_getPlatformVersion_returnsExpectedValue() {
  19 + val plugin = FileDocumentSaverPlugin()
  20 +
  21 + val call = MethodCall("getPlatformVersion", null)
  22 + val mockResult: MethodChannel.Result = Mockito.mock(MethodChannel.Result::class.java)
  23 + plugin.onMethodCall(call, mockResult)
  24 +
  25 + Mockito.verify(mockResult).success("Android " + android.os.Build.VERSION.RELEASE)
  26 + }
  27 +}
  1 +# Miscellaneous
  2 +*.class
  3 +*.log
  4 +*.pyc
  5 +*.swp
  6 +.DS_Store
  7 +.atom/
  8 +.buildlog/
  9 +.history
  10 +.svn/
  11 +migrate_working_dir/
  12 +
  13 +# IntelliJ related
  14 +*.iml
  15 +*.ipr
  16 +*.iws
  17 +.idea/
  18 +
  19 +# The .vscode folder contains launch configuration and tasks you configure in
  20 +# VS Code which you may wish to be included in version control, so this line
  21 +# is commented out by default.
  22 +#.vscode/
  23 +
  24 +# Flutter/Dart/Pub related
  25 +**/doc/api/
  26 +**/ios/Flutter/.last_build_id
  27 +.dart_tool/
  28 +.flutter-plugins
  29 +.flutter-plugins-dependencies
  30 +.pub-cache/
  31 +.pub/
  32 +/build/
  33 +
  34 +# Symbolication related
  35 +app.*.symbols
  36 +
  37 +# Obfuscation related
  38 +app.*.map.json
  39 +
  40 +# Android Studio will place build artifacts here
  41 +/android/app/debug
  42 +/android/app/profile
  43 +/android/app/release
  1 +# file_document_saver_example
  2 +
  3 +Demonstrates how to use the file_document_saver plugin.
  4 +
  5 +## Getting Started
  6 +
  7 +This project is a starting point for a Flutter application.
  8 +
  9 +A few resources to get you started if this is your first Flutter project:
  10 +
  11 +- [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab)
  12 +- [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook)
  13 +
  14 +For help getting started with Flutter development, view the
  15 +[online documentation](https://docs.flutter.dev/), which offers tutorials,
  16 +samples, guidance on mobile development, and a full API reference.
  1 +# This file configures the analyzer, which statically analyzes Dart code to
  2 +# check for errors, warnings, and lints.
  3 +#
  4 +# The issues identified by the analyzer are surfaced in the UI of Dart-enabled
  5 +# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
  6 +# invoked from the command line by running `flutter analyze`.
  7 +
  8 +# The following line activates a set of recommended lints for Flutter apps,
  9 +# packages, and plugins designed to encourage good coding practices.
  10 +include: package:flutter_lints/flutter.yaml
  11 +
  12 +linter:
  13 + # The lint rules applied to this project can be customized in the
  14 + # section below to disable rules from the `package:flutter_lints/flutter.yaml`
  15 + # included above or to enable additional rules. A list of all available lints
  16 + # and their documentation is published at https://dart.dev/lints.
  17 + #
  18 + # Instead of disabling a lint rule for the entire project in the
  19 + # section below, it can also be suppressed for a single line of code
  20 + # or a specific dart file by using the `// ignore: name_of_lint` and
  21 + # `// ignore_for_file: name_of_lint` syntax on the line or in the file
  22 + # producing the lint.
  23 + rules:
  24 + # avoid_print: false # Uncomment to disable the `avoid_print` rule
  25 + # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
  26 +
  27 +# Additional information about this file can be found at
  28 +# https://dart.dev/guides/language/analysis-options
  1 +gradle-wrapper.jar
  2 +/.gradle
  3 +/captures/
  4 +/gradlew
  5 +/gradlew.bat
  6 +/local.properties
  7 +GeneratedPluginRegistrant.java
  8 +
  9 +# Remember to never publicly share your keystore.
  10 +# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app
  11 +key.properties
  12 +**/*.keystore
  13 +**/*.jks
  1 +plugins {
  2 + id "com.android.application"
  3 + id "kotlin-android"
  4 + // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins.
  5 + id "dev.flutter.flutter-gradle-plugin"
  6 +}
  7 +
  8 +def localProperties = new Properties()
  9 +def localPropertiesFile = rootProject.file("local.properties")
  10 +if (localPropertiesFile.exists()) {
  11 + localPropertiesFile.withReader("UTF-8") { reader ->
  12 + localProperties.load(reader)
  13 + }
  14 +}
  15 +
  16 +def flutterVersionCode = localProperties.getProperty("flutter.versionCode")
  17 +if (flutterVersionCode == null) {
  18 + flutterVersionCode = "1"
  19 +}
  20 +
  21 +def flutterVersionName = localProperties.getProperty("flutter.versionName")
  22 +if (flutterVersionName == null) {
  23 + flutterVersionName = "1.0"
  24 +}
  25 +
  26 +android {
  27 + namespace = "com.example.file_document_saver_example"
  28 + compileSdk = flutter.compileSdkVersion
  29 + ndkVersion = flutter.ndkVersion
  30 +
  31 + compileOptions {
  32 + sourceCompatibility = JavaVersion.VERSION_1_8
  33 + targetCompatibility = JavaVersion.VERSION_1_8
  34 + }
  35 +
  36 + defaultConfig {
  37 + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
  38 + applicationId = "com.example.file_document_saver_example"
  39 + // You can update the following values to match your application needs.
  40 + // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
  41 + minSdk = flutter.minSdkVersion
  42 + targetSdk = flutter.targetSdkVersion
  43 + versionCode = flutterVersionCode.toInteger()
  44 + versionName = flutterVersionName
  45 + }
  46 +
  47 + buildTypes {
  48 + release {
  49 + // TODO: Add your own signing config for the release build.
  50 + // Signing with the debug keys for now, so `flutter run --release` works.
  51 + signingConfig = signingConfigs.debug
  52 + }
  53 + }
  54 +}
  55 +
  56 +flutter {
  57 + source = "../.."
  58 +}
  1 +<manifest xmlns:android="http://schemas.android.com/apk/res/android">
  2 + <!-- The INTERNET permission is required for development. Specifically,
  3 + the Flutter tool needs it to communicate with the running application
  4 + to allow setting breakpoints, to provide hot reload, etc.
  5 + -->
  6 + <uses-permission android:name="android.permission.INTERNET"/>
  7 +</manifest>
  1 +<manifest xmlns:android="http://schemas.android.com/apk/res/android">
  2 + <application
  3 + android:label="file_document_saver_example"
  4 + android:name="${applicationName}"
  5 + android:icon="@mipmap/ic_launcher">
  6 + <activity
  7 + android:name=".MainActivity"
  8 + android:exported="true"
  9 + android:launchMode="singleTop"
  10 + android:taskAffinity=""
  11 + android:theme="@style/LaunchTheme"
  12 + android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
  13 + android:hardwareAccelerated="true"
  14 + android:windowSoftInputMode="adjustResize">
  15 + <!-- Specifies an Android theme to apply to this Activity as soon as
  16 + the Android process has started. This theme is visible to the user
  17 + while the Flutter UI initializes. After that, this theme continues
  18 + to determine the Window background behind the Flutter UI. -->
  19 + <meta-data
  20 + android:name="io.flutter.embedding.android.NormalTheme"
  21 + android:resource="@style/NormalTheme"
  22 + />
  23 + <intent-filter>
  24 + <action android:name="android.intent.action.MAIN"/>
  25 + <category android:name="android.intent.category.LAUNCHER"/>
  26 + </intent-filter>
  27 + </activity>
  28 + <!-- Don't delete the meta-data below.
  29 + This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
  30 + <meta-data
  31 + android:name="flutterEmbedding"
  32 + android:value="2" />
  33 + </application>
  34 + <!-- Required to query activities that can process text, see:
  35 + https://developer.android.com/training/package-visibility and
  36 + https://developer.android.com/reference/android/content/Intent#ACTION_PROCESS_TEXT.
  37 +
  38 + In particular, this is used by the Flutter engine in io.flutter.plugin.text.ProcessTextPlugin. -->
  39 + <queries>
  40 + <intent>
  41 + <action android:name="android.intent.action.PROCESS_TEXT"/>
  42 + <data android:mimeType="text/plain"/>
  43 + </intent>
  44 + </queries>
  45 +</manifest>
  1 +package com.example.file_document_saver_example
  2 +
  3 +import io.flutter.embedding.android.FlutterActivity
  4 +
  5 +class MainActivity: FlutterActivity()
  1 +<?xml version="1.0" encoding="utf-8"?>
  2 +<!-- Modify this file to customize your launch splash screen -->
  3 +<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
  4 + <item android:drawable="?android:colorBackground" />
  5 +
  6 + <!-- You can insert your own image assets here -->
  7 + <!-- <item>
  8 + <bitmap
  9 + android:gravity="center"
  10 + android:src="@mipmap/launch_image" />
  11 + </item> -->
  12 +</layer-list>
  1 +<?xml version="1.0" encoding="utf-8"?>
  2 +<!-- Modify this file to customize your launch splash screen -->
  3 +<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
  4 + <item android:drawable="@android:color/white" />
  5 +
  6 + <!-- You can insert your own image assets here -->
  7 + <!-- <item>
  8 + <bitmap
  9 + android:gravity="center"
  10 + android:src="@mipmap/launch_image" />
  11 + </item> -->
  12 +</layer-list>
  1 +<?xml version="1.0" encoding="utf-8"?>
  2 +<resources>
  3 + <!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is on -->
  4 + <style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
  5 + <!-- Show a splash screen on the activity. Automatically removed when
  6 + the Flutter engine draws its first frame -->
  7 + <item name="android:windowBackground">@drawable/launch_background</item>
  8 + </style>
  9 + <!-- Theme applied to the Android Window as soon as the process has started.
  10 + This theme determines the color of the Android Window while your
  11 + Flutter UI initializes, as well as behind your Flutter UI while its
  12 + running.
  13 +
  14 + This Theme is only used starting with V2 of Flutter's Android embedding. -->
  15 + <style name="NormalTheme" parent="@android:style/Theme.Black.NoTitleBar">
  16 + <item name="android:windowBackground">?android:colorBackground</item>
  17 + </style>
  18 +</resources>
  1 +<?xml version="1.0" encoding="utf-8"?>
  2 +<resources>
  3 + <!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is off -->
  4 + <style name="LaunchTheme" parent="@android:style/Theme.Light.NoTitleBar">
  5 + <!-- Show a splash screen on the activity. Automatically removed when
  6 + the Flutter engine draws its first frame -->
  7 + <item name="android:windowBackground">@drawable/launch_background</item>
  8 + </style>
  9 + <!-- Theme applied to the Android Window as soon as the process has started.
  10 + This theme determines the color of the Android Window while your
  11 + Flutter UI initializes, as well as behind your Flutter UI while its
  12 + running.
  13 +
  14 + This Theme is only used starting with V2 of Flutter's Android embedding. -->
  15 + <style name="NormalTheme" parent="@android:style/Theme.Light.NoTitleBar">
  16 + <item name="android:windowBackground">?android:colorBackground</item>
  17 + </style>
  18 +</resources>
  1 +<manifest xmlns:android="http://schemas.android.com/apk/res/android">
  2 + <!-- The INTERNET permission is required for development. Specifically,
  3 + the Flutter tool needs it to communicate with the running application
  4 + to allow setting breakpoints, to provide hot reload, etc.
  5 + -->
  6 + <uses-permission android:name="android.permission.INTERNET"/>
  7 +</manifest>
  1 +allprojects {
  2 + repositories {
  3 + google()
  4 + mavenCentral()
  5 + }
  6 +}
  7 +
  8 +rootProject.buildDir = "../build"
  9 +subprojects {
  10 + project.buildDir = "${rootProject.buildDir}/${project.name}"
  11 +}
  12 +subprojects {
  13 + project.evaluationDependsOn(":app")
  14 +}
  15 +
  16 +tasks.register("clean", Delete) {
  17 + delete rootProject.buildDir
  18 +}
  1 +org.gradle.jvmargs=-Xmx4G -XX:+HeapDumpOnOutOfMemoryError
  2 +android.useAndroidX=true
  3 +android.enableJetifier=true
  1 +distributionBase=GRADLE_USER_HOME
  2 +distributionPath=wrapper/dists
  3 +zipStoreBase=GRADLE_USER_HOME
  4 +zipStorePath=wrapper/dists
  5 +distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.3-all.zip
  1 +pluginManagement {
  2 + def flutterSdkPath = {
  3 + def properties = new Properties()
  4 + file("local.properties").withInputStream { properties.load(it) }
  5 + def flutterSdkPath = properties.getProperty("flutter.sdk")
  6 + assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
  7 + return flutterSdkPath
  8 + }()
  9 +
  10 + includeBuild("$flutterSdkPath/packages/flutter_tools/gradle")
  11 +
  12 + repositories {
  13 + google()
  14 + mavenCentral()
  15 + gradlePluginPortal()
  16 + }
  17 +}
  18 +
  19 +plugins {
  20 + id "dev.flutter.flutter-plugin-loader" version "1.0.0"
  21 + id "com.android.application" version "7.3.0" apply false
  22 + id "org.jetbrains.kotlin.android" version "1.7.10" apply false
  23 +}
  24 +
  25 +include ":app"
  1 +// This is a basic Flutter integration test.
  2 +//
  3 +// Since integration tests run in a full Flutter application, they can interact
  4 +// with the host side of a plugin implementation, unlike Dart unit tests.
  5 +//
  6 +// For more information about Flutter integration tests, please see
  7 +// https://docs.flutter.dev/cookbook/testing/integration/introduction
  8 +
  9 +
  10 +import 'package:flutter_test/flutter_test.dart';
  11 +import 'package:integration_test/integration_test.dart';
  12 +
  13 +import 'package:file_document_saver/file_document_saver.dart';
  14 +
  15 +void main() {
  16 + IntegrationTestWidgetsFlutterBinding.ensureInitialized();
  17 +
  18 + testWidgets('getPlatformVersion test', (WidgetTester tester) async {
  19 + final FileDocumentSaver plugin = FileDocumentSaver();
  20 + final String? version = await plugin.getPlatformVersion();
  21 + // The version string depends on the host platform running the test, so
  22 + // just assert that some non-empty string is returned.
  23 + expect(version?.isNotEmpty, true);
  24 + });
  25 +}
  1 +**/dgph
  2 +*.mode1v3
  3 +*.mode2v3
  4 +*.moved-aside
  5 +*.pbxuser
  6 +*.perspectivev3
  7 +**/*sync/
  8 +.sconsign.dblite
  9 +.tags*
  10 +**/.vagrant/
  11 +**/DerivedData/
  12 +Icon?
  13 +**/Pods/
  14 +**/.symlinks/
  15 +profile
  16 +xcuserdata
  17 +**/.generated/
  18 +Flutter/App.framework
  19 +Flutter/Flutter.framework
  20 +Flutter/Flutter.podspec
  21 +Flutter/Generated.xcconfig
  22 +Flutter/ephemeral/
  23 +Flutter/app.flx
  24 +Flutter/app.zip
  25 +Flutter/flutter_assets/
  26 +Flutter/flutter_export_environment.sh
  27 +ServiceDefinitions.json
  28 +Runner/GeneratedPluginRegistrant.*
  29 +
  30 +# Exceptions to above rules.
  31 +!default.mode1v3
  32 +!default.mode2v3
  33 +!default.pbxuser
  34 +!default.perspectivev3
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
  3 +<plist version="1.0">
  4 +<dict>
  5 + <key>CFBundleDevelopmentRegion</key>
  6 + <string>en</string>
  7 + <key>CFBundleExecutable</key>
  8 + <string>App</string>
  9 + <key>CFBundleIdentifier</key>
  10 + <string>io.flutter.flutter.app</string>
  11 + <key>CFBundleInfoDictionaryVersion</key>
  12 + <string>6.0</string>
  13 + <key>CFBundleName</key>
  14 + <string>App</string>
  15 + <key>CFBundlePackageType</key>
  16 + <string>FMWK</string>
  17 + <key>CFBundleShortVersionString</key>
  18 + <string>1.0</string>
  19 + <key>CFBundleSignature</key>
  20 + <string>????</string>
  21 + <key>CFBundleVersion</key>
  22 + <string>1.0</string>
  23 + <key>MinimumOSVersion</key>
  24 + <string>12.0</string>
  25 +</dict>
  26 +</plist>
  1 +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
  2 +#include "Generated.xcconfig"
  1 +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
  2 +#include "Generated.xcconfig"
  1 +# Uncomment this line to define a global platform for your project
  2 +# platform :ios, '12.0'
  3 +
  4 +# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
  5 +ENV['COCOAPODS_DISABLE_STATS'] = 'true'
  6 +
  7 +project 'Runner', {
  8 + 'Debug' => :debug,
  9 + 'Profile' => :release,
  10 + 'Release' => :release,
  11 +}
  12 +
  13 +def flutter_root
  14 + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__)
  15 + unless File.exist?(generated_xcode_build_settings_path)
  16 + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first"
  17 + end
  18 +
  19 + File.foreach(generated_xcode_build_settings_path) do |line|
  20 + matches = line.match(/FLUTTER_ROOT\=(.*)/)
  21 + return matches[1].strip if matches
  22 + end
  23 + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get"
  24 +end
  25 +
  26 +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
  27 +
  28 +flutter_ios_podfile_setup
  29 +
  30 +target 'Runner' do
  31 + use_frameworks!
  32 + use_modular_headers!
  33 +
  34 + flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
  35 + target 'RunnerTests' do
  36 + inherit! :search_paths
  37 + end
  38 +end
  39 +
  40 +post_install do |installer|
  41 + installer.pods_project.targets.each do |target|
  42 + flutter_additional_ios_build_settings(target)
  43 + end
  44 +end
  1 +// !$*UTF8*$!
  2 +{
  3 + archiveVersion = 1;
  4 + classes = {
  5 + };
  6 + objectVersion = 54;
  7 + objects = {
  8 +
  9 +/* Begin PBXBuildFile section */
  10 + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
  11 + 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; };
  12 + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
  13 + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
  14 + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
  15 + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
  16 + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
  17 +/* End PBXBuildFile section */
  18 +
  19 +/* Begin PBXContainerItemProxy section */
  20 + 331C8085294A63A400263BE5 /* PBXContainerItemProxy */ = {
  21 + isa = PBXContainerItemProxy;
  22 + containerPortal = 97C146E61CF9000F007C117D /* Project object */;
  23 + proxyType = 1;
  24 + remoteGlobalIDString = 97C146ED1CF9000F007C117D;
  25 + remoteInfo = Runner;
  26 + };
  27 +/* End PBXContainerItemProxy section */
  28 +
  29 +/* Begin PBXCopyFilesBuildPhase section */
  30 + 9705A1C41CF9048500538489 /* Embed Frameworks */ = {
  31 + isa = PBXCopyFilesBuildPhase;
  32 + buildActionMask = 2147483647;
  33 + dstPath = "";
  34 + dstSubfolderSpec = 10;
  35 + files = (
  36 + );
  37 + name = "Embed Frameworks";
  38 + runOnlyForDeploymentPostprocessing = 0;
  39 + };
  40 +/* End PBXCopyFilesBuildPhase section */
  41 +
  42 +/* Begin PBXFileReference section */
  43 + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
  44 + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
  45 + 331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = "<group>"; };
  46 + 331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
  47 + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
  48 + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
  49 + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
  50 + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
  51 + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
  52 + 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
  53 + 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
  54 + 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
  55 + 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
  56 + 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
  57 + 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
  58 +/* End PBXFileReference section */
  59 +
  60 +/* Begin PBXFrameworksBuildPhase section */
  61 + 97C146EB1CF9000F007C117D /* Frameworks */ = {
  62 + isa = PBXFrameworksBuildPhase;
  63 + buildActionMask = 2147483647;
  64 + files = (
  65 + );
  66 + runOnlyForDeploymentPostprocessing = 0;
  67 + };
  68 +/* End PBXFrameworksBuildPhase section */
  69 +
  70 +/* Begin PBXGroup section */
  71 + 331C8082294A63A400263BE5 /* RunnerTests */ = {
  72 + isa = PBXGroup;
  73 + children = (
  74 + 331C807B294A618700263BE5 /* RunnerTests.swift */,
  75 + );
  76 + path = RunnerTests;
  77 + sourceTree = "<group>";
  78 + };
  79 + 9740EEB11CF90186004384FC /* Flutter */ = {
  80 + isa = PBXGroup;
  81 + children = (
  82 + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
  83 + 9740EEB21CF90195004384FC /* Debug.xcconfig */,
  84 + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
  85 + 9740EEB31CF90195004384FC /* Generated.xcconfig */,
  86 + );
  87 + name = Flutter;
  88 + sourceTree = "<group>";
  89 + };
  90 + 97C146E51CF9000F007C117D = {
  91 + isa = PBXGroup;
  92 + children = (
  93 + 9740EEB11CF90186004384FC /* Flutter */,
  94 + 97C146F01CF9000F007C117D /* Runner */,
  95 + 97C146EF1CF9000F007C117D /* Products */,
  96 + 331C8082294A63A400263BE5 /* RunnerTests */,
  97 + );
  98 + sourceTree = "<group>";
  99 + };
  100 + 97C146EF1CF9000F007C117D /* Products */ = {
  101 + isa = PBXGroup;
  102 + children = (
  103 + 97C146EE1CF9000F007C117D /* Runner.app */,
  104 + 331C8081294A63A400263BE5 /* RunnerTests.xctest */,
  105 + );
  106 + name = Products;
  107 + sourceTree = "<group>";
  108 + };
  109 + 97C146F01CF9000F007C117D /* Runner */ = {
  110 + isa = PBXGroup;
  111 + children = (
  112 + 97C146FA1CF9000F007C117D /* Main.storyboard */,
  113 + 97C146FD1CF9000F007C117D /* Assets.xcassets */,
  114 + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
  115 + 97C147021CF9000F007C117D /* Info.plist */,
  116 + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */,
  117 + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
  118 + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */,
  119 + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */,
  120 + );
  121 + path = Runner;
  122 + sourceTree = "<group>";
  123 + };
  124 +/* End PBXGroup section */
  125 +
  126 +/* Begin PBXNativeTarget section */
  127 + 331C8080294A63A400263BE5 /* RunnerTests */ = {
  128 + isa = PBXNativeTarget;
  129 + buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */;
  130 + buildPhases = (
  131 + 331C807D294A63A400263BE5 /* Sources */,
  132 + 331C807F294A63A400263BE5 /* Resources */,
  133 + );
  134 + buildRules = (
  135 + );
  136 + dependencies = (
  137 + 331C8086294A63A400263BE5 /* PBXTargetDependency */,
  138 + );
  139 + name = RunnerTests;
  140 + productName = RunnerTests;
  141 + productReference = 331C8081294A63A400263BE5 /* RunnerTests.xctest */;
  142 + productType = "com.apple.product-type.bundle.unit-test";
  143 + };
  144 + 97C146ED1CF9000F007C117D /* Runner */ = {
  145 + isa = PBXNativeTarget;
  146 + buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
  147 + buildPhases = (
  148 + 9740EEB61CF901F6004384FC /* Run Script */,
  149 + 97C146EA1CF9000F007C117D /* Sources */,
  150 + 97C146EB1CF9000F007C117D /* Frameworks */,
  151 + 97C146EC1CF9000F007C117D /* Resources */,
  152 + 9705A1C41CF9048500538489 /* Embed Frameworks */,
  153 + 3B06AD1E1E4923F5004D2608 /* Thin Binary */,
  154 + );
  155 + buildRules = (
  156 + );
  157 + dependencies = (
  158 + );
  159 + name = Runner;
  160 + productName = Runner;
  161 + productReference = 97C146EE1CF9000F007C117D /* Runner.app */;
  162 + productType = "com.apple.product-type.application";
  163 + };
  164 +/* End PBXNativeTarget section */
  165 +
  166 +/* Begin PBXProject section */
  167 + 97C146E61CF9000F007C117D /* Project object */ = {
  168 + isa = PBXProject;
  169 + attributes = {
  170 + BuildIndependentTargetsInParallel = YES;
  171 + LastUpgradeCheck = 1510;
  172 + ORGANIZATIONNAME = "";
  173 + TargetAttributes = {
  174 + 331C8080294A63A400263BE5 = {
  175 + CreatedOnToolsVersion = 14.0;
  176 + TestTargetID = 97C146ED1CF9000F007C117D;
  177 + };
  178 + 97C146ED1CF9000F007C117D = {
  179 + CreatedOnToolsVersion = 7.3.1;
  180 + LastSwiftMigration = 1100;
  181 + };
  182 + };
  183 + };
  184 + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
  185 + compatibilityVersion = "Xcode 9.3";
  186 + developmentRegion = en;
  187 + hasScannedForEncodings = 0;
  188 + knownRegions = (
  189 + en,
  190 + Base,
  191 + );
  192 + mainGroup = 97C146E51CF9000F007C117D;
  193 + productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
  194 + projectDirPath = "";
  195 + projectRoot = "";
  196 + targets = (
  197 + 97C146ED1CF9000F007C117D /* Runner */,
  198 + 331C8080294A63A400263BE5 /* RunnerTests */,
  199 + );
  200 + };
  201 +/* End PBXProject section */
  202 +
  203 +/* Begin PBXResourcesBuildPhase section */
  204 + 331C807F294A63A400263BE5 /* Resources */ = {
  205 + isa = PBXResourcesBuildPhase;
  206 + buildActionMask = 2147483647;
  207 + files = (
  208 + );
  209 + runOnlyForDeploymentPostprocessing = 0;
  210 + };
  211 + 97C146EC1CF9000F007C117D /* Resources */ = {
  212 + isa = PBXResourcesBuildPhase;
  213 + buildActionMask = 2147483647;
  214 + files = (
  215 + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
  216 + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
  217 + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
  218 + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
  219 + );
  220 + runOnlyForDeploymentPostprocessing = 0;
  221 + };
  222 +/* End PBXResourcesBuildPhase section */
  223 +
  224 +/* Begin PBXShellScriptBuildPhase section */
  225 + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
  226 + isa = PBXShellScriptBuildPhase;
  227 + alwaysOutOfDate = 1;
  228 + buildActionMask = 2147483647;
  229 + files = (
  230 + );
  231 + inputPaths = (
  232 + "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}",
  233 + );
  234 + name = "Thin Binary";
  235 + outputPaths = (
  236 + );
  237 + runOnlyForDeploymentPostprocessing = 0;
  238 + shellPath = /bin/sh;
  239 + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
  240 + };
  241 + 9740EEB61CF901F6004384FC /* Run Script */ = {
  242 + isa = PBXShellScriptBuildPhase;
  243 + alwaysOutOfDate = 1;
  244 + buildActionMask = 2147483647;
  245 + files = (
  246 + );
  247 + inputPaths = (
  248 + );
  249 + name = "Run Script";
  250 + outputPaths = (
  251 + );
  252 + runOnlyForDeploymentPostprocessing = 0;
  253 + shellPath = /bin/sh;
  254 + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
  255 + };
  256 +/* End PBXShellScriptBuildPhase section */
  257 +
  258 +/* Begin PBXSourcesBuildPhase section */
  259 + 331C807D294A63A400263BE5 /* Sources */ = {
  260 + isa = PBXSourcesBuildPhase;
  261 + buildActionMask = 2147483647;
  262 + files = (
  263 + 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */,
  264 + );
  265 + runOnlyForDeploymentPostprocessing = 0;
  266 + };
  267 + 97C146EA1CF9000F007C117D /* Sources */ = {
  268 + isa = PBXSourcesBuildPhase;
  269 + buildActionMask = 2147483647;
  270 + files = (
  271 + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */,
  272 + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
  273 + );
  274 + runOnlyForDeploymentPostprocessing = 0;
  275 + };
  276 +/* End PBXSourcesBuildPhase section */
  277 +
  278 +/* Begin PBXTargetDependency section */
  279 + 331C8086294A63A400263BE5 /* PBXTargetDependency */ = {
  280 + isa = PBXTargetDependency;
  281 + target = 97C146ED1CF9000F007C117D /* Runner */;
  282 + targetProxy = 331C8085294A63A400263BE5 /* PBXContainerItemProxy */;
  283 + };
  284 +/* End PBXTargetDependency section */
  285 +
  286 +/* Begin PBXVariantGroup section */
  287 + 97C146FA1CF9000F007C117D /* Main.storyboard */ = {
  288 + isa = PBXVariantGroup;
  289 + children = (
  290 + 97C146FB1CF9000F007C117D /* Base */,
  291 + );
  292 + name = Main.storyboard;
  293 + sourceTree = "<group>";
  294 + };
  295 + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = {
  296 + isa = PBXVariantGroup;
  297 + children = (
  298 + 97C147001CF9000F007C117D /* Base */,
  299 + );
  300 + name = LaunchScreen.storyboard;
  301 + sourceTree = "<group>";
  302 + };
  303 +/* End PBXVariantGroup section */
  304 +
  305 +/* Begin XCBuildConfiguration section */
  306 + 249021D3217E4FDB00AE95B9 /* Profile */ = {
  307 + isa = XCBuildConfiguration;
  308 + buildSettings = {
  309 + ALWAYS_SEARCH_USER_PATHS = NO;
  310 + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
  311 + CLANG_ANALYZER_NONNULL = YES;
  312 + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
  313 + CLANG_CXX_LIBRARY = "libc++";
  314 + CLANG_ENABLE_MODULES = YES;
  315 + CLANG_ENABLE_OBJC_ARC = YES;
  316 + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
  317 + CLANG_WARN_BOOL_CONVERSION = YES;
  318 + CLANG_WARN_COMMA = YES;
  319 + CLANG_WARN_CONSTANT_CONVERSION = YES;
  320 + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
  321 + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
  322 + CLANG_WARN_EMPTY_BODY = YES;
  323 + CLANG_WARN_ENUM_CONVERSION = YES;
  324 + CLANG_WARN_INFINITE_RECURSION = YES;
  325 + CLANG_WARN_INT_CONVERSION = YES;
  326 + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
  327 + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
  328 + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
  329 + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
  330 + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
  331 + CLANG_WARN_STRICT_PROTOTYPES = YES;
  332 + CLANG_WARN_SUSPICIOUS_MOVE = YES;
  333 + CLANG_WARN_UNREACHABLE_CODE = YES;
  334 + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
  335 + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
  336 + COPY_PHASE_STRIP = NO;
  337 + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
  338 + ENABLE_NS_ASSERTIONS = NO;
  339 + ENABLE_STRICT_OBJC_MSGSEND = YES;
  340 + ENABLE_USER_SCRIPT_SANDBOXING = NO;
  341 + GCC_C_LANGUAGE_STANDARD = gnu99;
  342 + GCC_NO_COMMON_BLOCKS = YES;
  343 + GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
  344 + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
  345 + GCC_WARN_UNDECLARED_SELECTOR = YES;
  346 + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
  347 + GCC_WARN_UNUSED_FUNCTION = YES;
  348 + GCC_WARN_UNUSED_VARIABLE = YES;
  349 + IPHONEOS_DEPLOYMENT_TARGET = 12.0;
  350 + MTL_ENABLE_DEBUG_INFO = NO;
  351 + SDKROOT = iphoneos;
  352 + SUPPORTED_PLATFORMS = iphoneos;
  353 + TARGETED_DEVICE_FAMILY = "1,2";
  354 + VALIDATE_PRODUCT = YES;
  355 + };
  356 + name = Profile;
  357 + };
  358 + 249021D4217E4FDB00AE95B9 /* Profile */ = {
  359 + isa = XCBuildConfiguration;
  360 + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
  361 + buildSettings = {
  362 + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
  363 + CLANG_ENABLE_MODULES = YES;
  364 + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
  365 + DEVELOPMENT_TEAM = 8J59HM8B82;
  366 + ENABLE_BITCODE = NO;
  367 + INFOPLIST_FILE = Runner/Info.plist;
  368 + LD_RUNPATH_SEARCH_PATHS = (
  369 + "$(inherited)",
  370 + "@executable_path/Frameworks",
  371 + );
  372 + PRODUCT_BUNDLE_IDENTIFIER = com.example.fileDocumentSaverExample;
  373 + PRODUCT_NAME = "$(TARGET_NAME)";
  374 + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
  375 + SWIFT_VERSION = 5.0;
  376 + VERSIONING_SYSTEM = "apple-generic";
  377 + };
  378 + name = Profile;
  379 + };
  380 + 331C8088294A63A400263BE5 /* Debug */ = {
  381 + isa = XCBuildConfiguration;
  382 + buildSettings = {
  383 + BUNDLE_LOADER = "$(TEST_HOST)";
  384 + CODE_SIGN_STYLE = Automatic;
  385 + CURRENT_PROJECT_VERSION = 1;
  386 + GENERATE_INFOPLIST_FILE = YES;
  387 + MARKETING_VERSION = 1.0;
  388 + PRODUCT_BUNDLE_IDENTIFIER = com.example.fileDocumentSaverExample.RunnerTests;
  389 + PRODUCT_NAME = "$(TARGET_NAME)";
  390 + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
  391 + SWIFT_OPTIMIZATION_LEVEL = "-Onone";
  392 + SWIFT_VERSION = 5.0;
  393 + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
  394 + };
  395 + name = Debug;
  396 + };
  397 + 331C8089294A63A400263BE5 /* Release */ = {
  398 + isa = XCBuildConfiguration;
  399 + buildSettings = {
  400 + BUNDLE_LOADER = "$(TEST_HOST)";
  401 + CODE_SIGN_STYLE = Automatic;
  402 + CURRENT_PROJECT_VERSION = 1;
  403 + GENERATE_INFOPLIST_FILE = YES;
  404 + MARKETING_VERSION = 1.0;
  405 + PRODUCT_BUNDLE_IDENTIFIER = com.example.fileDocumentSaverExample.RunnerTests;
  406 + PRODUCT_NAME = "$(TARGET_NAME)";
  407 + SWIFT_VERSION = 5.0;
  408 + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
  409 + };
  410 + name = Release;
  411 + };
  412 + 331C808A294A63A400263BE5 /* Profile */ = {
  413 + isa = XCBuildConfiguration;
  414 + buildSettings = {
  415 + BUNDLE_LOADER = "$(TEST_HOST)";
  416 + CODE_SIGN_STYLE = Automatic;
  417 + CURRENT_PROJECT_VERSION = 1;
  418 + GENERATE_INFOPLIST_FILE = YES;
  419 + MARKETING_VERSION = 1.0;
  420 + PRODUCT_BUNDLE_IDENTIFIER = com.example.fileDocumentSaverExample.RunnerTests;
  421 + PRODUCT_NAME = "$(TARGET_NAME)";
  422 + SWIFT_VERSION = 5.0;
  423 + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
  424 + };
  425 + name = Profile;
  426 + };
  427 + 97C147031CF9000F007C117D /* Debug */ = {
  428 + isa = XCBuildConfiguration;
  429 + buildSettings = {
  430 + ALWAYS_SEARCH_USER_PATHS = NO;
  431 + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
  432 + CLANG_ANALYZER_NONNULL = YES;
  433 + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
  434 + CLANG_CXX_LIBRARY = "libc++";
  435 + CLANG_ENABLE_MODULES = YES;
  436 + CLANG_ENABLE_OBJC_ARC = YES;
  437 + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
  438 + CLANG_WARN_BOOL_CONVERSION = YES;
  439 + CLANG_WARN_COMMA = YES;
  440 + CLANG_WARN_CONSTANT_CONVERSION = YES;
  441 + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
  442 + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
  443 + CLANG_WARN_EMPTY_BODY = YES;
  444 + CLANG_WARN_ENUM_CONVERSION = YES;
  445 + CLANG_WARN_INFINITE_RECURSION = YES;
  446 + CLANG_WARN_INT_CONVERSION = YES;
  447 + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
  448 + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
  449 + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
  450 + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
  451 + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
  452 + CLANG_WARN_STRICT_PROTOTYPES = YES;
  453 + CLANG_WARN_SUSPICIOUS_MOVE = YES;
  454 + CLANG_WARN_UNREACHABLE_CODE = YES;
  455 + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
  456 + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
  457 + COPY_PHASE_STRIP = NO;
  458 + DEBUG_INFORMATION_FORMAT = dwarf;
  459 + ENABLE_STRICT_OBJC_MSGSEND = YES;
  460 + ENABLE_TESTABILITY = YES;
  461 + ENABLE_USER_SCRIPT_SANDBOXING = NO;
  462 + GCC_C_LANGUAGE_STANDARD = gnu99;
  463 + GCC_DYNAMIC_NO_PIC = NO;
  464 + GCC_NO_COMMON_BLOCKS = YES;
  465 + GCC_OPTIMIZATION_LEVEL = 0;
  466 + GCC_PREPROCESSOR_DEFINITIONS = (
  467 + "DEBUG=1",
  468 + "$(inherited)",
  469 + );
  470 + GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
  471 + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
  472 + GCC_WARN_UNDECLARED_SELECTOR = YES;
  473 + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
  474 + GCC_WARN_UNUSED_FUNCTION = YES;
  475 + GCC_WARN_UNUSED_VARIABLE = YES;
  476 + IPHONEOS_DEPLOYMENT_TARGET = 12.0;
  477 + MTL_ENABLE_DEBUG_INFO = YES;
  478 + ONLY_ACTIVE_ARCH = YES;
  479 + SDKROOT = iphoneos;
  480 + TARGETED_DEVICE_FAMILY = "1,2";
  481 + };
  482 + name = Debug;
  483 + };
  484 + 97C147041CF9000F007C117D /* Release */ = {
  485 + isa = XCBuildConfiguration;
  486 + buildSettings = {
  487 + ALWAYS_SEARCH_USER_PATHS = NO;
  488 + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
  489 + CLANG_ANALYZER_NONNULL = YES;
  490 + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
  491 + CLANG_CXX_LIBRARY = "libc++";
  492 + CLANG_ENABLE_MODULES = YES;
  493 + CLANG_ENABLE_OBJC_ARC = YES;
  494 + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
  495 + CLANG_WARN_BOOL_CONVERSION = YES;
  496 + CLANG_WARN_COMMA = YES;
  497 + CLANG_WARN_CONSTANT_CONVERSION = YES;
  498 + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
  499 + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
  500 + CLANG_WARN_EMPTY_BODY = YES;
  501 + CLANG_WARN_ENUM_CONVERSION = YES;
  502 + CLANG_WARN_INFINITE_RECURSION = YES;
  503 + CLANG_WARN_INT_CONVERSION = YES;
  504 + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
  505 + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
  506 + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
  507 + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
  508 + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
  509 + CLANG_WARN_STRICT_PROTOTYPES = YES;
  510 + CLANG_WARN_SUSPICIOUS_MOVE = YES;
  511 + CLANG_WARN_UNREACHABLE_CODE = YES;
  512 + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
  513 + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
  514 + COPY_PHASE_STRIP = NO;
  515 + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
  516 + ENABLE_NS_ASSERTIONS = NO;
  517 + ENABLE_STRICT_OBJC_MSGSEND = YES;
  518 + ENABLE_USER_SCRIPT_SANDBOXING = NO;
  519 + GCC_C_LANGUAGE_STANDARD = gnu99;
  520 + GCC_NO_COMMON_BLOCKS = YES;
  521 + GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
  522 + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
  523 + GCC_WARN_UNDECLARED_SELECTOR = YES;
  524 + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
  525 + GCC_WARN_UNUSED_FUNCTION = YES;
  526 + GCC_WARN_UNUSED_VARIABLE = YES;
  527 + IPHONEOS_DEPLOYMENT_TARGET = 12.0;
  528 + MTL_ENABLE_DEBUG_INFO = NO;
  529 + SDKROOT = iphoneos;
  530 + SUPPORTED_PLATFORMS = iphoneos;
  531 + SWIFT_COMPILATION_MODE = wholemodule;
  532 + SWIFT_OPTIMIZATION_LEVEL = "-O";
  533 + TARGETED_DEVICE_FAMILY = "1,2";
  534 + VALIDATE_PRODUCT = YES;
  535 + };
  536 + name = Release;
  537 + };
  538 + 97C147061CF9000F007C117D /* Debug */ = {
  539 + isa = XCBuildConfiguration;
  540 + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
  541 + buildSettings = {
  542 + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
  543 + CLANG_ENABLE_MODULES = YES;
  544 + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
  545 + DEVELOPMENT_TEAM = 8J59HM8B82;
  546 + ENABLE_BITCODE = NO;
  547 + INFOPLIST_FILE = Runner/Info.plist;
  548 + LD_RUNPATH_SEARCH_PATHS = (
  549 + "$(inherited)",
  550 + "@executable_path/Frameworks",
  551 + );
  552 + PRODUCT_BUNDLE_IDENTIFIER = com.example.fileDocumentSaverExample;
  553 + PRODUCT_NAME = "$(TARGET_NAME)";
  554 + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
  555 + SWIFT_OPTIMIZATION_LEVEL = "-Onone";
  556 + SWIFT_VERSION = 5.0;
  557 + VERSIONING_SYSTEM = "apple-generic";
  558 + };
  559 + name = Debug;
  560 + };
  561 + 97C147071CF9000F007C117D /* Release */ = {
  562 + isa = XCBuildConfiguration;
  563 + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
  564 + buildSettings = {
  565 + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
  566 + CLANG_ENABLE_MODULES = YES;
  567 + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
  568 + DEVELOPMENT_TEAM = 8J59HM8B82;
  569 + ENABLE_BITCODE = NO;
  570 + INFOPLIST_FILE = Runner/Info.plist;
  571 + LD_RUNPATH_SEARCH_PATHS = (
  572 + "$(inherited)",
  573 + "@executable_path/Frameworks",
  574 + );
  575 + PRODUCT_BUNDLE_IDENTIFIER = com.example.fileDocumentSaverExample;
  576 + PRODUCT_NAME = "$(TARGET_NAME)";
  577 + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
  578 + SWIFT_VERSION = 5.0;
  579 + VERSIONING_SYSTEM = "apple-generic";
  580 + };
  581 + name = Release;
  582 + };
  583 +/* End XCBuildConfiguration section */
  584 +
  585 +/* Begin XCConfigurationList section */
  586 + 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = {
  587 + isa = XCConfigurationList;
  588 + buildConfigurations = (
  589 + 331C8088294A63A400263BE5 /* Debug */,
  590 + 331C8089294A63A400263BE5 /* Release */,
  591 + 331C808A294A63A400263BE5 /* Profile */,
  592 + );
  593 + defaultConfigurationIsVisible = 0;
  594 + defaultConfigurationName = Release;
  595 + };
  596 + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = {
  597 + isa = XCConfigurationList;
  598 + buildConfigurations = (
  599 + 97C147031CF9000F007C117D /* Debug */,
  600 + 97C147041CF9000F007C117D /* Release */,
  601 + 249021D3217E4FDB00AE95B9 /* Profile */,
  602 + );
  603 + defaultConfigurationIsVisible = 0;
  604 + defaultConfigurationName = Release;
  605 + };
  606 + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = {
  607 + isa = XCConfigurationList;
  608 + buildConfigurations = (
  609 + 97C147061CF9000F007C117D /* Debug */,
  610 + 97C147071CF9000F007C117D /* Release */,
  611 + 249021D4217E4FDB00AE95B9 /* Profile */,
  612 + );
  613 + defaultConfigurationIsVisible = 0;
  614 + defaultConfigurationName = Release;
  615 + };
  616 +/* End XCConfigurationList section */
  617 + };
  618 + rootObject = 97C146E61CF9000F007C117D /* Project object */;
  619 +}
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<Workspace
  3 + version = "1.0">
  4 + <FileRef
  5 + location = "self:">
  6 + </FileRef>
  7 +</Workspace>
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
  3 +<plist version="1.0">
  4 +<dict>
  5 + <key>IDEDidComputeMac32BitWarning</key>
  6 + <true/>
  7 +</dict>
  8 +</plist>
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
  3 +<plist version="1.0">
  4 +<dict>
  5 + <key>PreviewsEnabled</key>
  6 + <false/>
  7 +</dict>
  8 +</plist>
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<Scheme
  3 + LastUpgradeVersion = "1510"
  4 + version = "1.3">
  5 + <BuildAction
  6 + parallelizeBuildables = "YES"
  7 + buildImplicitDependencies = "YES">
  8 + <BuildActionEntries>
  9 + <BuildActionEntry
  10 + buildForTesting = "YES"
  11 + buildForRunning = "YES"
  12 + buildForProfiling = "YES"
  13 + buildForArchiving = "YES"
  14 + buildForAnalyzing = "YES">
  15 + <BuildableReference
  16 + BuildableIdentifier = "primary"
  17 + BlueprintIdentifier = "97C146ED1CF9000F007C117D"
  18 + BuildableName = "Runner.app"
  19 + BlueprintName = "Runner"
  20 + ReferencedContainer = "container:Runner.xcodeproj">
  21 + </BuildableReference>
  22 + </BuildActionEntry>
  23 + </BuildActionEntries>
  24 + </BuildAction>
  25 + <TestAction
  26 + buildConfiguration = "Debug"
  27 + selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
  28 + selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
  29 + shouldUseLaunchSchemeArgsEnv = "YES">
  30 + <MacroExpansion>
  31 + <BuildableReference
  32 + BuildableIdentifier = "primary"
  33 + BlueprintIdentifier = "97C146ED1CF9000F007C117D"
  34 + BuildableName = "Runner.app"
  35 + BlueprintName = "Runner"
  36 + ReferencedContainer = "container:Runner.xcodeproj">
  37 + </BuildableReference>
  38 + </MacroExpansion>
  39 + <Testables>
  40 + <TestableReference
  41 + skipped = "NO"
  42 + parallelizable = "YES">
  43 + <BuildableReference
  44 + BuildableIdentifier = "primary"
  45 + BlueprintIdentifier = "331C8080294A63A400263BE5"
  46 + BuildableName = "RunnerTests.xctest"
  47 + BlueprintName = "RunnerTests"
  48 + ReferencedContainer = "container:Runner.xcodeproj">
  49 + </BuildableReference>
  50 + </TestableReference>
  51 + </Testables>
  52 + </TestAction>
  53 + <LaunchAction
  54 + buildConfiguration = "Debug"
  55 + selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
  56 + selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
  57 + launchStyle = "0"
  58 + useCustomWorkingDirectory = "NO"
  59 + ignoresPersistentStateOnLaunch = "NO"
  60 + debugDocumentVersioning = "YES"
  61 + debugServiceExtension = "internal"
  62 + allowLocationSimulation = "YES">
  63 + <BuildableProductRunnable
  64 + runnableDebuggingMode = "0">
  65 + <BuildableReference
  66 + BuildableIdentifier = "primary"
  67 + BlueprintIdentifier = "97C146ED1CF9000F007C117D"
  68 + BuildableName = "Runner.app"
  69 + BlueprintName = "Runner"
  70 + ReferencedContainer = "container:Runner.xcodeproj">
  71 + </BuildableReference>
  72 + </BuildableProductRunnable>
  73 + </LaunchAction>
  74 + <ProfileAction
  75 + buildConfiguration = "Profile"
  76 + shouldUseLaunchSchemeArgsEnv = "YES"
  77 + savedToolIdentifier = ""
  78 + useCustomWorkingDirectory = "NO"
  79 + debugDocumentVersioning = "YES">
  80 + <BuildableProductRunnable
  81 + runnableDebuggingMode = "0">
  82 + <BuildableReference
  83 + BuildableIdentifier = "primary"
  84 + BlueprintIdentifier = "97C146ED1CF9000F007C117D"
  85 + BuildableName = "Runner.app"
  86 + BlueprintName = "Runner"
  87 + ReferencedContainer = "container:Runner.xcodeproj">
  88 + </BuildableReference>
  89 + </BuildableProductRunnable>
  90 + </ProfileAction>
  91 + <AnalyzeAction
  92 + buildConfiguration = "Debug">
  93 + </AnalyzeAction>
  94 + <ArchiveAction
  95 + buildConfiguration = "Release"
  96 + revealArchiveInOrganizer = "YES">
  97 + </ArchiveAction>
  98 +</Scheme>
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<Workspace
  3 + version = "1.0">
  4 + <FileRef
  5 + location = "group:Runner.xcodeproj">
  6 + </FileRef>
  7 +</Workspace>
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
  3 +<plist version="1.0">
  4 +<dict>
  5 + <key>IDEDidComputeMac32BitWarning</key>
  6 + <true/>
  7 +</dict>
  8 +</plist>
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
  3 +<plist version="1.0">
  4 +<dict>
  5 + <key>PreviewsEnabled</key>
  6 + <false/>
  7 +</dict>
  8 +</plist>
  1 +import Flutter
  2 +import UIKit
  3 +
  4 +@UIApplicationMain
  5 +@objc class AppDelegate: FlutterAppDelegate {
  6 + override func application(
  7 + _ application: UIApplication,
  8 + didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
  9 + ) -> Bool {
  10 + GeneratedPluginRegistrant.register(with: self)
  11 + return super.application(application, didFinishLaunchingWithOptions: launchOptions)
  12 + }
  13 +}
  1 +{
  2 + "images" : [
  3 + {
  4 + "size" : "20x20",
  5 + "idiom" : "iphone",
  6 + "filename" : "Icon-App-20x20@2x.png",
  7 + "scale" : "2x"
  8 + },
  9 + {
  10 + "size" : "20x20",
  11 + "idiom" : "iphone",
  12 + "filename" : "Icon-App-20x20@3x.png",
  13 + "scale" : "3x"
  14 + },
  15 + {
  16 + "size" : "29x29",
  17 + "idiom" : "iphone",
  18 + "filename" : "Icon-App-29x29@1x.png",
  19 + "scale" : "1x"
  20 + },
  21 + {
  22 + "size" : "29x29",
  23 + "idiom" : "iphone",
  24 + "filename" : "Icon-App-29x29@2x.png",
  25 + "scale" : "2x"
  26 + },
  27 + {
  28 + "size" : "29x29",
  29 + "idiom" : "iphone",
  30 + "filename" : "Icon-App-29x29@3x.png",
  31 + "scale" : "3x"
  32 + },
  33 + {
  34 + "size" : "40x40",
  35 + "idiom" : "iphone",
  36 + "filename" : "Icon-App-40x40@2x.png",
  37 + "scale" : "2x"
  38 + },
  39 + {
  40 + "size" : "40x40",
  41 + "idiom" : "iphone",
  42 + "filename" : "Icon-App-40x40@3x.png",
  43 + "scale" : "3x"
  44 + },
  45 + {
  46 + "size" : "60x60",
  47 + "idiom" : "iphone",
  48 + "filename" : "Icon-App-60x60@2x.png",
  49 + "scale" : "2x"
  50 + },
  51 + {
  52 + "size" : "60x60",
  53 + "idiom" : "iphone",
  54 + "filename" : "Icon-App-60x60@3x.png",
  55 + "scale" : "3x"
  56 + },
  57 + {
  58 + "size" : "20x20",
  59 + "idiom" : "ipad",
  60 + "filename" : "Icon-App-20x20@1x.png",
  61 + "scale" : "1x"
  62 + },
  63 + {
  64 + "size" : "20x20",
  65 + "idiom" : "ipad",
  66 + "filename" : "Icon-App-20x20@2x.png",
  67 + "scale" : "2x"
  68 + },
  69 + {
  70 + "size" : "29x29",
  71 + "idiom" : "ipad",
  72 + "filename" : "Icon-App-29x29@1x.png",
  73 + "scale" : "1x"
  74 + },
  75 + {
  76 + "size" : "29x29",
  77 + "idiom" : "ipad",
  78 + "filename" : "Icon-App-29x29@2x.png",
  79 + "scale" : "2x"
  80 + },
  81 + {
  82 + "size" : "40x40",
  83 + "idiom" : "ipad",
  84 + "filename" : "Icon-App-40x40@1x.png",
  85 + "scale" : "1x"
  86 + },
  87 + {
  88 + "size" : "40x40",
  89 + "idiom" : "ipad",
  90 + "filename" : "Icon-App-40x40@2x.png",
  91 + "scale" : "2x"
  92 + },
  93 + {
  94 + "size" : "76x76",
  95 + "idiom" : "ipad",
  96 + "filename" : "Icon-App-76x76@1x.png",
  97 + "scale" : "1x"
  98 + },
  99 + {
  100 + "size" : "76x76",
  101 + "idiom" : "ipad",
  102 + "filename" : "Icon-App-76x76@2x.png",
  103 + "scale" : "2x"
  104 + },
  105 + {
  106 + "size" : "83.5x83.5",
  107 + "idiom" : "ipad",
  108 + "filename" : "Icon-App-83.5x83.5@2x.png",
  109 + "scale" : "2x"
  110 + },
  111 + {
  112 + "size" : "1024x1024",
  113 + "idiom" : "ios-marketing",
  114 + "filename" : "Icon-App-1024x1024@1x.png",
  115 + "scale" : "1x"
  116 + }
  117 + ],
  118 + "info" : {
  119 + "version" : 1,
  120 + "author" : "xcode"
  121 + }
  122 +}
  1 +{
  2 + "images" : [
  3 + {
  4 + "idiom" : "universal",
  5 + "filename" : "LaunchImage.png",
  6 + "scale" : "1x"
  7 + },
  8 + {
  9 + "idiom" : "universal",
  10 + "filename" : "LaunchImage@2x.png",
  11 + "scale" : "2x"
  12 + },
  13 + {
  14 + "idiom" : "universal",
  15 + "filename" : "LaunchImage@3x.png",
  16 + "scale" : "3x"
  17 + }
  18 + ],
  19 + "info" : {
  20 + "version" : 1,
  21 + "author" : "xcode"
  22 + }
  23 +}
  1 +# Launch Screen Assets
  2 +
  3 +You can customize the launch screen with your own desired assets by replacing the image files in this directory.
  4 +
  5 +You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images.
  1 +<?xml version="1.0" encoding="UTF-8" standalone="no"?>
  2 +<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="12121" systemVersion="16G29" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
  3 + <dependencies>
  4 + <deployment identifier="iOS"/>
  5 + <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12089"/>
  6 + </dependencies>
  7 + <scenes>
  8 + <!--View Controller-->
  9 + <scene sceneID="EHf-IW-A2E">
  10 + <objects>
  11 + <viewController id="01J-lp-oVM" sceneMemberID="viewController">
  12 + <layoutGuides>
  13 + <viewControllerLayoutGuide type="top" id="Ydg-fD-yQy"/>
  14 + <viewControllerLayoutGuide type="bottom" id="xbc-2k-c8Z"/>
  15 + </layoutGuides>
  16 + <view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
  17 + <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
  18 + <subviews>
  19 + <imageView opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" image="LaunchImage" translatesAutoresizingMaskIntoConstraints="NO" id="YRO-k0-Ey4">
  20 + </imageView>
  21 + </subviews>
  22 + <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
  23 + <constraints>
  24 + <constraint firstItem="YRO-k0-Ey4" firstAttribute="centerX" secondItem="Ze5-6b-2t3" secondAttribute="centerX" id="1a2-6s-vTC"/>
  25 + <constraint firstItem="YRO-k0-Ey4" firstAttribute="centerY" secondItem="Ze5-6b-2t3" secondAttribute="centerY" id="4X2-HB-R7a"/>
  26 + </constraints>
  27 + </view>
  28 + </viewController>
  29 + <placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
  30 + </objects>
  31 + <point key="canvasLocation" x="53" y="375"/>
  32 + </scene>
  33 + </scenes>
  34 + <resources>
  35 + <image name="LaunchImage" width="168" height="185"/>
  36 + </resources>
  37 +</document>
  1 +<?xml version="1.0" encoding="UTF-8" standalone="no"?>
  2 +<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="10117" systemVersion="15F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="BYZ-38-t0r">
  3 + <dependencies>
  4 + <deployment identifier="iOS"/>
  5 + <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10085"/>
  6 + </dependencies>
  7 + <scenes>
  8 + <!--Flutter View Controller-->
  9 + <scene sceneID="tne-QT-ifu">
  10 + <objects>
  11 + <viewController id="BYZ-38-t0r" customClass="FlutterViewController" sceneMemberID="viewController">
  12 + <layoutGuides>
  13 + <viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/>
  14 + <viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
  15 + </layoutGuides>
  16 + <view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
  17 + <rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
  18 + <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
  19 + <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
  20 + </view>
  21 + </viewController>
  22 + <placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
  23 + </objects>
  24 + </scene>
  25 + </scenes>
  26 +</document>
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
  3 +<plist version="1.0">
  4 +<dict>
  5 + <key>CFBundleDevelopmentRegion</key>
  6 + <string>$(DEVELOPMENT_LANGUAGE)</string>
  7 + <key>CFBundleDisplayName</key>
  8 + <string>File Document Saver</string>
  9 + <key>CFBundleExecutable</key>
  10 + <string>$(EXECUTABLE_NAME)</string>
  11 + <key>CFBundleIdentifier</key>
  12 + <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
  13 + <key>CFBundleInfoDictionaryVersion</key>
  14 + <string>6.0</string>
  15 + <key>CFBundleName</key>
  16 + <string>file_document_saver_example</string>
  17 + <key>CFBundlePackageType</key>
  18 + <string>APPL</string>
  19 + <key>CFBundleShortVersionString</key>
  20 + <string>$(FLUTTER_BUILD_NAME)</string>
  21 + <key>CFBundleSignature</key>
  22 + <string>????</string>
  23 + <key>CFBundleVersion</key>
  24 + <string>$(FLUTTER_BUILD_NUMBER)</string>
  25 + <key>LSRequiresIPhoneOS</key>
  26 + <true/>
  27 + <key>UILaunchStoryboardName</key>
  28 + <string>LaunchScreen</string>
  29 + <key>UIMainStoryboardFile</key>
  30 + <string>Main</string>
  31 + <key>UISupportedInterfaceOrientations</key>
  32 + <array>
  33 + <string>UIInterfaceOrientationPortrait</string>
  34 + <string>UIInterfaceOrientationLandscapeLeft</string>
  35 + <string>UIInterfaceOrientationLandscapeRight</string>
  36 + </array>
  37 + <key>UISupportedInterfaceOrientations~ipad</key>
  38 + <array>
  39 + <string>UIInterfaceOrientationPortrait</string>
  40 + <string>UIInterfaceOrientationPortraitUpsideDown</string>
  41 + <string>UIInterfaceOrientationLandscapeLeft</string>
  42 + <string>UIInterfaceOrientationLandscapeRight</string>
  43 + </array>
  44 + <key>CADisableMinimumFrameDurationOnPhone</key>
  45 + <true/>
  46 + <key>UIApplicationSupportsIndirectInputEvents</key>
  47 + <true/>
  48 +</dict>
  49 +</plist>
  1 +import Flutter
  2 +import UIKit
  3 +import XCTest
  4 +
  5 +@testable import file_document_saver
  6 +
  7 +// This demonstrates a simple unit test of the Swift portion of this plugin's implementation.
  8 +//
  9 +// See https://developer.apple.com/documentation/xctest for more information about using XCTest.
  10 +
  11 +class RunnerTests: XCTestCase {
  12 +
  13 + func testGetPlatformVersion() {
  14 + let plugin = FileDocumentSaverPlugin()
  15 +
  16 + let call = FlutterMethodCall(methodName: "getPlatformVersion", arguments: [])
  17 +
  18 + let resultExpectation = expectation(description: "result block must be called.")
  19 + plugin.handle(call) { result in
  20 + XCTAssertEqual(result as! String, "iOS " + UIDevice.current.systemVersion)
  21 + resultExpectation.fulfill()
  22 + }
  23 + waitForExpectations(timeout: 1)
  24 + }
  25 +
  26 +}
  1 +import 'package:flutter/material.dart';
  2 +import 'dart:async';
  3 +
  4 +import 'package:flutter/services.dart';
  5 +import 'package:file_document_saver/file_document_saver.dart';
  6 +
  7 +void main() {
  8 + runApp(const MyApp());
  9 +}
  10 +
  11 +class MyApp extends StatefulWidget {
  12 + const MyApp({super.key});
  13 +
  14 + @override
  15 + State<MyApp> createState() => _MyAppState();
  16 +}
  17 +
  18 +class _MyAppState extends State<MyApp> {
  19 + String _platformVersion = 'Unknown';
  20 + final _fileDocumentSaverPlugin = FileDocumentSaver();
  21 +
  22 + @override
  23 + void initState() {
  24 + super.initState();
  25 + initPlatformState();
  26 + }
  27 +
  28 + // Platform messages are asynchronous, so we initialize in an async method.
  29 + Future<void> initPlatformState() async {
  30 + String platformVersion;
  31 + // Platform messages may fail, so we use a try/catch PlatformException.
  32 + // We also handle the message potentially returning null.
  33 + try {
  34 + platformVersion =
  35 + await _fileDocumentSaverPlugin.getPlatformVersion() ?? 'Unknown platform version';
  36 + } on PlatformException {
  37 + platformVersion = 'Failed to get platform version.';
  38 + }
  39 +
  40 + // If the widget was removed from the tree while the asynchronous platform
  41 + // message was in flight, we want to discard the reply rather than calling
  42 + // setState to update our non-existent appearance.
  43 + if (!mounted) return;
  44 +
  45 + setState(() {
  46 + _platformVersion = platformVersion;
  47 + });
  48 + }
  49 +
  50 + @override
  51 + Widget build(BuildContext context) {
  52 + return MaterialApp(
  53 + home: Scaffold(
  54 + appBar: AppBar(
  55 + title: const Text('Plugin example app'),
  56 + ),
  57 + body: Center(
  58 + child: Text('Running on: $_platformVersion\n'),
  59 + ),
  60 + ),
  61 + );
  62 + }
  63 +}
  1 +/node_modules
  2 +/oh_modules
  3 +/local.properties
  4 +/.idea
  5 +**/build
  6 +/.hvigor
  7 +.cxx
  8 +/.clangd
  9 +/.clang-format
  10 +/.clang-tidy
  11 +**/.test
  12 +**/BuildProfile.ets
  13 +**/oh-package-lock.json5
  14 +/package.json
  15 +/package-lock.json
  16 +
  17 +**/src/main/resources/rawfile/flutter_assets/
  18 +**/libs/**/libapp.so
  19 +**/libs/**/libflutter.so
  20 +**/libs/**/libvmservice_snapshot.so
  1 +{
  2 + "app": {
  3 + "bundleName": "com.example.file_document_saver_example",
  4 + "vendor": "example",
  5 + "versionCode": 1000000,
  6 + "versionName": "1.0.0",
  7 + "icon": "$media:app_icon",
  8 + "label": "$string:app_name"
  9 + }
  10 +}
  1 +{
  2 + "string": [
  3 + {
  4 + "name": "app_name",
  5 + "value": "file_document_saver_example"
  6 + }
  7 + ]
  8 +}
  1 +
  2 +{
  3 + "app": {
  4 + "signingConfigs": [],
  5 + "products": [
  6 + {
  7 + "name": "default",
  8 + "signingConfig": "default",
  9 + "compatibleSdkVersion": "5.1.0(18)",
  10 + "runtimeOS": "HarmonyOS",
  11 + }
  12 + ],
  13 + "buildModeSet": [
  14 + {
  15 + "name": "debug"
  16 + },
  17 + {
  18 + "name": "profile"
  19 + },
  20 + {
  21 + "name": "release"
  22 + }
  23 + ]
  24 + },
  25 + "modules": [
  26 + {
  27 + "name": "entry",
  28 + "srcPath": "./entry",
  29 + "targets": [
  30 + {
  31 + "name": "default",
  32 + "applyToProducts": [
  33 + "default"
  34 + ]
  35 + }
  36 + ]
  37 + }
  38 + ]
  39 +}
  1 +/node_modules
  2 +/oh_modules
  3 +/.preview
  4 +/build
  5 +/.cxx
  6 +/.test
  7 +GeneratedPluginRegistrant.ets
  1 +
  2 +{
  3 + "apiType": 'stageMode',
  4 + "buildOption": {
  5 + },
  6 + "targets": [
  7 + {
  8 + "name": "default",
  9 + "runtimeOS": "HarmonyOS"
  10 + },
  11 + {
  12 + "name": "ohosTest",
  13 + }
  14 + ]
  15 +}
  1 +
  2 +// Script for compiling build behavior. It is built in the build plug-in and cannot be modified currently.
  3 +import { hapTasks } from '@ohos/hvigor-ohos-plugin';
  4 +export default {
  5 + system: hapTasks, /* Built-in plugin of Hvigor. It cannot be modified. */
  6 + plugins: [] /* Custom plugin to extend the functionality of Hvigor. */
  7 +}