Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ struct About: View {
Text("R2 Reader wouldn't have been developed without the financial help of the French State.")
Image("rf")
}
.padding()
.navigationTitle("About")
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,27 @@ import SwiftUI

struct Bookshelf: View {

@ObservedObject var viewModel: BookshelfViewModel
let bookRepository: BookRepository

@State private var showingSheet = false
@State private var books: [Book] = []

var body: some View {
NavigationView {
VStack {
// TODO figure out what the best column layout is for phones and tablets
if let books = viewModel.books {
let columns: [GridItem] = Array(repeating: .init(.adaptive(minimum: 170)), count: 2)
ScrollView {
LazyVGrid(columns: columns, spacing: 20) {
ForEach(books, id: \.self) { item in
BookCover(book: item)
}
let columns: [GridItem] = [GridItem(.adaptive(minimum: 150 + 8))]
ScrollView {
LazyVGrid(columns: columns, spacing: 20) {
ForEach(books, id: \.self) { book in
BookCover(title: book.title, authors: book.authors, url: book.cover)
}
}
.onReceive(bookRepository.all()) {
books = $0
}
}

}
.navigationTitle("Bookshelf")
.toolbar(content: toolbarContent)
Expand Down
102 changes: 102 additions & 0 deletions TestApp/Sources/Catalogs/Views/CatalogFeed.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
//
// Copyright 2022 Readium Foundation. All rights reserved.
// Use of this source code is governed by the BSD-style license
// available in the top-level LICENSE file of the project.
//

import SwiftUI
import R2Shared
import ReadiumOPDS

struct CatalogFeed: View {

var catalog: Catalog
@State private var parseData: ParseData?

let catalogFeed: (Catalog) -> CatalogFeed
let publicationDetail: (Publication) -> PublicationDetail

var body: some View {

ScrollView {
VStack(alignment: .leading) {
if let feed = parseData?.feed {
if !feed.navigation.isEmpty {
ForEach(feed.navigation, id: \.self) { link in
let navigationLink = Catalog(title: link.title ?? "Catalog", url: link.href)
NavigationLink(destination: catalogFeed(navigationLink)) {
ListRowItem(title: link.title!)
}
}
Divider().frame(height: 50)
}

// TODO This probably needs its own file
if !feed.publications.isEmpty {
let columns: [GridItem] = [GridItem(.adaptive(minimum: 150 + 8))]
LazyVGrid(columns: columns) {
ForEach(feed.publications) { publication in
let authors = publication.metadata.authors
.map { $0.name }
.joined(separator: ", ")
NavigationLink(destination: publicationDetail(publication)) {
BookCover(
title: publication.metadata.title,
authors: authors,
url: publication.images.first
.flatMap { URL(string: $0.href) }
)
}
.buttonStyle(.plain)
}
}
Divider().frame(height: 50)
}

if !feed.groups.isEmpty {
ForEach(feed.groups as [R2Shared.Group]) { group in
CatalogGroup(group: group, publicationDetail: publicationDetail, catalogFeed: catalogFeed)
.padding([.bottom], 25)
}
}
}
}
}
.padding()
.navigationTitle(catalog.title)
.navigationBarTitleDisplayMode(.inline)
.task {
if parseData == nil {
await parseFeed()
}
}
}
}

extension CatalogFeed {

func parseFeed() async {
if let url = URL(string: catalog.url) {
self.parseData = try? await OPDSParser.parseURL(url: url)
}
}
}

// FIXME this causes a Swift compiler error segmentation fault 11

//struct CatalogDetail_Previews: PreviewProvider {
// static var previews: some View {
// let catalog = Catalog(title: "Test", url: "https://www.test.com")
// let catalogDetail: (Catalog) -> CatalogDetail = { CatalogDetail(CatalogDetailViewModel(catalog: catalog)) }
// CatalogDetail(viewModel: CatalogDetailViewModel(catalog: catalog), catalogDetail: catalogDetail)
// }
//}

struct CatalogDetail_Previews: PreviewProvider {
static var previews: some View {
let catalog = Catalog(title: "Test", url: "https://www.test.com")
CatalogFeed(catalog: catalog, catalogFeed: { _ in fatalError() },
publicationDetail: { _ in fatalError() }
)
}
}
63 changes: 63 additions & 0 deletions TestApp/Sources/Catalogs/Views/CatalogGroup.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
//
// Copyright 2022 Readium Foundation. All rights reserved.
// Use of this source code is governed by the BSD-style license
// available in the top-level LICENSE file of the project.
//

import SwiftUI
import R2Shared

struct CatalogGroup: View {

var group: R2Shared.Group
let publicationDetail: (Publication) -> PublicationDetail
let catalogFeed: (Catalog) -> CatalogFeed

var body: some View {
VStack(alignment: .leading) {
let rows = [GridItem(.flexible(), alignment: .top)]
HStack {
Text(group.metadata.title).font(.title3)
if !group.links.isEmpty {
let navigationLink = Catalog(title: group.links.first!.title ?? "Catalog", url: group.links.first!.href)
NavigationLink(destination: catalogFeed(navigationLink)) {
ListRowItem(title: "See All").frame(maxWidth: .infinity, alignment: .trailing)
}
}
}
if !group.publications.isEmpty {
ScrollView(.horizontal, showsIndicators: false) {
LazyHGrid(rows: rows, spacing: 30) {
ForEach(group.publications) { publication in
let authors = publication.metadata.authors
.map { $0.name }
.joined(separator: ", ")
NavigationLink(destination: publicationDetail(publication)) {
// FIXME Ideally the title and author should not be truncated
BookCover(
title: publication.metadata.title,
authors: authors,
url: publication.images.first
.map { URL(string: $0.href)! }
)
}
.buttonStyle(.plain)
}
}
}
}
ForEach(group.navigation, id: \.self) { navigation in
let navigationLink = Catalog(title: navigation.title ?? "Catalog", url: navigation.href)
NavigationLink(destination: catalogFeed(navigationLink)) {
ListRowItem(title: navigation.title!)
}
}
}
}
}

//struct CatalogGroup_Previews: PreviewProvider {
// static var previews: some View {
// CatalogGroup()
// }
//}
Original file line number Diff line number Diff line change
Expand Up @@ -7,27 +7,36 @@
import SwiftUI
import ReadiumOPDS

struct Catalogs: View {
struct CatalogList: View {

@ObservedObject var viewModel: CatalogsViewModel
let catalogDetail: (Catalog) -> CatalogDetail
let catalogRepository: CatalogRepository
let catalogFeed: (Catalog) -> CatalogFeed

@State private var showingSheet = false
@State private var showingAlert = false
@State private var catalogs: [Catalog] = []

var body: some View {
NavigationView {
VStack {
if let catalogs = viewModel.catalogs {
List() {
ForEach(catalogs, id: \.id) { catalog in
NavigationLink(destination: catalogDetail(catalog)) {
ListRowItem(title: catalog.title)
}
List() {
ForEach(catalogs, id: \.id) { catalog in
NavigationLink(destination: catalogFeed(catalog)) {
ListRowItem(title: catalog.title)
}
}
.listStyle(DefaultListStyle())
.onDelete { offsets in
let catalogIds = offsets.map { catalogs[$0].id! }
Task {
try await deleteCatalogs(ids: catalogIds)
}
}
}
.onReceive(catalogRepository.all()) {
catalogs = $0 ?? []
}
.listStyle(DefaultListStyle())

}
.navigationTitle("Catalogs")
.toolbar(content: toolbarContent)
Expand All @@ -38,7 +47,7 @@ struct Catalogs: View {
Task {
do {
_ = try await OPDSParser.parseURL(url: URL(string: url)!)
try await viewModel.addCatalog(catalog: Catalog(title: title, url: url))
try await addCatalog(catalog: Catalog(title: title, url: url))
} catch {
showingAlert = true
}
Expand All @@ -61,3 +70,15 @@ struct Catalogs: View {
}
}
}

extension CatalogList {

func addCatalog(catalog: Catalog) async throws {
var savedCatalog = catalog
try? await catalogRepository.save(&savedCatalog)
}

func deleteCatalogs(ids: [Catalog.Id]) async throws {
try? await catalogRepository.delete(ids: ids)
}
}
54 changes: 54 additions & 0 deletions TestApp/Sources/Catalogs/Views/PublicationDetail.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
//
// Copyright 2022 Readium Foundation. All rights reserved.
// Use of this source code is governed by the BSD-style license
// available in the top-level LICENSE file of the project.
//

import SwiftUI
import R2Shared

struct PublicationDetail: View {

@State var publication: Publication

var body: some View {
let authors = publication.metadata.authors
.map { $0.name }
.joined(separator: ", ")
ScrollView {
VStack {
AsyncImage(
url: publication.images.first
.map { URL(string: $0.href)! },
content: { $0
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 225, height: 330)
},
placeholder: { ProgressView() }
)
Text(publication.metadata.title).font(.largeTitle)
Text(authors).font(.title2)
Text(publication.metadata.description ?? "")
.padding([.top, .bottom], 20)
}
}
.padding()
.toolbar(content: toolbarContent)
}

@ToolbarContentBuilder
private func toolbarContent() -> some ToolbarContent {
ToolbarItem(placement: .navigationBarTrailing) {
Button(.download) {
// TODO download the publication
}
}
}
}

//struct PublicationDetail_Previews: PreviewProvider {
// static var previews: some View {
// PublicationDetail()
// }
//}
10 changes: 10 additions & 0 deletions TestApp/Sources/Common/Toolkit/Extensions/R2Shared.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
//
// Copyright 2022 Readium Foundation. All rights reserved.
// Use of this source code is governed by the BSD-style license
// available in the top-level LICENSE file of the project.
//

import R2Shared

extension R2Shared.Publication: Identifiable {}
extension R2Shared.Group : Identifiable {}
22 changes: 15 additions & 7 deletions TestApp/Sources/Container.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
//

import Foundation
import R2Shared

class Container {

Expand All @@ -22,22 +23,29 @@ class Container {
private lazy var bookRepository = BookRepository(db: db)

func bookshelf() -> Bookshelf {
Bookshelf(viewModel: BookshelfViewModel(bookRepository: bookRepository))
Bookshelf(bookRepository: bookRepository)
}

// Catalogs

private lazy var catalogRepository = CatalogRepository(db: db)

func catalogs() -> Catalogs {
Catalogs(
viewModel: CatalogsViewModel(catalogRepository: catalogRepository),
catalogDetail: catalogDetail(with:)
func catalogs() -> CatalogList {
CatalogList(
catalogRepository: catalogRepository,
catalogFeed: catalogFeed(with:)
)
}

func catalogDetail(with catalog: Catalog) -> CatalogDetail {
CatalogDetail(viewModel: CatalogDetailViewModel(catalog: catalog))
func catalogFeed(with catalog: Catalog) -> CatalogFeed {
CatalogFeed(catalog: catalog,
catalogFeed: catalogFeed(with:),
publicationDetail: publicationDetail(with:)
)
}

func publicationDetail(with publication: Publication) -> PublicationDetail {
PublicationDetail(publication: publication)
}

// About
Expand Down
Loading