Skip to content

Commit

Permalink
Merge pull request #1 from just1103/search
Browse files Browse the repository at this point in the history
네트워크 및 목록 화면을 구현했습니다.
  • Loading branch information
just1103 authored Aug 2, 2022
2 parents d77ecca + 266f452 commit 1a4d88f
Show file tree
Hide file tree
Showing 24 changed files with 1,088 additions and 81 deletions.
114 changes: 110 additions & 4 deletions BookFinder.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion BookFinder/App/SceneDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
window?.makeKeyAndVisible()

let navigationController = UINavigationController()
navigationController.view.backgroundColor = .white
// navigationController.view.backgroundColor = .white
window?.rootViewController = navigationController

appCoordinator = AppCoordinator(navigationController: navigationController)
Expand Down
8 changes: 4 additions & 4 deletions BookFinder/Data/RemoteDB/BookFinderURL.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,19 @@ struct BookFinderURL {
let method: HttpMethod = .get

init(
keywords: String,
searchText: String,
pageNumber: Int = 1,
itemPerPage: Int = 20,
baseURL: String = baseURL
) {
let itemPerPage = 10
let startIndex = (pageNumber - 1) * itemPerPage

var urlComponents = URLComponents(string: "\(baseURL)volumes?")
let keywordsForTitleOrAuthorsQuery = URLQueryItem(name: "q", value: "\(keywords)") // TODO: 검색 구체화 (제목, 저자로 항목 한정)
let searchTextQuery = URLQueryItem(name: "q", value: "\(searchText)") // TODO: 검색 구체화 (제목, 저자로 항목 한정)
let startIndexQuery = URLQueryItem(name: "startIndex", value: "\(startIndex)")
let maxResultsQuery = URLQueryItem(name: "maxResults", value: "\(itemPerPage)")
urlComponents?.queryItems?.append(
contentsOf: [keywordsForTitleOrAuthorsQuery, startIndexQuery, maxResultsQuery]
contentsOf: [searchTextQuery, startIndexQuery, maxResultsQuery]
)

self.url = urlComponents?.url
Expand Down
7 changes: 4 additions & 3 deletions BookFinder/Data/RemoteDB/Entities/VolumeInfoDTO.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,14 @@ struct VolumeInfoDTO: Codable {
let title: String?
let subtitle: String?
let authors: [String]?
let publisher, publishedDate, volumeInfoDescription: String?
let publisher, publishedDate, volumeDescription: String?
let industryIdentifiers: [IndustryIdentifier]?
let readingModes: ReadingModes?
let pageCount: Int?
let printType: String?
let categories: [String]?
let averageRating, ratingsCount: Int?
let averageRating: Double?
let ratingsCount: Int?
let maturityRating: String?
let allowAnonLogging: Bool?
let contentVersion: String?
Expand All @@ -29,7 +30,7 @@ struct VolumeInfoDTO: Codable {

enum CodingKeys: String, CodingKey {
case title, subtitle, authors, publisher, publishedDate
case volumeInfoDescription = "description"
case volumeDescription = "description"
case industryIdentifiers, readingModes, pageCount, printType, categories, averageRating, ratingsCount,
maturityRating, allowAnonLogging, contentVersion, panelizationSummary, imageLinks, language,
previewLink, infoLink, canonicalVolumeLink
Expand Down
13 changes: 0 additions & 13 deletions BookFinder/Data/RemoteDB/NetworkProvider.swift
Original file line number Diff line number Diff line change
Expand Up @@ -48,19 +48,6 @@ struct NetworkProvider {
}
}

// func request(api: Requestable) -> Observable<Data> {
// return Observable.create { emitter in
// guard let task = dataTask(api: api, emitter: emitter) else {
// return Disposables.create()
// }
// task.resume()
//
// return Disposables.create {
// task.cancel()
// }
// }
// }

private func dataTask<T: Codable>(api: APIProtocol, emitter: AnyObserver<T>) -> URLSessionDataTask? {
guard let urlRequest = URLRequest(api: api) else {
emitter.onError(NetworkError.urlIsNil)
Expand Down
14 changes: 14 additions & 0 deletions BookFinder/Extensions/Array+Subscript.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
//
// Array+Subscript.swift
// BookFinder
//
// Created by Hyoju Son on 2022/07/31.
//

import Foundation

extension Array {
subscript(safe index: Int) -> Element? {
return indices ~= index ? self[index] : nil
}
}
16 changes: 16 additions & 0 deletions BookFinder/Extensions/UIColor+CustomColor.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
//
// UIColor+CustomColor.swift
// BookFinder
//
// Created by Hyoju Son on 2022/07/31.
//

import UIKit

extension UIColor {
static let background: UIColor = #colorLiteral(red: 0.9524367452, green: 0.9455882907, blue: 0.9387311935, alpha: 1)
static let lightGreen: UIColor = #colorLiteral(red: 0.5567998886, green: 0.7133290172, blue: 0.6062341332, alpha: 1)
static let darkGreen: UIColor = #colorLiteral(red: 0.137904644, green: 0.3246459067, blue: 0.2771841288, alpha: 1)
static let lightGray = #colorLiteral(red: 0.9137251377, green: 0.9137259126, blue: 0.9309338927, alpha: 1) // light mode의 systemGray6
static let mediumLightGray = #colorLiteral(red: 0.8196074367, green: 0.8196083307, blue: 0.8411096334, alpha: 1) // light mode의 systemGray4
}
39 changes: 39 additions & 0 deletions BookFinder/Extensions/UIImageView+Load+Cache.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
//
// UIImageView+Load+Cache.swift
// BookFinder
//
// Created by Hyoju Son on 2022/07/31.
//

import UIKit

extension UIImageView {
func loadCachedImage(of key: String) {
let cacheKey = NSString(string: key)
if let cachedImage = ImageCacheManager.shared.object(forKey: cacheKey) {
self.image = cachedImage
return
}

DispatchQueue.global().async {
guard
let url = URL(string: key),
var urlCompoentns = URLComponents(url: url, resolvingAgainstBaseURL: false)
else { return }

urlCompoentns.scheme = "https"

guard
let imageURL = urlCompoentns.url,
let imageData = try? Data(contentsOf: imageURL),
let loadedImage = UIImage(data: imageData)
else { return }

ImageCacheManager.shared.setObject(loadedImage, forKey: cacheKey)

DispatchQueue.main.async {
self.image = loadedImage
}
}
}
}
81 changes: 68 additions & 13 deletions BookFinder/Model/BookItem.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,25 +7,80 @@

import Foundation

struct BookItem {
final class BookItem: Hashable {
let id: String

// VolumeInformation
let title: String
let authors: [String]
let publisher: String

let publishedDate: String
let volumeDescription: String
let pageCount: Int?
let categories: [String]?
let averageRating: Int?
let averageRating: Double?
let ratingsCount: Int?
let language: String
let smallThumbnailURL: String // ImageLinks
let thumbnailURL: String
let smallThumbnailURL: String? // ImageLinks

init(
id: String?,
title: String?,
authors: [String]?,
publishedDate: String?,
averageRating: Double?,
ratingsCount: Int?,
smallThumbnailURL: String?
) {
self.id = id ?? "id 정보 없음"
self.title = title ?? "제목 없음"
self.authors = authors ?? ["저자 정보 없음"]
self.publishedDate = publishedDate ?? "출간일 정보 없음"
self.averageRating = averageRating
self.ratingsCount = ratingsCount
self.smallThumbnailURL = smallThumbnailURL // TODO: 정보없음 이미지로 교체
}

static func == (lhs: BookItem, rhs: BookItem) -> Bool {
return lhs.id == rhs.id
}

// TODO: 상세화면 부가기능 고려
// AccessInformation
let isEbookAvailable: Bool // Epub.isAvailable
let istextToSpeechAvailable: Bool // textToSpeechPermission == "ALLOWED"
func hash(into hasher: inout Hasher) {
hasher.combine(id)
}
}

//struct BookItem: Hashable {
// let id: String
//
// // VolumeInformation
// let title: String
// let authors: [String]
// let publisher: String
// let publishedDate: String
// let volumeDescription: String
// let averageRating: Double?
// let ratingsCount: Int?
// let smallThumbnailURL: String // ImageLinks
// let thumbnailURL: String
//
// init(
// id: String?,
// title: String?,
// authors: [String]?,
// publisher: String?,
// publishedDate: String?,
// volumeDescription: String?,
// averageRating: Double?,
// ratingsCount: Int?,
// smallThumbnailURL: String?,
// thumbnailURL: String?
// ) {
// self.id = id ?? "id 정보 없음"
// self.title = title ?? "제목 없음"
// self.authors = authors ?? ["저자 정보 없음"]
// self.publisher = publisher ?? "출판사 정보 없음"
// self.publishedDate = publishedDate ?? "출간일 정보 없음"
// self.volumeDescription = volumeDescription ?? "상세정보 없음"
// self.averageRating = averageRating
// self.ratingsCount = ratingsCount
// self.smallThumbnailURL = smallThumbnailURL ?? "" // TODO: 정보없음 이미지로 교체
// self.thumbnailURL = thumbnailURL ?? ""
// }
//}
14 changes: 0 additions & 14 deletions BookFinder/Model/SearchResult.swift

This file was deleted.

19 changes: 5 additions & 14 deletions BookFinder/Presentation/AppCoordinator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,22 +20,13 @@ final class AppCoordinator: CoordinatorProtocol {

// MARK: - Methods
func start() {
showSearchPage()
showSearchListPage()
}

private func showSearchPage() {
private func showSearchListPage() {
guard let navigationController = navigationController else { return }
// let searchCoordinator = SearchCoordinator(navigationController: navigationController)
// childCoordinators.append(searchCoordinator)
// searchCoordinator.start()
let searchListCoordinator = SearchListCoordinator(navigationController: navigationController)
childCoordinators.append(searchListCoordinator)
searchListCoordinator.start()
}

// func removeFromChildCoordinators(coordinator: CoordinatorProtocol) {
// let updatedChildCoordinators = childCoordinators.filter { $0 !== coordinator }
// childCoordinators = updatedChildCoordinators
// }

// func popCurrentPage() {
// navigationController?.popViewController(animated: true)
// }
}
45 changes: 45 additions & 0 deletions BookFinder/Presentation/SearchListPage/SearchListCoordinator.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
//
// SearchCoordinator.swift
// BookFinder
//
// Created by Hyoju Son on 2022/07/31.
//

import UIKit

final class SearchListCoordinator: CoordinatorProtocol {
// MARK: - Properties
var navigationController: UINavigationController?
var childCoordinators = [CoordinatorProtocol]()
var type: CoordinatorType = .searchList

// MARK: - Initializers
init(navigationController: UINavigationController) {
self.navigationController = navigationController
}

// MARK: - Methods
func start() {
showSearchListPage()
}

private func showSearchListPage() {
guard let navigationController = navigationController else { return }
let searchListViewModel = SearchListViewModel(coordinator: self)
let searchListViewController = SearchListViewController(viewModel: searchListViewModel)

navigationController.pushViewController(searchListViewController, animated: false)
}

func showDetailPage(with bookItem: BookItem) {
guard let navigationController = navigationController else { return }
// let detailCoordinator = DetailCoordinator(navigationController: navigationController)
// childCoordinators.append(detailCoordinator)
// detailCoordinator.start()
}

// func removeFromChildCoordinators(coordinator: CoordinatorProtocol) {
// let updatedChildCoordinators = childCoordinators.filter { $0 !== coordinator }
// childCoordinators = updatedChildCoordinators
// }
}
Loading

0 comments on commit 1a4d88f

Please sign in to comment.