Skip to content

Commit

Permalink
Merge pull request #28 from enebin/release/0.5.0
Browse files Browse the repository at this point in the history
release/0.5.0
  • Loading branch information
enebin authored Dec 5, 2023
2 parents 420346a + ec3fc18 commit 2e7e1e0
Show file tree
Hide file tree
Showing 33 changed files with 1,172 additions and 207 deletions.
23 changes: 23 additions & 0 deletions .github/workflows/github_issue_auto_resolve.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@

name: Close inactive issues
on:
schedule:
- cron: "30 1 * * *"

jobs:
close-issues:
runs-on: ubuntu-latest
permissions:
issues: write
pull-requests: write
steps:
- uses: actions/stale@v5
with:
days-before-issue-stale: 30
days-before-issue-close: 14
stale-issue-label: "stale"
stale-issue-message: "This issue is stale because it has been open for 30 days with no activity."
close-issue-message: "This issue was closed because it has been inactive for 14 days since being marked as stale."
days-before-pr-stale: -1
days-before-pr-close: -1
repo-token: ${{ secrets.GITHUB_TOKEN }}
66 changes: 66 additions & 0 deletions .swiftpm/xcode/xcshareddata/xcschemes/Aespa.xcscheme
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1500"
version = "1.7">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "Aespa"
BuildableName = "Aespa"
BlueprintName = "Aespa"
ReferencedContainer = "container:">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
shouldAutocreateTestPlan = "YES">
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "Aespa"
BuildableName = "Aespa"
BlueprintName = "Aespa"
ReferencedContainer = "container:">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
10 changes: 4 additions & 6 deletions Demo/Aespa-iOS/SettingView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ struct SettingView: View {
}
.modifier(TitledPicker(title: "Asset quality"))
.onChange(of: quality) { newValue in
viewModel.aespaSession.quality(to: newValue)
viewModel.aespaSession.common(.quality(preset: newValue))
}

Picker("Focus", selection: $focusMode) {
Expand All @@ -49,7 +49,7 @@ struct SettingView: View {
}
.modifier(TitledPicker(title: "Focus mode"))
.onChange(of: focusMode) { newValue in
viewModel.aespaSession.focus(mode: newValue)
viewModel.aespaSession.common(.focus(mode: newValue))
}
}

Expand All @@ -60,9 +60,7 @@ struct SettingView: View {
}
.modifier(TitledPicker(title: "Mute"))
.onChange(of: isMuted) { newValue in
_ = newValue ?
viewModel.aespaSession.mute() :
viewModel.aespaSession.unmute()
viewModel.aespaSession.video(newValue ? .mute : .unmute)
}
}

