Git Product home page Git Product logo

mediapicker's Introduction

     

Media Picker

SwiftUI library for a customizable media picker.

SPM Compatible Cocoapods Compatible Carthage Compatible License: MIT

Features

  • Photo and video picker
  • Single and multiple selection
  • Full-screen view
  • Live photo preview & capture
  • Full customization

MediaPicker vs PhotosPicker

  • The iOS 16 PhotosPicker only provides you with a button, while this library gives you the whole view, meaning you can build it into you own screens and customize it as you see fit.
  • PhotosPicker only lets you pick photos from the library - no camera.
  • MediaPicker provides a default looking library picker, with ability to manage albums, and also a camera view to take photos/video

!SPM Renaming!

SPM package is now called ExyteMediaPicker instead of MediaPicker, sorry for any inconveniences.

Usage

  1. Add a binding Bool to control the picker presentation state.
  2. Add Media array to save selection ([Media]).
  3. Initialize the media picker and present it however you like - for example, using the .sheet modifier
.sheet(isPresented: $showMediaPicker) {
    MediaPicker(
        isPresented: $showMediaPicker,
        onChange: { medias = $0 }
    )
}

Media model

The lbrary will return an array of Media structs for you to use as you see fit. It has the following fields and methods (all the methods use async/await API):

  • type - .image or .video
  • duration - nil for .image
  • getURL() - returns URL to media (automatically stores in temporary directory if needed)
  • getThumbnailURL() - returns URL to media's thumbnail (for image just returns the image itself)
  • getData() - returns media's Data representation
  • getThumbnailData() - returns media's thumbnail Data representation

Modes

This library lets you use both photo library and camera

Photos grid

Default photos grid screen has a standard header which contains the 'Done' and 'Cancel' buttons, and a simple switcher between Photos and Albums. Use it for a basic out-of-the box picker (see default picker in example project for an usage example). This can be customized (see "Init - view builders" section)

Camera

After making one photo, you see a preview of it and a little plus icon, by tapping it you return back to camera mode and can continue making as many photos as you like. Press "Done" once you're finished and you will be able to scroll through all the photos you've taken before confirming you'd like to use them. This preview screen of photos you've taken can also be customized (see "Init - view builders" section)

Init - required parameters

isPresented - a binding to determine whether the picker should be displayed or not
onChange - a closure that returns the selected media every time the selection changes

Init - optional view builders

You can pass 1-3 view builders in order to add your own buttons and other elements to media picker screens. You can pass all, some or none of these when creating your MediaPicker (see the custom picker in the example project for usage example). First screen you can customize is default photos grid view. Pass albumSelectionBuilder closure like this to replace the standard one with your own view:

MediaPicker(
    isPresented: $isPresented,
    onChange: { selectedMedia = $0 },
    albumSelectionBuilder: { defaultHeaderView, albumSelectionView, isInFullscreen in
        VStack {
            if !isInFullscreen {
                defaultHeaderView
            }
            albumSelectionView
            Spacer()
            footerView
        }
        .background(Color.black)
    }
)

albumSelectionBuilder gives you two views to work with:

  • defaultHeaderView - a default looking header with photos/albums mode switcher
  • albumSelectionView - the photos grid itself
  • isInFullscreen - is fullscreen photo details screen displayed. Use for example to hide the header while in fullscreen mode.

The second customizable screen is the one you see after taking a photo. Pass cameraSelectionBuilder like this:

MediaPicker(
    isPresented: $isPresented,
    onChange: { selectedMedia = $0 },
    cameraSelectionBuilder: { addMoreClosure, cancelClosure, cameraSelectionView in
        VStack {
            HStack {
                Spacer()
                Button("Done", action: { isPresented = false })
            }
            cameraSelectionView
            HStack {
                Button("Cancel", action: cancelClosure)
                Spacer()
                Button(action: addMoreClosure) {
                    Text("Take more photos")
                }
            }
        }
    }
)

cameraSelectionBuilder gives you these parameters:

  • addMoreClosure - you can call this closure on tap of your own button, it will work same as default plus icon on camera selection preview screen
  • cancelClosure - show confirmation and return to photos grid screen if confirmed
  • cameraSelectionView - swipable camera photos preview collection itself

The last one is live camera screen

