feat: ios mobil arayüz tasarımı
This commit is contained in:
135
ios/Bookibra/Models/BookRemote.swift
Normal file
135
ios/Bookibra/Models/BookRemote.swift
Normal file
@@ -0,0 +1,135 @@
|
||||
import Foundation
|
||||
|
||||
struct BookRemote: Codable, Identifiable, Hashable {
|
||||
var id: String { isbn13 ?? isbn10 ?? title + (authors.first ?? "") }
|
||||
|
||||
let remoteId: String?
|
||||
let title: String
|
||||
let authors: [String]
|
||||
let publishedYear: Int?
|
||||
let isbn10: String?
|
||||
let isbn13: String?
|
||||
let coverImageUrl: URL?
|
||||
let language: String?
|
||||
let description: String?
|
||||
let pageCount: Int?
|
||||
let categories: [String]
|
||||
let publisher: String?
|
||||
let sourceLocale: String?
|
||||
|
||||
init(
|
||||
remoteId: String? = nil,
|
||||
title: String,
|
||||
authors: [String] = [],
|
||||
publishedYear: Int? = nil,
|
||||
isbn10: String? = nil,
|
||||
isbn13: String? = nil,
|
||||
coverImageUrl: URL? = nil,
|
||||
language: String? = nil,
|
||||
description: String? = nil,
|
||||
pageCount: Int? = nil,
|
||||
categories: [String] = [],
|
||||
publisher: String? = nil,
|
||||
sourceLocale: String? = nil
|
||||
) {
|
||||
self.remoteId = remoteId
|
||||
self.title = title
|
||||
self.authors = authors
|
||||
self.publishedYear = publishedYear
|
||||
self.isbn10 = isbn10
|
||||
self.isbn13 = isbn13
|
||||
self.coverImageUrl = coverImageUrl
|
||||
self.language = language
|
||||
self.description = description
|
||||
self.pageCount = pageCount
|
||||
self.categories = categories
|
||||
self.publisher = publisher
|
||||
self.sourceLocale = sourceLocale
|
||||
}
|
||||
}
|
||||
|
||||
struct BookSearchResponse: Decodable {
|
||||
let items: [BookRemote]
|
||||
|
||||
init(from decoder: Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||
|
||||
// Endpoint 1: /isbn returns { data: { tr: {...}, en: {...} } }
|
||||
if let localeMap = try? container.decode([String: RawBook].self, forKey: .data) {
|
||||
self.items = localeMap.map { locale, raw in raw.toBook(locale: locale) }
|
||||
return
|
||||
}
|
||||
|
||||
// Endpoint 2/3: /title and /filter returns { data: [{ locale, items: [...] }] }
|
||||
if let groups = try? container.decode([LocaleGroup].self, forKey: .data) {
|
||||
self.items = groups.flatMap { group in
|
||||
group.items.map { $0.toBook(locale: group.locale) }
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
self.items = []
|
||||
}
|
||||
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case data
|
||||
}
|
||||
}
|
||||
|
||||
private struct LocaleGroup: Decodable {
|
||||
let locale: String
|
||||
let items: [RawBook]
|
||||
}
|
||||
|
||||
private struct RawBook: Decodable {
|
||||
let asin: String?
|
||||
let title: String?
|
||||
let authorName: String?
|
||||
let author: String?
|
||||
let isbn: String?
|
||||
let thumbImage: String?
|
||||
let image: String?
|
||||
let date: String?
|
||||
let publisher: String?
|
||||
let page: Int?
|
||||
let description: String?
|
||||
let categories: [String]?
|
||||
let locale: String?
|
||||
|
||||
func toBook(locale: String?) -> BookRemote {
|
||||
let coverRaw = thumbImage ?? image
|
||||
let authorsText = authorName ?? author ?? ""
|
||||
let authors = authorsText
|
||||
.replacingOccurrences(of: "[Yazar]", with: "")
|
||||
.split(separator: ",")
|
||||
.map { $0.trimmingCharacters(in: .whitespacesAndNewlines) }
|
||||
.filter { !$0.isEmpty }
|
||||
|
||||
let isbnClean = isbn?.filter { $0.isNumber || $0.uppercased() == "X" }
|
||||
let isbn10 = isbnClean?.count == 10 ? isbnClean : nil
|
||||
let isbn13 = isbnClean?.count == 13 ? isbnClean : nil
|
||||
|
||||
return BookRemote(
|
||||
remoteId: asin,
|
||||
title: title ?? "Untitled",
|
||||
authors: authors,
|
||||
publishedYear: Self.extractYear(from: date),
|
||||
isbn10: isbn10,
|
||||
isbn13: isbn13,
|
||||
coverImageUrl: coverRaw.flatMap(URL.init(string:)),
|
||||
language: locale,
|
||||
description: description,
|
||||
pageCount: page,
|
||||
categories: categories ?? [],
|
||||
publisher: publisher,
|
||||
sourceLocale: locale
|
||||
)
|
||||
}
|
||||
|
||||
private static func extractYear(from value: String?) -> Int? {
|
||||
guard let value else { return nil }
|
||||
let digits = value.components(separatedBy: CharacterSet.decimalDigits.inverted).joined()
|
||||
guard digits.count >= 4 else { return nil }
|
||||
return Int(String(digits.prefix(4)))
|
||||
}
|
||||
}
|
||||
63
ios/Bookibra/Models/LibraryBook.swift
Normal file
63
ios/Bookibra/Models/LibraryBook.swift
Normal file
@@ -0,0 +1,63 @@
|
||||
import Foundation
|
||||
import SwiftData
|
||||
|
||||
@Model
|
||||
final class LibraryBook {
|
||||
@Attribute(.unique) var localId: UUID
|
||||
var title: String
|
||||
var authorsString: String
|
||||
var coverUrlString: String?
|
||||
var isbn10: String?
|
||||
var isbn13: String?
|
||||
var publishedYear: Int?
|
||||
var categoriesString: String
|
||||
var summary: String?
|
||||
var dateAdded: Date
|
||||
var language: String?
|
||||
var sourceLocale: String?
|
||||
var remotePayloadJson: String?
|
||||
|
||||
init(
|
||||
localId: UUID = UUID(),
|
||||
title: String,
|
||||
authorsString: String,
|
||||
coverUrlString: String? = nil,
|
||||
isbn10: String? = nil,
|
||||
isbn13: String? = nil,
|
||||
publishedYear: Int? = nil,
|
||||
categoriesString: String = "",
|
||||
summary: String? = nil,
|
||||
dateAdded: Date = .now,
|
||||
language: String? = nil,
|
||||
sourceLocale: String? = nil,
|
||||
remotePayloadJson: String? = nil
|
||||
) {
|
||||
self.localId = localId
|
||||
self.title = title
|
||||
self.authorsString = authorsString
|
||||
self.coverUrlString = coverUrlString
|
||||
self.isbn10 = isbn10
|
||||
self.isbn13 = isbn13
|
||||
self.publishedYear = publishedYear
|
||||
self.categoriesString = categoriesString
|
||||
self.summary = summary
|
||||
self.dateAdded = dateAdded
|
||||
self.language = language
|
||||
self.sourceLocale = sourceLocale
|
||||
self.remotePayloadJson = remotePayloadJson
|
||||
}
|
||||
|
||||
var authors: [String] {
|
||||
authorsString
|
||||
.split(separator: ",")
|
||||
.map { $0.trimmingCharacters(in: .whitespacesAndNewlines) }
|
||||
.filter { !$0.isEmpty }
|
||||
}
|
||||
|
||||
var categories: [String] {
|
||||
categoriesString
|
||||
.split(separator: ",")
|
||||
.map { $0.trimmingCharacters(in: .whitespacesAndNewlines) }
|
||||
.filter { !$0.isEmpty }
|
||||
}
|
||||
}
|
||||
10
ios/Bookibra/Models/UserProfile.swift
Normal file
10
ios/Bookibra/Models/UserProfile.swift
Normal file
@@ -0,0 +1,10 @@
|
||||
import Foundation
|
||||
|
||||
struct UserProfile: Codable, Equatable {
|
||||
struct User: Codable, Equatable {
|
||||
let id: String
|
||||
let email: String
|
||||
}
|
||||
|
||||
let user: User
|
||||
}
|
||||
Reference in New Issue
Block a user