Expand All @@ -74,7 +72,7 @@ struct SettingView: View {
}
.modifier(TitledPicker(title: "Flash mode"))
.onChange(of: flashMode) { newValue in
viewModel.aespaSession.flashMode(to: newValue)
viewModel.aespaSession.photo(.flashMode(mode: newValue))
}
}
}
Expand Down
6 changes: 3 additions & 3 deletions Demo/Aespa-iOS/VideoContentView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ struct VideoContentView: View {

// Position change + button
Button(action: {
viewModel.aespaSession.position(to: isFront ? .back : .front)
viewModel.aespaSession.common(.position(position: isFront ? .back : .front))
isFront.toggle()
}) {
Image(systemName: "arrow.triangle.2.circlepath.camera.fill")
Expand All @@ -100,11 +100,11 @@ struct VideoContentView: View {
viewModel.aespaSession.stopRecording()
isRecording = false
} else {
viewModel.aespaSession.startRecording()
viewModel.aespaSession.startRecording(autoVideoOrientationEnabled: true)
isRecording = true
}
case .photo:
viewModel.aespaSession.capturePhoto()
viewModel.aespaSession.capturePhoto(autoVideoOrientationEnabled: true)
}
}
}
Expand Down
30 changes: 15 additions & 15 deletions Demo/Aespa-iOS/VideoContentViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@ class VideoContentViewModel: ObservableObject {
let aespaSession: AespaSession

var preview: some View {
return aespaSession.interactivePreview()
aespaSession.interactivePreview()

// Or you can give some options
// let option = InteractivePreviewOption(enableShowingCrosshair: false)
// let option = InteractivePreviewOption(enableZoom: true)
// return aespaSession.interactivePreview(option: option)
}

Expand All @@ -31,31 +31,31 @@ class VideoContentViewModel: ObservableObject {
@Published var photoFiles: [PhotoAsset] = []

init() {
var option = AespaOption(albumName: "Aespa-Demo-App")
let option = AespaOption(albumName: "YOUR_ALBUM_NAME")
self.aespaSession = Aespa.session(with: option)

// Common setting
aespaSession
.focus(mode: .continuousAutoFocus)
.changeMonitoring(enabled: true)
.orientation(to: .portrait)
.quality(to: .high)
.custom(WideColorCameraTuner()) { result in
.common(.focus(mode: .continuousAutoFocus))
.common(.changeMonitoring(enabled: true))
.common(.orientation(orientation: .portrait))
.common(.quality(preset: .high))
.common(.custom(tuner: WideColorCameraTuner())) { result in
if case .failure(let error) = result {
print("Error: ", error)
}
}

// Photo-only setting
aespaSession
.flashMode(to: .on)
.redEyeReduction(enabled: true)
.photo(.flashMode(mode: .on))
.photo(.redEyeReduction(enabled: true))

// Video-only setting
aespaSession
.mute()
.stabilization(mode: .auto)
.video(.mute)
.video(.stabilization(mode: .auto))

// Prepare video album cover
aespaSession.videoFilePublisher
.receive(on: DispatchQueue.main)
Expand Down
86 changes: 58 additions & 28 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -198,47 +198,68 @@ https://github.com/enebin/Aespa.git
- iOS 14.0+

### Getting started
``` Swift
```swift
import Aespa
```

let aespaOption = AespaOption(albumName: "YOUR_ALBUM_NAME")
// If you don't need album add this line
// aespaOption.asset.synchronizeWithLocalAlbum = false
let aespaSession = Aespa.session(with: aespaOption)
<!-- INSERT_CODE: GETTING_STARTED -->
```swift
let option = AespaOption(albumName: "YOUR_ALBUM_NAME")
self.aespaSession = Aespa.session(with: option)
```
<!-- INSERT_CODE: END -->

## Implementation Exapmles
### Configuration
``` Swift
<!-- INSERT_CODE: COMMON_SETTING -->
```swift
// Common setting
aespaSession
.focus(mode: .continuousAutoFocus)
.orientation(to: .portrait)
.quality(to: .high)
.common(.focus(mode: .continuousAutoFocus))
.common(.changeMonitoring(enabled: true))
.common(.orientation(orientation: .portrait))
.common(.quality(preset: .high))
.common(.custom(tuner: WideColorCameraTuner())) { result in
if case .failure(let error) = result {
print("Error: ", error)
}
}
```
<!-- INSERT_CODE: END -->

<!-- INSERT_CODE: PHOTO_SETTING -->
```swift
// Photo-only setting
aespaSession
.flashMode(to: .on)
.redEyeReduction(enabled: true)
.photo(.flashMode(mode: .on))
.photo(.redEyeReduction(enabled: true))
```
<!-- INSERT_CODE: END -->

<!-- INSERT_CODE: VIDEO_SETTING -->
```swift
// Video-only setting
aespaSession
.mute()
.stabilization(mode: .auto)
.video(.mute)
.video(.stabilization(mode: .auto))
```
<!-- INSERT_CODE: END -->

### Recording & Capture
``` Swift
<!-- INSERT_CODE: RECORDING_AND_CAPTURE -->
```swift
// Start recording
aespaSession.startRecording()
// Later... stop recording
aespaSession.stopRecording()

// Capture photo
aespaSession.capturePhoto()
```
<!-- INSERT_CODE: END -->

### Get result
``` Swift
<!-- INSERT_CODE: GET_RESULT -->
```swift
aespaSession.stopRecording { result in
switch result {
case .success(let file):
Expand All @@ -248,25 +269,30 @@ aespaSession.stopRecording { result in
}
}

// or...
aespaSession.fetchVideoFiles(limit: 1)
// or...
Task {
let files = await aespaSession.fetchVideoFiles(limit: 1)
}

// or you can use publisher
aespaSession.videoFilePublisher.sink { result in ... }
aespaSession.videoFilePublisher.sink { result in
print(result)
}
```
<!-- INSERT_CODE: END -->

## SwiftUI Integration
Aespa also provides a super-easy way to integrate video capture functionality into SwiftUI applications. `AespaSession` includes a helper method to create a SwiftUI `UIViewRepresentable` that provides a preview of the video capture.

### Example usage

<!-- INSERT_CODE: SWIFTUI_INTEGRATION -->
```swift
import Aespa
import SwiftUI

struct VideoContentView: View {
@StateObject private var viewModel = VideoContentViewModel()

var body: some View {
ZStack {
viewModel.preview
Expand All @@ -284,20 +310,24 @@ class VideoContentViewModel: ObservableObject {
var preview: some View {
aespaSession.interactivePreview()
}

init() {
let option = AespaOption(albumName: "Aespa-Demo")
let option = AespaOption(albumName: "YOUR_ALBUM_NAME")
self.aespaSession = Aespa.session(with: option)


setUp()
}

func setUp() {
aespaSession
.autofocusing(mode: .continuousAutoFocus)
.orientation(to: .portrait)
.quality(to: .high)
.common(.quality(preset: .high))

// Other settings...
// Other options
// ...
}
}
```
<!-- INSERT_CODE: END -->

> **Note**
>
Expand Down
Loading

0 comments on commit 2e7e1e0

Please sign in to comment.