MediaPicker(
    isPresented: $isPresented,
    onChange: { selectedMedia = $0 },
    cameraViewBuilder: { cameraSheetView, cancelClosure, showPreviewClosure, takePhotoClosure, startVideoCaptureClosure, stopVideoCaptureClosure, toggleFlash, flipCamera in
        cameraSheetView
            .overlay(alignment: .topLeading) {
                HStack {
                    Button("Cancel") { cancelClosure() }
                        .foregroundColor(Color("CustomPurple"))
                    Spacer()
                    Button("Done") { showPreviewClosure() }
                        .foregroundColor(Color("CustomPurple"))
                }
                .padding()
            }
            .overlay(alignment: .bottom) {
                HStack {
                    Button("Take photo") { takePhotoClosure() }
                        .greenButtonStyle()
                    Button(videoIsBeingRecorded ? "Stop video capture" : "Capture video") {
                        videoIsBeingRecorded ? stopVideoCaptureClosure() : startVideoCaptureClosure()
                        videoIsBeingRecorded.toggle()
                    }
                    .greenButtonStyle()
                }
                .padding()
            }
    }
)

cameraViewBuilder live camera capture view and a lot of closures to do with as you please:

  • cameraSheetView - live camera capture view
  • cancelClosure - if you want to display "are you sure" before closing
  • showPreviewClosure - shows preview of taken photos
  • cancelClosure - if you want to display "are you sure" before closing
  • startVideoCaptureClosure - starts video capture, you'll need a bollean varialbe to track recording state
  • stopVideoCaptureClosure - stops video capture
  • toggleFlash - flash off/on
  • flipCamera - camera back/front

Available modifiers

showLiveCameraCell - show live camera feed cell in the top left corner of the gallery grid
mediaSelectionType - limit displayed media type: .photo, .video or both
mediaSelectionStyle - a way to display selected/unselected media state: a counter or a simple checkmark
mediaSelectionLimit - the maximum selection quantity allowed, 'nil' for unlimited selection
showFullscreenPreview - if true - tap on media opens fullscreen preview, if false - tap on image immediately selects this image and closes the picker

Available modifiers - filtering

applyFilter((Media) async -> Media?) - pass a closure to apply to each of medias individually. Closures's return type is Media?: return Media the closure gives to you if you want it to be displayed on photo grid, or nil if you want to exclude it. The code you apply to each media can be asyncronous (using async/await syntactics, check out FilterMediaPicker in example project) applyFilter(([Media]) async -> [Media]) - same but apply the closure to whole medias array. Can also be used for reodering.

Available modifiers - screen rotation

If your app restricts screen rotation, you can skip this section.

We recommend locking orientation for MediaPicker, because default rotation animations don't look good on the camera screen. At the moment SwiftUI doesn't provide a way of locking screen orientation, so the library has an initializer with an orientationHandler parameter - a closure that is called when you enter/leave the camera screen inside MediaPicker. In this closure you need to use AppDelegate to lock/unlock the rotation - see example project for implementation.

Available modifiers: managing albums

albums - a list of user's albums (like in Photos app), if you want to display them differently than showingDefaultHeader does.
pickerMode - set this if you don't plan to use the default header. Available options are:
* .photos - displays the default photos grid
* .albums - displays a list of albums with one preview photo for each
* .album(Album) - displays one album
* .camera - shows a fullscreen cover camera sheet * .cameraSelection - displays a preview of photos taken with camera (see the custom picker in the example project for implementation)

Available modifiers: theme

mediaPickerTheme - color settings. Example usage (see MediaPickerTheme for all available settings):

MediaPicker(...)
  .mediaPickerTheme(
      main: .init(
          background: .black
      ),
      selection: .init(
          emptyTint: .white,
          emptyBackground: .black.opacity(0.25),
          selectedTint: Color("CustomPurple")
      )
  )

Here is an example of how you can customize colors and elements to create a custom looking picker:

Examples

To try out the MediaPicker examples:

  • Clone the repo https://github.com/exyte/MediaPicker.git
  • Open Examples/Examples.xcworkspace in the Xcode
  • Run it!

Installation

dependencies: [
    .package(url: "https://github.com/exyte/ExyteMediaPicker.git")
]

CocoaPods

pod 'ExyteMediaPicker'

Carthage

github "Exyte/MediaPicker"

Requirements

  • iOS 16+
  • Xcode 13+

Our other open source SwiftUI libraries

PopupView - Toasts and popups library
Grid - The most powerful Grid container
ScalingHeaderScrollView - A scroll view with a sticky header which shrinks as you scroll
AnimatedTabBar - A tabbar with a number of preset animations
Chat - Chat UI framework with fully customizable message cells, input view, and a built-in media picker
OpenAI Wrapper lib for OpenAI REST API
AnimatedGradient - Animated linear gradient
ConcentricOnboarding - Animated onboarding flow
FloatingButton - Floating button menu
ActivityIndicatorView - A number of animated loading indicators
ProgressIndicatorView - A number of animated progress indicators
FlagAndCountryCode - Phone codes and flags for every country
SVGView - SVG parser
LiquidSwipe - Liquid navigation animation

