Skip to content

Commit

Permalink
feat: sprite preview on long press
Browse files Browse the repository at this point in the history
  • Loading branch information
castdrian committed Jun 22, 2024
1 parent 4bd59a7 commit 860d592
Show file tree
Hide file tree
Showing 3 changed files with 146 additions and 4 deletions.
4 changes: 4 additions & 0 deletions CoreDex.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
objects = {

/* Begin PBXBuildFile section */
3A2F99112C27698E0098F106 /* DocumentInteractionController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A2F99102C27698E0098F106 /* DocumentInteractionController.swift */; };
3A3C38092B8CD67E006E5CDE /* ScanButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A3C38082B8CD67E006E5CDE /* ScanButton.swift */; };
3A3C380B2B8CE160006E5CDE /* ScannerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A3C380A2B8CE160006E5CDE /* ScannerViewController.swift */; };
3A3C380D2B8CE1AB006E5CDE /* ScannerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A3C380C2B8CE1AB006E5CDE /* ScannerView.swift */; };
Expand All @@ -30,6 +31,7 @@
/* End PBXBuildFile section */

/* Begin PBXFileReference section */
3A2F99102C27698E0098F106 /* DocumentInteractionController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DocumentInteractionController.swift; sourceTree = "<group>"; };
3A3C38082B8CD67E006E5CDE /* ScanButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScanButton.swift; sourceTree = "<group>"; };
3A3C380A2B8CE160006E5CDE /* ScannerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScannerViewController.swift; sourceTree = "<group>"; };
3A3C380C2B8CE1AB006E5CDE /* ScannerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScannerView.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -142,6 +144,7 @@
3ACEBA362B8B9E8F00BFF4CF /* ColorUtils.swift */,
3ACEBA382B8BD40000BFF4CF /* AudioPlayerDelegate.swift */,
3A3C380A2B8CE160006E5CDE /* ScannerViewController.swift */,
3A2F99102C27698E0098F106 /* DocumentInteractionController.swift */,
);
path = Util;
sourceTree = "<group>";
Expand Down Expand Up @@ -235,6 +238,7 @@
3AB6ED602B8A5B41009B24B4 /* ContentView.swift in Sources */,
3ACEBA372B8B9E8F00BFF4CF /* ColorUtils.swift in Sources */,
3A3C38152B8FAE31006E5CDE /* Dex.mlmodel in Sources */,
3A2F99112C27698E0098F106 /* DocumentInteractionController.swift in Sources */,
3AB6ED8D2B8A924E009B24B4 /* ImagePredictor.swift in Sources */,
3AB6ED5E2B8A5B41009B24B4 /* CoreDexApp.swift in Sources */,
3ACEBA392B8BD40000BFF4CF /* AudioPlayerDelegate.swift in Sources */,
Expand Down
61 changes: 61 additions & 0 deletions CoreDex/Util/DocumentInteractionController.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
//
// DocumentInteractionController.swift
// CoreDex
//
// Created by Adrian Castro on 22.06.24.
//

import SwiftUI
import UIKit

struct DocumentInteractionController: UIViewControllerRepresentable {
let url: URL

func makeUIViewController(context: Context) -> UIViewController {
let viewController = UIViewController()
DispatchQueue.main.async {
let documentInteractionController = UIDocumentInteractionController(url: self.url)
documentInteractionController.delegate = context.coordinator
documentInteractionController.presentPreview(animated: true)
}
return viewController
}

func updateUIViewController(_ uiViewController: UIViewController, context: Context) {
let documentInteractionController = UIDocumentInteractionController(url: url)
documentInteractionController.delegate = context.coordinator
documentInteractionController.presentPreview(animated: true)

if let rootVC = uiViewController.presentingViewController {
documentInteractionController.presentOptionsMenu(from: rootVC.view.bounds, in: rootVC.view, animated: true)
}
}

func makeCoordinator() -> Coordinator {
Coordinator(self)
}

class Coordinator: NSObject, UIDocumentInteractionControllerDelegate {
var parent: DocumentInteractionController

init(_ parent: DocumentInteractionController) {
self.parent = parent
}

func documentInteractionControllerViewControllerForPreview(_ controller: UIDocumentInteractionController) -> UIViewController {
guard let scene = UIApplication.shared.connectedScenes.first as? UIWindowScene,
let rootViewController = scene.windows.first?.rootViewController else {
fatalError("Unable to find the root view controller")
}
return rootViewController
}

func documentInteractionControllerDidEndPreview(_ controller: UIDocumentInteractionController) {
do {
try FileManager.default.removeItem(at: parent.url)
} catch {
print("Error removing temporary file: \(error)")
}
}
}
}
85 changes: 81 additions & 4 deletions CoreDex/Views/DexEntryView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,25 @@ struct StatInfo: Identifiable {
var color: Color
}

