feat: add delete confirmation for bookmarks and UI improvements
- Add confirmation alert before deleting a bookmark to prevent accidental deletions (BookmarksView) - Add localized strings for delete confirmation dialog - Improve layout and logic in BookmarkDetailView (alignment, locale, progress jump) - Show read progress only for non-archived/non-marked bookmarks (BookmarkCardView) - Refine WebView: remove debug code, improve scroll/height update logic, disable scroll
This commit is contained in:
parent
dd1b2628b6
commit
176885442e
@ -70,6 +70,9 @@
|
||||
},
|
||||
"Archive bookmark" : {
|
||||
|
||||
},
|
||||
"Are you sure you want to delete this bookmark? This action cannot be undone." : {
|
||||
|
||||
},
|
||||
"Are you sure you want to log out? This will delete all your login credentials and return you to setup." : {
|
||||
|
||||
@ -100,6 +103,9 @@
|
||||
},
|
||||
"Delete" : {
|
||||
|
||||
},
|
||||
"Delete Bookmark" : {
|
||||
|
||||
},
|
||||
"Developer: Ilyas Hallak" : {
|
||||
|
||||
|
||||
@ -48,7 +48,7 @@ struct BookmarkDetailView: View {
|
||||
.frame(height: 0)
|
||||
ZStack(alignment: .top) {
|
||||
headerView(geometry: outerGeo)
|
||||
VStack(alignment: .center, spacing: 16) {
|
||||
VStack(alignment: .leading, spacing: 16) {
|
||||
Color.clear.frame(height: viewModel.bookmarkDetail.imageUrl.isEmpty ? 84 : headerHeight)
|
||||
titleSection
|
||||
Divider().padding(.horizontal)
|
||||
@ -57,7 +57,9 @@ struct BookmarkDetailView: View {
|
||||
}
|
||||
if let settings = viewModel.settings, !viewModel.articleContent.isEmpty {
|
||||
WebView(htmlContent: viewModel.articleContent, settings: settings, onHeightChange: { height in
|
||||
if webViewHeight != height {
|
||||
webViewHeight = height
|
||||
}
|
||||
})
|
||||
.frame(height: webViewHeight)
|
||||
.cornerRadius(14)
|
||||
@ -82,12 +84,15 @@ struct BookmarkDetailView: View {
|
||||
.padding(.horizontal)
|
||||
.padding(.top, 0)
|
||||
}
|
||||
Spacer(minLength: 40)
|
||||
|
||||
if viewModel.isLoadingArticle == false && viewModel.isLoading == false {
|
||||
VStack(alignment: .center) {
|
||||
archiveSection
|
||||
.transition(.opacity.combined(with: .move(edge: .bottom)))
|
||||
.animation(.easeInOut, value: viewModel.articleContent)
|
||||
}
|
||||
.frame(maxWidth: .infinity)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -358,7 +363,7 @@ struct BookmarkDetailView: View {
|
||||
let displayFormatter = DateFormatter()
|
||||
displayFormatter.dateStyle = .medium
|
||||
displayFormatter.timeStyle = .short
|
||||
displayFormatter.locale = Locale(identifier: "de_DE")
|
||||
displayFormatter.locale = .autoupdatingCurrent
|
||||
return displayFormatter.string(from: date)
|
||||
}
|
||||
return dateString
|
||||
@ -417,14 +422,12 @@ struct BookmarkDetailView: View {
|
||||
@ViewBuilder
|
||||
func JumpButton() -> some View {
|
||||
Button(action: {
|
||||
if #available(iOS 17.0, *) {
|
||||
let maxOffset = webViewHeight - scrollViewHeight
|
||||
let offset = maxOffset * (Double(viewModel.readProgress) / 100.0)
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
|
||||
scrollPosition = ScrollPosition(y: offset)
|
||||
showJumpToProgressButton = false
|
||||
}
|
||||
}
|
||||
}) {
|
||||
Text("Jump to last read position (\(viewModel.readProgress)%)")
|
||||
.font(.subheadline)
|
||||
|
||||
@ -28,7 +28,7 @@ struct BookmarkCardView: View {
|
||||
}
|
||||
.clipShape(RoundedRectangle(cornerRadius: 8))
|
||||
|
||||
if bookmark.readProgress > 0 {
|
||||
if bookmark.readProgress > 0 && bookmark.isArchived == false && bookmark.isMarked == false {
|
||||
ZStack {
|
||||
Circle()
|
||||
.fill(Color(.systemBackground))
|
||||
|
||||
@ -12,6 +12,7 @@ struct BookmarksView: View {
|
||||
@State private var showingAddBookmarkFromShare = false
|
||||
@State private var shareURL = ""
|
||||
@State private var shareTitle = ""
|
||||
@State private var bookmarkToDelete: Bookmark? = nil
|
||||
|
||||
let state: BookmarkState
|
||||
let type: [BookmarkType]
|
||||
@ -19,7 +20,6 @@ struct BookmarksView: View {
|
||||
@EnvironmentObject var playerUIState: PlayerUIState
|
||||
let tag: String?
|
||||
|
||||
|
||||
// MARK: Environments
|
||||
|
||||
@Environment(\.horizontalSizeClass) var horizontalSizeClass
|
||||
@ -65,9 +65,7 @@ struct BookmarksView: View {
|
||||
}
|
||||
},
|
||||
onDelete: { bookmark in
|
||||
Task {
|
||||
await viewModel.deleteBookmark(bookmark: bookmark)
|
||||
}
|
||||
bookmarkToDelete = bookmark
|
||||
},
|
||||
onToggleFavorite: { bookmark in
|
||||
Task {
|
||||
@ -150,6 +148,18 @@ struct BookmarksView: View {
|
||||
AddBookmarkView(prefilledURL: shareURL, prefilledTitle: shareTitle)
|
||||
}
|
||||
)
|
||||
.alert(item: $bookmarkToDelete) { bookmark in
|
||||
Alert(
|
||||
title: Text("Delete Bookmark"),
|
||||
message: Text("Are you sure you want to delete this bookmark? This action cannot be undone."),
|
||||
primaryButton: .destructive(Text("Delete")) {
|
||||
Task {
|
||||
await viewModel.deleteBookmark(bookmark: bookmark)
|
||||
}
|
||||
},
|
||||
secondaryButton: .cancel()
|
||||
)
|
||||
}
|
||||
.onAppear {
|
||||
Task {
|
||||
await viewModel.loadBookmarks(state: state, type: type, tag: tag)
|
||||
|
||||
@ -11,7 +11,7 @@ struct WebView: UIViewRepresentable {
|
||||
func makeUIView(context: Context) -> WKWebView {
|
||||
let webView = WKWebView()
|
||||
webView.navigationDelegate = context.coordinator
|
||||
webView.scrollView.isScrollEnabled = true
|
||||
webView.scrollView.isScrollEnabled = false
|
||||
webView.isOpaque = false
|
||||
webView.backgroundColor = UIColor.clear
|
||||
|
||||
@ -214,17 +214,13 @@ struct WebView: UIViewRepresentable {
|
||||
<body>
|
||||
\(htmlContent)
|
||||
<script>
|
||||
console.log('Script loaded!');
|
||||
alert('Script loaded!');
|
||||
function updateHeight() {
|
||||
const height = document.body.scrollHeight;
|
||||
window.webkit.messageHandlers.heightUpdate.postMessage(height);
|
||||
}
|
||||
|
||||
window.addEventListener('load', updateHeight);
|
||||
setTimeout(updateHeight, 100);
|
||||
setTimeout(updateHeight, 500);
|
||||
setTimeout(updateHeight, 1000);
|
||||
|
||||
// Höhe bei Bild-Ladevorgängen aktualisieren
|
||||
document.querySelectorAll('img').forEach(img => {
|
||||
@ -236,7 +232,6 @@ struct WebView: UIViewRepresentable {
|
||||
var docHeight = document.documentElement.scrollHeight - document.documentElement.clientHeight;
|
||||
var progress = docHeight > 0 ? scrollTop / docHeight : 0;
|
||||
window.webkit.messageHandlers.scrollProgress.postMessage(progress);
|
||||
console.log('Scroll event fired, progress:', progress);
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
@ -290,7 +285,10 @@ class WebViewCoordinator: NSObject, WKNavigationDelegate, WKScriptMessageHandler
|
||||
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
|
||||
if message.name == "heightUpdate", let height = message.body as? CGFloat {
|
||||
DispatchQueue.main.async {
|
||||
if self.hasHeightUpdate == false {
|
||||
self.onHeightChange?(height)
|
||||
self.hasHeightUpdate = true
|
||||
}
|
||||
}
|
||||
}
|
||||
if message.name == "scrollProgress", let progress = message.body as? Double {
|
||||
@ -299,4 +297,6 @@ class WebViewCoordinator: NSObject, WKNavigationDelegate, WKScriptMessageHandler
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var hasHeightUpdate: Bool = false
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user