- added accent color
- fixed iPad layout with split view
This commit is contained in:
parent
6ae1b5853e
commit
c1eb2109ed
@ -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 */;
|
||||
}
|
||||
|
||||
@ -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
|
||||
}
|
||||
@ -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 -> ()"
|
||||
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 -> ()"
|
||||
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>
|
||||
|
||||
@ -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...")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user