- added accent color

- fixed iPad layout with split view
This commit is contained in:
Ilyas Hallak 2025-06-26 20:52:02 +02:00
parent 6ae1b5853e
commit c1eb2109ed
7 changed files with 234 additions and 29 deletions

View File

@ -8,6 +8,7 @@
/* Begin PBXBuildFile section */
5D2B7FB92DFA27A400EBDB2B /* URLShare.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 5D2B7FAF2DFA27A400EBDB2B /* URLShare.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
5D348CC32E0C9F4F00D0AF21 /* netfox in Frameworks */ = {isa = PBXBuildFile; productRef = 5D348CC22E0C9F4F00D0AF21 /* netfox */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@ -133,6 +134,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
5D348CC32E0C9F4F00D0AF21 /* netfox in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -220,6 +222,7 @@
);
name = readeck;
packageProductDependencies = (
5D348CC22E0C9F4F00D0AF21 /* netfox */,
);
productName = readeck;
productReference = 5D45F9C82DF858680048D5B8 /* readeck.app */;
@ -306,6 +309,9 @@
);
mainGroup = 5D45F9BF2DF858680048D5B8;
minimizedProjectReferenceProxies = 1;
packageReferences = (
5D348CC12E0C9F4F00D0AF21 /* XCRemoteSwiftPackageReference "netfox" */,
);
preferredProjectObjectVersion = 77;
productRefGroup = 5D45F9C92DF858680048D5B8 /* Products */;
projectDirPath = "";
@ -790,6 +796,25 @@
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
/* Begin XCRemoteSwiftPackageReference section */
5D348CC12E0C9F4F00D0AF21 /* XCRemoteSwiftPackageReference "netfox" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/kasketis/netfox";
requirement = {
kind = upToNextMajorVersion;
minimumVersion = 1.21.0;
};
};
/* End XCRemoteSwiftPackageReference section */
/* Begin XCSwiftPackageProductDependency section */
5D348CC22E0C9F4F00D0AF21 /* netfox */ = {
isa = XCSwiftPackageProductDependency;
package = 5D348CC12E0C9F4F00D0AF21 /* XCRemoteSwiftPackageReference "netfox" */;
productName = netfox;
};
/* End XCSwiftPackageProductDependency section */
};
rootObject = 5D45F9C02DF858680048D5B8 /* Project object */;
}

View File

@ -0,0 +1,15 @@
{
"originHash" : "7374154e7686de69a9f88fbafb081b646b02140f8d82770f46fa750840581e0e",
"pins" : [
{
"identity" : "netfox",
"kind" : "remoteSourceControl",
"location" : "https://github.com/kasketis/netfox",
"state" : {
"revision" : "557576032736fd3140422baefb68b8f76c55088f",
"version" : "1.21.0"
}
}
],
"version" : 3
}

View File

@ -3,4 +3,52 @@
uuid = "FAD7B3BD-946C-4129-A614-E1823F18EC12"
type = "1"
version = "2.0">
<Breakpoints>
<BreakpointProxy
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
<BreakpointContent
uuid = "B67988B8-09FD-461D-A5FA-7D72A318247D"
shouldBeEnabled = "Yes"
ignoreCount = "0"
continueAfterRunningActions = "No"
filePath = "readeck/UI/BookmarkDetail/BookmarkDetailViewModel.swift"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "39"
endingLineNumber = "39"
landmarkName = "loadBookmarkDetail(id:)"
landmarkType = "7">
<Locations>
<Location
uuid = "B67988B8-09FD-461D-A5FA-7D72A318247D - 5494d64ddd867e19"
shouldBeEnabled = "Yes"
ignoreCount = "0"
continueAfterRunningActions = "No"
symbolName = "(6) suspend resume partial function for readeck.BookmarkDetailViewModel.loadBookmarkDetail(id: Swift.String) async -&gt; ()"
moduleName = "readeck.debug.dylib"
usesParentBreakpointCondition = "Yes"
urlString = "file:///Users/ilyashallak/Privat/Projects/readeck/readeck/UI/BookmarkDetail/BookmarkDetailViewModel.swift"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "39"
endingLineNumber = "39">
</Location>
<Location
uuid = "B67988B8-09FD-461D-A5FA-7D72A318247D - ac249dd33728018"
shouldBeEnabled = "Yes"
ignoreCount = "0"
continueAfterRunningActions = "No"
symbolName = "(7) suspend resume partial function for readeck.BookmarkDetailViewModel.loadBookmarkDetail(id: Swift.String) async -&gt; ()"
moduleName = "readeck.debug.dylib"
usesParentBreakpointCondition = "Yes"
urlString = "file:///Users/ilyashallak/Privat/Projects/readeck/readeck/UI/BookmarkDetail/BookmarkDetailViewModel.swift"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "39"
endingLineNumber = "39">
</Location>
</Locations>
</BreakpointContent>
</BreakpointProxy>
</Breakpoints>
</Bucket>

View File

