From d036c2e658344edc99215d80cd919bd51df0fd84 Mon Sep 17 00:00:00 2001 From: Ilyas Hallak Date: Wed, 30 Jul 2025 21:18:34 +0200 Subject: [PATCH] feat: Improve AddBookmarkView and loading animations - Simplify AddBookmarkView header by removing large icon and title - Add clipboard monitoring with button directly under URL field - Improve clipboard detection logic with smart URL comparison - Add dismiss functionality for clipboard suggestions - Enhance loading animations in BookmarksView: - Better initial loading screen with centered animation - Use pull-to-refresh instead of overlay for reloading - Add 1-second delay after creating bookmark for server sync - Remove custom Close button styling for default appearance - Improve overall UX with more natural iOS patterns --- Localizable.xcstrings | 13 +-- readeck.xcodeproj/project.pbxproj | 4 +- readeck/UI/AddBookmark/AddBookmarkView.swift | 93 +++++++++---------- .../UI/AddBookmark/AddBookmarkViewModel.swift | 18 +++- .../BookmarkDetail/BookmarkLabelsView.swift | 1 - readeck/UI/Bookmarks/BookmarksView.swift | 31 ++++++- 6 files changed, 95 insertions(+), 65 deletions(-) diff --git a/Localizable.xcstrings b/Localizable.xcstrings index a687d85..6cd4684 100644 --- a/Localizable.xcstrings +++ b/Localizable.xcstrings @@ -50,9 +50,6 @@ }, "Add" : { - }, - "Add a new link to your collection" : { - }, "Add new tag..." : { @@ -94,9 +91,6 @@ }, "Clear cache" : { - }, - "Clipboard" : { - }, "Close" : { @@ -182,7 +176,7 @@ "Labels" : { }, - "Loading %@..." : { + "Loading %@" : { }, "Loading article..." : { @@ -235,6 +229,9 @@ }, "Paste" : { + }, + "Please wait while we fetch your bookmarks..." : { + }, "Preview" : { @@ -345,7 +342,7 @@ "URL" : { }, - "URL found:" : { + "URL in clipboard:" : { }, "Username" : { diff --git a/readeck.xcodeproj/project.pbxproj b/readeck.xcodeproj/project.pbxproj index 3b6050d..10c6f1e 100644 --- a/readeck.xcodeproj/project.pbxproj +++ b/readeck.xcodeproj/project.pbxproj @@ -620,7 +620,7 @@ CODE_SIGN_ENTITLEMENTS = readeck/readeck.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 11; + CURRENT_PROJECT_VERSION = 12; DEVELOPMENT_ASSET_PATHS = "\"readeck/Preview Content\""; DEVELOPMENT_TEAM = 8J69P655GN; ENABLE_HARDENED_RUNTIME = YES; @@ -664,7 +664,7 @@ CODE_SIGN_ENTITLEMENTS = readeck/readeck.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 11; + CURRENT_PROJECT_VERSION = 12; DEVELOPMENT_ASSET_PATHS = "\"readeck/Preview Content\""; DEVELOPMENT_TEAM = 8J69P655GN; ENABLE_HARDENED_RUNTIME = YES; diff --git a/readeck/UI/AddBookmark/AddBookmarkView.swift b/readeck/UI/AddBookmark/AddBookmarkView.swift index fbde167..f0a72dc 100644 --- a/readeck/UI/AddBookmark/AddBookmarkView.swift +++ b/readeck/UI/AddBookmark/AddBookmarkView.swift @@ -19,24 +19,7 @@ struct AddBookmarkView: View { VStack(spacing: 0) { // Scrollable Form Content ScrollView { - VStack(spacing: 24) { - // Header - VStack(spacing: 8) { - Image(systemName: "bookmark.circle.fill") - .font(.system(size: 48)) - .foregroundColor(.accentColor) - - Text("New Bookmark") - .font(.title2) - .fontWeight(.semibold) - - Text("Add a new link to your collection") - .font(.subheadline) - .foregroundColor(.secondary) - .multilineTextAlignment(.center) - } - .padding(.top, 20) - + VStack(spacing: 20) { // Form Fields VStack(spacing: 20) { // URL Field @@ -58,6 +41,46 @@ struct AddBookmarkView: View { .keyboardType(.URL) .autocapitalization(.none) .autocorrectionDisabled() + .onChange(of: viewModel.url) { _, _ in + viewModel.checkClipboard() + } + + // Clipboard Button + if viewModel.showClipboardButton { + HStack { + VStack(alignment: .leading, spacing: 4) { + Text("URL in clipboard:") + .font(.caption) + .foregroundColor(.secondary) + + Text(viewModel.clipboardURL ?? "") + .font(.subheadline) + .lineLimit(1) + .truncationMode(.middle) + } + + Spacer() + + HStack(spacing: 8) { + Button("Paste") { + viewModel.pasteFromClipboard() + } + .buttonStyle(SecondaryButtonStyle()) + + Button(action: { + viewModel.dismissClipboard() + }) { + Image(systemName: "xmark.circle.fill") + .font(.caption) + .foregroundColor(.secondary) + } + } + } + .padding() + .background(Color(.systemGray6)) + .clipShape(RoundedRectangle(cornerRadius: 12)) + .transition(.opacity.combined(with: .move(edge: .top))) + } } // Title Field @@ -98,38 +121,6 @@ struct AddBookmarkView: View { .padding(.top, 8) } } - - // Clipboard Section - if viewModel.clipboardURL != nil { - VStack(alignment: .leading, spacing: 12) { - Label("Clipboard", systemImage: "doc.on.clipboard") - .font(.headline) - .foregroundColor(.primary) - - HStack { - VStack(alignment: .leading, spacing: 4) { - Text("URL found:") - .font(.caption) - .foregroundColor(.secondary) - - Text(viewModel.clipboardURL ?? "") - .font(.subheadline) - .lineLimit(2) - .truncationMode(.middle) - } - - Spacer() - - Button("Paste") { - viewModel.pasteFromClipboard() - } - .buttonStyle(SecondaryButtonStyle()) - } - .padding() - .background(Color(.systemGray6)) - .clipShape(RoundedRectangle(cornerRadius: 12)) - } - } } .padding(.horizontal, 20) @@ -183,6 +174,7 @@ struct AddBookmarkView: View { } .background(Color(.systemBackground)) } + .navigationTitle("New Bookmark") .navigationBarTitleDisplayMode(.inline) .toolbar { ToolbarItem(placement: .navigationBarTrailing) { @@ -190,7 +182,6 @@ struct AddBookmarkView: View { dismiss() viewModel.clearForm() } - .foregroundColor(.secondary) } } .alert("Error", isPresented: $viewModel.showErrorAlert) { diff --git a/readeck/UI/AddBookmark/AddBookmarkViewModel.swift b/readeck/UI/AddBookmark/AddBookmarkViewModel.swift index 46c1664..6064bca 100644 --- a/readeck/UI/AddBookmark/AddBookmarkViewModel.swift +++ b/readeck/UI/AddBookmark/AddBookmarkViewModel.swift @@ -14,6 +14,7 @@ class AddBookmarkViewModel { var showErrorAlert: Bool = false var hasCreated: Bool = false var clipboardURL: String? + var showClipboardButton: Bool = false var isValid: Bool { !url.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty && @@ -68,20 +69,35 @@ class AddBookmarkViewModel { guard let clipboardString = UIPasteboard.general.string, URL(string: clipboardString) != nil else { clipboardURL = nil + showClipboardButton = false return } - clipboardURL = clipboardString + // Only show clipboard button if the URL is different from current URL + let currentURL = url.trimmingCharacters(in: .whitespacesAndNewlines) + if clipboardString != currentURL { + clipboardURL = clipboardString + showClipboardButton = true + } else { + showClipboardButton = false + } } func pasteFromClipboard() { guard let clipboardURL = clipboardURL else { return } url = clipboardURL + showClipboardButton = false + } + + func dismissClipboard() { + showClipboardButton = false } func clearForm() { url = "" title = "" labelsText = "" + clipboardURL = nil + showClipboardButton = false } } diff --git a/readeck/UI/BookmarkDetail/BookmarkLabelsView.swift b/readeck/UI/BookmarkDetail/BookmarkLabelsView.swift index 8ef3a81..0c9a798 100644 --- a/readeck/UI/BookmarkDetail/BookmarkLabelsView.swift +++ b/readeck/UI/BookmarkDetail/BookmarkLabelsView.swift @@ -11,7 +11,6 @@ struct BookmarkLabelsView: View { UIPageControl.appearance().currentPageIndicatorTintColor = UIColor(Color.primary) UIPageControl.appearance().pageIndicatorTintColor = UIColor(Color.primary).withAlphaComponent(0.2) - } var body: some View { diff --git a/readeck/UI/Bookmarks/BookmarksView.swift b/readeck/UI/Bookmarks/BookmarksView.swift index 23b348b..d13a01d 100644 --- a/readeck/UI/Bookmarks/BookmarksView.swift +++ b/readeck/UI/Bookmarks/BookmarksView.swift @@ -38,7 +38,31 @@ struct BookmarksView: View { var body: some View { ZStack { if viewModel.isLoading && viewModel.bookmarks?.bookmarks.isEmpty == true { - ProgressView("Loading \(state.displayName)...") + VStack(spacing: 20) { + Spacer() + + VStack(spacing: 16) { + ProgressView() + .scaleEffect(1.3) + .tint(.accentColor) + + VStack(spacing: 8) { + Text("Loading \(state.displayName)") + .font(.headline) + .foregroundColor(.primary) + + Text("Please wait while we fetch your bookmarks...") + .font(.subheadline) + .foregroundColor(.secondary) + .multilineTextAlignment(.center) + } + } + .padding(.horizontal, 40) + + Spacer() + } + .frame(maxWidth: .infinity, maxHeight: .infinity) + .background(Color(R.color.bookmark_list_bg)) } else { List { ForEach(viewModel.bookmarks?.bookmarks ?? [], id: \.id) { bookmark in @@ -169,7 +193,10 @@ struct BookmarksView: View { // Refresh bookmarks when sheet is dismissed if oldValue && !newValue { Task { - await viewModel.loadBookmarks(state: state, type: type) + // Wait a bit for the server to process the new bookmark + try? await Task.sleep(nanoseconds: 1_000_000_000) // 1 second + + await viewModel.refreshBookmarks() } } }