|
| 1 | +import { showActionSheet } from '@tarojs/taro-h5' |
| 2 | + |
| 3 | +import native from '../../../NativeApi' |
| 4 | +import { shouldBeObject } from '../../../utils' |
| 5 | +import { MethodHandler } from '../../../utils/handler' |
| 6 | + |
| 7 | +namespace chooseMedium { |
| 8 | + export interface Option { |
| 9 | + /** 最多可以选择的文件个数 |
| 10 | + * @default 9 |
| 11 | + * @supported harmny-hybrid |
| 12 | + */ |
| 13 | + count?: number |
| 14 | + /** 文件类型 |
| 15 | + * @default ['image', 'video'] |
| 16 | + * @supported harmny-hybrid |
| 17 | + */ |
| 18 | + mediaType?: Array<keyof mediaType> |
| 19 | + /** 图片和视频选择的来源 |
| 20 | + * @default ['album', 'camera'] |
| 21 | + * @supported harmny-hybrid |
| 22 | + */ |
| 23 | + sourceType?: Array<keyof sourceType> |
| 24 | + /** 拍摄视频最长拍摄时间,单位秒。时间范围为 3s 至 60s 之间 |
| 25 | + * @default 10 |
| 26 | + * @supported harmny-hybrid |
| 27 | + */ |
| 28 | + maxDuration?: number |
| 29 | + /** 仅在 sourceType 为 camera 时生效,是否压缩文件 |
| 30 | + * @default ['original', 'compressed'] |
| 31 | + * @supported harmny-hybrid |
| 32 | + */ |
| 33 | + sizeType?: Array<'original' | 'compressed'> |
| 34 | + /** 仅在 sourceType 为 camera 时生效,使用前置或后置摄像头 |
| 35 | + * @default "back" |
| 36 | + * @supported harmny-hybrid |
| 37 | + */ |
| 38 | + camera?: string |
| 39 | + /** 仅在 sourceType 为 album 时生效,相册中是否允许拍照 |
| 40 | + * @default "false" |
| 41 | + * @supported harmny-hybrid |
| 42 | + */ |
| 43 | + takingSupported?: boolean |
| 44 | + /** 仅在 sourceType 为 album 时生效,相册中是否允许编辑照片 |
| 45 | + * @default "false" |
| 46 | + * @supported harmny-hybrid |
| 47 | + */ |
| 48 | + editSupported?: boolean |
| 49 | + /** 仅在 sourceType 为 album 时生效,相册中是否允许搜索 |
| 50 | + * @default "false" |
| 51 | + * @supported harmny-hybrid |
| 52 | + */ |
| 53 | + searchSupported?: boolean |
| 54 | + /** 接口调用结束的回调函数(调用成功、失败都会执行) */ |
| 55 | + complete?: (res: TaroGeneral.CallbackResult) => void |
| 56 | + /** 接口调用失败的回调函数 */ |
| 57 | + fail?: (res: TaroGeneral.CallbackResult) => void |
| 58 | + /** 接口调用成功的回调函数 */ |
| 59 | + success?: (result: SuccessCallbackResult) => void |
| 60 | + /** 用来上传的input元素ID |
| 61 | + * @supported harmny-hybrid |
| 62 | + */ |
| 63 | + mediaId?: string |
| 64 | + } |
| 65 | + export interface SuccessCallbackResult extends TaroGeneral.CallbackResult { |
| 66 | + /** 本地临时文件列表 */ |
| 67 | + tempFiles: ChooseMedium[] |
| 68 | + /** 文件类型,有效值有 image 、video、mix */ |
| 69 | + type: string |
| 70 | + } |
| 71 | + |
| 72 | + /** 本地临时文件列表 */ |
| 73 | + export interface ChooseMedium { |
| 74 | + /** 本地临时文件路径 (本地路径) */ |
| 75 | + tempFilePath: string |
| 76 | + /** 本地临时文件大小,单位 B */ |
| 77 | + size: number |
| 78 | + /** 视频的时间长度 */ |
| 79 | + duration: number |
| 80 | + /** 视频的高度 */ |
| 81 | + height: number |
| 82 | + /** 视频的宽度 */ |
| 83 | + width: number |
| 84 | + /** 视频缩略图临时文件路径 */ |
| 85 | + thumbTempFilePath: string |
| 86 | + /** 选择的文件的类型 */ |
| 87 | + fileType: string |
| 88 | + } |
| 89 | + export interface mediaType { |
| 90 | + /** 只能拍摄视频或从相册选择视频 */ |
| 91 | + video |
| 92 | + /** 只能拍摄图片或从相册选择图片 */ |
| 93 | + image |
| 94 | + /** 可同时选择图片和视频 */ |
| 95 | + mix |
| 96 | + } |
| 97 | + export interface sourceType { |
| 98 | + /** 从相册选择 */ |
| 99 | + album |
| 100 | + /** 使用相机拍摄 */ |
| 101 | + camera |
| 102 | + } |
| 103 | + export interface camera { |
| 104 | + /** 使用后置摄像头 */ |
| 105 | + back |
| 106 | + /** 使用前置摄像头 */ |
| 107 | + front |
| 108 | + } |
| 109 | +} |
| 110 | + |
| 111 | + |
| 112 | +interface harmony { |
| 113 | + /** 拍摄或从手机相册中选择图片或视频。 |
| 114 | + * @supported harmony_hybrid |
| 115 | + * @example |
| 116 | + * ```tsx |
| 117 | + * Taro.chooseMedium({ |
| 118 | + * count: 9, |
| 119 | + * mediaType: ['image','video'], |
| 120 | + * sourceType: ['album', 'camera'], |
| 121 | + * maxDuration: 30, |
| 122 | + * camera: 'back', |
| 123 | + * takingSupported: false, |
| 124 | + * editSupported: false, |
| 125 | + * searchSupported: false, |
| 126 | + * success: (res) => { |
| 127 | + * console.log(res.tempFiles) |
| 128 | + * console.log(res.type) |
| 129 | + * } |
| 130 | + * }) |
| 131 | + * ``` |
| 132 | + */ |
| 133 | + chooseMedium (option: chooseMedium.Option): Promise<chooseMedium.SuccessCallbackResult> |
| 134 | +} |
| 135 | +/** |
| 136 | + * 拍摄或从手机相册中选择图片或视频 |
| 137 | + * |
| 138 | + * @canUse chooseMedium |
| 139 | + * @__object [count, mediaType[video, image, mix], sourceType[album, camera], maxDuration, sizeType, camera[back, front],takingSupported,editSupported,searchSupported] |
| 140 | + * @__success [tempFiles, type] |
| 141 | + */ |
| 142 | +export const chooseMedium: harmony['chooseMedium'] = async (options) => { |
| 143 | + const name = 'chooseMedium' |
| 144 | + |
| 145 | + // options must be an Object |
| 146 | + const isValid = shouldBeObject(options).flag || typeof options === 'undefined' |
| 147 | + if (!isValid) { |
| 148 | + const res = { errMsg: `${name}:fail invalid params` } |
| 149 | + console.error(res.errMsg) |
| 150 | + return Promise.reject(res) |
| 151 | + } |
| 152 | + |
| 153 | + const { |
| 154 | + count = 9, |
| 155 | + mediaType = ['video', 'image'], |
| 156 | + sourceType = ['album', 'camera'], |
| 157 | + maxDuration = 10, |
| 158 | + sizeType = ['original', 'compressed'], |
| 159 | + camera = 'back', |
| 160 | + takingSupported = false, |
| 161 | + editSupported = false, |
| 162 | + searchSupported = false, |
| 163 | + success, |
| 164 | + fail, |
| 165 | + } = options as Exclude<typeof options, undefined> |
| 166 | + |
| 167 | + const handle = new MethodHandler<{ |
| 168 | + tempFiles?: chooseMedium.ChooseMedium[] |
| 169 | + type?: string |
| 170 | + errMsg?: string |
| 171 | + }>({ name, success, fail }) |
| 172 | + |
| 173 | + let sourceSelected |
| 174 | + if (sourceType.length === 1) { |
| 175 | + sourceSelected = sourceType[0] |
| 176 | + } else if (typeof sourceType !== 'object' || (sourceType.includes('album') && sourceType.includes('camera'))) { |
| 177 | + const selected = await showActionSheet({ itemList: ['拍摄', '从相册选择'] }).then( |
| 178 | + (res) => { |
| 179 | + sourceSelected = res.tapIndex === 0 ? 'camera' : 'album' |
| 180 | + return true |
| 181 | + }, |
| 182 | + () => { |
| 183 | + return false |
| 184 | + } |
| 185 | + ) |
| 186 | + if (!selected) { |
| 187 | + return handle.fail({ errMsg: 'fail cancel' }) |
| 188 | + } |
| 189 | + } |
| 190 | + |
| 191 | + return new Promise<chooseMedium.SuccessCallbackResult>((resolve, reject) => { |
| 192 | + native.chooseMediumAssets({ |
| 193 | + count: count, |
| 194 | + mediaType: mediaType, |
| 195 | + sourceType: sourceSelected, |
| 196 | + maxDuration: maxDuration, |
| 197 | + sizeType: sizeType, |
| 198 | + camera: camera, |
| 199 | + takingSupported: takingSupported, |
| 200 | + editSupported: editSupported, |
| 201 | + searchSupported: searchSupported, |
| 202 | + apiName: name, |
| 203 | + success: (res: any) => { |
| 204 | + const result: chooseMedium.SuccessCallbackResult = { |
| 205 | + tempFiles: res.tempFiles, |
| 206 | + type: res.type, |
| 207 | + errMsg: res.errMsg, |
| 208 | + } |
| 209 | + handle.success(result, { resolve, reject }) |
| 210 | + }, |
| 211 | + fail: (err: any) => { |
| 212 | + handle.fail(err, { resolve, reject }) |
| 213 | + }, |
| 214 | + }) |
| 215 | + }) |
| 216 | +} |
0 commit comments