From 604aa7d937f0fd7e87ccf7b5f6def8a9f8e7dd9a Mon Sep 17 00:00:00 2001 From: wwyang <137208408@qq.com> Date: Tue, 26 Nov 2024 16:49:40 +0800 Subject: [PATCH] =?UTF-8?q?=E5=9B=BE=E7=89=87=E9=80=89=E6=8B=A9=E5=99=A8?= =?UTF-8?q?=E7=A4=BA=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: wwyang <137208408@qq.com> --- .../assets/images/selected.png | Bin 0 -> 2108 bytes .../assets/images/unselected.png | Bin 0 -> 2030 bytes .../lib/main.dart | 129 +++++++ .../lib/photoPicker.dart | 328 ++++++++++++++++++ .../ohos/.gitignore | 19 + .../ohos/AppScope/app.json5 | 10 + .../resources/base/element/string.json | 8 + .../resources/base/media/app_icon.png | Bin 0 -> 6790 bytes .../ohos/build-profile.json5 | 43 +++ .../ohos/entry/.gitignore | 7 + .../ohos/entry/build-profile.json5 | 29 ++ .../ohos/entry/hvigorfile.ts | 17 + .../ohos/entry/oh-package.json5 | 9 + .../ets/entryability/CameraPermissions.ets | 94 +++++ .../main/ets/entryability/EntryAbility.ets | 27 ++ .../src/main/ets/entryability/FileUtils.ets | 80 +++++ .../ets/entryability/PhotoPickerPlugin.ets | 173 +++++++++ .../ohos/entry/src/main/ets/pages/Index.ets | 38 ++ .../ohos/entry/src/main/module.json5 | 73 ++++ .../main/resources/base/element/color.json | 8 + .../main/resources/base/element/string.json | 20 ++ .../src/main/resources/base/media/icon.png | Bin 0 -> 6790 bytes .../resources/base/profile/main_pages.json | 5 + .../main/resources/en_US/element/string.json | 20 ++ .../main/resources/zh_CN/element/string.json | 16 + .../ohos/hvigor/hvigor-config.json5 | 20 ++ .../ohos/hvigorfile.ts | 21 ++ .../ohos/oh-package.json5 | 33 ++ .../ohos_flutter_photoviewpicker/pubspec.yaml | 90 +++++ 29 files changed, 1317 insertions(+) create mode 100644 ohos/ohos_flutter_photoviewpicker/assets/images/selected.png create mode 100644 ohos/ohos_flutter_photoviewpicker/assets/images/unselected.png create mode 100644 ohos/ohos_flutter_photoviewpicker/lib/main.dart create mode 100644 ohos/ohos_flutter_photoviewpicker/lib/photoPicker.dart create mode 100644 ohos/ohos_flutter_photoviewpicker/ohos/.gitignore create mode 100644 ohos/ohos_flutter_photoviewpicker/ohos/AppScope/app.json5 create mode 100644 ohos/ohos_flutter_photoviewpicker/ohos/AppScope/resources/base/element/string.json create mode 100644 ohos/ohos_flutter_photoviewpicker/ohos/AppScope/resources/base/media/app_icon.png create mode 100644 ohos/ohos_flutter_photoviewpicker/ohos/build-profile.json5 create mode 100644 ohos/ohos_flutter_photoviewpicker/ohos/entry/.gitignore create mode 100644 ohos/ohos_flutter_photoviewpicker/ohos/entry/build-profile.json5 create mode 100644 ohos/ohos_flutter_photoviewpicker/ohos/entry/hvigorfile.ts create mode 100644 ohos/ohos_flutter_photoviewpicker/ohos/entry/oh-package.json5 create mode 100644 ohos/ohos_flutter_photoviewpicker/ohos/entry/src/main/ets/entryability/CameraPermissions.ets create mode 100644 ohos/ohos_flutter_photoviewpicker/ohos/entry/src/main/ets/entryability/EntryAbility.ets create mode 100644 ohos/ohos_flutter_photoviewpicker/ohos/entry/src/main/ets/entryability/FileUtils.ets create mode 100644 ohos/ohos_flutter_photoviewpicker/ohos/entry/src/main/ets/entryability/PhotoPickerPlugin.ets create mode 100644 ohos/ohos_flutter_photoviewpicker/ohos/entry/src/main/ets/pages/Index.ets create mode 100644 ohos/ohos_flutter_photoviewpicker/ohos/entry/src/main/module.json5 create mode 100644 ohos/ohos_flutter_photoviewpicker/ohos/entry/src/main/resources/base/element/color.json create mode 100644 ohos/ohos_flutter_photoviewpicker/ohos/entry/src/main/resources/base/element/string.json create mode 100644 ohos/ohos_flutter_photoviewpicker/ohos/entry/src/main/resources/base/media/icon.png create mode 100644 ohos/ohos_flutter_photoviewpicker/ohos/entry/src/main/resources/base/profile/main_pages.json create mode 100644 ohos/ohos_flutter_photoviewpicker/ohos/entry/src/main/resources/en_US/element/string.json create mode 100644 ohos/ohos_flutter_photoviewpicker/ohos/entry/src/main/resources/zh_CN/element/string.json create mode 100644 ohos/ohos_flutter_photoviewpicker/ohos/hvigor/hvigor-config.json5 create mode 100644 ohos/ohos_flutter_photoviewpicker/ohos/hvigorfile.ts create mode 100644 ohos/ohos_flutter_photoviewpicker/ohos/oh-package.json5 create mode 100644 ohos/ohos_flutter_photoviewpicker/pubspec.yaml diff --git a/ohos/ohos_flutter_photoviewpicker/assets/images/selected.png b/ohos/ohos_flutter_photoviewpicker/assets/images/selected.png new file mode 100644 index 0000000000000000000000000000000000000000..695096e4719c452840b1d1b1e0b2c539653165f1 GIT binary patch literal 2108 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 z z-8;5iF7IIGDP_x6gN%Y01*ubxWCLD)s2}G(c$83%De(90#nfCcQNx93F-1TM2ea&{hLphuV^)- zUzo5TP34stM4Z!rH%IoHLgy*@%8YA$8lF)Q1Sem3a8TP5xtWlHzs2*sP8Yu?k&rr_ za{GWJN`zI~scBxDL&P18dQ;5Sc~AgI0#dX3oCcs-$e$|n4*3=EKeVVieWYYbeEb^rhX literal 0 HcmV?d00001 diff --git a/ohos/ohos_flutter_photoviewpicker/lib/main.dart b/ohos/ohos_flutter_photoviewpicker/lib/main.dart new file mode 100644 index 00000000..7a38a33c --- /dev/null +++ b/ohos/ohos_flutter_photoviewpicker/lib/main.dart @@ -0,0 +1,129 @@ +/* +* Copyright (c) 2023 Hunan OpenValley Digital Industry Development Co., Ltd. +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +import 'dart:io'; + +import 'package:flutter/material.dart'; +import 'package:ohos_flutter_photoviewpicker/photoPicker.dart'; + +void main() { + runApp(const MyApp()); +} + +class MyApp extends StatelessWidget { + const MyApp({super.key}); + + @override + Widget build(BuildContext context) { + return MaterialApp( + title: 'Flutter Demo', + theme: ThemeData( + primarySwatch: Colors.blue, + ), + home: const MyHomePage(title: 'Flutter Demo Home Page'), + ); + } +} + +class MyHomePage extends StatefulWidget { + const MyHomePage({super.key, required this.title}); + + final String title; + + @override + State createState() => _MyHomePageState(); +} + +class _MyHomePageState extends State { + var id; + Future>? _loadPhoto; + final List list = []; + + Future buildThumbnail(path) async { + return Image.file( + File(path), + fit: BoxFit.cover, + filterQuality: FilterQuality.high, + width: 100, + height: 100, + ); + } + + Widget getGridView(BuildContext context, AsyncSnapshot> snapshot) { + if (snapshot.connectionState == ConnectionState.done) { + if (snapshot.hasData) { + final Map combined = snapshot.data!; + combined.forEach((key, value) async { + Widget widget = await buildThumbnail(value); + list.add(widget); + }); + } + } + return Expanded( + child: GridView( + shrinkWrap: true, + gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 4, + childAspectRatio: 1.0, + ), + children: [...list], + ), + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text(widget.title), + ), + body: Center( + child: Column( + children: [ + Column( + children: [ + Padding( + padding: const EdgeInsets.all(10.0), + child: ElevatedButton( + child: const Text('打开图库'), + onPressed: () async { + Navigator.push( + context, + MaterialPageRoute(builder: (context) => const PhotoPickerPage()), + ).then((value) { + setState(() { + list.clear(); + _loadPhoto = new Future(() => value); + Future.delayed(Duration(milliseconds: 100), () { + setState(() {}); + }); + }); + }); + + }, + ), + ), + ], + ), + FutureBuilder>( + future: _loadPhoto, + builder: getGridView, + ), + ], + ), + ), + ); + } +} diff --git a/ohos/ohos_flutter_photoviewpicker/lib/photoPicker.dart b/ohos/ohos_flutter_photoviewpicker/lib/photoPicker.dart new file mode 100644 index 00000000..d3e81f0c --- /dev/null +++ b/ohos/ohos_flutter_photoviewpicker/lib/photoPicker.dart @@ -0,0 +1,328 @@ +/* +* Copyright (c) 2023 Hunan OpenValley Digital Industry Development Co., Ltd. +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +import 'dart:io'; + +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; + +const MethodChannel channel = MethodChannel('ohos.flutter.picker/photoviewpicker'); + +// 获取缩略图 +Future getThumbnail(id) async { + return await channel.invokeMethod( + 'getThumbnail', + {'assetId': id}, + ); +} + +// 获取媒体文件 +Future getFullImage(id) async { + return await channel.invokeMethod( + 'getFullImage', + {'assetId': id}, + ); +} + +// 获取媒体文件 +Future getPhotoType(id) async { + return await channel.invokeMethod( + 'getPhotoType', + {'assetId': id}, + ); +} + +class PhotoPickerPage extends StatelessWidget { + const PhotoPickerPage({super.key}); + + @override + Widget build(BuildContext context) { + return PhotoPicker( + title: 'Photo Picker', + ); + } +} + +class PhotoPicker extends StatefulWidget { + const PhotoPicker({super.key, required this.title}); + + final String title; + + @override + State createState() => _PhotoPickerState(); +} + +class _PhotoPickerState extends State { + Future>? _loadAllPhoto; + List widgetList = []; + List pathList = []; + final List select = []; // 选中的图片id + + bool isFullImage = false; // 是否选择原图 + bool isFullViwe = false; // 是否大图 + String? id; + + @override + void initState() { + super.initState(); + print("initState====>"); + this.getAllImage(); + Future.delayed(Duration(milliseconds: 300), () { + setState(() {}); + }); + } + + void getAllImage() async { + var result = await channel.invokeMethod( + 'getAllImage', + {}, + ); + setState(() { + _loadAllPhoto = new Future(() => result); + }); + } + + Future buildThumbnail(id) async { + var path = await getThumbnail(id); + return ImageView(id, path, (value) { + if (value) { + this.select.add(id); + } else { + this.select.remove(id); + } + print("是否选中:$value"); + }, (id) { + print('放大$id'); + + setState(() { + this.id = id; + isFullViwe = true; + }); + }); + } + + // 返回选中图片路径 + void getResult() async { + var result = new Map(); + for (var i = 0; i < this.select.length; i++) { + var id = this.select.elementAt(i); + var path = this.isFullImage ? await getFullImage(id) : await getThumbnail(id); + result[id] = path; + } + Navigator.pop(context, result); + } + + Widget _buildGridView(BuildContext context, AsyncSnapshot> snapshot) { + if (snapshot.connectionState == ConnectionState.done) { + if (snapshot.hasData) { + try { + final Map combined = snapshot.data!; + combined.forEach((key, value) async { + if(!pathList.contains(value)) { + pathList.add(value); + Widget widget = await buildThumbnail(value); + widgetList.add(widget); + } + }); + }catch(error) { + print("发生错误:$error"); + } + } + } + return Expanded( + child: GridView( + shrinkWrap: true, + gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 4, + childAspectRatio: 1.0, + ), + children: [...widgetList], + ), + ); + } + + @override + Widget build(BuildContext context) { + return isFullViwe + ? LargeView(this.id!, () { + setState(() { + this.isFullViwe = false; + }); + }) + : Scaffold( + appBar: AppBar( + title: Text(widget.title), + centerTitle: true, + ), + body: Center( + child: Column( + children: [ + FutureBuilder>( + future: _loadAllPhoto, + builder: _buildGridView, + ), + Column( + children: [ + Padding( + padding: const EdgeInsets.all(10.0), + child: ElevatedButton( + child: const Text('完成'), + onPressed: () { + this.getResult(); + }, + ), + ), + ], + ), + ], + ), + ), + ); + } +} + +class ImageView extends StatefulWidget { + final String path; + final String id; + final ValueChanged changed; + final ValueChanged onTap; + ImageView(this.id, this.path, this.changed, this.onTap, {super.key}); + + @override + State createState() => _ImageViewState(); +} + +class _ImageViewState extends State { + bool selected = false; + @override + Widget build(BuildContext context) { + return Stack( + children: [ + GestureDetector( + onTap: () { + widget.onTap(widget.id); + }, + child: Image.file( + File(widget.path), + fit: BoxFit.cover, + filterQuality: FilterQuality.high, + width: 100, + height: 100, + ), + ), + Positioned( + right: 10, + top: 10, + child: Container( + // color: Colors.orange, + height: 20, + width: 20, + child: GestureDetector( + onTap: () { + setState(() { + selected = !selected; + widget.changed(selected); + }); + }, + child: selected ? Image.asset('assets/images/selected.png') : Image.asset('assets/images/unselected.png'), + ), + ), + ), + ], + ); + } +} + +class LargeView extends StatefulWidget { + final String id; + final VoidCallback back; + const LargeView(this.id, this.back, {super.key}); + + @override + State createState() => _LargeViewState(); +} + +class _LargeViewState extends State { + num photoType = 1; + String? path; + @override + void initState() { + + getType().then((value) => { + setState(() { + photoType = value; + }) + }); + + getPath().then((value) { + setState(() { + path = value; + }); + }); + print('$path'); + super.initState(); + } + + Future getType() async{ + var a = await getPhotoType(widget.id); + return a; + } + + Future getPath() async { + return await getFullImage(widget.id); + } + + @override + Widget build(BuildContext context) { + return path != null + ? SafeArea( + child: Column(children: [ + Container( + height: 50, + color: Colors.orange, + child: Row( + children: [ + GestureDetector( + child: Icon(Icons.backpack_outlined), + onTap: () { + // widget.onTap(widget.id); + print('点击手势'); + widget.back(); + }) + ], + ), + ), + Expanded( + child: GestureDetector( + onTap: () { + // widget.onTap(widget.id); + print('点击手势'); + }, + child: photoType == 1? Image.file( + File(path!), + fit: BoxFit.contain, + filterQuality: FilterQuality.high, + ):Text('这是视频'), + ), + ), + Container( + height: 50, + color: Colors.orange, + ), + ]), + ) + : Container(); + } +} diff --git a/ohos/ohos_flutter_photoviewpicker/ohos/.gitignore b/ohos/ohos_flutter_photoviewpicker/ohos/.gitignore new file mode 100644 index 00000000..6ca13b31 --- /dev/null +++ b/ohos/ohos_flutter_photoviewpicker/ohos/.gitignore @@ -0,0 +1,19 @@ +/node_modules +/oh_modules +/local.properties +/.idea +**/build +/.hvigor +.cxx +/.clangd +/.clang-format +/.clang-tidy +**/.test +*.har +**/BuildProfile.ets +**/oh-package-lock.json5 + +**/src/main/resources/rawfile/flutter_assets/ +**/libs/arm64-v8a/libapp.so +**/libs/arm64-v8a/libflutter.so +**/libs/arm64-v8a/libvmservice_snapshot.so diff --git a/ohos/ohos_flutter_photoviewpicker/ohos/AppScope/app.json5 b/ohos/ohos_flutter_photoviewpicker/ohos/AppScope/app.json5 new file mode 100644 index 00000000..ccadc892 --- /dev/null +++ b/ohos/ohos_flutter_photoviewpicker/ohos/AppScope/app.json5 @@ -0,0 +1,10 @@ +{ + "app": { + "bundleName": "com.example.ohos_flutter_photoviewpicker", + "vendor": "example", + "versionCode": 1000000, + "versionName": "1.0.0", + "icon": "$media:app_icon", + "label": "$string:app_name" + } +} \ No newline at end of file diff --git a/ohos/ohos_flutter_photoviewpicker/ohos/AppScope/resources/base/element/string.json b/ohos/ohos_flutter_photoviewpicker/ohos/AppScope/resources/base/element/string.json new file mode 100644 index 00000000..3338b2bc --- /dev/null +++ b/ohos/ohos_flutter_photoviewpicker/ohos/AppScope/resources/base/element/string.json @@ -0,0 +1,8 @@ +{ + "string": [ + { + "name": "app_name", + "value": "ohos_flutter_photoviewpicker" + } + ] +} diff --git a/ohos/ohos_flutter_photoviewpicker/ohos/AppScope/resources/base/media/app_icon.png b/ohos/ohos_flutter_photoviewpicker/ohos/AppScope/resources/base/media/app_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..ce307a8827bd75456441ceb57d530e4c8d45d36c GIT binary patch literal 6790 zcmX|G1ymHk)?T_}Vd;>R?p|tHQo6fg38|$UVM!6BLrPFWk?s;$LOP{GmJpBl$qoSA!PUg~PA65-S00{{S`XKG6NkG0RgjEntPrmV+?0|00mu7;+5 zrdpa{2QLqPJ4Y{j7=Mrl{BaxrkdY69+c~(w{Fv-v&aR%aEI&JYSeRTLWm!zbv;?)_ ziZB;fwGbbeL5Q}YLx`J$lp~A09KK8t_z}PZ=4ZzgdeKtgoc+o5EvN9A1K1_<>M?MBqb#!ASf&# zEX?<)!RH(7>1P+j=jqG(58}TVN-$psA6K}atCuI!KTJD&FMmH-78ZejBm)0qc{ESp z|LuG1{QnBUJRg_E=h1#XMWt2%fcoN@l7eAS!Es?Q+;XsRNPhiiE=@AqlLkJzF`O18 zbsbSmKN=aaq8k3NFYZfDWpKmM!coBU0(XnL8R{4=i|wi{!uWYM2je{U{B*K2PVdu&=E zTq*-XsEsJ$u5H4g6DIm2Y!DN`>^v|AqlwuCD;w45K0@eqauiqWf7l&o)+YLHm~|L~ z7$0v5mkobriU!H<@mVJHLlmQqzQ3d6Rh_-|%Yy2li*tHO>_vcnuZ7OR_xkAIuIU&x z-|8Y0wj|6|a6_I(v91y%k_kNw6pnkNdxjqG8!%Vz_d%c_!X+6-;1`GC9_FpjoHev5fEV7RhJ>r=mh-jp$fqbqRJ=obwdgLDVP5+s zy1=_DWG0Y-Jb3t^WXmkr(d9~08k-|#Ly zaNOmT(^9tIb&eb4%CzIT zAm3CUtWSr1t4?h1kk#NBi{U|pJslvME{q|_eS^3En>SOqSxyuN1x;Is@8~m?*>}** znrRFArP!K_52RpX*&JHMR<^lVdm8ypJ}0R(SD(51j;6@ni$6bQ+2XL+R^|NnSp5}(kzvMZ^(@4fD_{QVu$(&K6H|C37TG1Am9Re{<<3gd zh@`>;BqkXMW&p0T6rt|iB$)~CvFe(XC)F9WgAZn*0@t$oZo;!*}r@_`h?KKH&6A@3= zISXoQB+~`op>NP-buiA*^0n{@i{_?MRG)&k)c)k_F+-2Lud!S9pc+i`s74NpBCaGF zXN+pHkubw*msGBTY27BKHv)RRh3;nMg4&$fD_6X9Vt~;_4D+5XPH~#Kn-yjcy!$}1 zigv#FNY>TqMhtIBb@UoF!cE~Q8~;!Pek>SQQwHnHuWKoVBosAiOr}q>!>aE*Krc)V zBUMEcJ5NU0g8}-h6i1zpMY9>m4ne?=U2~`w7K7Q0gB_=p@$5K7p6}thw z-~3dMj?YNX2X$lZ+7ngQ$=s}3mizNN@kE%OtB)?c&i~2L55z8^=yz;xMHLmlY>&Q# zJj?!)M#q_SyfkQh)k?j8IfLtB)ZCp|*vf4_B zos?73yd^h-Ac+;?E4*bpf=o*^3x3-`TVjbY4n6!EN10K6o@fxdyps05Vo3PU)otB} z`3kR+2w7_C#8Z!q`J)p{Vh!+m9-UP!$STp+Hb}}#@#_u^SsUQg<}59< zTvH3%XS4G+6FF^(m6bVF&nSUIXcl;nw{=H$%fgeJ>CgDYiLdpDXr{;-AnG z8dvcrHYVMI&`R6;GWekI@Ir3!uo)oz4^{6q0m^}@f2tM9&=YHNi6-?rh0-{+k@cQm zdp`g#YdQn%MDVg2GR>wZ`n2<0l4)9nx1Wfr&!Dvz=bPwU!h2S?ez6MVc5APE4-xLB zi&W9Q8k2@0w!C53g?iAIQ}~p*3O(@zja6KQ=M3zfW*_6o5SwR-)6VBh~m7{^-=MC-owYH5-u40a}a0liho3QZZ5L{bS_xM1)4}19)zTU$$MY zq3eZML1WC{K%YFd`Be0M-rkO^l?h{kM{$2oK1*A@HVJ57*yhDkUF!2WZ&oA4Y-sK( zCY69%#`mBCi6>6uw(x4gbFaP0+FD*JKJ-q!F1E?vLJ+d35!I5d7@^eU?(CS|C^tmI5?lv@s{{*|1F zFg|OzNpZ0hxljdjaW%45O0MOttRrd(Z?h{HYbB-KFUx&9GfFL3b8NwZ$zNu)WbBD` zYkj$^UB5%3Pj1MDr>S2Ejr9pUcgA!;ZG!@{uAy12)vG=*^9-|dNQBc8&`oxBlU~#y zs!anJX&T?57Jdr^sb>e+V`MVfY>Y0ESg7MG<7W0g&bR-ZYzzZ%2H&Etcp zcd6QeXO1D!5A#zM0lx*GH}`M)2~ZFLE;sP^RSB5wVMNfiZXPd(cmO>j=OSA3`o5r& zna(|^jGXbdN7PK)U8b7^zYtYkkeb%<%F~=OqB~kXMQkq}ii|skh@WSRt>5za;cjP0 zZ~nD%6)wzedqE}BMLt~qKwlvTr33))#uP~xyw#*Eaa|DbMQ_%mG0U8numf8)0DX`r zRoG2bM;#g|p-8gWnwRV5SCW0tLjLO&9Z?K>FImeIxlGUgo0Zk`9Qzhj1eco~7XZy+hXc@YF&ZQ=? zn*^1O56yK^x{y}q`j7}blGCx%dydV!c7)g~tJzmHhV=W~jbWRRR{1<^oDK+1clprm zz$eCy7y9+?{E|YgkW~}}iB#I4XoJ*xr8R?i_Hv$=Cof5bo-Nj~f`-DLebH}&0% zfQj9@WGd4;N~Y?mzQsHJTJq6!Qzl^-vwol(+fMt#Pl=Wh#lI5Vmu@QM0=_r+1wHt` z+8WZ~c2}KQQ+q)~2Ki77QvV&`xb|xVcTms99&cD$Zz4+-^R4kvUBxG8gDk7Y`K*)JZ^2rL(+ZWV~%W(@6 z)0bPArG#BROa_PHs~&WplQ_UIrpd)1N1QGPfv!J(Z9jNT#i%H?CE6|pPZb9hJ1JW4 z^q;ft#!HRNV0YgPojzIYT`8LuET2rUe-J|c!9l4`^*;4WtY@Ew@pL>wkjmMgGfN7 ze}}GtmU0@<_#08~I-Suk=^*9GLW=H4xhsml;vAV{%hy5Eegl@!6qKqbG024%n2HHw zCc@ivW_$@5ZoHP70(7D+(`PvgjW1Pd`wsiuv-aCukMrafwDm)B!xXVy*j2opohhoU zcJz%ADmj>i3`-3-$7nQKBQQuGY;2Qt&+(L~C>vSGFj5{Mlv?T_^dql;{zkpe4R1}R z%XfZyQ}wr*sr>jrKgm*PWLjuVc%6&&`Kbf1SuFpHPN&>W)$GmqC;pIoBC`=4-hPY8 zT*>%I2fP}vGW;R=^!1be?ta2UQd2>alOFFbVl;(SQJ4Jk#)4Z0^wpWEVvY4=vyDk@ zqlModi@iVPMC+{?rm=4(n+<;|lmUO@UKYA>EPTS~AndtK^Wy^%#3<;(dQdk3WaUkRtzSMC9}7x2||CNpF#(3T4C)@ z$~RWs`BNABKX|{cmBt>Q=&gkXl&x!!NK_%5hW0LS)Z4PB>%sV?F-{Wyj#s7W%$F{D zXdK^Fp3wvy+48+GP6F_|^PCRx=ddcTO3sG;B23A49~Qaw31SZ0Rc~`r4qqt%#OGW{ zCA_(LG5^N>yzUn&kAgVmxb=EA8s&tBXC}S1CZ(KoW)(%^JjLTPo^fs`Va;`=YlVPgmB$!yB}<(4ym6OeZ3xAJJ#;)2+B%p3P1Wt+d$eo`vz`T zXfUP2))kBDPoscH;Jc7I3NU<({|@wM$&GaDt`n7WLgIY3IA7A6-_R?z8N3mz|}*i z(zl5ot--Oq@f2-nv{X(ujT2T(k1vY_qh93pK@>H-qc%2Xta)IP0Q%zt%bqYgI`o!wv!0QerB`nCN^1n|@$sVOQ!V0teVG!I z_fD%JvfDeT1cK#-{o6Gv7}& zY0#NWin~kVaf$aufV&;63Hbs|`QVZWpDX6IMk1Hj2G}fiH9e-^6u2zf^FIr^BwD<6zjw63+{yUe8PUFvk8v{sJ=R{d#`O!sz`Q13~< zPT$JS(w=yQfU2`zPCNfSw=&zup@DXc(98afjhv@1w_f!m2Z>rMJ19AB&dB%P#Ls3b z=lK7OILM+SQ&VEd=1GN6o&>YVVtIzoZ%=Z_SdqJN2}E43{bE`>w+A;=y->@^k{oCC z$F*WTY&?34;kfyFV?b*Xb1Pq`Z=%OgwEg)Rz)tx=`f%5#w_INP=x&z5!jI;#;N$ma zhO)+MDm;SxOEVL15; zGq(v2pL3&P1Sl)8P*;G-fd{l1QJsv@e@d8)1PK4w2m*M%V3j-V~L^$i|&C@b?D?9tfwE{B^}Z$k8e5FmQ>v7Xz)sG32g9t}YBt zyR$+*_00RmPx+0mW+vVG4mxd(n$(eQf3-w>JPl2UJpafrPaL5@2j}%{VE-) zBI%6Qpj*dsdH<;g!S!avA~bv^0E+ zfyJbSjPb+j;J52U)<|cIcntQBI2T#>2;tOxu{%D?kML476AErF(qN9hPva5Nkc@BF zC-tLF@3ZFb%Kpj)M<{)x*l|*Ia@ECeXo2E4h2f!aV=cHAhi_E_mfUth(sM4^hJq7B zQsGWqdZUm9S%F`$nQ*_#NcuD`&)Ek%_s{&^78{9Hm ztri&rYLOxgFdG>O@+XHy z9#;|&vBCPXH5Mon^I`jSuR$&~ZWtyB67ujzFSj!51>#C}C17~TffQ{c-!QFQkTQ%! zIR^b1`zHx|*1GU?tbBx23weFLz5H?y_Q%N&t$}k?w+``2A=aotj0;2v$~AL z{scF-cL{wsdrmPvf#a9OHyYLcwQD4Kcm)`LLwMh4WT~p29f7M!iafJSU`IV}QY5Wa z(n44-9oA}?J{a+ah*@31WTs#&J#o1`H98#6IQf;Wv0N_!);f&9g7o-k(lW5rWnDUR zQBFIRG+X=6NnsI@mxnwm;tf5;_Uxg?jZ8m-m0}&6+DA!qam(p$mN5R})yA_7m$q@| zFEd|dpS595rxQr-n#GjI5i-AhnUE>Cr;jpCqSrD~EwK_DqI^7%3#p5)%T_od!t3SOmH9MyXeeGO2(UQL;ax|x?Ncixmeo1=$ z{-);Au{*tfzOG?KQ~K|ak8-HQ?`Pekhe2WM(8s{xv-p>Zmu_6{G!-oE$7$mY`MOJorI=+mMx?H;`pr!;fVYz?5~yXBACruWB`Ph zZM}90_<^OBxIhyZ9BW$`>6JvO;%VFpqVr8|7t3~AmxYak6?`Pp#c;**_SYmi`&z23 z`p6_~ePvH)C6x-G9$hgL=eVALq`-AiamN>!3~Lxw&{H(b{B(7xSRm6<3<{%{yXiH# zos5Rv1L+8fUKJLo%P>4I&$}y void; + +const cameraPermission: Array = + [ + 'ohos.permission.READ_IMAGEVIDEO', + 'ohos.permission.WRITE_IMAGEVIDEO']; + +async function checkAccessToken(permission: Permissions): Promise { + let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager(); + let grantStatus: abilityAccessCtrl.GrantStatus = abilityAccessCtrl.GrantStatus.PERMISSION_DENIED; + + // 获取应用程序的accessTokenID + let tokenId: number = 0; + try { + let bundleInfo: bundleManager.BundleInfo = await bundleManager.getBundleInfoForSelf(bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION); + let appInfo: bundleManager.ApplicationInfo = bundleInfo.appInfo; + tokenId = appInfo.accessTokenId; + } catch (error) { + let err: BusinessError = error as BusinessError; + console.error(`Failed to get bundle info for self. Code is ${err.code}, message is ${err.message}`); + } + + // 校验应用是否被授予权限 + try { + grantStatus = await atManager.checkAccessToken(tokenId, permission); + } catch (error) { + let err: BusinessError = error as BusinessError; + console.error(`Failed to check access token. Code is ${err.code}, message is ${err.message}`); + } + + return grantStatus; +} + +async function checkPermissions(permissions: Array): Promise { + let grantStatus: abilityAccessCtrl.GrantStatus = await checkAccessToken(permissions[0]); + return grantStatus === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED; +} + +export class CameraPermissions { + async requestPermissions( + context: Context, + callback: ResultCallback + ) { + const hasCameraPermission: boolean = await checkPermissions(cameraPermission); + + if (!hasCameraPermission) { + let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager(); + + // requestPermissionsFromUser会判断权限的授权状态来决定是否唤起弹窗 + atManager.requestPermissionsFromUser(context,cameraPermission) + .then((data: PermissionRequestResult) => { + let grantStatus: Array = data.authResults; + let length: number = grantStatus.length; + for (let i = 0; i < length; i++) { + if (grantStatus[i] !== 0) { + // 用户拒绝授权,提示用户必须授权才能访问当前页面的功能,并引导用户到系统设置中打开相应的权限 + callback('errCode', '未授权相机权限'); + return; + } + } + // 用户授权,可以继续访问目标操作 + callback(null, null); + }).catch((err: BusinessError) => { + console.error(`Failed to request permissions from user. Code is ${err.code}, message is ${err.message}`); + callback(String(err.code), err.message); + }) + } else { + // Permissions already exist. Call the callback with success. + callback(null, null); + } + } +} + + + diff --git a/ohos/ohos_flutter_photoviewpicker/ohos/entry/src/main/ets/entryability/EntryAbility.ets b/ohos/ohos_flutter_photoviewpicker/ohos/entry/src/main/ets/entryability/EntryAbility.ets new file mode 100644 index 00000000..17db7b5c --- /dev/null +++ b/ohos/ohos_flutter_photoviewpicker/ohos/entry/src/main/ets/entryability/EntryAbility.ets @@ -0,0 +1,27 @@ +/* +* Copyright (c) 2023 Hunan OpenValley Digital Industry Development Co., Ltd. +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +import { FlutterAbility } from '@ohos/flutter_ohos' +import { GeneratedPluginRegistrant } from '../plugins/GeneratedPluginRegistrant'; +import FlutterEngine from '@ohos/flutter_ohos/src/main/ets/embedding/engine/FlutterEngine'; +import { PhotoPickerPlugin } from './PhotoPickerPlugin'; + +export default class EntryAbility extends FlutterAbility { + configureFlutterEngine(flutterEngine: FlutterEngine) { + super.configureFlutterEngine(flutterEngine) + GeneratedPluginRegistrant.registerWith(flutterEngine) + this.addPlugin(new PhotoPickerPlugin()); + } +} diff --git a/ohos/ohos_flutter_photoviewpicker/ohos/entry/src/main/ets/entryability/FileUtils.ets b/ohos/ohos_flutter_photoviewpicker/ohos/entry/src/main/ets/entryability/FileUtils.ets new file mode 100644 index 00000000..21f05062 --- /dev/null +++ b/ohos/ohos_flutter_photoviewpicker/ohos/entry/src/main/ets/entryability/FileUtils.ets @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2023 Hunan OpenValley Digital Industry Development Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import common from '@ohos.app.ability.common'; +import fs from '@ohos.file.fs'; +import util from '@ohos.util'; +import Log from '@ohos/flutter_ohos/src/main/ets/util/Log'; + +const TAG = "FileUtils"; + +export default class FileUtils { + static getPathFromUri(context: common.Context | null, uri: string, defExtension?: string) { + Log.i(TAG, "getPathFromUri : " + uri); + let inputFile: fs.File; + try { + inputFile = fs.openSync(uri); + } catch (err) { + Log.e(TAG, "open uri file failed err:" + err) + return null; + } + if (inputFile == null) { + return null; + } + const uuid = util.generateRandomUUID(); + if (!context) { + return + } + { + const targetDirectoryPath = context.tempDir + "/" + uuid; + try { + fs.mkdirSync(targetDirectoryPath); + let targetDir = fs.openSync(targetDirectoryPath); + Log.i(TAG, "mkdirSync success targetDirectoryPath:" + targetDirectoryPath + " fd: " + targetDir.fd); + fs.closeSync(targetDir); + } catch (err) { + Log.e(TAG, "mkdirSync failed err:" + err); + return null; + } + + const inputFilePath = uri.substring(uri.lastIndexOf("/") + 1); + const inputFilePathSplits = inputFilePath.split("."); + Log.i(TAG, "getPathFromUri inputFilePath: " + inputFilePath); + const outputFileName = inputFilePathSplits[0]; + let extension: string; + if (inputFilePathSplits.length == 2) { + extension = "." + inputFilePathSplits[1]; + } else { + if (defExtension) { + extension = defExtension; + } else { + extension = ".jpg"; + } + } + const outputFilePath = targetDirectoryPath + "/" + outputFileName + extension; + const outputFile = fs.openSync(outputFilePath, fs.OpenMode.CREATE); + try { + Log.i(TAG, "copyFileSync inputFile fd:" + inputFile.fd + " outputFile fd:" + outputFile.fd); + fs.copyFileSync(inputFile.fd, outputFilePath); + } catch (err) { + Log.e(TAG, "copyFileSync failed err:" + err); + return null; + } finally { + fs.closeSync(inputFile); + fs.closeSync(outputFile); + } + return outputFilePath; + } + } +} \ No newline at end of file diff --git a/ohos/ohos_flutter_photoviewpicker/ohos/entry/src/main/ets/entryability/PhotoPickerPlugin.ets b/ohos/ohos_flutter_photoviewpicker/ohos/entry/src/main/ets/entryability/PhotoPickerPlugin.ets new file mode 100644 index 00000000..124c7e49 --- /dev/null +++ b/ohos/ohos_flutter_photoviewpicker/ohos/entry/src/main/ets/entryability/PhotoPickerPlugin.ets @@ -0,0 +1,173 @@ +/* +* Copyright (c) 2023 Hunan OpenValley Digital Industry Development Co., Ltd. +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +import { MethodCall, MethodCallHandler, MethodChannel, MethodResult } from '@ohos/flutter_ohos'; +import common from '@ohos.app.ability.common'; +import picker from '@ohos.file.picker'; +import { BusinessError } from '@kit.BasicServicesKit'; +import { dataSharePredicates } from '@kit.ArkData'; +import { photoAccessHelper } from '@kit.MediaLibraryKit'; +import fs from '@ohos.file.fs'; +import { fileIo } from '@kit.CoreFileKit'; +import { fileUri } from '@kit.CoreFileKit'; + +import { + FlutterPlugin, + FlutterPluginBinding +} from '@ohos/flutter_ohos/src/main/ets/embedding/engine/plugins/FlutterPlugin'; +import FileUtils from './FileUtils'; +import { CameraPermissions } from './CameraPermissions'; + +import util from '@ohos.util'; +import { ArrayList } from '@kit.ArkTS'; +import { image } from '@kit.ImageKit'; + + +export const randomAssetID = () => util.generateRandomUUID(true); + +export const randomFilename = () => randomAssetID().replace("-", ""); + +export class PhotoPickerPlugin implements FlutterPlugin, MethodCallHandler { + private channel?: MethodChannel; + private context: common.Context = getContext(this); + private photoPicker = new picker.PhotoViewPicker(this.context); + private phAccessHelper = photoAccessHelper.getPhotoAccessHelper(getContext(this)); + private permission = new CameraPermissions(); + private photoMap = new Map(); + private assetPathMap = new Map(); + private thumbnailPathMap = new Map(); + + getUniqueClassName(): string { + return 'CustomPlugin'; + } + + onAttachedToEngine(binding: FlutterPluginBinding): void { + this.channel = new MethodChannel(binding.getBinaryMessenger(), "ohos.flutter.picker/photoviewpicker"); + this.channel.setMethodCallHandler(this); + } + + onAttachedToAbility(): void { + + } + + async getAllObjects(result: MethodResult) { + this.permission.requestPermissions(this.context, (code, des) => { + console.info('getAssets'); + let predicates: dataSharePredicates.DataSharePredicates = new dataSharePredicates.DataSharePredicates(); + let fetchOptions: photoAccessHelper.FetchOptions = { + fetchColumns: [], + predicates: predicates + }; + + this.photoMap.clear(); + this.phAccessHelper.getAssets(fetchOptions, async (err, fetchResult) => { + if (fetchResult !== undefined) { + console.info('fetchResult success'); + + // 查询相册全部图片和视频 + let photoAssetList: Array = await fetchResult.getAllObjects(); + console.info('photoAssetList length: ', photoAssetList.length); + + let assetIds = new Array(); + photoAssetList.forEach((asset: photoAccessHelper.PhotoAsset, index) => { + console.info('PhotoAsset name: ', asset.displayName); + + assetIds.push(asset.displayName); + this.photoMap.set(asset.displayName, asset); + }); + result.success(assetIds); + } else { + result.error('0', 'getAssets failed', null); + } + }); + }) + } + + getThumbnail(assetId: string, result: MethodResult) { + let photoAsset: photoAccessHelper.PhotoAsset = this.photoMap.get(assetId)!; + + // 获取文件的缩略图,返回pixelMap,需要将pixelMap写入文件,返回路径给dart层显示 + photoAsset.getThumbnail(async (err, pixelMap) => { + if (err === undefined) { + const path = this.context.tempDir + '/thumbnail_' + randomFilename(); + const packOpts: image.PackingOption = { format: "image/jpeg", quality: 100 } + let file = fileIo.openSync(path, fileIo.OpenMode.CREATE | fileIo.OpenMode.READ_WRITE); + const imagePacker: image.ImagePacker = image.createImagePacker(); + imagePacker.packToFile(pixelMap, file.fd, packOpts) + .then(() => { + this.thumbnailPathMap.set(assetId, path); + result.success(path); + console.info('saveThumbnail Succeeded in packing the image to file.'); + }).catch((error: BusinessError) => { + console.error(`saveThumbnail Failed to pack the image to file.code ${error.code},message is ${error.message}`); + }) + } else { + result.error('0', err.message, null); + console.error(`getThumbnail fail with error: ${err.code}, ${err.message}`); + } + }); + } + + // 获取原图路径,将相册图片拷贝到应用沙箱,返回沙箱路径 + getFullImage(id: string, result: MethodResult) { + const photoAsset: photoAccessHelper.PhotoAsset = this.photoMap.get(id)!; + const path = FileUtils.getPathFromUri(this.context, photoAsset.uri)!; + this.assetPathMap.set(id, path); + result.success(path); + } + + // 获取媒体文件类型 1-图片 2-视频 + getPhotoType(id:string){ + const photoAsset: photoAccessHelper.PhotoAsset = this.photoMap.get(id)!; + return photoAsset.photoType.valueOf(); + } + + onMethodCall(call: MethodCall, result: MethodResult): void { + + switch (call.method) { + case 'getAllImage': + this.getAllObjects(result); + break; + case 'getThumbnail': { + const id: string = call.argument('assetId'); + const path = this.thumbnailPathMap.get(id); + if (path) { + result.success(path); + } else { + this.getThumbnail(id, result); + } + break; + } + case 'getPhotoType':{ + const id: string = call.argument('assetId'); + result.success(this.getPhotoType(id)); + } + case 'getFullImage': { + const id: string = call.argument('assetId'); + const path = this.assetPathMap.get(id); + if (path) { + result.success(path); + } else { + this.getFullImage(id, result); + } + break; + } + + } + } + + + onDetachedFromEngine(binding: FlutterPluginBinding): void { + } +} \ No newline at end of file diff --git a/ohos/ohos_flutter_photoviewpicker/ohos/entry/src/main/ets/pages/Index.ets b/ohos/ohos_flutter_photoviewpicker/ohos/entry/src/main/ets/pages/Index.ets new file mode 100644 index 00000000..1125f9fd --- /dev/null +++ b/ohos/ohos_flutter_photoviewpicker/ohos/entry/src/main/ets/pages/Index.ets @@ -0,0 +1,38 @@ +/* +* Copyright (c) 2023 Hunan OpenValley Digital Industry Development Co., Ltd. +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +import common from '@ohos.app.ability.common'; +import { FlutterPage } from '@ohos/flutter_ohos' + +let storage = LocalStorage.getShared() +const EVENT_BACK_PRESS = 'EVENT_BACK_PRESS' + +@Entry(storage) +@Component +struct Index { + private context = getContext(this) as common.UIAbilityContext + @LocalStorageLink('viewId') viewId: string = ""; + + build() { + Column() { + FlutterPage({ viewId: this.viewId }) + } + } + + onBackPress(): boolean { + this.context.eventHub.emit(EVENT_BACK_PRESS) + return true + } +} \ No newline at end of file diff --git a/ohos/ohos_flutter_photoviewpicker/ohos/entry/src/main/module.json5 b/ohos/ohos_flutter_photoviewpicker/ohos/entry/src/main/module.json5 new file mode 100644 index 00000000..51b00493 --- /dev/null +++ b/ohos/ohos_flutter_photoviewpicker/ohos/entry/src/main/module.json5 @@ -0,0 +1,73 @@ +/* +* Copyright (c) 2023 Hunan OpenValley Digital Industry Development Co., Ltd. +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +{ + "module": { + "name": "entry", + "type": "entry", + "description": "$string:module_desc", + "mainElement": "EntryAbility", + "deviceTypes": [ + "phone" + ], + "deliveryWithInstall": true, + "installationFree": false, + "pages": "$profile:main_pages", + "abilities": [ + { + "name": "EntryAbility", + "srcEntry": "./ets/entryability/EntryAbility.ets", + "description": "$string:EntryAbility_desc", + "icon": "$media:icon", + "label": "$string:EntryAbility_label", + "startWindowIcon": "$media:icon", + "startWindowBackground": "$color:start_window_background", + "exported": true, + "skills": [ + { + "entities": [ + "entity.system.home" + ], + "actions": [ + "action.system.home" + ] + } + ] + } + ], + "requestPermissions": [ + {"name" : "ohos.permission.INTERNET"}, + { + "name": "ohos.permission.READ_IMAGEVIDEO", + "reason": "$string:reason", + "usedScene": { + "abilities": [ + "FormAbility" + ], + "when": "inuse" + } + }, + { + "name": "ohos.permission.WRITE_IMAGEVIDEO", + "reason": "$string:reason", + "usedScene": { + "abilities": [ + "FormAbility" + ], + "when": "inuse" + } + } + ] + } +} \ No newline at end of file diff --git a/ohos/ohos_flutter_photoviewpicker/ohos/entry/src/main/resources/base/element/color.json b/ohos/ohos_flutter_photoviewpicker/ohos/entry/src/main/resources/base/element/color.json new file mode 100644 index 00000000..3c712962 --- /dev/null +++ b/ohos/ohos_flutter_photoviewpicker/ohos/entry/src/main/resources/base/element/color.json @@ -0,0 +1,8 @@ +{ + "color": [ + { + "name": "start_window_background", + "value": "#FFFFFF" + } + ] +} \ No newline at end of file diff --git a/ohos/ohos_flutter_photoviewpicker/ohos/entry/src/main/resources/base/element/string.json b/ohos/ohos_flutter_photoviewpicker/ohos/entry/src/main/resources/base/element/string.json new file mode 100644 index 00000000..2f65997a --- /dev/null +++ b/ohos/ohos_flutter_photoviewpicker/ohos/entry/src/main/resources/base/element/string.json @@ -0,0 +1,20 @@ +{ + "string": [ + { + "name": "module_desc", + "value": "module description" + }, + { + "name": "EntryAbility_desc", + "value": "description" + }, + { + "name": "EntryAbility_label", + "value": "ohos_flutter_photoviewpicker" + }, + { + "name": "reason", + "value": "reason" + } + ] +} \ No newline at end of file diff --git a/ohos/ohos_flutter_photoviewpicker/ohos/entry/src/main/resources/base/media/icon.png b/ohos/ohos_flutter_photoviewpicker/ohos/entry/src/main/resources/base/media/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..ce307a8827bd75456441ceb57d530e4c8d45d36c GIT binary patch literal 6790 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.19.6 <3.0.0' + +# Dependencies specify other packages that your package needs in order to work. +# To automatically upgrade your package dependencies to the latest versions +# consider running `flutter pub upgrade --major-versions`. Alternatively, +# dependencies can be manually updated by changing the version numbers below to +# the latest version available on pub.dev. To see which dependencies have newer +# versions available, run `flutter pub outdated`. +dependencies: + flutter: + sdk: flutter + + + # The following adds the Cupertino Icons font to your application. + # Use with the CupertinoIcons class for iOS style icons. + cupertino_icons: ^1.0.2 + +dev_dependencies: + flutter_test: + sdk: flutter + + # The "flutter_lints" package below contains a set of recommended lints to + # encourage good coding practices. The lint set provided by the package is + # activated in the `analysis_options.yaml` file located at the root of your + # package. See that file for information about deactivating specific lint + # rules and activating additional ones. + flutter_lints: ^2.0.0 + +# For information on the generic Dart part of this file, see the +# following page: https://dart.dev/tools/pub/pubspec + +# The following section is specific to Flutter packages. +flutter: + + # The following line ensures that the Material Icons font is + # included with your application, so that you can use the icons in + # the material Icons class. + uses-material-design: true + + # To add assets to your application, add an assets section, like this: + assets: + - assets/images/ + # - images/a_dot_ham.jpeg + + # An image asset can refer to one or more resolution-specific "variants", see + # https://flutter.dev/assets-and-images/#resolution-aware + + # For details regarding adding assets from package dependencies, see + # https://flutter.dev/assets-and-images/#from-packages + + # To add custom fonts to your application, add a fonts section here, + # in this "flutter" section. Each entry in this list should have a + # "family" key with the font family name, and a "fonts" key with a + # list giving the asset and other descriptors for the font. For + # example: + # fonts: + # - family: Schyler + # fonts: + # - asset: fonts/Schyler-Regular.ttf + # - asset: fonts/Schyler-Italic.ttf + # style: italic + # - family: Trajan Pro + # fonts: + # - asset: fonts/TrajanPro.ttf + # - asset: fonts/TrajanPro_Bold.ttf + # weight: 700 + # + # For details regarding fonts from package dependencies, + # see https://flutter.dev/custom-fonts/#from-packages -- Gitee