Home

Awesome

<!-- Copyright 2019 The FlutterCandies author. All rights reserved. Use of this source code is governed by an Apache license that can be found in the LICENSE file. -->

Flutter WeChat Assets Picker

pub package pub package CodeFactor

Build status GitHub license GitHub stars GitHub forks

Awesome Flutter Flutter Candies QQ群

Language: English | 中文

An image picker (also with videos and audios) for Flutter projects based on the WeChat's UI.

Current WeChat version that UI based on: 8.3.x UI designs will be updated following the WeChat update in anytime.

To take a photo or a video for assets, please check the detailed usage in the example, and head over to wechat_camera_picker. The package is a standalone extension that can to be used with combination.

See the Migration Guide to learn how to migrate between breaking changes.

Versions compatibility

The package only guarantees to be working on the stable version of Flutter. We won't update it in real-time to align with other channels of Flutter.

3.03.33.73.103.133.16
8.9.0+
8.7.0+
8.5.0+
8.4.0+
8.0.0+
7.3.0+

If you got a resolve conflict error when running flutter pub get, please use dependency_overrides to fix it.

Package credits

The package is built from these wonderful packages.

NameFeatures
photo_managerThe basic abstractions and management for assets.
extended_imagePreview assets with expected behaviors.
providerHelps to manage the interaction state of the picker.
video_playerPlays videos and audios correspondingly.

Their implementation should be relatively stable in the package. If you've found any issues related to them when using the picker, submit issues to our issue tracker first.

<details> <summary>Table of content</summary> <!-- TOC --> <!-- TOC --> </details>

Features ✨

Notes 📝

  1. HEIF (HEIC) images are support to obtain and conversion, but the display with them are based on Flutter's image decoder. See flutter/flutter#20522. Use entity.file or AssetEntityImage for them when displays.
  2. Due to limitations on iOS and macOS, audio can only be fetched within the sandbox.

Projects using this plugin 🖼️

namepubgithub
insta_assets_pickerpub packagestar

Screenshots 📸

123
456
789
101012

READ THIS FIRST ‼️

Be aware of below notices before you started anything:

When you have questions about related APIs and behaviors, check photo_manager's API docs for more details.

Most usages are detailed covered by the example. Please walk through the example carefully before you have any questions.

Preparing for use 🍭

Flutter

Run flutter pub add wechat_assets_picker, or add wechat_assets_picker to pubspec.yaml dependencies manually.

dependencies:
  wechat_assets_picker: ^latest_version

The latest stable version is: pub package

The latest dev version is: pub package

Then import the package in your code:

import 'package:wechat_assets_picker/wechat_assets_picker.dart';

Android

When using the package, please upgrade targetSdkVersion and compileSdkVersion to 33. Otherwise, no assets can be fetched on Android 13.

Permissions

NameRequiredDeclaredMax API LevelOthers
READ_EXTERNAL_STORAGEYESYES32
WRITE_EXTERNAL_STORAGENONO29
ACCESS_MEDIA_LOCATIONYES*NON/ARequired when reading EXIF
READ_MEDIA_IMAGESYES*YESN/ARequired when reading images
READ_MEDIA_VIDEOYES*YESN/ARequired when reading videos
READ_MEDIA_AUDIOYES*YESN/ARequired when reading audios

If you're targeting Android SDK 33+, and you don't need to load photos, videos or audios, consider declare only relevant permission in your apps, more specifically:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.your.app">
    <!--Requesting access to images and videos.-->
    <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
    <uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
    <!--When your app has no need to access audio, remove it or comment it out.-->
    <!--<uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />-->
</manifest>

iOS

  1. Platform version has to be at least 11.0. Modify ios/Podfile and update accordingly.
    platform :ios, '11.0'
    
    Remove the # heading if the line starts with it.
  2. Add the following content to Info.plist.
<key>NSPhotoLibraryUsageDescription</key>
<string>Replace with your permission description.</string>

macOS

  1. Platform version has to be at least 10.15. Modify macos/Podfile and update accordingly.
    platform :osx, '10.15'
    
    Remove the # heading if the line starts with it.
  2. Set the minimum deployment target of the macOS to 10.15. Use XCode to open macos/Runner.xcworkspace .
  3. Follow the iOS instructions and modify Info.plist accordingly.

Usage 📖

Localizations

