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

Feature: visionOS support #189

Closed
wants to merge 9 commits into from
27 changes: 6 additions & 21 deletions MedoDelirioBrasilia.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -1090,7 +1090,6 @@
D992146F2A8F21C2004E82BC /* RecurringDonationBanner.swift in Sources */ = {isa = PBXBuildFile; fileRef = D992146E2A8F21C2004E82BC /* RecurringDonationBanner.swift */; };
D9943F152863CC4D002C6B97 /* A impiedosa justica de Deus.mp3 in Resources */ = {isa = PBXBuildFile; fileRef = D9943F142863CC4D002C6B97 /* A impiedosa justica de Deus.mp3 */; };
D9943F172863DAE1002C6B97 /* FolderDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D9943F162863DAE1002C6B97 /* FolderDetailView.swift */; };
D9943F1A286406AF002C6B97 /* Kingfisher in Frameworks */ = {isa = PBXBuildFile; productRef = D9943F19286406AF002C6B97 /* Kingfisher */; };
D9943F1C28641917002C6B97 /* LocalDatabase+Favorite.swift in Sources */ = {isa = PBXBuildFile; fileRef = D9943F1B28641917002C6B97 /* LocalDatabase+Favorite.swift */; };
D9943F1E286419C2002C6B97 /* LocalDatabase+TopChart.swift in Sources */ = {isa = PBXBuildFile; fileRef = D9943F1D286419C2002C6B97 /* LocalDatabase+TopChart.swift */; };
D9943F20286419CE002C6B97 /* LocalDatabase+Statistic.swift in Sources */ = {isa = PBXBuildFile; fileRef = D9943F1F286419CE002C6B97 /* LocalDatabase+Statistic.swift */; };
Expand Down Expand Up @@ -2823,7 +2822,6 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
D9943F1A286406AF002C6B97 /* Kingfisher in Frameworks */,
D9E69592283D2E2C00C341B2 /* SQLite in Frameworks */,
D94656D928450535008B4785 /* SQLiteMigrationManager in Frameworks */,
);
Expand Down Expand Up @@ -4769,7 +4767,6 @@
packageProductDependencies = (
D9E69591283D2E2C00C341B2 /* SQLite */,
D94656D828450535008B4785 /* SQLiteMigrationManager */,
D9943F19286406AF002C6B97 /* Kingfisher */,
);
productName = MedoDelirioBrasilia;
productReference = D9625E7A28238F9A00080852 /* MedoDelirio.app */;
Expand Down Expand Up @@ -4825,7 +4822,6 @@
packageReferences = (
D9E69590283D2E2C00C341B2 /* XCRemoteSwiftPackageReference "SQLite" */,
D94656D728450535008B4785 /* XCRemoteSwiftPackageReference "SQLiteMigrationManager" */,
D9943F18286406AF002C6B97 /* XCRemoteSwiftPackageReference "Kingfisher" */,
);
productRefGroup = D9625E7B28238F9A00080852 /* Products */;
projectDirPath = "";
Expand Down Expand Up @@ -6426,9 +6422,10 @@
MARKETING_VERSION = 6.38;
PRODUCT_BUNDLE_IDENTIFIER = com.rafaelschmitt.MedoDelirioBrasilia;
PRODUCT_NAME = MedoDelirio;
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator xros xrsimulator";
SUPPORTS_MACCATALYST = NO;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
Expand Down Expand Up @@ -6466,9 +6463,10 @@
MARKETING_VERSION = 6.38;
PRODUCT_BUNDLE_IDENTIFIER = com.rafaelschmitt.MedoDelirioBrasilia;
PRODUCT_NAME = MedoDelirio;
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator xros xrsimulator";
SUPPORTS_MACCATALYST = NO;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
Expand Down Expand Up @@ -6562,14 +6560,6 @@
minimumVersion = 0.8.0;
};
};
D9943F18286406AF002C6B97 /* XCRemoteSwiftPackageReference "Kingfisher" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/onevcat/Kingfisher";
requirement = {
kind = upToNextMajorVersion;
minimumVersion = 7.3.2;
};
};
D9E69590283D2E2C00C341B2 /* XCRemoteSwiftPackageReference "SQLite" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/stephencelis/SQLite.swift";
Expand All @@ -6586,11 +6576,6 @@
package = D94656D728450535008B4785 /* XCRemoteSwiftPackageReference "SQLiteMigrationManager" */;
productName = SQLiteMigrationManager;
};
D9943F19286406AF002C6B97 /* Kingfisher */ = {
isa = XCSwiftPackageProductDependency;
package = D9943F18286406AF002C6B97 /* XCRemoteSwiftPackageReference "Kingfisher" */;
productName = Kingfisher;
};
D9E69591283D2E2C00C341B2 /* SQLite */ = {
isa = XCSwiftPackageProductDependency;
package = D9E69590283D2E2C00C341B2 /* XCRemoteSwiftPackageReference "SQLite" */;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,5 @@
{
"pins" : [
{
"identity" : "kingfisher",
"kind" : "remoteSourceControl",
"location" : "https://github.com/onevcat/Kingfisher",
"state" : {
"revision" : "c1f60c63f356d364f4284ba82961acbe7de79bcc",
"version" : "7.8.1"
}
},
{
"identity" : "sqlite.swift",
"kind" : "remoteSourceControl",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ class AppDelegate: NSObject, UIApplicationDelegate {
prepareAudioPlayerOnMac()
collectTelemetry()

print(UIDevice.current.systemName)
print(ProcessInfo.processInfo.isiOSAppOnMac)

return true
}

Expand Down
14 changes: 9 additions & 5 deletions MedoDelirioBrasilia/Sources/Extensions/UIDevice+Extensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@ import UIKit
extension UIDevice {

static var is4InchDevice: Bool {
guard UIDevice.current.userInterfaceIdiom == .phone else {
return false
}
return UIScreen.main.bounds.width == 320
// guard UIDevice.current.userInterfaceIdiom == .phone else {
// return false
// }
// return UIScreen.main.bounds.width == 320
return false
}

static var isiPadMini: Bool {
Expand Down Expand Up @@ -103,11 +104,14 @@ public extension UIDevice {
case "iPad8,11", "iPad8,12": return "iPad Pro (12.9-inch) (4th generation)"
case "iPad13,8", "iPad13,9", "iPad13,10", "iPad13,11": return "iPad Pro (12.9-inch) (5th generation)"
case "iPad14,5", "iPad14,6": return "iPad Pro (12.9-inch) (6th generation)"
case "RealityDevice14,1": return "Apple Vision Pro"
case "i386", "x86_64", "arm64": return "Simulator \(mapToDevice(identifier: ProcessInfo().environment["SIMULATOR_MODEL_IDENTIFIER"] ?? "iOS"))"
default: return identifier
}
#endif

#if os(visionOS)
return "Apple Vision Pro"
#endif
}

return mapToDevice(identifier: identifier)
Expand Down
8 changes: 8 additions & 0 deletions MedoDelirioBrasilia/Sources/Helpers/TapticHelper.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,31 @@ import UIKit
class TapticFeedback {

static func success() {
#if !os (xrOS)
let generator = UINotificationFeedbackGenerator()
generator.notificationOccurred(.success)
#endif
}

static func warning() {
#if !os (xrOS)
let generator = UINotificationFeedbackGenerator()
generator.notificationOccurred(.warning)
#endif
}

static func error() {
#if !os (xrOS)
let generator = UINotificationFeedbackGenerator()
generator.notificationOccurred(.error)
#endif
}

static func open() {
#if !os (xrOS)
let generator = UIImpactFeedbackGenerator(style: .medium)
generator.impactOccurred()
#endif
}

}
103 changes: 3 additions & 100 deletions MedoDelirioBrasilia/Sources/Helpers/VideoMaker.swift
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,8 @@ class VideoMaker {
let textColor = UIColor.black
let textFont = UIFont.systemFont(ofSize: 72, weight: .bold)

let scale = UIScreen.main.scale
UIGraphicsBeginImageContextWithOptions(image.size, false, scale)
//let scale = UIScreen.main.scale
UIGraphicsBeginImageContextWithOptions(image.size, false, 1.0)

let textFontAttributes = [
NSAttributedString.Key.font: textFont,
Expand All @@ -79,104 +79,7 @@ class VideoMaker {
exportType: IntendedVideoDestination,
success: @escaping ((URL) -> Void),
failure: @escaping ((Error?) -> Void)) {
let mixComposition: AVMutableComposition = AVMutableComposition()
var mutableCompositionVideoTrack: [AVMutableCompositionTrack] = []
var mutableCompositionAudioTrack: [AVMutableCompositionTrack] = []
let totalVideoCompositionInstruction: AVMutableVideoCompositionInstruction = AVMutableVideoCompositionInstruction()

let aVideoAsset: AVAsset = AVAsset(url: videoUrl)
let aAudioAsset: AVAsset = AVAsset(url: audioUrl)

if let videoTrack = mixComposition.addMutableTrack(withMediaType: .video, preferredTrackID: kCMPersistentTrackID_Invalid), let audioTrack = mixComposition.addMutableTrack(withMediaType: .audio, preferredTrackID: kCMPersistentTrackID_Invalid) {
mutableCompositionVideoTrack.append(videoTrack)
mutableCompositionAudioTrack.append(audioTrack)

if let aVideoAssetTrack: AVAssetTrack = aVideoAsset.tracks(withMediaType: .video).first, let aAudioAssetTrack: AVAssetTrack = aAudioAsset.tracks(withMediaType: .audio).first {
do {
try mutableCompositionVideoTrack.first?.insertTimeRange(CMTimeRangeMake(start: CMTime.zero, duration: aVideoAssetTrack.timeRange.duration), of: aVideoAssetTrack, at: CMTime.zero)

let videoDuration = aVideoAsset.duration
if CMTimeCompare(videoDuration, aAudioAsset.duration) == -1 {
try mutableCompositionAudioTrack.first?.insertTimeRange(CMTimeRangeMake(start: CMTime.zero, duration: aVideoAssetTrack.timeRange.duration), of: aAudioAssetTrack, at: CMTime.zero)
} else if CMTimeCompare(videoDuration, aAudioAsset.duration) == 1 {
var currentTime = CMTime.zero
while true {
var audioDuration = aAudioAsset.duration
let totalDuration = CMTimeAdd(currentTime, audioDuration)
if CMTimeCompare(totalDuration, videoDuration) == 1 {
audioDuration = CMTimeSubtract(totalDuration, videoDuration)
}
try mutableCompositionAudioTrack.first?.insertTimeRange(CMTimeRangeMake(start: CMTime.zero, duration: aVideoAssetTrack.timeRange.duration), of: aAudioAssetTrack, at: currentTime)

currentTime = CMTimeAdd(currentTime, audioDuration)
if CMTimeCompare(currentTime, videoDuration) == 1 || CMTimeCompare(currentTime, videoDuration) == 0 {
break
}
}
}
videoTrack.preferredTransform = aVideoAssetTrack.preferredTransform
} catch {
print(error)
}

totalVideoCompositionInstruction.timeRange = CMTimeRangeMake(start: CMTime.zero, duration: aVideoAssetTrack.timeRange.duration)
}
}

let mutableVideoComposition: AVMutableVideoComposition = AVMutableVideoComposition()
mutableVideoComposition.frameDuration = CMTimeMake(value: 1, timescale: 30)

var videoWidth: Int = 0
var videoHeight: Int = 0

if exportType == IntendedVideoDestination.twitter {
videoWidth = 1000
videoHeight = 1000
} else {
videoWidth = 1080
videoHeight = 1920
}

mutableVideoComposition.renderSize = CGSize(width: videoWidth, height: videoHeight)

if let documentsPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first {
let outputURL = URL(fileURLWithPath: documentsPath).appendingPathComponent("\(videoName).mov")

do {
if FileManager.default.fileExists(atPath: outputURL.path) {
try FileManager.default.removeItem(at: outputURL)
}
} catch {
print("Could not remove file: \(error.localizedDescription)")
}

if let exportSession = AVAssetExportSession(asset: mixComposition, presetName: AVAssetExportPresetHighestQuality) {
exportSession.outputURL = outputURL
exportSession.outputFileType = AVFileType.mp4
exportSession.shouldOptimizeForNetworkUse = true

// try to export the file and handle the status cases
exportSession.exportAsynchronously(completionHandler: {
switch exportSession.status {
case .failed:
if let error = exportSession.error {
failure(error)
}

case .cancelled:
if let error = exportSession.error {
failure(error)
}

default:
print("finished")
success(outputURL)
}
})
} else {
failure(nil)
}
}
return
}

static func createVideo(fromImage image: UIImage,
Expand Down
32 changes: 16 additions & 16 deletions MedoDelirioBrasilia/Sources/Views/Authors/AuthorCell.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
//

import SwiftUI
import Kingfisher
//import Kingfisher

struct AuthorCell: View {

Expand All @@ -23,21 +23,21 @@ struct AuthorCell: View {
.opacity(colorScheme == .dark ? 0.25 : 0.15)

HStack {
if authorImageURL.isEmpty == false {
KFImage(URL(string: authorImageURL))
.placeholder {
Image(systemName: "person.circle")
.resizable()
.scaledToFit()
.frame(height: 50)
.foregroundColor(.gray)
.opacity(0.3)
}
.resizable()
.scaledToFit()
.frame(width: 55)
.clipShape(Circle())
}
// if authorImageURL.isEmpty == false {
// KFImage(URL(string: authorImageURL))
// .placeholder {
// Image(systemName: "person.circle")
// .resizable()
// .scaledToFit()
// .frame(height: 50)
// .foregroundColor(.gray)
// .opacity(0.3)
// }
// .resizable()
// .scaledToFit()
// .frame(width: 55)
// .clipShape(Circle())
// }

VStack(alignment: .leading, spacing: 8) {
Text(authorName)
Expand Down
38 changes: 19 additions & 19 deletions MedoDelirioBrasilia/Sources/Views/Authors/AuthorDetailView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
//

import SwiftUI
import Kingfisher
//import Kingfisher

struct AuthorDetailView: View {

Expand Down Expand Up @@ -113,24 +113,24 @@ struct AuthorDetailView: View {
} else {
GeometryReader { scrollViewGeometry in
ScrollView {
if author.photo != nil {
GeometryReader { headerPhotoGeometry in
KFImage(URL(string: author.photo ?? .empty))
.placeholder {
Image(systemName: "photo.on.rectangle")
.resizable()
.scaledToFit()
.frame(height: 100)
.foregroundColor(.gray)
.opacity(0.3)
}
.resizable()
.scaledToFill()
.frame(width: headerPhotoGeometry.size.width, height: self.getHeightForHeaderImage(headerPhotoGeometry))
.clipped()
.offset(x: 0, y: self.getOffsetForHeaderImage(headerPhotoGeometry))
}.frame(height: 250)
}
// if author.photo != nil {
// GeometryReader { headerPhotoGeometry in
// KFImage(URL(string: author.photo ?? .empty))
// .placeholder {
// Image(systemName: "photo.on.rectangle")
// .resizable()
// .scaledToFit()
// .frame(height: 100)
// .foregroundColor(.gray)
// .opacity(0.3)
// }
// .resizable()
// .scaledToFill()
// .frame(width: headerPhotoGeometry.size.width, height: self.getHeightForHeaderImage(headerPhotoGeometry))
// .clipped()
// .offset(x: 0, y: self.getOffsetForHeaderImage(headerPhotoGeometry))
// }.frame(height: 250)
// }

VStack(alignment: .leading, spacing: 15) {
HStack {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ struct AuthorsView: View {
LazyVGrid(columns: columns, spacing: 20) {
if searchResults.isEmpty {
NoSearchResultsView(searchText: $searchText)
.padding(.vertical, UIScreen.main.bounds.height / 4)
//.padding(.vertical, UIScreen.main.bounds.height / 4)
} else {
ForEach(searchResults) { author in
NavigationLink(destination: AuthorDetailView(viewModel: AuthorDetailViewViewModel(originatingScreenName: searchText.isEmpty ? Shared.ScreenNames.authorsView : "\(Shared.ScreenNames.authorsView)(\(searchText))", authorName: author.name, currentSoundsListMode: $currentSoundsListMode), author: author, currentSoundsListMode: $currentSoundsListMode)) {
Expand Down
Loading