Update tab bar to allow opting into digest
This commit is contained in:
committed by
Hongbo Wu
parent
4e61b360d7
commit
2b53d7791a
@ -2,25 +2,31 @@ import Foundation
|
|||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
struct CustomTabBar: View {
|
struct CustomTabBar: View {
|
||||||
|
let displayTabs: [String]
|
||||||
@Binding var selectedTab: String
|
@Binding var selectedTab: String
|
||||||
let hideFollowingTab: Bool
|
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
HStack(spacing: 0) {
|
HStack(spacing: 0) {
|
||||||
if !hideFollowingTab {
|
if displayTabs.contains("following") {
|
||||||
TabBarButton(key: "following",
|
TabBarButton(key: "following",
|
||||||
image: Image.tabFollowing,
|
image: Image.tabFollowing,
|
||||||
selectedTab: $selectedTab,
|
selectedTab: $selectedTab,
|
||||||
selectionColor: Color(hex: "EE8232"))
|
selectionColor: Color(hex: "EE8232"))
|
||||||
}
|
}
|
||||||
TabBarButton(key: "digest",
|
if displayTabs.contains("digest") {
|
||||||
image: Image.tabDigest,
|
TabBarButton(key: "digest",
|
||||||
selectedTab: $selectedTab,
|
image: Image.tabDigest,
|
||||||
selectedImage: Image.tabDigestSelected)
|
selectedTab: $selectedTab,
|
||||||
TabBarButton(key: "inbox",
|
selectedImage: Image.tabDigestSelected)
|
||||||
image: Image.tabLibrary,
|
}
|
||||||
selectedTab: $selectedTab)
|
if displayTabs.contains("inbox") {
|
||||||
// TabBarButton(key: "profile", image: Image.tabProfile, selectedTab: $selectedTab)
|
TabBarButton(key: "inbox",
|
||||||
|
image: Image.tabLibrary,
|
||||||
|
selectedTab: $selectedTab)
|
||||||
|
}
|
||||||
|
if displayTabs.contains("profile") {
|
||||||
|
TabBarButton(key: "profile", image: Image.tabProfile, selectedTab: $selectedTab)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.padding(.top, 10)
|
.padding(.top, 10)
|
||||||
.padding(.bottom, 10)
|
.padding(.bottom, 10)
|
||||||
|
|||||||
@ -21,6 +21,9 @@ struct LibraryTabView: View {
|
|||||||
@AppStorage("LibraryTabView::hideFollowingTab") var hideFollowingTab = false
|
@AppStorage("LibraryTabView::hideFollowingTab") var hideFollowingTab = false
|
||||||
@AppStorage(UserDefaultKey.lastSelectedTabItem.rawValue) var selectedTab = "inbox"
|
@AppStorage(UserDefaultKey.lastSelectedTabItem.rawValue) var selectedTab = "inbox"
|
||||||
|
|
||||||
|
@AppStorage("LibraryTabView::digestEnabled") var digestEnabled = false
|
||||||
|
@AppStorage("LibraryTabView::hasCheckedForDigestFeature") var hasCheckedForDigestFeature = false
|
||||||
|
|
||||||
@State var isEditMode: EditMode = .inactive
|
@State var isEditMode: EditMode = .inactive
|
||||||
@State var showExpandedAudioPlayer = false
|
@State var showExpandedAudioPlayer = false
|
||||||
@State var presentPushContainer = true
|
@State var presentPushContainer = true
|
||||||
@ -76,6 +79,28 @@ struct LibraryTabView: View {
|
|||||||
@State var operationStatus: OperationStatus = .none
|
@State var operationStatus: OperationStatus = .none
|
||||||
@State var operationMessage: String?
|
@State var operationMessage: String?
|
||||||
|
|
||||||
|
var showDigest: Bool {
|
||||||
|
if digestEnabled, #available(iOS 17.0, *) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
var displayTabs: [String] {
|
||||||
|
var res = [String]()
|
||||||
|
if !hideFollowingTab {
|
||||||
|
res.append("following")
|
||||||
|
}
|
||||||
|
if showDigest {
|
||||||
|
res.append("digest")
|
||||||
|
}
|
||||||
|
res.append("inbox")
|
||||||
|
if !showDigest {
|
||||||
|
res.append("profile")
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
VStack(spacing: 0) {
|
VStack(spacing: 0) {
|
||||||
WindowLink(level: .alert, transition: .move(edge: .bottom), isPresented: $showOperationToast) {
|
WindowLink(level: .alert, transition: .move(edge: .bottom), isPresented: $showOperationToast) {
|
||||||
@ -116,24 +141,29 @@ struct LibraryTabView: View {
|
|||||||
}.tag("following")
|
}.tag("following")
|
||||||
}
|
}
|
||||||
|
|
||||||
if #available(iOS 17.0, *) {
|
if showDigest, #available(iOS 17.0, *) {
|
||||||
NavigationView {
|
NavigationView {
|
||||||
LibraryDigestView(dataService: dataService)
|
LibraryDigestView(dataService: dataService)
|
||||||
.navigationBarTitleDisplayMode(.inline)
|
.navigationBarTitleDisplayMode(.inline)
|
||||||
.navigationViewStyle(.stack)
|
.navigationViewStyle(.stack)
|
||||||
}.tag("digest")
|
}.tag("digest")
|
||||||
|
NavigationView {
|
||||||
|
HomeFeedContainerView(viewModel: inboxViewModel, isEditMode: $isEditMode)
|
||||||
|
.navigationBarTitleDisplayMode(.inline)
|
||||||
|
.navigationViewStyle(.stack)
|
||||||
|
}.tag("inbox")
|
||||||
} else {
|
} else {
|
||||||
NavigationView {
|
NavigationView {
|
||||||
HomeFeedContainerView(viewModel: inboxViewModel, isEditMode: $isEditMode)
|
HomeFeedContainerView(viewModel: inboxViewModel, isEditMode: $isEditMode)
|
||||||
.navigationBarTitleDisplayMode(.inline)
|
.navigationBarTitleDisplayMode(.inline)
|
||||||
.navigationViewStyle(.stack)
|
.navigationViewStyle(.stack)
|
||||||
}.tag("inbox")
|
}.tag("inbox")
|
||||||
|
NavigationView {
|
||||||
|
ProfileView()
|
||||||
|
.navigationViewStyle(.stack)
|
||||||
|
}.tag("profile")
|
||||||
}
|
}
|
||||||
|
|
||||||
NavigationView {
|
|
||||||
ProfileView()
|
|
||||||
.navigationViewStyle(.stack)
|
|
||||||
}.tag("profile")
|
|
||||||
}
|
}
|
||||||
if let audioProperties = audioController.itemAudioProperties {
|
if let audioProperties = audioController.itemAudioProperties {
|
||||||
MiniPlayerViewer(itemAudioProperties: audioProperties)
|
MiniPlayerViewer(itemAudioProperties: audioProperties)
|
||||||
@ -146,7 +176,9 @@ struct LibraryTabView: View {
|
|||||||
.frame(maxWidth: .infinity)
|
.frame(maxWidth: .infinity)
|
||||||
}
|
}
|
||||||
if isEditMode != .active {
|
if isEditMode != .active {
|
||||||
CustomTabBar(selectedTab: $selectedTab, hideFollowingTab: hideFollowingTab)
|
CustomTabBar(
|
||||||
|
displayTabs: displayTabs,
|
||||||
|
selectedTab: $selectedTab)
|
||||||
.padding(0)
|
.padding(0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -204,5 +236,19 @@ struct LibraryTabView: View {
|
|||||||
}
|
}
|
||||||
selectedTab = "inbox"
|
selectedTab = "inbox"
|
||||||
}
|
}
|
||||||
|
.task {
|
||||||
|
do {
|
||||||
|
if let viewer = try await dataService.fetchViewer() {
|
||||||
|
digestEnabled = viewer.digestEnabled ?? false
|
||||||
|
if !hasCheckedForDigestFeature {
|
||||||
|
hasCheckedForDigestFeature = true
|
||||||
|
selectedTab = "digest"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
print("ERROR FETCHING VIEWER: ", error)
|
||||||
|
print("")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||||
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="22522" systemVersion="23B81" minimumToolsVersion="Automatic" sourceLanguage="Swift" userDefinedModelVersionIdentifier="">
|
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="22757" systemVersion="23B81" minimumToolsVersion="Automatic" sourceLanguage="Swift" userDefinedModelVersionIdentifier="">
|
||||||
<entity name="Filter" representedClassName="Filter" syncable="YES" codeGenerationType="class">
|
<entity name="Filter" representedClassName="Filter" syncable="YES" codeGenerationType="class">
|
||||||
<attribute name="defaultFilter" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
|
<attribute name="defaultFilter" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
|
||||||
<attribute name="filter" optional="YES" attributeType="String"/>
|
<attribute name="filter" optional="YES" attributeType="String"/>
|
||||||
@ -137,6 +137,7 @@
|
|||||||
<attribute name="username" optional="YES" attributeType="String"/>
|
<attribute name="username" optional="YES" attributeType="String"/>
|
||||||
</entity>
|
</entity>
|
||||||
<entity name="Viewer" representedClassName="Viewer" syncable="YES" codeGenerationType="class">
|
<entity name="Viewer" representedClassName="Viewer" syncable="YES" codeGenerationType="class">
|
||||||
|
<attribute name="digestEnabled" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
|
||||||
<attribute name="name" attributeType="String"/>
|
<attribute name="name" attributeType="String"/>
|
||||||
<attribute name="profileImageURL" optional="YES" attributeType="String"/>
|
<attribute name="profileImageURL" optional="YES" attributeType="String"/>
|
||||||
<attribute name="userID" attributeType="String"/>
|
<attribute name="userID" attributeType="String"/>
|
||||||
|
|||||||
10
apple/OmnivoreKit/Sources/Models/DataModels/Feature.swift
Normal file
10
apple/OmnivoreKit/Sources/Models/DataModels/Feature.swift
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
|
||||||
|
public struct FeatureInternal {
|
||||||
|
public let name: String
|
||||||
|
public let enabled: Bool
|
||||||
|
|
||||||
|
public init(name: String, enabled: Bool) {
|
||||||
|
self.name = name
|
||||||
|
self.enabled = enabled
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@ -15,6 +15,8 @@ public enum RuleActionType {
|
|||||||
case delete
|
case delete
|
||||||
case markAsRead
|
case markAsRead
|
||||||
case sendNotification
|
case sendNotification
|
||||||
|
case export
|
||||||
|
case webhook
|
||||||
|
|
||||||
static func from(_ other: Enums.RuleActionType) -> RuleActionType {
|
static func from(_ other: Enums.RuleActionType) -> RuleActionType {
|
||||||
switch other {
|
switch other {
|
||||||
@ -28,6 +30,10 @@ public enum RuleActionType {
|
|||||||
return .sendNotification
|
return .sendNotification
|
||||||
case .delete:
|
case .delete:
|
||||||
return .delete
|
return .delete
|
||||||
|
case Enums.RuleActionType.export:
|
||||||
|
return .export
|
||||||
|
case Enums.RuleActionType.webhook:
|
||||||
|
return .webhook
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,7 +17,9 @@ public extension DataService {
|
|||||||
profileImageURL: try $0.profile(
|
profileImageURL: try $0.profile(
|
||||||
selection: .init { try $0.pictureUrl() }
|
selection: .init { try $0.pictureUrl() }
|
||||||
),
|
),
|
||||||
intercomHash: try $0.intercomHash()
|
intercomHash: try $0.intercomHash(),
|
||||||
|
digestEnabled: true // (try $0.featureList(selection: featureSelection.list.nullable)?
|
||||||
|
// .filter { $0.enabled && $0.name == "digest" } ?? []).count > 0
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,6 +67,7 @@ public struct ViewerInternal {
|
|||||||
public let name: String
|
public let name: String
|
||||||
public let profileImageURL: String?
|
public let profileImageURL: String?
|
||||||
public let intercomHash: String?
|
public let intercomHash: String?
|
||||||
|
public let digestEnabled: Bool?
|
||||||
|
|
||||||
func persist(context: NSManagedObjectContext) throws {
|
func persist(context: NSManagedObjectContext) throws {
|
||||||
try context.performAndWait {
|
try context.performAndWait {
|
||||||
@ -73,6 +76,7 @@ public struct ViewerInternal {
|
|||||||
viewer.username = username
|
viewer.username = username
|
||||||
viewer.name = name
|
viewer.name = name
|
||||||
viewer.profileImageURL = profileImageURL
|
viewer.profileImageURL = profileImageURL
|
||||||
|
viewer.digestEnabled = digestEnabled ?? false
|
||||||
|
|
||||||
do {
|
do {
|
||||||
try context.save()
|
try context.save()
|
||||||
|
|||||||
@ -0,0 +1,6 @@
|
|||||||
|
import Models
|
||||||
|
import SwiftGraphQL
|
||||||
|
|
||||||
|
let featureSelection = Selection.Feature {
|
||||||
|
FeatureInternal(name: try $0.name(), enabled: try $0.grantedAt() != nil)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user