diff options
17 files changed, 117 insertions, 27 deletions
diff --git a/Hotline.xcodeproj/project.pbxproj b/Hotline.xcodeproj/project.pbxproj index 32eadbf..22e9ce0 100644 --- a/Hotline.xcodeproj/project.pbxproj +++ b/Hotline.xcodeproj/project.pbxproj @@ -289,14 +289,14 @@ DADDB2892B22B2C60024040D /* Models */ = { isa = PBXGroup; children = ( - 11A726072BE0672A000C1DA7 /* FileDetails.swift */, + DADDB28E2B238D850024040D /* Hotline.swift */, DADDB28A2B22B31F0024040D /* Tracker.swift */, DAC3D9822BC33FD000A727C9 /* ApplicationState.swift */, DABE8C052B57A06100884D28 /* Bookmarks.swift */, DA2863D92B37BF6E00A7D050 /* Preferences.swift */, - DADDB28E2B238D850024040D /* Hotline.swift */, DADDB28C2B22B5920024040D /* Server.swift */, DA32CD482B2931640053B98B /* User.swift */, + 11A726072BE0672A000C1DA7 /* FileDetails.swift */, DA32CD4A2B29318E0053B98B /* FileInfo.swift */, DAAEE66A2B3FBC2100A5BA07 /* TransferInfo.swift */, DA2863DC2B3E8B7000A7D050 /* FilePreview.swift */, @@ -316,13 +316,13 @@ DAE734F82B2E4185000C56F6 /* ServerView.swift */, DAE734FE2B2E6750000C56F6 /* ChatView.swift */, DAE735042B3218D8000C56F6 /* NewsView.swift */, + DA72A0DC2B4CD0BF00A0F48A /* NewsEditorView.swift */, DAE735022B30C0BB000C56F6 /* MessageView.swift */, DAE734FC2B2E65E9000C56F6 /* MessageBoardView.swift */, DAE735002B2E71F2000C56F6 /* FilesView.swift */, DAAEE66E2B47625600A5BA07 /* FilePreviewImageView.swift */, DAB4D87D2B4C8BCA0048A05C /* FilePreviewTextView.swift */, 11A726092BE06759000C1DA7 /* FileDetailsView.swift */, - DA72A0DC2B4CD0BF00A0F48A /* NewsEditorView.swift */, DA2863D72B37AD1C00A7D050 /* SettingsView.swift */, DAE136B92B9D1147007D8307 /* HotlinePanelView.swift */, DA55AC762BE589F700034857 /* AboutView.swift */, diff --git a/Hotline/Assets.xcassets/Classic/176.imageset/176@2x.png b/Hotline/Assets.xcassets/Classic/176.imageset/176@2x.png Binary files differindex 929e7f0..983812e 100644 --- a/Hotline/Assets.xcassets/Classic/176.imageset/176@2x.png +++ b/Hotline/Assets.xcassets/Classic/176.imageset/176@2x.png diff --git a/Hotline/Assets.xcassets/Classic/176.imageset/176@3x.png b/Hotline/Assets.xcassets/Classic/176.imageset/176@3x.png Binary files differindex ae03a1d..a485383 100644 --- a/Hotline/Assets.xcassets/Classic/176.imageset/176@3x.png +++ b/Hotline/Assets.xcassets/Classic/176.imageset/176@3x.png diff --git a/Hotline/Assets.xcassets/Classic/2004.imageset/2004@2x.png b/Hotline/Assets.xcassets/Classic/2004.imageset/2004@2x.png Binary files differnew file mode 100644 index 0000000..8466dc7 --- /dev/null +++ b/Hotline/Assets.xcassets/Classic/2004.imageset/2004@2x.png diff --git a/Hotline/Assets.xcassets/Classic/2004.imageset/2004@3x.png b/Hotline/Assets.xcassets/Classic/2004.imageset/2004@3x.png Binary files differnew file mode 100644 index 0000000..4dedd55 --- /dev/null +++ b/Hotline/Assets.xcassets/Classic/2004.imageset/2004@3x.png diff --git a/Hotline/Assets.xcassets/Classic/2004.imageset/Contents.json b/Hotline/Assets.xcassets/Classic/2004.imageset/Contents.json index 188024d..43cde06 100644 --- a/Hotline/Assets.xcassets/Classic/2004.imageset/Contents.json +++ b/Hotline/Assets.xcassets/Classic/2004.imageset/Contents.json @@ -6,10 +6,12 @@ "scale" : "1x" }, { + "filename" : "2004@2x.png", "idiom" : "universal", "scale" : "2x" }, { + "filename" : "2004@3x.png", "idiom" : "universal", "scale" : "3x" } diff --git a/Hotline/Assets.xcassets/News Bundle.imageset/Contents.json b/Hotline/Assets.xcassets/News Bundle.imageset/Contents.json new file mode 100644 index 0000000..bfb6d35 --- /dev/null +++ b/Hotline/Assets.xcassets/News Bundle.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "Frame 3.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Frame 3@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Frame 3@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Hotline/Assets.xcassets/News Bundle.imageset/Frame 3.png b/Hotline/Assets.xcassets/News Bundle.imageset/Frame 3.png Binary files differnew file mode 100644 index 0000000..46d144d --- /dev/null +++ b/Hotline/Assets.xcassets/News Bundle.imageset/Frame 3.png diff --git a/Hotline/Assets.xcassets/News Bundle.imageset/Frame 3@2x.png b/Hotline/Assets.xcassets/News Bundle.imageset/Frame 3@2x.png Binary files differnew file mode 100644 index 0000000..2dbb989 --- /dev/null +++ b/Hotline/Assets.xcassets/News Bundle.imageset/Frame 3@2x.png diff --git a/Hotline/Assets.xcassets/News Bundle.imageset/Frame 3@3x.png b/Hotline/Assets.xcassets/News Bundle.imageset/Frame 3@3x.png Binary files differnew file mode 100644 index 0000000..649ab86 --- /dev/null +++ b/Hotline/Assets.xcassets/News Bundle.imageset/Frame 3@3x.png diff --git a/Hotline/Assets.xcassets/News Category.imageset/Contents.json b/Hotline/Assets.xcassets/News Category.imageset/Contents.json new file mode 100644 index 0000000..7245ec5 --- /dev/null +++ b/Hotline/Assets.xcassets/News Category.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "Frame 1.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Frame 1@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Frame 1@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Hotline/Assets.xcassets/News Category.imageset/Frame 1.png b/Hotline/Assets.xcassets/News Category.imageset/Frame 1.png Binary files differnew file mode 100644 index 0000000..1c3a080 --- /dev/null +++ b/Hotline/Assets.xcassets/News Category.imageset/Frame 1.png diff --git a/Hotline/Assets.xcassets/News Category.imageset/Frame 1@2x.png b/Hotline/Assets.xcassets/News Category.imageset/Frame 1@2x.png Binary files differnew file mode 100644 index 0000000..e1bce20 --- /dev/null +++ b/Hotline/Assets.xcassets/News Category.imageset/Frame 1@2x.png diff --git a/Hotline/Assets.xcassets/News Category.imageset/Frame 1@3x.png b/Hotline/Assets.xcassets/News Category.imageset/Frame 1@3x.png Binary files differnew file mode 100644 index 0000000..6a16cef --- /dev/null +++ b/Hotline/Assets.xcassets/News Category.imageset/Frame 1@3x.png diff --git a/Hotline/Models/Hotline.swift b/Hotline/Models/Hotline.swift index 598c787..48266a9 100644 --- a/Hotline/Models/Hotline.swift +++ b/Hotline/Models/Hotline.swift @@ -345,30 +345,58 @@ class Hotline: Equatable, HotlineClientDelegate, HotlineFileClientDelegate { self?.client.sendGetNewsArticles(path: path) { [weak self] articles in // let parentNews = self?.findNews(in: self?.news ?? [], at: path) print("GENERATING NEWS") - + var newArticles: [NewsInfo] = [] for article in articles { newArticles.append(NewsInfo(hotlineNewsArticle: article)) } + let organizedNewsArticles: [NewsInfo] = self?.organizeNewsList(newArticles) ?? [] + DispatchQueue.main.async { if let parent = existingNewsItem { print("UNDER PARENT:", parent.name) - parent.children = newArticles + parent.children = organizedNewsArticles print(parent.children) } else if path.isEmpty { - self?.news = newArticles + self?.news = organizedNewsArticles } - continuation.resume(returning: newArticles) + continuation.resume(returning: organizedNewsArticles) } } } } } + func organizeNewsList(_ news: [NewsInfo]) -> [NewsInfo] { + var articleMap: [UInt: NewsInfo] = [:] + + // Create lookup table of each news item. + for article in news { + if let articleID = article.articleID { + articleMap[articleID] = article + } + } + + // Place articles under their parent. + var organized: [NewsInfo] = [] + for article in news { + if let parentID = article.parentID, + parentID != 0, + let parentArticle = articleMap[parentID] { + parentArticle.children.append(article) + } + else { + organized.append(article) + } + } + + return organized + } + @MainActor func getNewsCategories(at path: [String] = []) async -> [NewsInfo] { return await withCheckedContinuation { [weak self] continuation in self?.client.sendGetNewsCategories(path: path) { [weak self] categories in diff --git a/Hotline/Models/NewsInfo.swift b/Hotline/Models/NewsInfo.swift index f95cba1..b635138 100644 --- a/Hotline/Models/NewsInfo.swift +++ b/Hotline/Models/NewsInfo.swift @@ -24,6 +24,7 @@ enum NewsInfoType { var articleFlavors: [String]? var articleUsername: String? var articleDate: Date? + var read: Bool = false init(hotlineNewsCategory: HotlineNewsCategory) { self.categoryID = hotlineNewsCategory.id diff --git a/Hotline/macOS/NewsView.swift b/Hotline/macOS/NewsView.swift index 875765e..e87a7f0 100644 --- a/Hotline/macOS/NewsView.swift +++ b/Hotline/macOS/NewsView.swift @@ -119,13 +119,14 @@ struct NewsView: View { } self.selection = clickedNews - if clickedNews.type == .bundle || clickedNews.type == .category { + if clickedNews.type == .bundle || clickedNews.type == .category || clickedNews.children.count > 0 { clickedNews.expanded.toggle() } } .onChange(of: selection) { self.articleText = nil if let article = selection, article.type == .article { + article.read = true if let articleFlavor = article.articleFlavors?.first, let articleID = article.articleID { Task { @@ -247,7 +248,7 @@ struct NewsItemView: View { var body: some View { HStack(alignment: .center, spacing: 6) { - if news.type == .bundle || news.type == .category { + if news.type == .bundle || news.type == .category || news.children.count > 0 { Button { news.expanded.toggle() } label: { @@ -261,19 +262,31 @@ struct NewsItemView: View { .frame(width: 10) .padding(.leading, 4) } - else if news.type == .article { - if news.parentID != nil { - Image(systemName: "arrowshape.turn.up.left.fill") - .resizable() - .renderingMode(.template) - .scaledToFit() - .frame(width: 10) - .foregroundStyle(.secondary) - .opacity(0.5) - } + else { + Spacer() + .frame(width: 14) } + + // Tree indent + Spacer() + .frame(width: CGFloat(max(0, depth-1)) * 16) + + switch news.type { + case .category: + Image("News Category") + .resizable() + .frame(width: 16, height: 16) + case .bundle: + Image("News Bundle") + .resizable() + .frame(width: 16, height: 16) + case .article: + Spacer() + .frame(width: 16) + } + Text(news.name) - .fontWeight((news.type == .bundle || news.type == .category) ? .bold : .regular) + .fontWeight((news.type == .bundle || news.type == .category || !news.read) ? .semibold : .regular) .lineLimit(1) .truncationMode(.tail) if news.type == .article && news.articleUsername != nil { @@ -282,8 +295,6 @@ struct NewsItemView: View { Spacer() if news.type == .bundle || news.type == .category { Text("^[\(news.count) \(news.type == .bundle ? "Category" : "Post")](inflect: true)") - -// Text("\(news.count) \(news.type == .bundle ? "Categories" : "Posts")") .foregroundStyle(.secondary) .lineLimit(1) .padding([.leading, .trailing], 8) @@ -297,13 +308,15 @@ struct NewsItemView: View { } } .frame(maxWidth: .infinity, maxHeight: .infinity) - .padding(.leading, CGFloat(depth * (12 + 10))) .onChange(of: news.expanded) { + guard news.expanded else { + return + } + + news.read = true if news.type == .bundle || news.type == .category { - if news.expanded { - Task { - await model.getNewsList(at: news.path) - } + Task { + await model.getNewsList(at: news.path) } } } |