mediapicker's People

Contributors

alex-m-b95 avatar alexandra-afonasova avatar denis-obukhov avatar f3dm76 avatar heoblitz avatar nikita-afonasov avatar villygreen avatar x901 avatar zapletnev avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

mediapicker's Issues

Separate Camera & Photo Album permission requests.

I want to use MediaPicker for camera only but when we initialise MediaPicker, it asks for Photo Album permission as well. The code for photo album permission executes even if we want to only use camera.

I feel code should be restructured so that when we want only camera access, only camera permissions should be asked and if we want photo album access, only photo album permissions should be asked.

Customize Gird

Could you add customize to gird item itself ?
for example add padding, add cornerRadius etc..

Support for camera capture customization

Hi,
It would be great to have the option to customize the camera capture view itself.

For example, I want to be able to first show the camera capture view, without the cancel button in the top left corner, and with gallery icon in the bottom left that will switch to the photo picker.

Right now this isn't an option as I can only change the preview screen.

performance main thread

`func image(size: CGSize, resultClosure: @escaping (UIImage?)->()) -> PHImageRequestID {
let requestSize = CGSize(width: size.width * UIScreen.main.scale, height: size.height * UIScreen.main.scale)

    let options = PHImageRequestOptions()
    options.isNetworkAccessAllowed = true
    options.deliveryMode = .fastFormat

    return PHCachingImageManager.default().requestImage(
        for: self,
        targetSize: requestSize,
        contentMode: .aspectFill,
        options: options,
        resultHandler: { image, info in
            DispatchQueue.main.async {      // add this
                resultClosure(image) // called for every quality approximation
            } 
        }
    )
}`

and also don't use geometry reader for getting cell size, because it's kill performance too, you should got cell size from UIScreen.main.bounds

Custom filter for images

I don't imagine this is supported, but what I am looking to do is be able to specify the images I want to load from the camera roll or a specific filter to filter based off of.

For example, I want to be able to run a VNDetectHumanRectanglesRequest or some other Request provided by Apple to filter what gets shown to the user before they select.

I would be willing to pay for this functionality if someone is up for it. It could be a custom fork of this library, whatever is easiest.

Why did you stop supporting iOS 15?

Hi,
I noticed a minimum support change from iOS 15 to iOS 16

I’m using it because I can fully customize it, and also because it supports iOS15

as I check the library, everything is Suppourt iOS 15, you don’t use any new feature that is not available in iOS 15

Images selected from library are not showing up in iOS 15

Getting this error when images are selected from Gallery. Only in iOS 15 working fine in iOS 16.

[ImageManager] Media resource request failed to return valid data or url with error: Error Domain=PHPhotosErrorDomain Code=3164 "(null)"

Image tapped is not image that I wanted

Hi,

Amazing projects and libraries, it's been really helpful, many thanks !

However, with media picker 1.3.0, I am seeing issue on ios 16.6, where the image selected becomes the image below it when it gets loaded, feels like a boundary issue, will continue debugging and provide updates

Landscape Swipe, Glitch when swiping between photos, illy navigation, and "empty data"

Hey there!

I wanted to share some feedback on your realization that I tested. Here are a few points I noticed:

The landscape swipe to dismiss feature doesn't seem to be working as intended.
While testing, I encountered a little glitch when pressing on one photo and trying to swipe between photos. It might need some attention to work smoothly.
The layout of the navigation buttons appears to be broken. They don't seem to be displaying correctly on the screen.
I also noticed a minor issue with the label "Empty data" blinking on the screen. It's a small annoyance that could be easily fixed.
Just for your reference, I tested the realization on iOS version 16.5.1(c) using an iPhone 13 Pro.

I hope you find this feedback helpful! Have a fantastic day!

Keep selection when reopen

It would be great if the library could keep the current selection when reopening it. This feature could be enabled/disable.

`showFullscreenPreview = false` not selecting the picture

Hi! Loving this package so far.

I'm using this picker from ExyteChat, and I'm passing the following options:

ChatView(messages: [])
.setMediaPickerSelectionParameters(MediaPickerParameters(mediaType: .photo, showFullscreenPreview: false))

However, when I disable showFullscreenPreview, when I tap on the photo, I see the photo gets immediately selected (good), and the picker is closed (good)... but the photo hasn't actually been added as an attachment, so I only have my text.

Could you please take a look at this? From the source code I can't see any obvious typo or anything like that.
Thanks!

How to only display image ?

Hi,
I want to allow user to select image only
I notice when the image picker appear I can see videos and images

how to hide videos from the list ?

also how to only allow user to take photo only ?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.