struct ActivityViewController: UIViewControllerRepresentable {
let activityItems: [Any]
let applicationActivities: [UIActivity]? = nil

func makeUIViewController(context: UIViewControllerRepresentableContext<ActivityViewController>) -> UIActivityViewController {
return UIActivityViewController(activityItems: activityItems, applicationActivities: applicationActivities)
}

func updateUIViewController(_ uiViewController: UIActivityViewController, context: UIViewControllerRepresentableContext<ActivityViewController>) {}
}

struct SpriteView: View {
let spriteURL: String
let shinySpriteURL: String
@Binding var showShinySprite: Bool
var playPokemonCry: () -> Void

@State private var documentURL: URL?
@State private var isLoading = false

var body: some View {
HStack {
KFAnimatedImage(URL(string: showShinySprite ? shinySpriteURL : spriteURL))
Expand All @@ -60,6 +73,66 @@ struct SpriteView: View {
showShinySprite.toggle()
}
}
.onLongPressGesture {
let generator = UIImpactFeedbackGenerator(style: .medium)
generator.impactOccurred()

loadImageData()
}
.background(
Group {
if documentURL != nil {
DocumentInteractionController(url: documentURL!)
.onAppear {
documentURL = nil
}
}
}
)
.overlay {
if isLoading {
ProgressView("Loading...")
}
}
}

private func loadImageData() {
isLoading = true
guard let imageURL = URL(string: showShinySprite ? shinySpriteURL : spriteURL) else {
isLoading = false
return
}

URLSession.shared.dataTask(with: imageURL) { data, response, error in
DispatchQueue.main.async {
isLoading = false
}
guard let data = data, error == nil else {
print("Error loading image data: \(String(describing: error))")
return
}

let tempURL = saveImageToTemporaryDirectory(imageData: data)

DispatchQueue.main.async {
if let tempURL = tempURL {
documentURL = tempURL
}
}
}.resume()
}

private func saveImageToTemporaryDirectory(imageData: Data) -> URL? {
let tempDirectory = FileManager.default.temporaryDirectory
let tempURL = tempDirectory.appendingPathComponent(UUID().uuidString).appendingPathExtension("gif")

do {
try imageData.write(to: tempURL)
return tempURL
} catch {
print("Error saving image to temporary directory: \(error)")
return nil
}
}
}

Expand All @@ -70,7 +143,8 @@ struct DexEntryView: View {
@State private var audioPlayerDelegate = AudioPlayerDelegate()
@State private var showShinySprite = false
@State private var selectedAbilityIndex = 0

@State private var hasAppeared = false

var body: some View {
ScrollView {
VStack(alignment: .leading, spacing: 10) {
Expand All @@ -84,8 +158,11 @@ struct DexEntryView: View {
}
.navigationBarTitle(Text("\(pokemon.species.capitalized) #\(pokemon.num)"), displayMode: .inline)
.onAppear {
playPokemonCry() {
readDexEntry()
if !hasAppeared {
playPokemonCry() {
readDexEntry()
}
hasAppeared = true
}
}
.onDisappear {
Expand Down

0 comments on commit 860d592

Please sign in to comment.