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 */; };
|
80B3AC6628583CBD00CB7B31 /* GrabooTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80B3AC6528583CBD00CB7B31 /* GrabooTests.swift */; };
|
||||||
80B3AC7028583CBD00CB7B31 /* GrabooUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80B3AC6F28583CBD00CB7B31 /* GrabooUITests.swift */; };
|
80B3AC7028583CBD00CB7B31 /* GrabooUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80B3AC6F28583CBD00CB7B31 /* GrabooUITests.swift */; };
|
||||||
80B3AC7228583CBD00CB7B31 /* GrabooUITestsLaunchTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80B3AC7128583CBD00CB7B31 /* GrabooUITestsLaunchTests.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 */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
/* Begin PBXContainerItemProxy 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; };
|
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>"; };
|
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>"; };
|
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 */
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
/* Begin PBXFrameworksBuildPhase section */
|
/* Begin PBXFrameworksBuildPhase section */
|
||||||
@ -94,6 +96,7 @@
|
|||||||
80B3AC5328583CBB00CB7B31 /* Graboo */ = {
|
80B3AC5328583CBB00CB7B31 /* Graboo */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
80B3AC7E28584E2100CB7B31 /* lib */,
|
||||||
80B3AC5428583CBB00CB7B31 /* GrabooApp.swift */,
|
80B3AC5428583CBB00CB7B31 /* GrabooApp.swift */,
|
||||||
80B3AC5628583CBB00CB7B31 /* ContentView.swift */,
|
80B3AC5628583CBB00CB7B31 /* ContentView.swift */,
|
||||||
80B3AC5828583CBD00CB7B31 /* Assets.xcassets */,
|
80B3AC5828583CBD00CB7B31 /* Assets.xcassets */,
|
||||||
@ -127,6 +130,14 @@
|
|||||||
path = GrabooUITests;
|
path = GrabooUITests;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
80B3AC7E28584E2100CB7B31 /* lib */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
80B3AC7F28584E3700CB7B31 /* Client.swift */,
|
||||||
|
);
|
||||||
|
path = lib;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
/* End PBXGroup section */
|
/* End PBXGroup section */
|
||||||
|
|
||||||
/* Begin PBXNativeTarget section */
|
/* Begin PBXNativeTarget section */
|
||||||
@ -259,6 +270,7 @@
|
|||||||
files = (
|
files = (
|
||||||
80B3AC5728583CBB00CB7B31 /* ContentView.swift in Sources */,
|
80B3AC5728583CBB00CB7B31 /* ContentView.swift in Sources */,
|
||||||
80B3AC5528583CBB00CB7B31 /* GrabooApp.swift in Sources */,
|
80B3AC5528583CBB00CB7B31 /* GrabooApp.swift in Sources */,
|
||||||
|
80B3AC8028584E3700CB7B31 /* Client.swift in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
@ -427,7 +439,7 @@
|
|||||||
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
|
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
|
||||||
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
|
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
|
||||||
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
|
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
@ -457,7 +469,7 @@
|
|||||||
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
|
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
|
||||||
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
|
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
|
||||||
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
|
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
|
@ -7,15 +7,59 @@
|
|||||||
|
|
||||||
import SwiftUI
|
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 {
|
struct ContentView: View {
|
||||||
|
|
||||||
|
@EnvironmentObject var model: ModelData
|
||||||
|
|
||||||
|
let cols = [
|
||||||
|
GridItem(.flexible()),
|
||||||
|
GridItem(.flexible()),
|
||||||
|
GridItem(.flexible()),
|
||||||
|
]
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
Text("Hello, world!")
|
NavigationView {
|
||||||
.padding()
|
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 {
|
struct ContentView_Previews: PreviewProvider {
|
||||||
|
|
||||||
static var previews: some View {
|
static var previews: some View {
|
||||||
ContentView()
|
ContentView()
|
||||||
|
.environmentObject(ModelData(searchTerms: ["hatsune_miku", "rating:general"]))
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,7 @@ struct GrabooApp: App {
|
|||||||
var body: some Scene {
|
var body: some Scene {
|
||||||
WindowGroup {
|
WindowGroup {
|
||||||
ContentView()
|
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