Skip to content

Commit

Permalink
Merge branch 'dev'
Browse files Browse the repository at this point in the history
  • Loading branch information
Rspoon3 committed Aug 4, 2024
2 parents 991c5fb + 3fb3531 commit 4ac0327
Show file tree
Hide file tree
Showing 61 changed files with 1,959 additions and 242 deletions.
Binary file added Marketing/iPad 12.9 (6th Generation)/widgets.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Marketing/iPhone 14/5.5/Widgets.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Marketing/iPhone 14/6.5/Widgets2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Marketing/raw/iPadWidgetRaw.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Marketing/raw/iPhoneWidgetRaw.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Marketing/raw/relayFM.jpeg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
293 changes: 282 additions & 11 deletions Shotbot.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

16 changes: 14 additions & 2 deletions Shotbot/ShotbotApp.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,19 @@ import Purchases
import Persistence
import MediaManager
import AppIntents
import WidgetKit
import OSLog
import Photos
import Models

@main
struct ShotbotApp: App {
@UIApplicationDelegateAdaptor(AppDelegateAdaptor.self) private var appDelegate
@StateObject private var persistenceManager = PersistenceManager.shared
@StateObject private var purchaseManager = PurchaseManager.shared
@StateObject private var tabManager = TabManager()
@Environment(\.scenePhase) private var scenePhase

private let logger = Logger(category: "ShotbotApp")

init() {
Expand All @@ -35,6 +40,7 @@ struct ShotbotApp: App {
AppTabNavigation()
.environmentObject(persistenceManager)
.environmentObject(purchaseManager)
.environmentObject(tabManager)
.task {
await purchaseManager.fetchOfferings()
}
Expand All @@ -43,8 +49,14 @@ struct ShotbotApp: App {
}
}
.onChange(of: scenePhase) { phase in
guard phase == .active else { return }
persistenceManager.numberOfActivations += 1
switch phase {
case .active:
persistenceManager.numberOfActivations += 1
case .background:
WidgetCenter.shared.reloadAllTimelines()
default:
break
}
}
#if os(visionOS)
.defaultSize(
Expand Down
12 changes: 10 additions & 2 deletions ShotbotCore/Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ let package = Package(
.library(name: "Purchases", targets: ["Purchases"]),
.library(name: "MediaManager", targets: ["MediaManager"]),
.library(name: "SettingsFeature", targets: ["SettingsFeature"]),
.library(name: "SBFoundation", targets: ["SBFoundation"])
.library(name: "SBFoundation", targets: ["SBFoundation"]),
.library(name: "WidgetFeature", targets: ["WidgetFeature"]),
],
dependencies: [
.package(
Expand Down Expand Up @@ -57,6 +58,7 @@ let package = Package(
"Purchases",
"MediaManager",
"SBFoundation",
"WidgetFeature",
.product(name: "AlertToast", package: "AlertToast")
]
),
Expand Down Expand Up @@ -96,6 +98,12 @@ let package = Package(
dependencies: [
"Models"
]
)
),
.target(
name: "WidgetFeature",
dependencies: [
.product(name: "CollectionConcurrencyKit", package: "CollectionConcurrencyKit"),
]
),
]
)
7 changes: 4 additions & 3 deletions ShotbotCore/Sources/AppFeature/AppTabNavigation.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,21 @@
//

import SwiftUI
import Models
import HomeFeature
import SettingsFeature

public struct AppTabNavigation: View {
@State private var tabSelection = Tab.home
@EnvironmentObject var tabManager: TabManager

// MARK: - Initializer

public init() {}

// MARK: - Body

public var body: some View {
TabView(selection: $tabSelection) {
TabView(selection: $tabManager.selectedTab) {
NavigationView {
HomeView(viewModel: .init())
}
Expand Down
115 changes: 115 additions & 0 deletions ShotbotCore/Sources/HomeFeature/AutoCRUDManager.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
//
// AutoCRUDManager.swift
// ShotbotCore
//
// Created by Richard Witherspoon on 7/24/24.
//

import SwiftUI
import Persistence
import OSLog
import MediaManager
import SBFoundation
import PhotosUI
import Models

public protocol AutoCRUDManaging {
func autoSaveIndividualImagesIfNeeded(
using shareableImages: [ShareableImage],
autoSave: @escaping ()-> Void
) async throws

func autoSaveCombinedIfNeeded(using combinedURL: URL?) async throws
func autoDeleteScreenshotsIfNeeded(items: [PhotosPickerItem]) async
}

/// An object thats responsible for auto saving individual and combined images as
/// well as auto deleting screenshots. All actions are only applicable with
/// certain user settings enabled.
public struct AutoCRUDManager: AutoCRUDManaging {
private var persistenceManager: any PersistenceManaging
private let logger = Logger(category: AutoCRUDManager.self)
private let clock: any Clock<Duration>
private let photoLibraryManager: PhotoLibraryManager
private let fileManager: any FileManaging

var canAutoSave: Bool {
persistenceManager.autoSaveToFiles || persistenceManager.autoSaveToPhotos
}

// MARK: - Initializer

public init(
persistenceManager: any PersistenceManaging = PersistenceManager.shared,
clock: any Clock<Duration> = ContinuousClock(),
photoLibraryManager: PhotoLibraryManager = .live,
fileManager: any FileManaging = FileManager.default
) {
self.persistenceManager = persistenceManager
self.clock = clock
self.photoLibraryManager = photoLibraryManager
self.fileManager = fileManager
}

/// Shows the `showAutoSaveToast` if the user has `autoSaveToFiles` or `autoSaveToPhotos` enabled
///
/// Using a slight delay in order to make the UI less jarring
public func autoSaveIndividualImagesIfNeeded(
using shareableImages: [ShareableImage],
autoSave: @escaping ()-> Void
) async throws {
guard canAutoSave else { return }

do {
for shareableImage in shareableImages {
if persistenceManager.autoSaveToFiles {
try fileManager.copyToiCloudFiles(from: shareableImage.url)
logger.info("Saving to iCloud.")
}

if persistenceManager.autoSaveToPhotos {
try await photoLibraryManager.savePhoto(shareableImage.url)
logger.info("Saving to Photo library.")
}
}

try await clock.sleep(for: .seconds(0.75))
autoSave()
try await clock.sleep(for: .seconds(0.75))
} catch {
logger.info("An autosave error occurred: \(error.localizedDescription, privacy: .public).")
throw error
}
}

/// Autosaves the combined image to photos and iCloud if the user has `autoSaveToFiles` and/or `autoSaveToPhotos` enabled
public func autoSaveCombinedIfNeeded(using combinedURL: URL?) async throws {
guard let combinedURL, canAutoSave else {
return
}

do {
if persistenceManager.autoSaveToFiles {
try fileManager.copyToiCloudFiles(from: combinedURL)
logger.info("Saving combined image to iCloud.")
}

if persistenceManager.autoSaveToPhotos {
try await photoLibraryManager.savePhoto(combinedURL)
logger.info("Saving combined image to Photo library.")
}
} catch {
logger.info("An autosave error occurred for the combined image: \(error.localizedDescription, privacy: .public).")
throw error
}
}

/// Asks the user to confirm deleting the selected photos from the photo library if this
/// setting is enabled.
public func autoDeleteScreenshotsIfNeeded(items: [PhotosPickerItem]) async {
guard persistenceManager.autoDeleteScreenshots else { return }
let ids = items.compactMap(\.itemIdentifier)
try? await photoLibraryManager.delete(ids)
logger.notice("Deleting \(ids.count, privacy: .public) images.")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,9 @@ import MediaManager

public struct HomeView: View {
@StateObject var viewModel = HomeViewModel()
@EnvironmentObject var tabManager: TabManager
@Environment(\.scenePhase) var scenePhase

// MARK: - Initializer

public init(viewModel: HomeViewModel) {
Expand Down Expand Up @@ -102,14 +103,16 @@ public struct HomeView: View {
}
.task {
await viewModel.requestPhotoLibraryAdditionAuthorization()
await viewModel.changeImageQualityIfNeeded()
}
.onChange(of: scenePhase) { newValue in
guard newValue == .background || newValue == .active else { return }
viewModel.clearImagesOnAppBackground()
}
.onAppear {
.onOpenURL { url in
tabManager.selectedTab = .home
Task {
await viewModel.changeImageQualityIfNeeded()
await viewModel.didOpenViaDeepLink(url)
}
}
.sheet(isPresented: $viewModel.showPurchaseView) {
Expand Down
Loading

0 comments on commit 4ac0327

Please sign in to comment.