@ -1,3 +1,5 @@
import Foundation
import Combine
import SwiftUI
struct BookmarksView: View {
@ -6,10 +8,15 @@ struct BookmarksView: View {
@State private var selectedBookmarkId: String?
let state: BookmarkState
@Binding var selectedBookmark: Bookmark?
@State private var showingAddBookmarkFromShare = false
@State private var shareURL = ""
@State private var shareTitle = ""
@Environment(\.horizontalSizeClass) var horizontalSizeClass
@Environment(\.verticalSizeClass) var verticalSizeClass
var body: some View {
NavigationStack {
ZStack {
@ -19,7 +26,11 @@ struct BookmarksView: View {
List {
ForEach(viewModel.bookmarks, id: \.id) { bookmark in
Button(action: {
selectedBookmarkId = bookmark.id
if UIDevice.isPhone {
selectedBookmarkId = bookmark.id
} else {
selectedBookmark = bookmark
}
}) {
BookmarkCardView(
bookmark: bookmark,
@ -105,13 +116,13 @@ struct BookmarksView: View {
.sheet(isPresented: $showingAddBookmark) {
AddBookmarkView(prefilledURL: shareURL, prefilledTitle: shareTitle)
}
.alert("Fehler", isPresented: .constant(viewModel.errorMessage != nil)) {
/*.alert("Fehler", isPresented: .constant(viewModel.errorMessage != nil)) {
Button("OK", role: .cancel) {
viewModel.errorMessage = nil
}
} message: {
Text(viewModel.errorMessage ?? "")
}
}*/
.task {
await viewModel.loadBookmarks(state: state)
}
@ -123,24 +134,8 @@ struct BookmarksView: View {
}
}
}
.onReceive(NotificationCenter.default.publisher(for: NSNotification.Name("AddBookmarkFromShare"))) { notification in
handleShareNotification(notification)
}
}
}
private func handleShareNotification(_ notification: Notification) {
guard let userInfo = notification.userInfo,
let url = userInfo["url"] as? String,
!url.isEmpty else {
return
}
shareURL = url
shareTitle = userInfo["title"] as? String ?? ""
showingAddBookmark = true
print("Received share notification - URL: \(url), Title: \(shareTitle)")
.searchable(text: $viewModel.searchQuery, placement: .automatic, prompt: "Search...")
}
}

View File

@ -24,6 +24,14 @@ class BookmarksViewModel {
private var offset = 0
private var hasMoreData = true
var searchQuery: String = "" {
didSet {
throttleSearch()
}
}
private var searchWorkItem: DispatchWorkItem?
init() {
setupNotificationObserver()
}
@ -53,6 +61,20 @@ class BookmarksViewModel {
print("Received share notification - URL: \(url)")
}
private func throttleSearch() {
searchWorkItem?.cancel()
let workItem = DispatchWorkItem { [weak self] in
guard let self = self else { return }
Task {
await self.loadBookmarks(state: self.currentState)
}
}
searchWorkItem = workItem
DispatchQueue.main.asyncAfter(deadline: .now() + 0.3, execute: workItem)
}
@MainActor
func loadBookmarks(state: BookmarkState = .unread) async {
isLoading = true
@ -62,7 +84,12 @@ class BookmarksViewModel {
hasMoreData = true // Pagination zurücksetzen
do {
let newBookmarks = try await getBooksmarksUseCase.execute(state: state, limit: limit, offset: offset)
let newBookmarks = try await getBooksmarksUseCase.execute(
state: state,
limit: limit,
offset: offset,
search: searchQuery // Suche integrieren
)
bookmarks = newBookmarks
hasMoreData = newBookmarks.count == limit // Prüfen, ob weitere Daten verfügbar sind
} catch {

View File

@ -1,7 +1,7 @@
import SwiftUI
import Foundation
enum BookmarkState: String, CaseIterable {
enum BookmarkState: String, CaseIterable {
case unread = "unread"
case favorite = "favorite"
case archived = "archived"
@ -31,22 +31,40 @@ enum BookmarkState: String, CaseIterable {
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)
BookmarksView(state: .unread, selectedBookmark: .constant(nil))
.tabItem {
Label("Ungelesen", systemImage: "house")
}
.tag("Ungelesen")
BookmarksView(state: .favorite)
BookmarksView(state: .favorite, selectedBookmark: .constant(nil))
.tabItem {
Label("Favoriten", systemImage: "heart")
}
.tag("Favoriten")
BookmarksView(state: .archived)
BookmarksView(state: .archived, selectedBookmark: .constant(nil))
.tabItem {
Label("Archiv", systemImage: "archivebox")
}
@ -56,12 +74,83 @@ struct MainTabView: View {
.tabItem {
Label("Settings", systemImage: "gear")
}
.tag("Settings")
.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)
}
}
.accentColor(.blue)
}
}
#Preview {
MainTabView()
}
extension UIDevice {
static var isPad: Bool {
return UIDevice.current.userInterfaceIdiom == .pad
}
static var isPhone: Bool {
return UIDevice.current.userInterfaceIdiom == .phone
}
}

View File

@ -6,6 +6,7 @@
//
import SwiftUI
import netfox
@main
struct readeckApp: App {
@ -18,6 +19,11 @@ struct readeckApp: App {
.onOpenURL { url in
handleIncomingURL(url)
}
.onAppear {
#if DEBUG
NFX.sharedInstance().start()
#endif
}
}
}