natysoz / expo-images-picker

Multiple Asset Photos Videos selecting package for Expo SDK
MIT License
95 stars 35 forks source link

Passing previously selected assets to AssetsSelector #20

Closed amosbastian closed 3 years ago

amosbastian commented 3 years ago

If you have already selected assets and then open AssetsSelector again there is no way to pass which assets you have selected previously, which means you have to completely reselect all assets you want. I think this is a common situation (e.g. user selects 1 asset, afterwards decides they want to add 1 more) so it would be nice to have.

Bronsky91 commented 3 years ago

I second this, I needed this exact functionality today

amosbastian commented 3 years ago

I second this, I needed this exact functionality today

I ended up adapting part of his code to implement this. Maybe this is useful for you:

// AssetsSelector.tsx
const AssetsSelector = ({initialAssets, onCancel, onConfirm}: AssetsSelectorProps): JSX.Element => {
  const [selectedItems, setSelectedItems] = useState<string[]>(initialAssets.map(asset => asset.id));
  const [assets, setAssets] = useAssets();

  ... 

  return (
    <Screen>
      <AssetsSelectorHeading onCancel={onCancel} onConfirm={handleConfirm} />
      <SelectableAssetsList
        assets={assets}
        loadMoreAssets={setAssets}
        onClick={onAssetSelect}
        selectedItems={selectedItems}
        size={width / NUM_COLUMNS}
      />
    </Screen>
  );
};
// useAssets.tsx
import {Asset, AssetsOptions, getAssetsAsync, PagedInfo} from 'expo-media-library';
import * as Permissions from 'expo-permissions';
import {useCallback, useEffect, useState} from 'react';
import showToast from '../utils/showToast';

export const useAssets = (): [Asset[], () => Promise<void> | undefined] => {
  const [assets, setAssets] = useState<Asset[]>([]);

  const [permissions, setPermissions] = useState({
    hasCameraPermission: false,
    hasCameraRollPermission: false,
  });

  const [options, setOptions] = useState<Partial<AssetsOptions> & Partial<PagedInfo<Asset>>>({
    first: 500,
    after: '',
    totalCount: 0,
    endCursor: '',
    hasNextPage: true,
  });

  const loadAssets = useCallback(
    async (assetsOptions: AssetsOptions) => {
      try {
        const {endCursor, assets: newAssets, hasNextPage} = await getAssetsAsync(assetsOptions);

        if (options.after === endCursor) return;

        setOptions({
          ...options,
          after: endCursor,
          hasNextPage: hasNextPage,
        });

        return setAssets([...assets, ...newAssets]);
      } catch (error) {
        showToast({text: error, type: 'danger'});
      }
    },
    [assets, permissions.hasCameraPermission]
  );

  const getCameraPermissions = useCallback(async () => {
    const {status: CAMERA} = await Permissions.askAsync(Permissions.CAMERA);

    const {status: MEDIA_LIBRARY} = await Permissions.askAsync(Permissions.MEDIA_LIBRARY);

    setPermissions({
      hasCameraPermission: CAMERA === 'granted',
      hasCameraRollPermission: MEDIA_LIBRARY === 'granted',
    });
  }, []);

  const getAssets = () => {
    try {
      if (options.hasNextPage) {
        const assetsOptions: AssetsOptions = {
          first: 200,
          mediaType: ['photo', 'video'],
          sortBy: ['creationTime'],
        };

        if (options.after) {
          assetsOptions.after = options.after;
        }

        if (!options.hasNextPage) return;

        return permissions.hasCameraRollPermission ? loadAssets(assetsOptions) : getCameraPermissions();
      }
    } catch (error) {
      showToast({text: error, type: 'danger'});
    }
  };

  useEffect(() => {
    getAssets();
  }, [permissions.hasCameraPermission, permissions.hasCameraRollPermission]);

  return [assets, getAssets];
};
natysoz commented 3 years ago

ill add this in the end of the month im busy atm , thanks for letting me know , on my list :)