When you're picking assets, the package will obtain the Locale? from your BuildContext, and return the corresponding text delegate of the current language. Make sure you have a valid Locale in your widget tree that can be accessed from the BuildContext. Otherwise, the default Chinese delegate will be used.

Embedded text delegates languages are:

If you want to use a custom/fixed text delegate, pass it through the AssetPickerConfig.textDelegate.

Simple usage

final List<AssetEntity>? result = await AssetPicker.pickAssets(context);

Use AssetPickerConfig for more picking behaviors.

final List<AssetEntity>? result = await AssetPicker.pickAssets(
  context,
  pickerConfig: const AssetPickerConfig(),
);

Fields in AssetPickerConfig:

NameTypeDescriptionDefault
selectedAssetsList<AssetEntity>?Selected assets. Prevent duplicate selection.null
maxAssetsintMaximum asset that the picker can pick.9
pageSizeint?Number of assets per page. Must be a multiple of gridCount.80
gridThumbnailSizeThumbnailSizeThumbnail size for the grid's item.ThumbnailSize.square(200)
pathThumbnailSizeThumbnailSizeThumbnail size for the path selector.ThumbnailSize.square(80)
previewThumbnailSizeThumbnailSize?Preview thumbnail size in the viewer.null
requestTypeRequestTypeRequest type for picker.RequestType.common
specialPickerTypeSpecialPickerType?Provides the option to integrate a custom picker type.null
keepScrollOffsetboolWhether the picker should save the scroll offset between pushes and pops.null
sortPathDelegateSortPathDelegate<AssetPathEntity>?Path entities sort delegate for the picker, sort paths as you want.CommonSortPathDelegate
sortPathsByModifiedDateboolWhether to allow sort delegates to sort paths with FilterOptionGroup.containsPathModified.false
filterOptionsPMFilter?Allow users to customize assets filter options.null
gridCountintGrid count in picker.4
themeColorColor?Main theme color for the picker.Color(0xff00bc56)
pickerThemeThemeData?Theme data provider for the picker and the viewer.null
textDelegateAssetPickerTextDelegate?Text delegate for the picker, for customize the texts.AssetPickerTextDelegate()
specialItemPositionSpecialItemPositionAllow users set a special item in the picker with several positions.SpecialItemPosition.none
specialItemBuilderSpecialItemBuilder?The widget builder for the special item.null
loadingIndicatorBuilderIndicatorBuilder?Indicates the loading status for the builder.null
selectPredicateAssetSelectPredicatePredicate whether an asset can be selected or unselected.null
shouldRevertGridbool?Whether the assets grid should revert.null
limitedPermissionOverlayPredicateLimitedPermissionOverlayPredicate?Predicate whether the limited permission overlay should be displayed.null
pathNameBuilderPathNameBuilder<AssetPathEntity>?Build customized path (album) name with the given path entity.null
assetsChangeCallbackAssetsChangeCallback<AssetPathEntity>?The callback that will be called when the system notifies assets changes.null
assetsChangeRefreshPredicateAssetsChangeRefreshPredicate<AssetPathEntity>?Whether assets changing should call refresh with the given call and the current selected path.null
shouldAutoPlayPreviewboolWhether the preview should auto play.false

Detailed usage

We've put multiple common usage with the packages in the example. You can both found List<PickMethod> pickMethods in here and here, which provide methods in multiple picking and single picking mode. Assets will be stored temporary and displayed at the below of the page.

Display selected assets

The AssetEntityImage and AssetEntityImageProvider can display the thumb image of images & videos, and the original data of image. Use it like a common Image and ImageProvider.

AssetEntityImage(asset, isOriginal: false);

Or:

Image(image: AssetEntityImageProvider(asset, isOriginal: false));

Register assets change observe callback

// Register callback.
AssetPicker.registerObserve();

// Unregister callback.
AssetPicker.unregisterObserve();

Upload an AssetEntity with a form data

There are multiple ways to upload an AssetEntity with I/O related methods. Be aware, I/O related methods will consume performance (typically time and memory), they should not be called frequently.

With http

http package: https://pub.dev/packages/http

The http package uses MultipartFile to handle files in requests.

Pseudo code:

import 'package:http/http.dart' as http;

Future<void> upload() async {
  final entity = await obtainYourEntity();
  final uri = Uri.https('example.com', 'create');
  final request = http.MultipartRequest('POST', uri)
    ..fields['test_field'] = 'test_value'
    ..files.add(await multipartFileFromAssetEntity(entity));
  final response = await request.send();
  if (response.statusCode == 200) {
    print('Uploaded!');
  }
}

