From 2d10756ca43b0e8284a8cbd851ff1ec2ce26be8a Mon Sep 17 00:00:00 2001 From: Stephen B <158498287+StephenDev0@users.noreply.github.com> Date: Wed, 4 Jun 2025 09:54:16 -0400 Subject: [PATCH] Add announcements to home view (#195) * Add announcement system * Fetch announcements from GitHub * Add visibility and timestamps to announcements --- StikJIT/Resources/announcements.json | 18 ++++++++ StikJIT/Utilities/AnnouncementManager.swift | 38 ++++++++++++++++ StikJIT/Views/AnnouncementCard.swift | 50 +++++++++++++++++++++ StikJIT/Views/HomeView.swift | 26 +++++++++-- 4 files changed, 128 insertions(+), 4 deletions(-) create mode 100644 StikJIT/Resources/announcements.json create mode 100644 StikJIT/Utilities/AnnouncementManager.swift create mode 100644 StikJIT/Views/AnnouncementCard.swift diff --git a/StikJIT/Resources/announcements.json b/StikJIT/Resources/announcements.json new file mode 100644 index 0000000..eed6227 --- /dev/null +++ b/StikJIT/Resources/announcements.json @@ -0,0 +1,18 @@ +[ + { + "id": 1, + "title": "Welcome!", + "body": "Thank you for using StikDebug. Stay tuned for updates.", + "date": "2025-06-04", + "time": "12:00", + "visible": true + }, + { + "id": 2, + "title": "New Feature", + "body": "Announcements are now shown on the home screen.", + "date": "2025-06-04", + "time": "12:30", + "visible": true + } +] diff --git a/StikJIT/Utilities/AnnouncementManager.swift b/StikJIT/Utilities/AnnouncementManager.swift new file mode 100644 index 0000000..eecce84 --- /dev/null +++ b/StikJIT/Utilities/AnnouncementManager.swift @@ -0,0 +1,38 @@ +import Foundation + +struct Announcement: Identifiable, Codable { + let id: Int + let title: String + let body: String + let date: String + let time: String + let visible: Bool +} + +class AnnouncementManager { + private static let announcementsURL = "https://raw.githubusercontent.com/0-Blu/StikJIT/main/StikJIT/Resources/announcements.json" + + static func fetchAnnouncements(completion: @escaping ([Announcement]) -> Void) { + guard let url = URL(string: announcementsURL) else { + completion([]) + return + } + + URLSession.shared.dataTask(with: url) { data, response, _ in + guard let data = data, + (response as? HTTPURLResponse)?.statusCode == 200, + let announcements = try? JSONDecoder().decode([Announcement].self, from: data) else { + DispatchQueue.main.async { + completion([]) + } + return + } + + let visibleAnnouncements = announcements.filter { $0.visible } + + DispatchQueue.main.async { + completion(visibleAnnouncements) + } + }.resume() + } +} diff --git a/StikJIT/Views/AnnouncementCard.swift b/StikJIT/Views/AnnouncementCard.swift new file mode 100644 index 0000000..0d6f710 --- /dev/null +++ b/StikJIT/Views/AnnouncementCard.swift @@ -0,0 +1,50 @@ +import SwiftUI + +struct AnnouncementCard: View { + var announcement: Announcement + @AppStorage("customAccentColor") private var customAccentColorHex: String = "" + + private var accentColor: Color { + if customAccentColorHex.isEmpty { + return .blue + } else { + return Color(hex: customAccentColorHex) ?? .blue + } + } + + var body: some View { + VStack(alignment: .leading, spacing: 8) { + Text(announcement.title) + .font(.headline) + .foregroundColor(.primary) + Text(announcement.body) + .font(.subheadline) + .foregroundColor(.secondary) + Text("\(announcement.date) \(announcement.time)") + .font(.caption) + .foregroundColor(.secondary) + } + .padding() + .frame(maxWidth: .infinity, alignment: .leading) + .background(Color(UIColor.secondarySystemBackground)) + .overlay( + RoundedRectangle(cornerRadius: 16) + .stroke(accentColor, lineWidth: 2) + ) + .cornerRadius(16) + .shadow(color: Color.black.opacity(0.08), radius: 3, x: 0, y: 2) + } +} + +#Preview { + AnnouncementCard( + announcement: Announcement( + id: 0, + title: "Title", + body: "Body", + date: "2025-01-01", + time: "00:00", + visible: true + ) + ) +} diff --git a/StikJIT/Views/HomeView.swift b/StikJIT/Views/HomeView.swift index cdd0562..c8229e8 100644 --- a/StikJIT/Views/HomeView.swift +++ b/StikJIT/Views/HomeView.swift @@ -8,6 +8,9 @@ import SwiftUI import UniformTypeIdentifiers +// Load announcements from remote JSON +import Foundation + extension UIDocumentPickerViewController { @objc func fix_init(forOpeningContentTypes contentTypes: [UTType], asCopy: Bool) -> UIDocumentPickerViewController { return fix_init(forOpeningContentTypes: contentTypes, asCopy: true) @@ -32,6 +35,8 @@ struct HomeView: View { @State private var isImportingFile = false @State private var showingConsoleLogsView = false @State private var importProgress: Float = 0.0 + + @State private var announcements: [Announcement] = [] @State private var pidTextAlertShow = false @State private var pidStr = "" @@ -60,14 +65,23 @@ struct HomeView: View { Text("Welcome to StikDebug \(username)!") .font(.system(.largeTitle, design: .rounded)) .fontWeight(.bold) - + Text(pairingFileExists ? "Click connect to get started" : "Pick pairing file to get started") .font(.system(.subheadline, design: .rounded)) .foregroundStyle(.secondary) .multilineTextAlignment(.center) } .padding(.top, 40) - + + if !announcements.isEmpty { + VStack(spacing: 12) { + ForEach(announcements) { announcement in + AnnouncementCard(announcement: announcement) + } + } + .padding(.horizontal, 20) + } + Button(action: { @@ -203,10 +217,14 @@ struct HomeView: View { checkPairingFileExists() // Don't initialize specific color value when empty - empty means "use system theme" // This was causing the toggle to turn off when returning to settings - + // Initialize background color refreshBackground() - + + AnnouncementManager.fetchAnnouncements { loaded in + announcements = loaded + } + // Add notification observer for showing pairing file picker NotificationCenter.default.addObserver( forName: NSNotification.Name("ShowPairingFilePicker"),