From d2e82289031e96dbf934a90bc7c5e0ad70e61098 Mon Sep 17 00:00:00 2001 From: Ilyas Hallak Date: Tue, 8 Jul 2025 16:30:27 +0200 Subject: [PATCH] feat: Add label management to bookmarks and UI improvements - BookmarkDetail: Add labels property, display and manage labels in detail view - Add AddLabelsToBookmarkUseCase and RemoveLabelsFromBookmarkUseCase - Update UpdateBookmarkUseCase and BookmarkUpdateRequest for label operations - UI: Show labels in BookmarkDetailView, add label management sheet - DefaultUseCaseFactory: Provide use cases for label management - Localizable: Add/adjust label-related strings, minor cleanup - SettingsServerView: Update debug endpoint - SidebarTab: Change 'Alle' to 'All' - Project: Remove unused region from Xcode project --- Localizable.xcstrings | 60 +++--- readeck.xcodeproj/project.pbxproj | 1 - .../Data/Repository/BookmarksRepository.swift | 1 + readeck/Domain/Model/BookmarkDetail.swift | 2 + .../Domain/Model/BookmarkUpdateRequest.swift | 8 + .../UseCase/AddLabelsToBookmarkUseCase.swift | 43 +++++ .../RemoveLabelsFromBookmarkUseCase.swift | 31 ++++ .../UseCase/UpdateBookmarkUseCase.swift | 10 + .../BookmarkDetail/BookmarkDetailView.swift | 75 +++++++- .../BookmarkDetailViewModel.swift | 5 + .../BookmarkDetail/BookmarkLabelsView.swift | 175 ++++++++++++++++++ .../BookmarkLabelsViewModel.swift | 86 +++++++++ readeck/UI/DefaultUseCaseFactory.swift | 10 + readeck/UI/Menu/SidebarTab.swift | 2 +- readeck/UI/Settings/SettingsServerView.swift | 2 +- 15 files changed, 471 insertions(+), 40 deletions(-) create mode 100644 readeck/Domain/UseCase/AddLabelsToBookmarkUseCase.swift create mode 100644 readeck/Domain/UseCase/RemoveLabelsFromBookmarkUseCase.swift create mode 100644 readeck/UI/BookmarkDetail/BookmarkLabelsView.swift create mode 100644 readeck/UI/BookmarkDetail/BookmarkLabelsViewModel.swift diff --git a/Localizable.xcstrings b/Localizable.xcstrings index f0d25af..ac9c214 100644 --- a/Localizable.xcstrings +++ b/Localizable.xcstrings @@ -14,20 +14,27 @@ }, "Abbrechen" : { - "localizations" : { - "de" : { - "stringUnit" : { - "state" : "needs_review", - "value" : "Abbrechen" - } - } - } + }, "Abmelden" : { }, "Add Item" : { + }, + "Aktuelle Labels" : { + + }, + "all" : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ale" + } + } + } }, "Anmelden & speichern" : { @@ -61,17 +68,6 @@ }, "Debug-Anmeldung" : { - }, - "done" : { - "extractionState" : "manual", - "localizations" : { - "de" : { - "stringUnit" : { - "state" : "translated", - "value" : "Fertig" - } - } - } }, "Einfügen" : { @@ -117,17 +113,6 @@ }, "Fertig mit Lesen?" : { - }, - "font_settings_title" : { - "extractionState" : "manual", - "localizations" : { - "de" : { - "stringUnit" : { - "state" : "translated", - "value" : "Schrift-Einstellungen" - } - } - } }, "Füge einen neuen Link zu deiner Sammlung hinzu" : { @@ -161,9 +146,21 @@ }, "Keine Ergebnisse" : { + }, + "Keine Labels vorhanden" : { + + }, + "Key" : { + "extractionState" : "manual" + }, + "Label eingeben..." : { + }, "Labels" : { + }, + "Labels verwalten" : { + }, "Lade %@..." : { @@ -185,6 +182,9 @@ }, "Neues Bookmark" : { + }, + "Neues Label hinzufügen" : { + }, "OK" : { diff --git a/readeck.xcodeproj/project.pbxproj b/readeck.xcodeproj/project.pbxproj index 731ac69..2918e14 100644 --- a/readeck.xcodeproj/project.pbxproj +++ b/readeck.xcodeproj/project.pbxproj @@ -319,7 +319,6 @@ knownRegions = ( en, Base, - "fr-CA", de, ); mainGroup = 5D45F9BF2DF858680048D5B8; diff --git a/readeck/Data/Repository/BookmarksRepository.swift b/readeck/Data/Repository/BookmarksRepository.swift index 5a63a4f..d5b02a7 100644 --- a/readeck/Data/Repository/BookmarksRepository.swift +++ b/readeck/Data/Repository/BookmarksRepository.swift @@ -38,6 +38,7 @@ class BookmarksRepository: PBookmarksRepository { hasArticle: bookmarkDetailDto.hasArticle, isMarked: bookmarkDetailDto.isMarked, isArchived: bookmarkDetailDto.isArchived, + labels: bookmarkDetailDto.labels, thumbnailUrl: bookmarkDetailDto.resources.thumbnail?.src ?? "", imageUrl: bookmarkDetailDto.resources.image?.src ?? "" ) diff --git a/readeck/Domain/Model/BookmarkDetail.swift b/readeck/Domain/Model/BookmarkDetail.swift index 9a6ea0e..37c37fb 100644 --- a/readeck/Domain/Model/BookmarkDetail.swift +++ b/readeck/Domain/Model/BookmarkDetail.swift @@ -14,6 +14,7 @@ struct BookmarkDetail { let hasArticle: Bool let isMarked: Bool var isArchived: Bool + let labels: [String] let thumbnailUrl: String let imageUrl: String } @@ -33,6 +34,7 @@ extension BookmarkDetail { hasArticle: false, isMarked: false, isArchived: false, + labels: [], thumbnailUrl: "", imageUrl: "" ) diff --git a/readeck/Domain/Model/BookmarkUpdateRequest.swift b/readeck/Domain/Model/BookmarkUpdateRequest.swift index 3c838c8..0b504b6 100644 --- a/readeck/Domain/Model/BookmarkUpdateRequest.swift +++ b/readeck/Domain/Model/BookmarkUpdateRequest.swift @@ -59,4 +59,12 @@ extension BookmarkUpdateRequest { static func updateLabels(_ labels: [String]) -> BookmarkUpdateRequest { return BookmarkUpdateRequest(labels: labels) } + + static func addLabels(_ labels: [String]) -> BookmarkUpdateRequest { + return BookmarkUpdateRequest(addLabels: labels) + } + + static func removeLabels(_ labels: [String]) -> BookmarkUpdateRequest { + return BookmarkUpdateRequest(removeLabels: labels) + } } \ No newline at end of file diff --git a/readeck/Domain/UseCase/AddLabelsToBookmarkUseCase.swift b/readeck/Domain/UseCase/AddLabelsToBookmarkUseCase.swift new file mode 100644 index 0000000..58869e3 --- /dev/null +++ b/readeck/Domain/UseCase/AddLabelsToBookmarkUseCase.swift @@ -0,0 +1,43 @@ +import Foundation + +class AddLabelsToBookmarkUseCase { + private let repository: PBookmarksRepository + + init(repository: PBookmarksRepository) { + self.repository = repository + } + + func execute(bookmarkId: String, labels: [String]) async throws { + // Validierung der Labels + guard !labels.isEmpty else { + throw BookmarkUpdateError.emptyLabels + } + + // Entferne leere Labels und Duplikate + let cleanLabels = Array(Set(labels.filter { !$0.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty })) + + guard !cleanLabels.isEmpty else { + throw BookmarkUpdateError.emptyLabels + } + + let request = BookmarkUpdateRequest.addLabels(cleanLabels) + try await repository.updateBookmark(id: bookmarkId, updateRequest: request) + } + + // Convenience method für einzelne Labels + func execute(bookmarkId: String, label: String) async throws { + try await execute(bookmarkId: bookmarkId, labels: [label]) + } +} + +// Custom error für Label-Operationen +enum BookmarkUpdateError: LocalizedError { + case emptyLabels + + var errorDescription: String? { + switch self { + case .emptyLabels: + return "Labels können nicht leer sein" + } + } +} \ No newline at end of file diff --git a/readeck/Domain/UseCase/RemoveLabelsFromBookmarkUseCase.swift b/readeck/Domain/UseCase/RemoveLabelsFromBookmarkUseCase.swift new file mode 100644 index 0000000..b9f3159 --- /dev/null +++ b/readeck/Domain/UseCase/RemoveLabelsFromBookmarkUseCase.swift @@ -0,0 +1,31 @@ +import Foundation + +class RemoveLabelsFromBookmarkUseCase { + private let repository: PBookmarksRepository + + init(repository: PBookmarksRepository) { + self.repository = repository + } + + func execute(bookmarkId: String, labels: [String]) async throws { + // Validierung der Labels + guard !labels.isEmpty else { + throw BookmarkUpdateError.emptyLabels + } + + // Entferne leere Labels und Duplikate + let cleanLabels = Array(Set(labels.filter { !$0.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty })) + + guard !cleanLabels.isEmpty else { + throw BookmarkUpdateError.emptyLabels + } + + let request = BookmarkUpdateRequest.removeLabels(cleanLabels) + try await repository.updateBookmark(id: bookmarkId, updateRequest: request) + } + + // Convenience method für einzelne Labels + func execute(bookmarkId: String, label: String) async throws { + try await execute(bookmarkId: bookmarkId, labels: [label]) + } +} \ No newline at end of file diff --git a/readeck/Domain/UseCase/UpdateBookmarkUseCase.swift b/readeck/Domain/UseCase/UpdateBookmarkUseCase.swift index fe1e06d..1aa71af 100644 --- a/readeck/Domain/UseCase/UpdateBookmarkUseCase.swift +++ b/readeck/Domain/UseCase/UpdateBookmarkUseCase.swift @@ -41,4 +41,14 @@ class UpdateBookmarkUseCase { let request = BookmarkUpdateRequest.updateLabels(labels) try await execute(bookmarkId: bookmarkId, updateRequest: request) } + + func addLabels(bookmarkId: String, labels: [String]) async throws { + let request = BookmarkUpdateRequest.addLabels(labels) + try await execute(bookmarkId: bookmarkId, updateRequest: request) + } + + func removeLabels(bookmarkId: String, labels: [String]) async throws { + let request = BookmarkUpdateRequest.removeLabels(labels) + try await execute(bookmarkId: bookmarkId, updateRequest: request) + } } \ No newline at end of file diff --git a/readeck/UI/BookmarkDetail/BookmarkDetailView.swift b/readeck/UI/BookmarkDetail/BookmarkDetailView.swift index d945404..9948975 100644 --- a/readeck/UI/BookmarkDetail/BookmarkDetailView.swift +++ b/readeck/UI/BookmarkDetail/BookmarkDetailView.swift @@ -6,8 +6,9 @@ struct BookmarkDetailView: View { @State private var viewModel = BookmarkDetailViewModel() @State private var webViewHeight: CGFloat = 300 @State private var showingFontSettings = false + @State private var showingLabelsSheet = false - private let headerHeight: CGFloat = 260 + private let headerHeight: CGFloat = 320 var body: some View { GeometryReader { geometry in @@ -29,10 +30,18 @@ struct BookmarkDetailView: View { .navigationBarTitleDisplayMode(.inline) .toolbar { ToolbarItem(placement: .navigationBarTrailing) { - Button(action: { - showingFontSettings = true - }) { - Image(systemName: "textformat") + HStack(spacing: 12) { + Button(action: { + showingLabelsSheet = true + }) { + Image(systemName: "tag") + } + + Button(action: { + showingFontSettings = true + }) { + Image(systemName: "textformat") + } } } } @@ -57,6 +66,9 @@ struct BookmarkDetailView: View { } } } + .sheet(isPresented: $showingLabelsSheet) { + BookmarkLabelsView(bookmarkId: bookmarkId, initialLabels: viewModel.bookmarkDetail.labels) + } .onChange(of: showingFontSettings) { _, isShowing in if !isShowing { // Reload settings when sheet is dismissed @@ -65,6 +77,14 @@ struct BookmarkDetailView: View { } } } + .onChange(of: showingLabelsSheet) { _, isShowing in + if !isShowing { + // Reload bookmark detail when labels sheet is dismissed + Task { + await viewModel.refreshBookmarkDetail(id: bookmarkId) + } + } + } .task { await viewModel.loadBookmarkDetail(id: bookmarkId) await viewModel.loadArticleContent(id: bookmarkId) @@ -91,13 +111,22 @@ struct BookmarkDetailView: View { .fill(Color.gray.opacity(0.4)) .frame(width: geometry.size.width, height: headerHeight) } + // Gradient overlay für bessere Button-Sichtbarkeit LinearGradient( - gradient: Gradient(colors: [Color.black.opacity(0.6), Color.clear]), + gradient: Gradient(colors: [ + Color.black.opacity(1.0), + Color.black.opacity(0.9), + Color.black.opacity(0.7), + Color.black.opacity(0.4), + Color.black.opacity(0.2), + Color.clear + ]), startPoint: .top, endPoint: .bottom ) - .frame(height: 120) + .frame(height: 240) .frame(maxWidth: .infinity) + .offset(y: (offset > 0 ? -offset : 0)) } } .frame(height: headerHeight) @@ -155,6 +184,38 @@ struct BookmarkDetailView: View { } metaRow(icon: "calendar", text: formatDate(viewModel.bookmarkDetail.created)) metaRow(icon: "textformat", text: "\(viewModel.bookmarkDetail.wordCount ?? 0) Wörter • \(viewModel.bookmarkDetail.readingTime ?? 0) min Lesezeit") + + // Labels section + if !viewModel.bookmarkDetail.labels.isEmpty { + HStack(alignment: .top, spacing: 8) { + Image(systemName: "tag") + .foregroundColor(.secondary) + .padding(.top, 2) + + ScrollView(.horizontal, showsIndicators: false) { + HStack(spacing: 6) { + ForEach(viewModel.bookmarkDetail.labels, id: \.self) { label in + Text(label) + .font(.caption) + .fontWeight(.medium) + .foregroundColor(.primary) + .padding(.horizontal, 8) + .padding(.vertical, 4) + .background( + RoundedRectangle(cornerRadius: 12) + .fill(Color.accentColor.opacity(0.1)) + .overlay( + RoundedRectangle(cornerRadius: 12) + .stroke(Color.accentColor.opacity(0.3), lineWidth: 1) + ) + ) + } + } + .padding(.trailing, 8) + } + } + } + metaRow(icon: "safari") { Button(action: { SafariUtil.openInSafari(url: viewModel.bookmarkDetail.url) diff --git a/readeck/UI/BookmarkDetail/BookmarkDetailViewModel.swift b/readeck/UI/BookmarkDetail/BookmarkDetailViewModel.swift index ccc4d73..2006c41 100644 --- a/readeck/UI/BookmarkDetail/BookmarkDetailViewModel.swift +++ b/readeck/UI/BookmarkDetail/BookmarkDetailViewModel.swift @@ -73,4 +73,9 @@ class BookmarkDetailViewModel { } isLoading = false } + + @MainActor + func refreshBookmarkDetail(id: String) async { + await loadBookmarkDetail(id: id) + } } diff --git a/readeck/UI/BookmarkDetail/BookmarkLabelsView.swift b/readeck/UI/BookmarkDetail/BookmarkLabelsView.swift new file mode 100644 index 0000000..afcad23 --- /dev/null +++ b/readeck/UI/BookmarkDetail/BookmarkLabelsView.swift @@ -0,0 +1,175 @@ +import SwiftUI + +struct BookmarkLabelsView: View { + let bookmarkId: String + @State private var viewModel: BookmarkLabelsViewModel + @Environment(\.dismiss) private var dismiss + + init(bookmarkId: String, initialLabels: [String]) { + self.bookmarkId = bookmarkId + self._viewModel = State(initialValue: BookmarkLabelsViewModel(initialLabels: initialLabels)) + } + + var body: some View { + NavigationView { + VStack(spacing: 16) { + // Add new label section + addLabelSection + + Divider() + .padding(.horizontal, -16) + + // Current labels section + currentLabelsSection + + Spacer() + } + .padding() + .background(Color(.systemGroupedBackground)) + .navigationTitle("Labels verwalten") + .navigationBarTitleDisplayMode(.inline) + .toolbar { + ToolbarItem(placement: .navigationBarLeading) { + Button("Abbrechen") { + dismiss() + } + } + ToolbarItem(placement: .navigationBarTrailing) { + Button("Fertig") { + dismiss() + } + } + } + .alert("Fehler", isPresented: $viewModel.showErrorAlert) { + Button("OK") { } + } message: { + Text(viewModel.errorMessage ?? "Unbekannter Fehler") + } + } + } + + private var addLabelSection: some View { + VStack(alignment: .leading, spacing: 12) { + Text("Neues Label hinzufügen") + .font(.headline) + .foregroundColor(.primary) + + HStack(spacing: 12) { + TextField("Label eingeben...", text: $viewModel.newLabelText) + .textFieldStyle(RoundedBorderTextFieldStyle()) + .onSubmit { + Task { + await viewModel.addLabel(to: bookmarkId, label: viewModel.newLabelText) + } + } + + Button(action: { + Task { + await viewModel.addLabel(to: bookmarkId, label: viewModel.newLabelText) + } + }) { + Image(systemName: "plus.circle.fill") + .font(.title2) + .foregroundColor(.white) + .frame(width: 32, height: 32) + .background( + Circle() + .fill(Color.accentColor) + ) + } + .disabled(viewModel.newLabelText.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty || viewModel.isLoading) + } + } + .padding() + .background( + RoundedRectangle(cornerRadius: 12) + .fill(Color(.secondarySystemGroupedBackground)) + ) + } + + private var currentLabelsSection: some View { + VStack(alignment: .leading, spacing: 8) { + HStack { + Text("Aktuelle Labels") + .font(.headline) + .foregroundColor(.primary) + + Spacer() + + if viewModel.isLoading { + ProgressView() + .scaleEffect(0.8) + } + } + + if viewModel.currentLabels.isEmpty { + VStack(spacing: 8) { + Image(systemName: "tag") + .font(.title2) + .foregroundColor(.secondary) + Text("Keine Labels vorhanden") + .font(.subheadline) + .foregroundColor(.secondary) + } + .frame(maxWidth: .infinity) + .padding(.vertical, 32) + } else { + LazyVGrid(columns: [ + GridItem(.adaptive(minimum: 80, maximum: 150)) + ], spacing: 4) { + ForEach(viewModel.currentLabels, id: \.self) { label in + LabelChip( + label: label, + onRemove: { + Task { + await viewModel.removeLabel(from: bookmarkId, label: label) + } + } + ) + } + } + } + } + .padding() + .background( + RoundedRectangle(cornerRadius: 12) + .fill(Color(.secondarySystemGroupedBackground)) + ) + } +} + +struct LabelChip: View { + let label: String + let onRemove: () -> Void + + var body: some View { + HStack(spacing: 6) { + Text(label) + .font(.caption) + .fontWeight(.medium) + .foregroundColor(.primary) + .lineLimit(1) + .truncationMode(.tail) + + Button(action: onRemove) { + Image(systemName: "xmark.circle.fill") + .font(.caption) + .foregroundColor(.secondary) + } + } + .padding(.horizontal, 10) + .padding(.vertical, 6) + .background( + RoundedRectangle(cornerRadius: 16) + .fill(Color.accentColor.opacity(0.15)) + .overlay( + RoundedRectangle(cornerRadius: 16) + .stroke(Color.accentColor.opacity(0.4), lineWidth: 1) + ) + ) + } +} + +#Preview { + BookmarkLabelsView(bookmarkId: "test-id", initialLabels: ["wichtig", "arbeit", "persönlich"]) +} \ No newline at end of file diff --git a/readeck/UI/BookmarkDetail/BookmarkLabelsViewModel.swift b/readeck/UI/BookmarkDetail/BookmarkLabelsViewModel.swift new file mode 100644 index 0000000..e43b01f --- /dev/null +++ b/readeck/UI/BookmarkDetail/BookmarkLabelsViewModel.swift @@ -0,0 +1,86 @@ +import Foundation + +@Observable +class BookmarkLabelsViewModel { + private let addLabelsUseCase = DefaultUseCaseFactory.shared.makeAddLabelsToBookmarkUseCase() + private let removeLabelsUseCase = DefaultUseCaseFactory.shared.makeRemoveLabelsFromBookmarkUseCase() + + var isLoading = false + var errorMessage: String? + var showErrorAlert = false + var currentLabels: [String] = [] + var newLabelText = "" + + init(initialLabels: [String] = []) { + self.currentLabels = initialLabels + } + + @MainActor + func addLabels(to bookmarkId: String, labels: [String]) async { + isLoading = true + errorMessage = nil + + do { + try await addLabelsUseCase.execute(bookmarkId: bookmarkId, labels: labels) + // Update local labels + currentLabels.append(contentsOf: labels) + currentLabels = Array(Set(currentLabels)) // Remove duplicates + } catch let error as BookmarkUpdateError { + errorMessage = error.localizedDescription + showErrorAlert = true + } catch { + errorMessage = "Fehler beim Hinzufügen der Labels" + showErrorAlert = true + } + + isLoading = false + } + + @MainActor + func addLabel(to bookmarkId: String, label: String) async { + let trimmedLabel = label.trimmingCharacters(in: .whitespacesAndNewlines) + guard !trimmedLabel.isEmpty else { return } + + await addLabels(to: bookmarkId, labels: [trimmedLabel]) + newLabelText = "" + } + + @MainActor + func removeLabels(from bookmarkId: String, labels: [String]) async { + isLoading = true + errorMessage = nil + + do { + try await removeLabelsUseCase.execute(bookmarkId: bookmarkId, labels: labels) + // Update local labels + currentLabels.removeAll { labels.contains($0) } + } catch let error as BookmarkUpdateError { + errorMessage = error.localizedDescription + showErrorAlert = true + } catch { + errorMessage = "Fehler beim Entfernen der Labels" + showErrorAlert = true + } + + isLoading = false + } + + @MainActor + func removeLabel(from bookmarkId: String, label: String) async { + await removeLabels(from: bookmarkId, labels: [label]) + } + + // Convenience method für das Umschalten eines Labels (hinzufügen wenn nicht vorhanden, entfernen wenn vorhanden) + @MainActor + func toggleLabel(for bookmarkId: String, label: String) async { + if currentLabels.contains(label) { + await removeLabel(from: bookmarkId, label: label) + } else { + await addLabel(to: bookmarkId, label: label) + } + } + + func updateLabels(_ labels: [String]) { + currentLabels = labels + } +} \ No newline at end of file diff --git a/readeck/UI/DefaultUseCaseFactory.swift b/readeck/UI/DefaultUseCaseFactory.swift index f137157..2a346f4 100644 --- a/readeck/UI/DefaultUseCaseFactory.swift +++ b/readeck/UI/DefaultUseCaseFactory.swift @@ -13,6 +13,8 @@ protocol UseCaseFactory { func makeLogoutUseCase() -> LogoutUseCase func makeSearchBookmarksUseCase() -> SearchBookmarksUseCase func makeSaveServerSettingsUseCase() -> SaveServerSettingsUseCase + func makeAddLabelsToBookmarkUseCase() -> AddLabelsToBookmarkUseCase + func makeRemoveLabelsFromBookmarkUseCase() -> RemoveLabelsFromBookmarkUseCase } class DefaultUseCaseFactory: UseCaseFactory { @@ -78,4 +80,12 @@ class DefaultUseCaseFactory: UseCaseFactory { func makeSaveServerSettingsUseCase() -> SaveServerSettingsUseCase { return SaveServerSettingsUseCase(repository: SettingsRepository()) } + + func makeAddLabelsToBookmarkUseCase() -> AddLabelsToBookmarkUseCase { + return AddLabelsToBookmarkUseCase(repository: bookmarksRepository) + } + + func makeRemoveLabelsFromBookmarkUseCase() -> RemoveLabelsFromBookmarkUseCase { + return RemoveLabelsFromBookmarkUseCase(repository: bookmarksRepository) + } } diff --git a/readeck/UI/Menu/SidebarTab.swift b/readeck/UI/Menu/SidebarTab.swift index a51c9b5..edbfb84 100644 --- a/readeck/UI/Menu/SidebarTab.swift +++ b/readeck/UI/Menu/SidebarTab.swift @@ -12,7 +12,7 @@ enum SidebarTab: Hashable, CaseIterable, Identifiable { var label: String { switch self { - case .all: return "Alle" + case .all: return "All" case .unread: return "Ungelesen" case .favorite: return "Favoriten" case .archived: return "Archiv" diff --git a/readeck/UI/Settings/SettingsServerView.swift b/readeck/UI/Settings/SettingsServerView.swift index d7a3bde..3bac051 100644 --- a/readeck/UI/Settings/SettingsServerView.swift +++ b/readeck/UI/Settings/SettingsServerView.swift @@ -126,7 +126,7 @@ struct SettingsServerView: View { Button("Debug-Anmeldung") { viewModel.username = "admin" viewModel.password = "Diggah123" - viewModel.endpoint = "https://readeck.mnk.any64.de" + viewModel.endpoint = "https://keep.mnk.any64.de" } .font(.caption) .foregroundColor(.secondary)