Future<http.MultipartFile> multipartFileFromAssetEntity(AssetEntity entity) async {
  http.MultipartFile mf;
  // Using the file path.
  final file = await entity.file;
  if (file == null) {
    throw StateError('Unable to obtain file of the entity ${entity.id}.');
  }
  mf = await http.MultipartFile.fromPath('test_file', file.path);
  // Using the bytes.
  final bytes = await entity.originBytes;
  if (bytes == null) {
    throw StateError('Unable to obtain bytes of the entity ${entity.id}.');
  }
  mf = http.MultipartFile.fromBytes('test_file', bytes);
  return mf;
}
With dio

dio package: https://pub.dev/packages/dio

The dio package also uses MultipartFile to handle files in requests.

Pseudo code:

import 'package:dio/dio.dart' as dio;

Future<void> upload() async {
  final entity = await obtainYourEntity();
  final uri = Uri.https('example.com', 'create');
  final response = dio.Dio().requestUri(
    uri,
    data: dio.FormData.fromMap({
      'test_field': 'test_value',
      'test_file': await multipartFileFromAssetEntity(entity),
    }),
  );
  print('Uploaded!');
}

Future<dio.MultipartFile> multipartFileFromAssetEntity(AssetEntity entity) async {
  dio.MultipartFile mf;
  // Using the file path.
  final file = await entity.file;
  if (file == null) {
    throw StateError('Unable to obtain file of the entity ${entity.id}.');
  }
  mf = await dio.MultipartFile.fromFile(file.path);
  // Using the bytes.
  final bytes = await entity.originBytes;
  if (bytes == null) {
    throw StateError('Unable to obtain bytes of the entity ${entity.id}.');
  }
  mf = dio.MultipartFile.fromBytes(bytes);
  return mf;
}

Custom pickers

AssetPickerBuilderDelegate, AssetPickerViewerBuilderDelegate, AssetPickerProvider and AssetPickerViewerProvider are all exposed and overridable. You can extend them and use your own type with generic type <A: Asset, P: Path>, then implement abstract methods.

To know about how to fully customize themes, widgets or layouts. See how to customize delegates in the custom pickers page in the example.

You can submit PRs to create your own implementation if you found your implementation might be useful for others. See Contribute custom implementations for more details.

Frequently asked question ❔

Changing the default album name (Recent to others)

Recent is the fix album name for the ALL assets on Android since the all assets' album is not an actual album, it only represents all media data records.

To solve that on Android, use pathNameBuilder, for example:

AssetPickerConfig(
  pathNameBuilder: (AssetPathEntity path) => switch (path) {
    final p when p.isAll => '最近',
    // You can apply similar conditions to other common paths.
    _ => path.name,
  },
)

Other albums or albums on other platforms (iOS/macOS) will follow the configured system localization and supported localizations. pathNameBuilder is available for all albums.

Execution failed for task ':photo_manager:compileDebugKotlin'

See photo_manager#561 for more details.

Create AssetEntity from File or Uint8List (rawData)

In order to combine this package with camera shooting or something related, there's a solution about how to create an AssetEntity with File or Uint8List object.

final File file = your_file; // Your `File` object
final String path = file.path;
final AssetEntity fileEntity = await PhotoManager.editor.saveImageWithPath(
  path,
  title: basename(path),
); // Saved in the device then create an AssetEntity

final Uint8List data = your_data; // Your `Uint8List` object
final AssetEntity imageEntity = await PhotoManager.editor.saveImage(
  file.path,
  title: 'title_with_extension.jpg',
); // Saved in the device then create an AssetEntity

Notice: If you don't want to keep the file in your device, use File for operations as much as possible. Deleting an AssetEntity might cause system popups show:

final List<String> result = await PhotoManager.editor.deleteWithIds(
  <String>[entity.id],
);

See photo_manager#from-raw-data and photo_manager#delete-entities for more details.

Glide warning 'Failed to find GeneratedAppGlideModule'

W/Glide   (21133): Failed to find GeneratedAppGlideModule. 
                   You should include an annotationProcessor compile dependency on com.github.bumptech.glide:compiler
                   in you application ana a @GlideModule annotated AppGlideModule implementation
                   or LibraryGlideModules will be silently ignored.

Glide needs annotation to keep singleton, prevent conflict between instances and versions, so while the photo manager uses Glide to implement image features, the project which import this should define its own AppGlideModule. See Glide Generated API docs for implementation.

