Added Gelbooru viewer
This commit is contained in:
parent
bf71d1d4f3
commit
d00139ba34
@ -14,6 +14,7 @@
|
||||
80B3AC6628583CBD00CB7B31 /* GrabooTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80B3AC6528583CBD00CB7B31 /* GrabooTests.swift */; };
|
||||
80B3AC7028583CBD00CB7B31 /* GrabooUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80B3AC6F28583CBD00CB7B31 /* GrabooUITests.swift */; };
|
||||
80B3AC7228583CBD00CB7B31 /* GrabooUITestsLaunchTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80B3AC7128583CBD00CB7B31 /* GrabooUITestsLaunchTests.swift */; };
|
||||
80B3AC8028584E3700CB7B31 /* Client.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80B3AC7F28584E3700CB7B31 /* Client.swift */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
@ -44,6 +45,7 @@
|
||||
80B3AC6B28583CBD00CB7B31 /* GrabooUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = GrabooUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
80B3AC6F28583CBD00CB7B31 /* GrabooUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GrabooUITests.swift; sourceTree = "<group>"; };
|
||||
80B3AC7128583CBD00CB7B31 /* GrabooUITestsLaunchTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GrabooUITestsLaunchTests.swift; sourceTree = "<group>"; };
|
||||
80B3AC7F28584E3700CB7B31 /* Client.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Client.swift; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
@ -94,6 +96,7 @@
|
||||
80B3AC5328583CBB00CB7B31 /* Graboo */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
80B3AC7E28584E2100CB7B31 /* lib */,
|
||||
80B3AC5428583CBB00CB7B31 /* GrabooApp.swift */,
|
||||
80B3AC5628583CBB00CB7B31 /* ContentView.swift */,
|
||||
80B3AC5828583CBD00CB7B31 /* Assets.xcassets */,
|
||||
@ -127,6 +130,14 @@
|
||||
path = GrabooUITests;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
80B3AC7E28584E2100CB7B31 /* lib */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
80B3AC7F28584E3700CB7B31 /* Client.swift */,
|
||||
);
|
||||
path = lib;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
@ -259,6 +270,7 @@
|
||||
files = (
|
||||
80B3AC5728583CBB00CB7B31 /* ContentView.swift in Sources */,
|
||||
80B3AC5528583CBB00CB7B31 /* GrabooApp.swift in Sources */,
|
||||
80B3AC8028584E3700CB7B31 /* Client.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@ -427,7 +439,7 @@
|
||||
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
|
||||
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
|
||||
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
@ -457,7 +469,7 @@
|
||||
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
|
||||
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
|
||||
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
|
@ -7,15 +7,59 @@
|
||||
|
||||
import SwiftUI
|
||||
|
||||
final class ModelData: ObservableObject {
|
||||
|
||||
@Published private(set) var imgs: [GelbooruImage] = []
|
||||
var searchTerms: [String]
|
||||
|
||||
init(searchTerms: [String]) {
|
||||
self.searchTerms = searchTerms
|
||||
GelbooruClient().searchTagImages(tags: searchTerms) { data, error in
|
||||
self.imgs = error != nil ? [] : data!
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
struct ContentView: View {
|
||||
|
||||
@EnvironmentObject var model: ModelData
|
||||
|
||||
let cols = [
|
||||
GridItem(.flexible()),
|
||||
GridItem(.flexible()),
|
||||
GridItem(.flexible()),
|
||||
]
|
||||
|
||||
var body: some View {
|
||||
Text("Hello, world!")
|
||||
.padding()
|
||||
NavigationView {
|
||||
ScrollView {
|
||||
Text(model.searchTerms.joined(separator: ", "))
|
||||
.font(.headline)
|
||||
LazyVGrid(columns: cols, spacing: 10) {
|
||||
ForEach(model.imgs, id: \.self) { pic in
|
||||
VStack {
|
||||
AsyncImage(url: URL(string: pic.sampleUrl)) { image in
|
||||
image.resizable().aspectRatio(contentMode: .fit)
|
||||
} placeholder: {
|
||||
ProgressView()
|
||||
}
|
||||
.frame(width: 100, height: 100 * CGFloat(pic.sampleHeight)/CGFloat(pic.sampleWidth))
|
||||
Text(String(pic.id))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.navigationTitle("Graboo")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct ContentView_Previews: PreviewProvider {
|
||||
|
||||
static var previews: some View {
|
||||
ContentView()
|
||||
.environmentObject(ModelData(searchTerms: ["hatsune_miku", "rating:general"]))
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ struct GrabooApp: App {
|
||||
var body: some Scene {
|
||||
WindowGroup {
|
||||
ContentView()
|
||||
.environmentObject(ModelData(searchTerms: ["hatsune_miku", "rating:general"]))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
65
Graboo/lib/Client.swift
Normal file
65
Graboo/lib/Client.swift
Normal file
@ -0,0 +1,65 @@
|
||||
//
|
||||
// Client.swift
|
||||
// Graboo
|
||||
//
|
||||
// Created by James Shiffer on 6/13/22.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
struct GelbooruSearchResults: Decodable {
|
||||
let post: [GelbooruImage];
|
||||
}
|
||||
|
||||
struct GelbooruImage: Decodable, Hashable {
|
||||
let id: Int;
|
||||
let fileUrl: String;
|
||||
let width: Int;
|
||||
let height: Int;
|
||||
let previewWidth: Int;
|
||||
let previewUrl: String;
|
||||
let previewHeight: Int;
|
||||
let sampleUrl: String;
|
||||
let sampleWidth: Int;
|
||||
let sampleHeight: Int;
|
||||
let tags: String;
|
||||
let rating: String;
|
||||
}
|
||||
|
||||
class GelbooruClient {
|
||||
let baseUrl: String
|
||||
|
||||
init(baseUrl: String = "https://gelbooru.com") {
|
||||
self.baseUrl = baseUrl
|
||||
}
|
||||
|
||||
func searchTagImages(tags: [String], completionHandler: @escaping ([GelbooruImage]?, Error?) -> Void) {
|
||||
let joinedTags = tags.joined(separator: " ").addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)!
|
||||
let url = URL(string: String(format: "%@/?page=dapi&s=post&q=index&json=1&tags=%@", self.baseUrl, joinedTags))!
|
||||
let task = URLSession.shared.dataTask(with: url) { (data, _, error) in
|
||||
guard let data = data, error == nil else {
|
||||
DispatchQueue.main.async {
|
||||
completionHandler(nil, error)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
let parser = JSONDecoder()
|
||||
parser.keyDecodingStrategy = .convertFromSnakeCase
|
||||
var searchResults: GelbooruSearchResults
|
||||
do {
|
||||
searchResults = try parser.decode(GelbooruSearchResults.self, from: data)
|
||||
} catch let e {
|
||||
DispatchQueue.main.async {
|
||||
completionHandler(nil, e)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
DispatchQueue.main.async {
|
||||
completionHandler(searchResults.post, nil)
|
||||
}
|
||||
}
|
||||
task.resume()
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user