Refactor UI navigation and settings management
- Split TabView and Sidebar logic into PhoneTabView, PadSidebarView, SidebarTab, and BookmarkState for better device adaptation - Remove old SettingsViewModel, introduce SettingsGeneralViewModel and SettingsServerViewModel for modular settings - Update BookmarksView and BookmarksViewModel for new paginated and filtered data model - Clean up and modularize settings UI (SettingsGeneralView, SettingsServerView, FontSettingsView) - Remove obsolete files (old TabView, File.swift, SettingsViewModel, etc.) - Add BookmarksPageDto and update related data flow - Various UI/UX improvements and code cleanup BREAKING: Settings and navigation structure refactored, old settings logic removed
This commit is contained in:
parent
e5040f54e1
commit
7df56687c7
14
readeck/Data/API/DTOs/BookmarksPageDto.swift
Normal file
14
readeck/Data/API/DTOs/BookmarksPageDto.swift
Normal file
@ -0,0 +1,14 @@
|
||||
//
|
||||
// BookmarksPageDto.swift
|
||||
// readeck
|
||||
//
|
||||
// Created by Ilyas Hallak on 01.07.25.
|
||||
//
|
||||
|
||||
struct BookmarksPageDto {
|
||||
let bookmarks: [BookmarkDto]
|
||||
let currentPage: Int?
|
||||
let totalCount: Int?
|
||||
let totalPages: Int?
|
||||
let links: [String]?
|
||||
}
|
||||
@ -1,6 +0,0 @@
|
||||
import Foundation
|
||||
|
||||
struct CreateBookmarkResponseDto: Codable {
|
||||
let message: String
|
||||
let status: Int
|
||||
}
|
||||
@ -1,11 +0,0 @@
|
||||
import Foundation
|
||||
|
||||
struct UserDto: Codable {
|
||||
let id: String
|
||||
let token: String
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case id
|
||||
case token
|
||||
}
|
||||
}
|
||||
27
readeck/UI/Menu/BookmarkState.swift
Normal file
27
readeck/UI/Menu/BookmarkState.swift
Normal file
@ -0,0 +1,27 @@
|
||||
enum BookmarkState: String, CaseIterable {
|
||||
case unread = "unread"
|
||||
case favorite = "favorite"
|
||||
case archived = "archived"
|
||||
|
||||
var displayName: String {
|
||||
switch self {
|
||||
case .unread:
|
||||
return "Ungelesen"
|
||||
case .favorite:
|
||||
return "Favoriten"
|
||||
case .archived:
|
||||
return "Archiv"
|
||||
}
|
||||
}
|
||||
|
||||
var systemImage: String {
|
||||
switch self {
|
||||
case .unread:
|
||||
return "house"
|
||||
case .favorite:
|
||||
return "heart"
|
||||
case .archived:
|
||||
return "archivebox"
|
||||
}
|
||||
}
|
||||
}
|
||||
76
readeck/UI/Menu/PadSidebarView.swift
Normal file
76
readeck/UI/Menu/PadSidebarView.swift
Normal file
@ -0,0 +1,76 @@
|
||||
struct PadSidebarView: View {
|
||||
@State private var selectedTab: SidebarTab = .unread
|
||||
@State private var selectedBookmark: Bookmark?
|
||||
|
||||
var body: some View {
|
||||
NavigationSplitView {
|
||||
List {
|
||||
ForEach(SidebarTab.allCases.filter { $0 != .settings }, id: \.self) { tab in
|
||||
Button(action: {
|
||||
selectedTab = tab
|
||||
}) {
|
||||
Label(tab.label, systemImage: tab.systemImage)
|
||||
.foregroundColor(selectedTab == tab ? .accentColor : .primary)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.contentShape(Rectangle())
|
||||
|
||||
if tab == .article {
|
||||
Spacer()
|
||||
}
|
||||
|
||||
if tab == .pictures {
|
||||
Divider()
|
||||
}
|
||||
}
|
||||
.listRowBackground(selectedTab == tab ? Color.accentColor.opacity(0.15) : Color.clear)
|
||||
}
|
||||
}
|
||||
.listStyle(.sidebar)
|
||||
.safeAreaInset(edge: .bottom, alignment: .center) {
|
||||
VStack(spacing: 0) {
|
||||
Divider()
|
||||
Button(action: {
|
||||
selectedTab = .settings
|
||||
}) {
|
||||
Label(SidebarTab.settings.label, systemImage: SidebarTab.settings.systemImage)
|
||||
.foregroundColor(selectedTab == .settings ? .accentColor : .primary)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.padding(.vertical, 12)
|
||||
.contentShape(Rectangle())
|
||||
}
|
||||
.listRowBackground(selectedTab == .settings ? Color.accentColor.opacity(0.15) : Color.clear)
|
||||
}
|
||||
.padding(.horizontal, 12)
|
||||
.background(Color(.systemGroupedBackground))
|
||||
}
|
||||
} content: {
|
||||
switch selectedTab {
|
||||
case .all:
|
||||
Text("All")
|
||||
case .unread:
|
||||
BookmarksView(state: .unread, selectedBookmark: $selectedBookmark)
|
||||
case .favorite:
|
||||
BookmarksView(state: .favorite, selectedBookmark: $selectedBookmark)
|
||||
case .archived:
|
||||
BookmarksView(state: .archived, selectedBookmark: $selectedBookmark)
|
||||
case .settings:
|
||||
SettingsView()
|
||||
case .article:
|
||||
Text("Artikel")
|
||||
case .videos:
|
||||
Text("Videos")
|
||||
case .pictures:
|
||||
Text("Pictures")
|
||||
case .tags:
|
||||
Text("Tags")
|
||||
}
|
||||
} detail: {
|
||||
if let bookmark = selectedBookmark, selectedTab != .settings {
|
||||
BookmarkDetailView(bookmarkId: bookmark.id)
|
||||
} else {
|
||||
Text(selectedTab == .settings ? "" : "Select a bookmark")
|
||||
.foregroundColor(.gray)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
28
readeck/UI/Menu/PhoneTabView.swift
Normal file
28
readeck/UI/Menu/PhoneTabView.swift
Normal file
@ -0,0 +1,28 @@
|
||||
struct PhoneTabView: View {
|
||||
var body: some View {
|
||||
TabView {
|
||||
NavigationStack {
|
||||
BookmarksView(state: .unread, selectedBookmark: .constant(nil))
|
||||
}
|
||||
.tabItem {
|
||||
Label("Ungelesen", systemImage: "house")
|
||||
}
|
||||
|
||||
BookmarksView(state: .favorite, selectedBookmark: .constant(nil))
|
||||
.tabItem {
|
||||
Label("Favoriten", systemImage: "heart")
|
||||
}
|
||||
|
||||
BookmarksView(state: .archived, selectedBookmark: .constant(nil))
|
||||
.tabItem {
|
||||
Label("Archiv", systemImage: "archivebox")
|
||||
}
|
||||
|
||||
SettingsView()
|
||||
.tabItem {
|
||||
Label("Settings", systemImage: "gear")
|
||||
}
|
||||
}
|
||||
.accentColor(.accentColor)
|
||||
}
|
||||
}
|
||||
33
readeck/UI/Menu/SidebarTab.swift
Normal file
33
readeck/UI/Menu/SidebarTab.swift
Normal file
@ -0,0 +1,33 @@
|
||||
enum SidebarTab: Hashable, CaseIterable, Identifiable {
|
||||
case all, unread, favorite, archived, settings, article, videos, pictures, tags
|
||||
|
||||
var id: Self { self }
|
||||
|
||||
var label: String {
|
||||
switch self {
|
||||
case .all: return "Alle"
|
||||
case .unread: return "Ungelesen"
|
||||
case .favorite: return "Favoriten"
|
||||
case .archived: return "Archiv"
|
||||
case .settings: return "Einstellungen"
|
||||
case .article: return "Artikel"
|
||||
case .videos: return "Videos"
|
||||
case .pictures: return "Bilder"
|
||||
case .tags: return "Tags"
|
||||
}
|
||||
}
|
||||
|
||||
var systemImage: String {
|
||||
switch self {
|
||||
case .unread: return "house"
|
||||
case .favorite: return "heart"
|
||||
case .archived: return "archivebox"
|
||||
case .settings: return "gear"
|
||||
case .all: return "list.bullet"
|
||||
case .article: return "doc.plaintext"
|
||||
case .videos: return "film"
|
||||
case .pictures: return "photo"
|
||||
case .tags: return "tag"
|
||||
}
|
||||
}
|
||||
}
|
||||
203
readeck/UI/Menu/TabView.swift
Normal file
203
readeck/UI/Menu/TabView.swift
Normal file
@ -0,0 +1,203 @@
|
||||
import SwiftUI
|
||||
import Foundation
|
||||
|
||||
enum BookmarkState: String, CaseIterable {
|
||||
case unread = "unread"
|
||||
case favorite = "favorite"
|
||||
case archived = "archived"
|
||||
|
||||
var displayName: String {
|
||||
switch self {
|
||||
case .unread:
|
||||
return "Ungelesen"
|
||||
case .favorite:
|
||||
return "Favoriten"
|
||||
case .archived:
|
||||
return "Archiv"
|
||||
}
|
||||
}
|
||||
|
||||
var systemImage: String {
|
||||
switch self {
|
||||
case .unread:
|
||||
return "house"
|
||||
case .favorite:
|
||||
return "heart"
|
||||
case .archived:
|
||||
return "archivebox"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct MainTabView: View {
|
||||
@State private var selectedTab: SidebarTab = .unread
|
||||
@State var selectedBookmark: Bookmark?
|
||||
|
||||
// sizeClass
|
||||
@Environment(\.horizontalSizeClass)
|
||||
var horizontalSizeClass
|
||||
|
||||
@Environment(\.verticalSizeClass)
|
||||
var verticalSizeClass
|
||||
|
||||
var body: some View {
|
||||
if UIDevice.isPhone {
|
||||
PhoneView()
|
||||
} else {
|
||||
PadSidebarView()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sidebar Tabs
|
||||
enum SidebarTab: Hashable, CaseIterable, Identifiable {
|
||||
case all, unread, favorite, archived, settings, article, videos, pictures, tags
|
||||
|
||||
var id: Self { self }
|
||||
|
||||
var label: String {
|
||||
switch self {
|
||||
case .all: return "Alle"
|
||||
case .unread: return "Ungelesen"
|
||||
case .favorite: return "Favoriten"
|
||||
case .archived: return "Archiv"
|
||||
case .settings: return "Einstellungen"
|
||||
case .article: return "Artikel"
|
||||
case .videos: return "Videos"
|
||||
case .pictures: return "Bilder"
|
||||
case .tags: return "Tags"
|
||||
}
|
||||
}
|
||||
|
||||
var systemImage: String {
|
||||
switch self {
|
||||
case .unread: return "house"
|
||||
case .favorite: return "heart"
|
||||
case .archived: return "archivebox"
|
||||
case .settings: return "gear"
|
||||
case .all: return "list.bullet"
|
||||
case .article: return "doc.plaintext"
|
||||
case .videos: return "film"
|
||||
case .pictures: return "photo"
|
||||
case .tags: return "tag"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct PadSidebarView: View {
|
||||
@State private var selectedTab: SidebarTab = .unread
|
||||
@State private var selectedBookmark: Bookmark?
|
||||
|
||||
var body: some View {
|
||||
NavigationSplitView {
|
||||
List {
|
||||
ForEach(SidebarTab.allCases.filter { $0 != .settings }, id: \.self) { tab in
|
||||
Button(action: {
|
||||
selectedTab = tab
|
||||
}) {
|
||||
Label(tab.label, systemImage: tab.systemImage)
|
||||
.foregroundColor(selectedTab == tab ? .accentColor : .primary)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.contentShape(Rectangle())
|
||||
|
||||
if tab == .article {
|
||||
Spacer()
|
||||
}
|
||||
|
||||
if tab == .pictures {
|
||||
Divider()
|
||||
}
|
||||
}
|
||||
.listRowBackground(selectedTab == tab ? Color.accentColor.opacity(0.15) : Color.clear)
|
||||
}
|
||||
}
|
||||
.listStyle(.sidebar)
|
||||
.safeAreaInset(edge: .bottom, alignment: .center) {
|
||||
VStack(spacing: 0) {
|
||||
Divider()
|
||||
Button(action: {
|
||||
selectedTab = .settings
|
||||
}) {
|
||||
Label(SidebarTab.settings.label, systemImage: SidebarTab.settings.systemImage)
|
||||
.foregroundColor(selectedTab == .settings ? .accentColor : .primary)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.padding(.vertical, 12)
|
||||
.contentShape(Rectangle())
|
||||
}
|
||||
.listRowBackground(selectedTab == .settings ? Color.accentColor.opacity(0.15) : Color.clear)
|
||||
}
|
||||
.padding(.horizontal, 12)
|
||||
.background(Color(.systemGroupedBackground))
|
||||
}
|
||||
} content: {
|
||||
switch selectedTab {
|
||||
case .all:
|
||||
Text("All")
|
||||
case .unread:
|
||||
BookmarksView(state: .unread, selectedBookmark: $selectedBookmark)
|
||||
case .favorite:
|
||||
BookmarksView(state: .favorite, selectedBookmark: $selectedBookmark)
|
||||
case .archived:
|
||||
BookmarksView(state: .archived, selectedBookmark: $selectedBookmark)
|
||||
case .settings:
|
||||
SettingsView()
|
||||
case .article:
|
||||
Text("Artikel")
|
||||
case .videos:
|
||||
Text("Videos")
|
||||
case .pictures:
|
||||
Text("Pictures")
|
||||
case .tags:
|
||||
Text("Tags")
|
||||
}
|
||||
} detail: {
|
||||
if let bookmark = selectedBookmark, selectedTab != .settings {
|
||||
BookmarkDetailView(bookmarkId: bookmark.id)
|
||||
} else {
|
||||
Text(selectedTab == .settings ? "" : "Select a bookmark")
|
||||
.foregroundColor(.gray)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// iPhone: TabView bleibt wie gehabt
|
||||
extension MainTabView {
|
||||
@ViewBuilder
|
||||
fileprivate func PhoneView() -> some View {
|
||||
TabView {
|
||||
NavigationStack {
|
||||
BookmarksView(state: .unread, selectedBookmark: .constant(nil))
|
||||
}
|
||||
.tabItem {
|
||||
Label("Ungelesen", systemImage: "house")
|
||||
}
|
||||
|
||||
NavigationView {
|
||||
BookmarksView(state: .favorite, selectedBookmark: .constant(nil))
|
||||
.tabItem {
|
||||
Label("Favoriten", systemImage: "heart")
|
||||
}
|
||||
}
|
||||
|
||||
NavigationView {
|
||||
BookmarksView(state: .archived, selectedBookmark: .constant(nil))
|
||||
.tabItem {
|
||||
Label("Archiv", systemImage: "archivebox")
|
||||
}
|
||||
}
|
||||
|
||||
NavigationView {
|
||||
SettingsView()
|
||||
.tabItem {
|
||||
Label("Settings", systemImage: "gear")
|
||||
}
|
||||
}
|
||||
}
|
||||
.accentColor(.accentColor)
|
||||
}
|
||||
}
|
||||
|
||||
#Preview {
|
||||
MainTabView()
|
||||
}
|
||||
74
readeck/UI/Settings/SettingsGeneralViewModel.swift
Normal file
74
readeck/UI/Settings/SettingsGeneralViewModel.swift
Normal file
@ -0,0 +1,74 @@
|
||||
import Foundation
|
||||
import Observation
|
||||
import SwiftUI
|
||||
|
||||
@Observable
|
||||
class SettingsGeneralViewModel {
|
||||
private let saveSettingsUseCase: SaveSettingsUseCase
|
||||
private let loadSettingsUseCase: LoadSettingsUseCase
|
||||
|
||||
// MARK: - UI Settings
|
||||
var selectedTheme: Theme = .system
|
||||
// MARK: - Sync Settings
|
||||
var autoSyncEnabled: Bool = true
|
||||
var syncInterval: Int = 15
|
||||
// MARK: - Reading Settings
|
||||
var enableReaderMode: Bool = false
|
||||
var openExternalLinksInApp: Bool = true
|
||||
var autoMarkAsRead: Bool = false
|
||||
// MARK: - App Info
|
||||
var appVersion: String = "1.0.0"
|
||||
var developerName: String = "Your Name"
|
||||
// MARK: - Messages
|
||||
var errorMessage: String?
|
||||
var successMessage: String?
|
||||
// MARK: - Data Management (Platzhalter)
|
||||
// func clearCache() async {}
|
||||
// func resetSettings() async {}
|
||||
|
||||
init() {
|
||||
let factory = DefaultUseCaseFactory.shared
|
||||
self.saveSettingsUseCase = factory.makeSaveSettingsUseCase()
|
||||
self.loadSettingsUseCase = factory.makeLoadSettingsUseCase()
|
||||
}
|
||||
|
||||
@MainActor
|
||||
func loadGeneralSettings() async {
|
||||
do {
|
||||
if let settings = try await loadSettingsUseCase.execute() {
|
||||
selectedTheme = .system // settings.theme ?? .system
|
||||
autoSyncEnabled = settings.autoSyncEnabled
|
||||
syncInterval = settings.syncInterval
|
||||
enableReaderMode = settings.enableReaderMode
|
||||
openExternalLinksInApp = settings.openExternalLinksInApp
|
||||
autoMarkAsRead = settings.autoMarkAsRead
|
||||
appVersion = settings.appVersion ?? "1.0.0"
|
||||
developerName = settings.developerName ?? "Your Name"
|
||||
}
|
||||
} catch {
|
||||
errorMessage = "Fehler beim Laden der Einstellungen"
|
||||
}
|
||||
}
|
||||
|
||||
@MainActor
|
||||
func saveGeneralSettings() async {
|
||||
do {
|
||||
try await saveSettingsUseCase.execute(
|
||||
selectedTheme: selectedTheme,
|
||||
autoSyncEnabled: autoSyncEnabled,
|
||||
syncInterval: syncInterval,
|
||||
enableReaderMode: enableReaderMode,
|
||||
openExternalLinksInApp: openExternalLinksInApp,
|
||||
autoMarkAsRead: autoMarkAsRead
|
||||
)
|
||||
successMessage = "Einstellungen gespeichert"
|
||||
} catch {
|
||||
errorMessage = "Fehler beim Speichern der Einstellungen"
|
||||
}
|
||||
}
|
||||
|
||||
func clearMessages() {
|
||||
errorMessage = nil
|
||||
successMessage = nil
|
||||
}
|
||||
}
|
||||
106
readeck/UI/Settings/SettingsServerViewModel.swift
Normal file
106
readeck/UI/Settings/SettingsServerViewModel.swift
Normal file
@ -0,0 +1,106 @@
|
||||
import Foundation
|
||||
import Observation
|
||||
import SwiftUI
|
||||
|
||||
@Observable
|
||||
class SettingsServerViewModel {
|
||||
private let loginUseCase: LoginUseCase
|
||||
private let logoutUseCase: LogoutUseCase
|
||||
private let saveSettingsUseCase: SaveSettingsUseCase
|
||||
private let loadSettingsUseCase: LoadSettingsUseCase
|
||||
private let settingsRepository: SettingsRepository
|
||||
|
||||
// MARK: - Server Settings
|
||||
var endpoint = ""
|
||||
var username = ""
|
||||
var password = ""
|
||||
var isLoading = false
|
||||
var isLoggedIn = false
|
||||
// MARK: - Messages
|
||||
var errorMessage: String?
|
||||
var successMessage: String?
|
||||
|
||||
init() {
|
||||
let factory = DefaultUseCaseFactory.shared
|
||||
self.loginUseCase = factory.makeLoginUseCase()
|
||||
self.logoutUseCase = factory.makeLogoutUseCase()
|
||||
self.saveSettingsUseCase = factory.makeSaveSettingsUseCase()
|
||||
self.loadSettingsUseCase = factory.makeLoadSettingsUseCase()
|
||||
self.settingsRepository = SettingsRepository()
|
||||
}
|
||||
|
||||
var isSetupMode: Bool {
|
||||
!settingsRepository.hasFinishedSetup
|
||||
}
|
||||
|
||||
@MainActor
|
||||
func loadServerSettings() async {
|
||||
do {
|
||||
if let settings = try await loadSettingsUseCase.execute() {
|
||||
endpoint = settings.endpoint ?? ""
|
||||
username = settings.username ?? ""
|
||||
password = settings.password ?? ""
|
||||
isLoggedIn = settings.isLoggedIn
|
||||
}
|
||||
} catch {
|
||||
errorMessage = "Fehler beim Laden der Einstellungen"
|
||||
}
|
||||
}
|
||||
|
||||
@MainActor
|
||||
func saveServerSettings() async {
|
||||
do {
|
||||
try await saveSettingsUseCase.execute(
|
||||
endpoint: endpoint,
|
||||
username: username,
|
||||
password: password
|
||||
)
|
||||
successMessage = "Server-Einstellungen gespeichert"
|
||||
} catch {
|
||||
errorMessage = "Fehler beim Speichern der Server-Einstellungen"
|
||||
}
|
||||
}
|
||||
|
||||
@MainActor
|
||||
func login() async {
|
||||
isLoading = true
|
||||
errorMessage = nil
|
||||
successMessage = nil
|
||||
do {
|
||||
let _ = try await loginUseCase.execute(username: username, password: password)
|
||||
isLoggedIn = true
|
||||
successMessage = "Erfolgreich angemeldet"
|
||||
try await settingsRepository.saveHasFinishedSetup(true)
|
||||
NotificationCenter.default.post(name: NSNotification.Name("SetupStatusChanged"), object: nil)
|
||||
await DefaultUseCaseFactory.shared.refreshConfiguration()
|
||||
} catch {
|
||||
errorMessage = "Anmeldung fehlgeschlagen"
|
||||
isLoggedIn = false
|
||||
}
|
||||
isLoading = false
|
||||
}
|
||||
|
||||
@MainActor
|
||||
func logout() async {
|
||||
do {
|
||||
try await logoutUseCase.execute()
|
||||
isLoggedIn = false
|
||||
successMessage = "Abgemeldet"
|
||||
NotificationCenter.default.post(name: NSNotification.Name("SetupStatusChanged"), object: nil)
|
||||
} catch {
|
||||
errorMessage = "Fehler beim Abmelden"
|
||||
}
|
||||
}
|
||||
|
||||
func clearMessages() {
|
||||
errorMessage = nil
|
||||
successMessage = nil
|
||||
}
|
||||
|
||||
var canSave: Bool {
|
||||
!endpoint.isEmpty && !username.isEmpty && !password.isEmpty
|
||||
}
|
||||
var canLogin: Bool {
|
||||
!username.isEmpty && !password.isEmpty
|
||||
}
|
||||
}
|
||||
@ -1,144 +0,0 @@
|
||||
import SwiftUI
|
||||
import Foundation
|
||||
|
||||
enum BookmarkState: String, CaseIterable {
|
||||
case unread = "unread"
|
||||
case favorite = "favorite"
|
||||
case archived = "archived"
|
||||
|
||||
var displayName: String {
|
||||
switch self {
|
||||
case .unread:
|
||||
return "Ungelesen"
|
||||
case .favorite:
|
||||
return "Favoriten"
|
||||
case .archived:
|
||||
return "Archiv"
|
||||
}
|
||||
}
|
||||
|
||||
var systemImage: String {
|
||||
switch self {
|
||||
case .unread:
|
||||
return "house"
|
||||
case .favorite:
|
||||
return "heart"
|
||||
case .archived:
|
||||
return "archivebox"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct MainTabView: View {
|
||||
@State private var selectedTab: String = "Ungelesen"
|
||||
|
||||
// sizeClass
|
||||
@Environment(\.horizontalSizeClass)
|
||||
var horizontalSizeClass
|
||||
|
||||
@Environment(\.verticalSizeClass)
|
||||
var verticalSizeClass
|
||||
|
||||
@State var selectedBookmark: Bookmark?
|
||||
|
||||
var body: some View {
|
||||
if UIDevice.isPhone {
|
||||
PhoneView()
|
||||
} else {
|
||||
PadView()
|
||||
}
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
private func PhoneView() -> some View {
|
||||
TabView(selection: $selectedTab) {
|
||||
BookmarksView(state: .unread, selectedBookmark: .constant(nil))
|
||||
.tabItem {
|
||||
Label("Ungelesen", systemImage: "house")
|
||||
}
|
||||
.tag("Ungelesen")
|
||||
|
||||
BookmarksView(state: .favorite, selectedBookmark: .constant(nil))
|
||||
.tabItem {
|
||||
Label("Favoriten", systemImage: "heart")
|
||||
}
|
||||
.tag("Favoriten")
|
||||
|
||||
BookmarksView(state: .archived, selectedBookmark: .constant(nil))
|
||||
.tabItem {
|
||||
Label("Archiv", systemImage: "archivebox")
|
||||
}
|
||||
.tag("Archiv")
|
||||
|
||||
SettingsView()
|
||||
.tabItem {
|
||||
Label("Settings", systemImage: "gear")
|
||||
}
|
||||
.tag("Settings")
|
||||
}
|
||||
.accentColor(.accentColor)
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
private func PadView() -> some View {
|
||||
TabView(selection: $selectedTab) {
|
||||
// Ungelesen Tab
|
||||
NavigationSplitView {
|
||||
BookmarksView(state: .unread, selectedBookmark: $selectedBookmark)
|
||||
} detail: {
|
||||
if let selectedBookmark = selectedBookmark {
|
||||
BookmarkDetailView(bookmarkId: selectedBookmark.id)
|
||||
} else {
|
||||
Text("Select a bookmark")
|
||||
.foregroundColor(.gray)
|
||||
}
|
||||
}
|
||||
.tabItem {
|
||||
Label("Unread", systemImage: "house")
|
||||
}
|
||||
.tag("Unread")
|
||||
|
||||
NavigationSplitViewContainer(state: .favorite, selectedBookmark: $selectedBookmark)
|
||||
.tabItem {
|
||||
Label("Favoriten", systemImage: "heart")
|
||||
}
|
||||
.tag("Favorite")
|
||||
|
||||
NavigationSplitViewContainer(state: .archived, selectedBookmark: $selectedBookmark)
|
||||
.tabItem {
|
||||
Label("Archive", systemImage: "archivebox")
|
||||
}
|
||||
.tag("Archive")
|
||||
|
||||
SettingsView()
|
||||
.tabItem {
|
||||
Label("Settings", systemImage: "gear")
|
||||
}
|
||||
.tag("Settings")
|
||||
}
|
||||
.accentColor(.accentColor)
|
||||
}
|
||||
}
|
||||
|
||||
// Container für NavigationSplitView
|
||||
struct NavigationSplitViewContainer: View {
|
||||
let state: BookmarkState
|
||||
@Binding var selectedBookmark: Bookmark?
|
||||
|
||||
var body: some View {
|
||||
NavigationSplitView {
|
||||
BookmarksView(state: state, selectedBookmark: $selectedBookmark)
|
||||
} detail: {
|
||||
if let selectedBookmark = selectedBookmark {
|
||||
BookmarkDetailView(bookmarkId: selectedBookmark.id)
|
||||
} else {
|
||||
Text("Select a bookmark")
|
||||
.foregroundColor(.gray)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#Preview {
|
||||
MainTabView()
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user