Contributors ✨

Many thanks to these wonderful people (emoji key):

<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section --> <!-- prettier-ignore-start --> <!-- markdownlint-disable --> <table> <tbody> <tr> <td align="center" valign="top" width="14.28%"><a href="https://blog.alexv525.com"><img src="https://avatars1.githubusercontent.com/u/15884415?v=4?s=50" width="50px;" alt="Alex Li"/><br /><sub><b>Alex Li</b></sub></a><br /><a href="https://github.com/fluttercandies/flutter_wechat_assets_picker/commits?author=AlexV525" title="Code">💻</a> <a href="#design-AlexV525" title="Design">🎨</a> <a href="https://github.com/fluttercandies/flutter_wechat_assets_picker/commits?author=AlexV525" title="Documentation">📖</a> <a href="#example-AlexV525" title="Examples">💡</a> <a href="#ideas-AlexV525" title="Ideas, Planning, & Feedback">🤔</a> <a href="#maintenance-AlexV525" title="Maintenance">🚧</a> <a href="#question-AlexV525" title="Answering Questions">💬</a> <a href="https://github.com/fluttercandies/flutter_wechat_assets_picker/pulls?q=is%3Apr+reviewed-by%3AAlexV525" title="Reviewed Pull Requests">👀</a> <a href="#a11y-AlexV525" title="Accessibility">️️️️♿️</a> <a href="#translation-AlexV525" title="Translation">🌍</a></td> <td align="center" valign="top" width="14.28%"><a href="https://www.kikt.top"><img src="https://avatars0.githubusercontent.com/u/14145407?v=4?s=50" width="50px;" alt="Caijinglong"/><br /><sub><b>Caijinglong</b></sub></a><br /><a href="#example-CaiJingLong" title="Examples">💡</a> <a href="#ideas-CaiJingLong" title="Ideas, Planning, & Feedback">🤔</a></td> <td align="center" valign="top" width="14.28%"><a href="https://github.com/SchnMar"><img src="https://avatars3.githubusercontent.com/u/12902321?v=4?s=50" width="50px;" alt="Marcel Schneider"/><br /><sub><b>Marcel Schneider</b></sub></a><br /><a href="https://github.com/fluttercandies/flutter_wechat_assets_picker/issues?q=author%3ASchnMar" title="Bug reports">🐛</a> <a href="https://github.com/fluttercandies/flutter_wechat_assets_picker/commits?author=SchnMar" title="Code">💻</a> <a href="#ideas-SchnMar" title="Ideas, Planning, & Feedback">🤔</a></td> <td align="center" valign="top" width="14.28%"><a href="https://github.com/ganlanshu0211"><img src="https://avatars0.githubusercontent.com/u/9670379?v=4?s=50" width="50px;" alt="ganlanshu0211"/><br /><sub><b>ganlanshu0211</b></sub></a><br /><a href="https://github.com/fluttercandies/flutter_wechat_assets_picker/issues?q=author%3Aganlanshu0211" title="Bug reports">🐛</a> <a href="#ideas-ganlanshu0211" title="Ideas, Planning, & Feedback">🤔</a></td> <td align="center" valign="top" width="14.28%"><a href="https://github.com/JasonHezz"><img src="https://avatars3.githubusercontent.com/u/15358765?v=4?s=50" width="50px;" alt="JasonHezz"/><br /><sub><b>JasonHezz</b></sub></a><br /><a href="https://github.com/fluttercandies/flutter_wechat_assets_picker/issues?q=author%3AJasonHezz" title="Bug reports">🐛</a> <a href="https://github.com/fluttercandies/flutter_wechat_assets_picker/commits?author=JasonHezz" title="Code">💻</a></td> <td align="center" valign="top" width="14.28%"><a href="https://github.com/yanivshaked"><img src="https://avatars.githubusercontent.com/u/13107481?v=4?s=50" width="50px;" alt="Yaniv Shaked"/><br /><sub><b>Yaniv Shaked</b></sub></a><br /><a href="#translation-yanivshaked" title="Translation">🌍</a> <a href="https://github.com/fluttercandies/flutter_wechat_assets_picker/commits?author=yanivshaked" title="Code">💻</a> <a href="https://github.com/fluttercandies/flutter_wechat_assets_picker/issues?q=author%3Ayanivshaked" title="Bug reports">🐛</a> <a href="#maintenance-yanivshaked" title="Maintenance">🚧</a></td> <td align="center" valign="top" width="14.28%"><a href="https://github.com/avi-yadav"><img src="https://avatars.githubusercontent.com/u/7314430?v=4?s=50" width="50px;" alt="avi-yadav"/><br /><sub><b>avi-yadav</b></sub></a><br /><a href="https://github.com/fluttercandies/flutter_wechat_assets_picker/commits?author=avi-yadav" title="Code">💻</a></td> </tr> <tr> <td align="center" valign="top" width="14.28%"><a href="https://github.com/Letalus"><img src="https://avatars.githubusercontent.com/u/41230136?v=4?s=50" width="50px;" alt="Letalus"/><br /><sub><b>Letalus</b></sub></a><br /><a href="https://github.com/fluttercandies/flutter_wechat_assets_picker/issues?q=author%3ALetalus" title="Bug reports">🐛</a> <a href="#translation-Letalus" title="Translation">🌍</a></td> <td align="center" valign="top" width="14.28%"><a href="https://github.com/greymag"><img src="https://avatars.githubusercontent.com/u/1502131?v=4?s=50" width="50px;" alt="greymag"/><br /><sub><b>greymag</b></sub></a><br /><a href="#translation-greymag" title="Translation">🌍</a></td> <td align="center" valign="top" width="14.28%"><a href="https://github.com/NaikSoftware"><img src="https://avatars.githubusercontent.com/u/4218994?v=4?s=50" width="50px;" alt="Nickolay Savchenko"/><br /><sub><b>Nickolay Savchenko</b></sub></a><br /><a href="#design-NaikSoftware" title="Design">🎨</a></td> <td align="center" valign="top" width="14.28%"><a href="https://github.com/KosukeSaigusa"><img src="https://avatars.githubusercontent.com/u/13669049?v=4?s=50" width="50px;" alt="Kosuke Saigusa"/><br /><sub><b>Kosuke Saigusa</b></sub></a><br /><a href="#translation-KosukeSaigusa" title="Translation">🌍</a></td> <td align="center" valign="top" width="14.28%"><a href="https://github.com/Jon-Millent"><img src="https://avatars.githubusercontent.com/u/17584565?v=4?s=50" width="50px;" alt="三闻书店"/><br /><sub><b>三闻书店</b></sub></a><br /><a href="https://github.com/fluttercandies/flutter_wechat_assets_picker/commits?author=Jon-Millent" title="Documentation">📖</a></td> <td align="center" valign="top" width="14.28%"><a href="https://github.com/didiosn"><img src="https://avatars.githubusercontent.com/u/15895051?v=4?s=50" width="50px;" alt="DidiosFaust"/><br /><sub><b>DidiosFaust</b></sub></a><br /><a href="#translation-didiosn" title="Translation">🌍</a></td> <td align="center" valign="top" width="14.28%"><a href="https://github.com/ConanXie"><img src="https://avatars.githubusercontent.com/u/10040846?v=4?s=50" width="50px;" alt="xiejie"/><br /><sub><b>xiejie</b></sub></a><br /><a href="https://github.com/fluttercandies/flutter_wechat_assets_picker/issues?q=author%3AConanXie" title="Bug reports">🐛</a></td> </tr> <tr> <td align="center" valign="top" width="14.28%"><a href="https://github.com/maxzod"><img src="https://avatars.githubusercontent.com/u/47630729?v=4?s=50" width="50px;" alt="Ahmed Masoud "/><br /><sub><b>Ahmed Masoud </b></sub></a><br /><a href="#translation-maxzod" title="Translation">🌍</a></td> <td align="center" valign="top" width="14.28%"><a href="https://github.com/luomo-pro"><img src="https://avatars.githubusercontent.com/u/41097395?v=4?s=50" width="50px;" alt="luomo-pro"/><br /><sub><b>luomo-pro</b></sub></a><br /><a href="#a11y-luomo-pro" title="Accessibility">️️️️♿️</a> <a href="https://github.com/fluttercandies/flutter_wechat_assets_picker/issues?q=author%3Aluomo-pro" title="Bug reports">🐛</a></td> <td align="center" valign="top" width="14.28%"><a href="https://github.com/paigupai"><img src="https://avatars.githubusercontent.com/u/44311361?v=4?s=50" width="50px;" alt="paigupai"/><br /><sub><b>paigupai</b></sub></a><br /><a href="#translation-paigupai" title="Translation">🌍</a></td> <td align="center" valign="top" width="14.28%"><a href="https://github.com/taqiabdulaziz"><img src="https://avatars.githubusercontent.com/u/30410316?v=4?s=50" width="50px;" alt="Muhammad Taqi Abdul Aziz"/><br /><sub><b>Muhammad Taqi Abdul Aziz</b></sub></a><br /><a href="https://github.com/fluttercandies/flutter_wechat_assets_picker/commits?author=taqiabdulaziz" title="Documentation">📖</a></td> <td align="center" valign="top" width="14.28%"><a href="https://github.com/hellohejinyu"><img src="https://avatars.githubusercontent.com/u/8766034?v=4?s=50" width="50px;" alt="何锦余"/><br /><sub><b>何锦余</b></sub></a><br /><a href="https://github.com/fluttercandies/flutter_wechat_assets_picker/issues?q=author%3Ahellohejinyu" title="Bug reports">🐛</a></td> <td align="center" valign="top" width="14.28%"><a href="https://github.com/leonpesdk"><img src="https://avatars.githubusercontent.com/u/57394644?v=4?s=50" width="50px;" alt="Leon Dudlik"/><br /><sub><b>Leon Dudlik</b></sub></a><br /><a href="https://github.com/fluttercandies/flutter_wechat_assets_picker/issues?q=author%3Aleonpesdk" title="Bug reports">🐛</a></td> <td align="center" valign="top" width="14.28%"><a href="https://www.legoffmael.fr"><img src="https://avatars.githubusercontent.com/u/22376981?v=4?s=50" width="50px;" alt="Maël"/><br /><sub><b>Maël</b></sub></a><br /><a href="https://github.com/fluttercandies/flutter_wechat_assets_picker/commits?author=LeGoffMael" title="Code">💻</a> <a href="#maintenance-LeGoffMael" title="Maintenance">🚧</a></td> </tr> <tr> <td align="center" valign="top" width="14.28%"><a href="https://github.com/dddrop"><img src="https://avatars.githubusercontent.com/u/5361175?v=4?s=50" width="50px;" alt="dddrop"/><br /><sub><b>dddrop</b></sub></a><br /><a href="https://github.com/fluttercandies/flutter_wechat_assets_picker/commits?author=dddrop" title="Code">💻</a></td> <td align="center" valign="top" width="14.28%"><a href="https://www.linkedin.com/in/loinp"><img src="https://avatars.githubusercontent.com/u/34020090?v=4?s=50" width="50px;" alt="Nguyen Phuc Loi"/><br /><sub><b>Nguyen Phuc Loi</b></sub></a><br /><a href="#translation-nploi" title="Translation">🌍</a></td> <td align="center" valign="top" width="14.28%"><a href="https://sqlturk.wordpress.com/"><img src="https://avatars.githubusercontent.com/u/12383547?v=4?s=50" width="50px;" alt="Cevheri"/><br /><sub><b>Cevheri</b></sub></a><br /><a href="#translation-cevheri" title="Translation">🌍</a></td> <td align="center" valign="top" width="14.28%"><a href="https://velog.io/@hee_mm_"><img src="https://avatars.githubusercontent.com/u/48482259?v=4?s=50" width="50px;" alt="mirimhee"/><br /><sub><b>mirimhee</b></sub></a><br /><a href="#translation-LIMMIHEE" title="Translation">🌍</a></td> <td align="center" valign="top" width="14.28%"><a href="https://amoshk.top"><img src="https://avatars.githubusercontent.com/u/32262985?v=4?s=50" width="50px;" alt="Amos"/><br /><sub><b>Amos</b></sub></a><br /><a href="https://github.com/fluttercandies/flutter_wechat_assets_picker/issues?q=author%3AAmosHuKe" title="Bug reports">🐛</a></td> </tr> </tbody> </table> <!-- markdownlint-restore --> <!-- prettier-ignore-end --> <!-- ALL-CONTRIBUTORS-LIST:END -->

This project follows the all-contributors specification. Contributions of any kind welcomed!!

Credits

Every aspect of IntelliJ IDEA has been designed to maximize developer productivity. Together, intelligent coding assistance and ergonomic design make development not only productive but also enjoyable.

Thanks to JetBrains for allocating free open-source licenses for IDEs such as IntelliJ IDEA.

<img src="https://github.com/fluttercandies/flutter_wechat_assets_picker/raw/main/.github/jetbrains-variant.png" width="200"/>