Allog config of digest

This commit is contained in:
Jackson Harper
2024-05-14 18:03:05 +08:00
parent d52e40ea5a
commit a034771848
6 changed files with 120 additions and 16 deletions

View File

@ -9,7 +9,7 @@ import Transmission
@MainActor
public class DigestConfigViewModel: ObservableObject {
@Published var isLoading = false
@Published var alreadyGranted = false
@Published var digestEnabled = false
@Published var isIneligible = false
@Published var hasOptInError = false
@ -23,7 +23,7 @@ public class DigestConfigViewModel: ObservableObject {
func checkAlreadyOptedIn(dataService: DataService) async {
isLoading = true
if let user = try? await dataService.fetchViewer() {
alreadyGranted = user.hasFeatureGranted("ai-digest")
digestEnabled = user.hasFeatureGranted("ai-digest")
}
isLoading = false
}
@ -35,6 +35,8 @@ public class DigestConfigViewModel: ObservableObject {
throw BasicError.message(messageText: "Could not opt into feature")
}
try await dataService.setupUserDigestConfig()
try await dataService.refreshDigest()
digestEnabled = true
} catch {
if error is IneligibleError {
isIneligible = true
@ -42,7 +44,6 @@ public class DigestConfigViewModel: ObservableObject {
hasOptInError = true
}
}
isLoading = false
}
}
@ -84,7 +85,8 @@ struct DigestConfigView: View {
ProgressView()
Spacer()
}
} else if viewModel.alreadyGranted {
.padding(.top, 50)
} else if viewModel.digestEnabled {
Text("You've been added to the AI Digest demo. You first issue should be ready soon.")
.padding(15)
} else if viewModel.isIneligible {
@ -160,7 +162,9 @@ struct DigestConfigView: View {
.buttonStyle(RoundedRectButtonStyle())
Button(action: {
// viewModel.en
Task {
await viewModel.enableDigest(dataService: dataService)
}
}, label: { Text("Enable digest") })
.buttonStyle(RoundedRectButtonStyle(color: Color.blue, textColor: Color.white))
}

View File

@ -38,6 +38,7 @@ func formatTimeInterval(_ time: TimeInterval) -> String? {
@MainActor
public class FullScreenDigestViewModel: ObservableObject {
@Published var isLoading = false
@Published var hasError = false
@Published var digest: DigestResult?
@Published var chapterInfo: [(DigestChapter, DigestChapterData)]?
@Published var presentedLibraryItem: String?
@ -46,6 +47,9 @@ public class FullScreenDigestViewModel: ObservableObject {
@AppStorage(UserDefaultKey.lastVisitedDigestId.rawValue) var lastVisitedDigestId = ""
func load(dataService: DataService, audioController: AudioController) async {
hasError = false
isLoading = true
if !dataService.digestNeedsRefresh() {
if let digest = dataService.loadStoredDigest() {
self.digest = digest
@ -72,6 +76,8 @@ public class FullScreenDigestViewModel: ObservableObject {
let chapterData = self.chapterInfo?.map { $0.1 }
audioController.play(itemAudioProperties: DigestAudioItem(digest: digest, chapters: chapterData ?? []))
}
} else {
hasError = true
}
isLoading = false
@ -164,6 +170,19 @@ struct FullScreenDigestView: View {
ProgressView()
Spacer()
}
} else if viewModel.hasError {
VStack {
Spacer()
Text("There was an error loading your digest.")
Button(action: {
Task {
await viewModel.load(dataService: dataService, audioController: audioController)
}
}, label: { Text("Try again") })
.buttonStyle(RoundedRectButtonStyle(color: Color.blue, textColor: Color.white))
Spacer()
}
} else {
itemBody
}

View File

@ -5866,6 +5866,68 @@ extension Selection where TypeLock == Never, Type == Never {
typealias DeviceTokensSuccess<T> = Selection<T, Objects.DeviceTokensSuccess>
}
extension Objects {
struct DigestConfig {
let __typename: TypeName = .digestConfig
let channels: [String: [String?]]
enum TypeName: String, Codable {
case digestConfig = "DigestConfig"
}
}
}
extension Objects.DigestConfig: Decodable {
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: DynamicCodingKeys.self)
var map = HashMap()
for codingKey in container.allKeys {
if codingKey.isTypenameKey { continue }
let alias = codingKey.stringValue
let field = GraphQLField.getFieldNameFromAlias(alias)
switch field {
case "channels":
if let value = try container.decode([String?]?.self, forKey: codingKey) {
map.set(key: field, hash: alias, value: value as Any)
}
default:
throw DecodingError.dataCorrupted(
DecodingError.Context(
codingPath: decoder.codingPath,
debugDescription: "Unknown key \(field)."
)
)
}
}
channels = map["channels"]
}
}
extension Fields where TypeLock == Objects.DigestConfig {
func channels() throws -> [String?]? {
let field = GraphQLField.leaf(
name: "channels",
arguments: []
)
select(field)
switch response {
case let .decoding(data):
return data.channels[field.alias!]
case .mocking:
return nil
}
}
}
extension Selection where TypeLock == Never, Type == Never {
typealias DigestConfig<T> = Selection<T, Objects.DigestConfig>
}
extension Objects {
struct DiscoverFeed {
let __typename: TypeName = .discoverFeed
@ -28003,7 +28065,7 @@ extension Selection where TypeLock == Never, Type == Never {
extension Objects {
struct UserPersonalization {
let __typename: TypeName = .userPersonalization
let digestConfig: [String: String]
let digestConfig: [String: Objects.DigestConfig]
let fields: [String: String]
let fontFamily: [String: String]
let fontSize: [String: Int]
@ -28036,7 +28098,7 @@ extension Objects.UserPersonalization: Decodable {
switch field {
case "digestConfig":
if let value = try container.decode(String?.self, forKey: codingKey) {
if let value = try container.decode(Objects.DigestConfig?.self, forKey: codingKey) {
map.set(key: field, hash: alias, value: value as Any)
}
case "fields":
@ -28114,18 +28176,19 @@ extension Objects.UserPersonalization: Decodable {
}
extension Fields where TypeLock == Objects.UserPersonalization {
func digestConfig() throws -> String? {
let field = GraphQLField.leaf(
func digestConfig<Type>(selection: Selection<Type, Objects.DigestConfig?>) throws -> Type {
let field = GraphQLField.composite(
name: "digestConfig",
arguments: []
arguments: [],
selection: selection.selection
)
select(field)
switch response {
case let .decoding(data):
return data.digestConfig[field.alias!]
return try selection.decode(data: data.digestConfig[field.alias!])
case .mocking:
return nil
return selection.mock()
}
}
@ -39401,6 +39464,21 @@ extension InputObjects {
}
}
extension InputObjects {
struct DigestConfigInput: Encodable, Hashable {
var channels: OptionalArgument<[OptionalArgument<String>]> = .absent()
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
if channels.hasValue { try container.encode(channels, forKey: .channels) }
}
enum CodingKeys: String, CodingKey {
case channels
}
}
}
extension InputObjects {
struct EditDiscoverFeedInput: Encodable, Hashable {
var feedId: String
@ -40379,7 +40457,7 @@ extension InputObjects {
extension InputObjects {
struct SetUserPersonalizationInput: Encodable, Hashable {
var digestConfig: OptionalArgument<String> = .absent()
var digestConfig: OptionalArgument<InputObjects.DigestConfigInput> = .absent()
var fields: OptionalArgument<String> = .absent()

View File

@ -40,7 +40,6 @@
}
}
@available(iOS 16.0, *)
struct LibraryItemEntity: AppEntity {
static var defaultQuery = LibraryItemQuery()

View File

@ -27,7 +27,9 @@ export async function updateDigestConfigMutation(
}
... on SetUserPersonalizationSuccess {
updatedUserPersonalization {
digestConfig
digestConfig {
channels
}
}
}
}

View File

@ -58,7 +58,9 @@ export function useGetUserPersonalization(): UserPersonalizationResult {
getUserPersonalization {
... on GetUserPersonalizationSuccess {
userPersonalization {
digestConfig
digestConfig {
channels
}
}
}
... on GetUserPersonalizationError {