Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update forked branch #1

Open
wants to merge 49 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
dfbc2e2
Only ask for camera permission when necessary
f3dm76 Aug 14, 2023
2189ab9
Use current fullscreen media if nothing else is selected
f3dm76 Aug 14, 2023
2a182bc
Add sim check
f3dm76 Aug 17, 2023
6d404a5
Add header hiding in fullscreen
f3dm76 Aug 17, 2023
e855bee
Fix single selection mode
f3dm76 Aug 17, 2023
61f70ea
Forbid screen rotation for the whole picker
f3dm76 Aug 22, 2023
7c8fe5a
Fix orientation locking
f3dm76 Aug 22, 2023
a51c02f
Fix slow camera dismissal
f3dm76 Aug 22, 2023
2b57f10
Don't show circles in the library for single selection
f3dm76 Aug 22, 2023
9c36467
Don't make media smaller while keyboard is displayed
f3dm76 Aug 24, 2023
1192d7e
Current fullscreen item fix
f3dm76 Aug 24, 2023
eaaf60c
Fix video size calculations
f3dm76 Aug 25, 2023
b58ddea
Fix single media selection mode
f3dm76 Sep 1, 2023
b60bd25
Add audio capture for videos
f3dm76 Sep 1, 2023
154ec10
Add custom bg for video player
f3dm76 Sep 4, 2023
e5cae02
Add keyboard dismiss on tap
f3dm76 Sep 4, 2023
922bde1
add cell style
X901 Oct 3, 2023
6c0b9d0
fix issue when tap on MediaCell open wrong image
Oct 10, 2023
75f4393
Renew example project
f3dm76 Oct 11, 2023
777d395
Fix padding
f3dm76 Oct 11, 2023
9947ee5
Simplify keyboard avoidence
f3dm76 Oct 16, 2023
d25d750
Fix current fullscreen item
f3dm76 Oct 16, 2023
6a67be9
Merge branch 'main' into main
f3dm76 Oct 16, 2023
792fad4
Merge pull request #18 from X901/main
f3dm76 Oct 16, 2023
2b2644f
Raise ios target to 16
f3dm76 Oct 16, 2023
8e5e4d8
Fix "empty data" flashing
f3dm76 Oct 16, 2023
97d1f33
Add option to remove fullscreen preview
f3dm76 Oct 18, 2023
ed48423
Add live camera view customization closure
f3dm76 Oct 18, 2023
f493425
Allow to pass selection parameters struct
f3dm76 Oct 19, 2023
467ba6d
Bump version
f3dm76 Oct 19, 2023
708e9d2
Add iOs 15 support;
Alex-M-B95 Oct 23, 2023
a8c58ab
Add a new feature: deselect photo/video from camera;
Alex-M-B95 Oct 25, 2023
1d3c061
Correct code formatting;
Alex-M-B95 Oct 25, 2023
e53d3af
Merge pull request #21 from exyte/feature/deselect-items-from-camera
f3dm76 Oct 25, 2023
e8d1bc3
Fix a crash when the application does not have camera permission;
Alex-M-B95 Oct 25, 2023
4129507
Merge pull request #22 from exyte/fix/app-crashes-without-camera-perm…
f3dm76 Oct 25, 2023
7577cce
Apply the main text color from the theme for “Empty Data” texts;
Alex-M-B95 Oct 25, 2023
37bb06d
Merge pull request #23 from exyte/fix/empty-data-text-color
f3dm76 Oct 25, 2023
97b4b29
Merge branch 'main' into fix/support-ios-15
f3dm76 Oct 31, 2023
8d4f1d4
Add show preview closure to camera builder
f3dm76 Oct 31, 2023
3cb62be
Bump version
f3dm76 Oct 31, 2023
4ec0d23
Add more color customization
f3dm76 Dec 14, 2023
f2dbedb
fix showFullscreenPreview selection style
villyGreen Mar 6, 2024
b5741e6
fix comment
villyGreen Mar 6, 2024
cbbf95b
Merge pull request #27 from exyte/feature/showFullscreenPreviewSelection
f3dm76 Mar 7, 2024
f4f756d
fix close action in camera stub view
villyGreen Mar 11, 2024
71e81ea
Merge pull request #29 from exyte/fix/cameraStubCloseAction
f3dm76 Mar 11, 2024
88769b1
Only ask permissions when needed
f3dm76 May 6, 2024
2738cd0
Update README.md
f3dm76 Jul 10, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 0 additions & 12 deletions Examples/Example-iOS/Info.plist

