iOS basic UI for recommending
This commit is contained in:
@ -1,8 +1,115 @@
|
||||
//
|
||||
// File.swift
|
||||
//
|
||||
//
|
||||
// Created by Jackson Harper on 12/5/22.
|
||||
//
|
||||
import Models
|
||||
import Services
|
||||
import SwiftUI
|
||||
import Views
|
||||
|
||||
import Foundation
|
||||
@MainActor final class RecommendToViewModel: ObservableObject {
|
||||
@Published var isLoading = false
|
||||
@Published var networkError = true
|
||||
@Published var recommendationGroups = [InternalRecommendationGroup]()
|
||||
@Published var selectedGroups = [String]()
|
||||
@Published var isRunning = false
|
||||
@Published var showError = false
|
||||
|
||||
let pageID: String
|
||||
|
||||
init(pageID: String) {
|
||||
self.pageID = pageID
|
||||
}
|
||||
|
||||
func loadGroups(dataService: DataService) async {
|
||||
isLoading = true
|
||||
|
||||
do {
|
||||
recommendationGroups = try await dataService.recommendationGroups()
|
||||
} catch {
|
||||
networkError = true
|
||||
}
|
||||
|
||||
isLoading = false
|
||||
}
|
||||
|
||||
func recommend(dataService: DataService) async {
|
||||
isRunning = true
|
||||
|
||||
do {
|
||||
try await dataService.recommendPage(pageID: pageID, groupIDs: selectedGroups)
|
||||
} catch {
|
||||
showError = true
|
||||
}
|
||||
|
||||
isRunning = false
|
||||
}
|
||||
}
|
||||
|
||||
struct RecommendToView: View {
|
||||
var dataService: DataService
|
||||
@StateObject var viewModel: RecommendToViewModel
|
||||
@Environment(\.dismiss) private var dismiss
|
||||
|
||||
var nextButton: some View {
|
||||
if viewModel.isRunning {
|
||||
return AnyView(ProgressView())
|
||||
} else {
|
||||
return AnyView(Button(action: {
|
||||
Task {
|
||||
await viewModel.recommend(dataService: dataService)
|
||||
Snackbar.show(message: "Recommendation sent")
|
||||
dismiss()
|
||||
}
|
||||
}, label: {
|
||||
Text("Next")
|
||||
})
|
||||
.disabled(viewModel.selectedGroups.isEmpty)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
VStack {
|
||||
List {
|
||||
ForEach(viewModel.recommendationGroups) { group in
|
||||
HStack {
|
||||
Text(group.name)
|
||||
|
||||
Spacer()
|
||||
|
||||
if viewModel.selectedGroups.contains(group.id) {
|
||||
Image(systemName: "checkmark")
|
||||
}
|
||||
}
|
||||
.contentShape(Rectangle())
|
||||
.onTapGesture {
|
||||
let idx = viewModel.selectedGroups.firstIndex(of: group.id)
|
||||
if let idx = idx {
|
||||
viewModel.selectedGroups.remove(at: idx)
|
||||
} else {
|
||||
viewModel.selectedGroups.append(group.id)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.listStyle(.grouped)
|
||||
|
||||
Spacer()
|
||||
}
|
||||
.alert(isPresented: $viewModel.showError) {
|
||||
Alert(
|
||||
title: Text("Error recommending this page"),
|
||||
dismissButton: .cancel(Text("Ok")) {
|
||||
viewModel.showError = false
|
||||
}
|
||||
)
|
||||
}
|
||||
.navigationBarTitle("Recommend To")
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
.navigationViewStyle(.stack)
|
||||
.navigationBarItems(leading: Button(action: {
|
||||
dismiss()
|
||||
}, label: { Text("Cancel") }),
|
||||
trailing: nextButton)
|
||||
.task {
|
||||
await viewModel.loadGroups(dataService: dataService)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -29,6 +29,7 @@ struct WebReaderContainerView: View {
|
||||
@State private var bottomBarOpacity = 0.0
|
||||
@State private var errorAlertMessage: String?
|
||||
@State private var showErrorAlertMessage = false
|
||||
@State private var displayRecommendSheet = false
|
||||
|
||||
@EnvironmentObject var dataService: DataService
|
||||
@EnvironmentObject var audioController: AudioController
|
||||
@ -219,6 +220,13 @@ struct WebReaderContainerView: View {
|
||||
action: delete,
|
||||
label: { Label("Delete", systemImage: "trash") }
|
||||
)
|
||||
Button(
|
||||
action: {
|
||||
// dataService.updateLinkReadingProgress(itemID: item.unwrappedID, readingProgress: 0, anchorIndex: 0)
|
||||
displayRecommendSheet = true
|
||||
},
|
||||
label: { Label("Recommend", systemImage: "sparkles") }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -351,6 +359,14 @@ struct WebReaderContainerView: View {
|
||||
showErrorAlertMessage = false
|
||||
})
|
||||
}
|
||||
.formSheet(isPresented: $displayRecommendSheet) {
|
||||
NavigationView {
|
||||
RecommendToView(
|
||||
dataService: dataService,
|
||||
viewModel: RecommendToViewModel(pageID: item.unwrappedID)
|
||||
)
|
||||
}
|
||||
}
|
||||
.sheet(isPresented: $showHighlightAnnotationModal) {
|
||||
HighlightAnnotationSheet(
|
||||
annotation: $annotation,
|
||||
|
||||
@ -1,8 +1,48 @@
|
||||
//
|
||||
// File.swift
|
||||
//
|
||||
//
|
||||
// Created by Jackson Harper on 12/5/22.
|
||||
//
|
||||
|
||||
import CoreData
|
||||
import Foundation
|
||||
import Models
|
||||
import SwiftGraphQL
|
||||
|
||||
public extension DataService {
|
||||
func recommendPage(pageID: String, groupIDs: [String]) async throws {
|
||||
enum MutationResult {
|
||||
case saved(taskNames: [String])
|
||||
case error(errorMessage: String)
|
||||
}
|
||||
|
||||
let selection = Selection<MutationResult, Unions.RecommendResult> {
|
||||
try $0.on(
|
||||
recommendError: .init { .error(errorMessage: try $0.errorCodes().first.toString()) },
|
||||
recommendSuccess: .init {
|
||||
.saved(taskNames: try $0.taskNames())
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
let mutation = Selection.Mutation {
|
||||
try $0.recommend(
|
||||
input: .init(groupIds: groupIDs, pageId: pageID),
|
||||
selection: selection
|
||||
)
|
||||
}
|
||||
|
||||
let path = appEnvironment.graphqlPath
|
||||
let headers = networker.defaultHeaders
|
||||
|
||||
return try await withCheckedThrowingContinuation { continuation in
|
||||
send(mutation, to: path, headers: headers) { queryResult in
|
||||
guard let payload = try? queryResult.get() else {
|
||||
continuation.resume(throwing: BasicError.message(messageText: "network error"))
|
||||
return
|
||||
}
|
||||
|
||||
switch payload.data {
|
||||
case .saved:
|
||||
continuation.resume()
|
||||
case let .error(errorMessage: errorMessage):
|
||||
continuation.resume(throwing: BasicError.message(messageText: errorMessage))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -70,7 +70,7 @@ log(`Migrating to ${targetMigrationLabel}.\n`)
|
||||
const logAppliedMigrations = (
|
||||
appliedMigrations: Postgrator.Migration[]
|
||||
): void => {
|
||||
if (appliedMigrations.length > 0) {
|
||||
if (appliedMigrations && appliedMigrations.length > 0) {
|
||||
log(
|
||||
`Applied ${chalk.green(
|
||||
appliedMigrations.length.toString()
|
||||
|
||||
Reference in New Issue
Block a user