This file was deleted.

2 changes: 1 addition & 1 deletion ExyteMediaPicker.podspec
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = "ExyteMediaPicker"
s.version = "1.2.4"
s.version = "2.2.3"
s.summary = "MediaPicker is a customizable photo/video picker for iOS written in pure SwiftUI"

s.homepage = 'https://github.com/exyte/MediaPicker.git'
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ final class AppDelegate: NSObject, UIApplicationDelegate, ObservableObject {
private var orientationLock = UIInterfaceOrientationMask.all

func lockOrientationToPortrait() {
orientationLock = .portrait
if #available(iOS 16, *) {
if let scene = UIApplication.shared.connectedScenes.first as? UIWindowScene {
scene.requestGeometryUpdate(.iOS(interfaceOrientations: .portrait))
Expand All @@ -21,7 +22,6 @@ final class AppDelegate: NSObject, UIApplicationDelegate, ObservableObject {
} else {
UIDevice.current.setValue(UIDeviceOrientation.portrait.rawValue, forKey: "orientation")
}
orientationLock = .portrait
}

func unlockOrientation() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ struct ContentView: View {
onChange: { medias = $0 }
)
.showLiveCameraCell()
.mediaSelectionLimit(1)
.orientationHandler {
switch $0 {
case .lock: appDelegate.lockOrientationToPortrait()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,23 @@ struct CustomizedMediaPicker: View {

@State private var mediaPickerMode = MediaPickerMode.photos
@State private var selectedAlbum: Album?
@State private var currentFullscreenMedia: Media?
@State private var showAlbumsDropDown: Bool = false
@State private var videoIsBeingRecorded: Bool = false

let maxCount: Int = 5

var body: some View {
MediaPicker(
isPresented: $isPresented,
onChange: { medias = $0 },
albumSelectionBuilder: { _, albumSelectionView in
albumSelectionBuilder: { _, albumSelectionView, _ in
VStack {
headerView
albumSelectionView
Spacer()
footerView
.background(Color.black)
}
.background(Color.black)
},
Expand All @@ -40,28 +43,50 @@ struct CustomizedMediaPicker: View {
Spacer()
Button("Done", action: { isPresented = false })
}
.padding()
cameraSelectionView
HStack {
Button("Cancel", action: cancelClosure)
Spacer()
Button(action: addMoreClosure) {
Text("Take more photos")
.font(.headline)
.foregroundColor(.black)
.padding()
}
.background {
Color("CustomGreen")
.cornerRadius(16)
.greenButtonStyle()
}
}
.padding()
}
.background(Color.black)
},
cameraViewBuilder: { cameraSheetView, cancelClosure, showPreviewClosure, takePhotoClosure, startVideoCaptureClosure, stopVideoCaptureClosure, _, _ 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()
}
}
)
.showLiveCameraCell()
.albums($albums)
.pickerMode($mediaPickerMode)
.currentFullscreenMedia($currentFullscreenMedia)
.orientationHandler {
switch $0 {
case .lock: appDelegate.lockOrientationToPortrait()
Expand Down Expand Up @@ -116,13 +141,12 @@ struct CustomizedMediaPicker: View {

var footerView: some View {
HStack {
Button {
medias = []
isPresented = false
} label: {
Text("Cancel")
.foregroundColor(.white.opacity(0.7))
}
TextField("", text: .constant(""), prompt: Text("Add a caption").foregroundColor(.gray))
.padding()
.background {
Color.white.opacity(0.2)
.cornerRadius(6)
}

Spacer(minLength: 70)

Expand All @@ -137,18 +161,12 @@ struct CustomizedMediaPicker: View {
.background(Color.white)
.clipShape(Circle())
}
.font(.headline)
.foregroundColor(.black)
.padding(.horizontal)
.padding(.vertical, 15)
.frame(maxWidth: .infinity)
}
.background {
Color("CustomGreen")
.cornerRadius(16)
}
.greenButtonStyle()
}
.padding(.horizontal)
.padding(.vertical, 8)
}

var albumsDropdown: some View {
Expand All @@ -167,3 +185,15 @@ struct CustomizedMediaPicker: View {
.frame(maxHeight: 300)
}
}

extension View {
func greenButtonStyle() -> some View {
self.font(.headline)
.foregroundColor(.black)
.padding()
.background {
Color("CustomGreen")
.cornerRadius(16)
}
}
}
5 changes: 2 additions & 3 deletions Package.swift
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
// swift-tools-version: 5.6
// swift-tools-version: 5.7
// The swift-tools-version declares the minimum version of Swift required to build this package.

import PackageDescription

let package = Package(
name: "ExyteMediaPicker",
platforms: [
.iOS(.v15),
.macOS(.v11)
.iOS(.v15)
],
products: [
.library(
Expand Down
65 changes: 57 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,14 +68,16 @@ After making one photo, you see a preview of it and a little plus icon, by tappi
`onChange` - a closure that returns the selected media every time the selection changes

### Init - optional view builders
You can pass two view builders in order to add your own buttons and other elements to media picker screens. First screen you can customize is default photos grid view. Pass `albumSelectionBuilder` closure like this to replace the standard one with your own view:
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:
```swift
MediaPicker(
isPresented: $isPresented,
onChange: { selectedMedia = $0 },
albumSelectionBuilder: { defaultHeaderView, albumSelectionView in
albumSelectionBuilder: { defaultHeaderView, albumSelectionView, isInFullscreen in
VStack {
defaultHeaderView
if !isInFullscreen {
defaultHeaderView
}
albumSelectionView
Spacer()
footerView
Expand All @@ -88,6 +90,7 @@ MediaPicker(
`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:
```swift
Expand Down Expand Up @@ -117,13 +120,56 @@ MediaPicker(
- `cancelClosure` - show confirmation and return to photos grid screen if confirmed
- `cameraSelectionView` - swipable camera photos preview collection itself

You can pass one, both or none of these when creating your `MediaPicker`. (see the custom picker in the example project for usage example)
The last one is live camera screen

```swift
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)
Expand Down Expand Up @@ -196,18 +242,21 @@ github "Exyte/MediaPicker"

## Requirements

* iOS 15+
* iOS 16+
* Xcode 13+

## Our other open source SwiftUI libraries
[PopupView](https://github.com/exyte/PopupView) - Toasts and popups library
[Grid](https://github.com/exyte/Grid) - The most powerful Grid container
[ScalingHeaderScrollView](https://github.com/exyte/ScalingHeaderScrollView) - A scroll view with a sticky header which shrinks as you scroll
[AnimatedTabBar](https://github.com/exyte/AnimatedTabBar) - A tabbar with number of preset animations
[Chat](https://github.com/exyte/chat) - Chat UI framework with fully customizable message cells, input view, and a built-in media picker
[ScalingHeaderScrollView](https://github.com/exyte/ScalingHeaderScrollView) - A scroll view with a sticky header which shrinks as you scroll
[AnimatedTabBar](https://github.com/exyte/AnimatedTabBar) - A tabbar with a number of preset animations
[Chat](https://github.com/exyte/chat) - Chat UI framework with fully customizable message cells, input view, and a built-in media picker
[OpenAI](https://github.com/exyte/OpenAI) Wrapper lib for [OpenAI REST API](https://platform.openai.com/docs/api-reference/introduction)
[AnimatedGradient](https://github.com/exyte/AnimatedGradient) - Animated linear gradient
[ConcentricOnboarding](https://github.com/exyte/ConcentricOnboarding) - Animated onboarding flow
[FloatingButton](https://github.com/exyte/FloatingButton) - Floating button menu
[ActivityIndicatorView](https://github.com/exyte/ActivityIndicatorView) - A number of animated loading indicators
[ProgressIndicatorView](https://github.com/exyte/ProgressIndicatorView) - A number of animated progress indicators
[FlagAndCountryCode](https://github.com/exyte/FlagAndCountryCode) - Phone codes and flags for every country
[SVGView](https://github.com/exyte/SVGView) - SVG parser
[LiquidSwipe](https://github.com/exyte/LiquidSwipe) - Liquid navigation animation
Loading