diff --git a/Sources/Roadmap/Extensions/ArrayExtensions.swift b/Sources/Roadmap/Extensions/ArrayExtensions.swift deleted file mode 100644 index ebe4207..0000000 --- a/Sources/Roadmap/Extensions/ArrayExtensions.swift +++ /dev/null @@ -1,29 +0,0 @@ -// -// ArrayExtensions.swift -// Roadmap -// -// Created by Antoine van der Lee on 19/02/2023. -// - -import Foundation - -//// To save ids in appstorage -//extension Array: RawRepresentable where Element: Codable { -// public init?(rawValue: String) { -// guard let data = rawValue.data(using: .utf8), -// let result = try? JSONDecoder().decode([Element].self, from: data) -// else { -// return nil -// } -// self = result -// } -// -// public var rawValue: String { -// guard let data = try? JSONEncoder().encode(self), -// let result = String(data: data, encoding: .utf8) -// else { -// return "[]" -// } -// return result -// } -//} diff --git a/Sources/Roadmap/Extensions/ColorExtensions.swift b/Sources/Roadmap/Extensions/ColorExtensions.swift index 646019f..41c0b0e 100644 --- a/Sources/Roadmap/Extensions/ColorExtensions.swift +++ b/Sources/Roadmap/Extensions/ColorExtensions.swift @@ -11,9 +11,9 @@ extension Color { static public var defaultCellColor : Color { #if os(macOS) - return Color.primary.opacity(0.08) + .primary.opacity(0.08) #else - return Color(uiColor: .secondarySystemFill) + Color(uiColor: .secondarySystemFill) #endif } } diff --git a/Sources/Roadmap/Models/RoadmapFeature.swift b/Sources/Roadmap/Models/RoadmapFeature.swift index f9b8658..fff5dc3 100644 --- a/Sources/Roadmap/Models/RoadmapFeature.swift +++ b/Sources/Roadmap/Models/RoadmapFeature.swift @@ -34,17 +34,17 @@ public struct RoadmapFeature: Codable, Identifiable, Sendable { var hasVoted: Bool { get { - guard let votes = UserDefaults.standard.array(forKey: "roadmap_votes") as? [String] else { return false } + let votes = Set(UserDefaults.standard.stringArray(forKey: "roadmap_votes") ?? []) return votes.contains(id) } nonmutating set { - var votes = (UserDefaults.standard.array(forKey: "roadmap_votes") as? [String]) ?? [] + var votes = Set(UserDefaults.standard.stringArray(forKey: "roadmap_votes") ?? []) if newValue { - votes.append(id) + votes.insert(id) } else { - votes.removeAll(where: { $0 == id }) + votes.remove(id) } - UserDefaults.standard.set(votes, forKey: "roadmap_votes") + UserDefaults.standard.set(Array(votes), forKey: "roadmap_votes") } } diff --git a/Sources/Roadmap/RoadmapView.swift b/Sources/Roadmap/RoadmapView.swift index fcbd23e..d635f9d 100644 --- a/Sources/Roadmap/RoadmapView.swift +++ b/Sources/Roadmap/RoadmapView.swift @@ -15,19 +15,19 @@ public struct RoadmapView: View { private var filterHorizontalPadding: CGFloat { #if os(macOS) - return 12 + 12 #elseif os(visionOS) - return 42 + 42 #else - return 22 + 22 #endif } private var filterTopPadding: CGFloat { #if os(macOS) - return 12 + 12 #else - return 0 + 0 #endif } diff --git a/Sources/Roadmap/RoadmapViewModel.swift b/Sources/Roadmap/RoadmapViewModel.swift index 90e0b81..dd93010 100644 --- a/Sources/Roadmap/RoadmapViewModel.swift +++ b/Sources/Roadmap/RoadmapViewModel.swift @@ -17,38 +17,14 @@ final class RoadmapViewModel { var statusToFilter = RoadmapViewModel.allStatusFilter var filteredFeatures: [RoadmapFeature] { - if statusToFilter == "all" && searchText.isEmpty { - return features - } else if statusToFilter != "all" && searchText.isEmpty { - if searchText.isEmpty { - return features.filter { feature in - feature.localizedFeatureStatus == statusToFilter - } - } else { - return features.filter { feature in - (feature - .localizedFeatureTitle // check title field... - .lowercased() // Roadmap localizes strings in Roadmap.json, so avoid .localizedCaseInsensitiveContains() - .contains(searchText.lowercased()) || - feature - .localizedFeatureDescription // ...and check description field - .lowercased() - .contains(searchText.lowercased())) - && - feature.localizedFeatureStatus == statusToFilter - } - } - } else { - return features.filter { feature in - feature - .localizedFeatureTitle // check title field... - .lowercased() // Roadmap localizes strings in Roadmap.json, so avoid .localizedCaseInsensitiveContains() - .contains(searchText.lowercased()) || - feature - .localizedFeatureDescription // ...and check description field - .lowercased() - .contains(searchText.lowercased()) - } + features.filter { feature in + let matchesStatus = statusToFilter == "all" || feature.localizedFeatureStatus == statusToFilter + let matchesSearch = + searchText.isEmpty || + feature.localizedFeatureTitle.lowercased().contains(searchText.lowercased()) || + feature.localizedFeatureDescription.lowercased().contains(searchText.lowercased()) + + return matchesStatus && matchesSearch } } diff --git a/Sources/Roadmap/RoadmapVoteButton.swift b/Sources/Roadmap/RoadmapVoteButton.swift index 32f55a0..138058d 100644 --- a/Sources/Roadmap/RoadmapVoteButton.swift +++ b/Sources/Roadmap/RoadmapVoteButton.swift @@ -153,10 +153,7 @@ struct RoadmapVoteButton: View { // MARK: - A11y helpers private var accessibilityValue: String { - let c = viewModel.voteCount - if c == 0 { return "0 votes" } - if c == 1 { return "1 vote" } - return "\(c) votes" + "\(viewModel.voteCount) vote\(viewModel.voteCount == 1 ? "" : "s")" } private func announceAccessibility(_ text: String) { diff --git a/Sources/Roadmap/Styling/RoadmapStyle.swift b/Sources/Roadmap/Styling/RoadmapStyle.swift index cf09a24..dd3cda0 100644 --- a/Sources/Roadmap/Styling/RoadmapStyle.swift +++ b/Sources/Roadmap/Styling/RoadmapStyle.swift @@ -90,19 +90,19 @@ public struct RoadmapStyle: Sendable { var cellBackground: some ShapeStyle { #if os(visionOS) if let cellMaterial { - return AnyShapeStyle(cellMaterial) + AnyShapeStyle(cellMaterial) } else if let cellColor { - return AnyShapeStyle(cellColor) + AnyShapeStyle(cellColor) } else { - return AnyShapeStyle(Material.defaultCellMaterial) + AnyShapeStyle(Material.defaultCellMaterial) } #else if let cellColor { - return AnyShapeStyle(cellColor) + AnyShapeStyle(cellColor) } else if let cellMaterial { - return AnyShapeStyle(cellMaterial) + AnyShapeStyle(cellMaterial) } else { - return AnyShapeStyle(Color.defaultCellColor) + AnyShapeStyle(Color.defaultCellColor) } #endif } diff --git a/Sources/Roadmap/Styling/RoadmapTemplates.swift b/Sources/Roadmap/Styling/RoadmapTemplates.swift index 95c492a..8ec7460 100644 --- a/Sources/Roadmap/Styling/RoadmapTemplates.swift +++ b/Sources/Roadmap/Styling/RoadmapTemplates.swift @@ -49,29 +49,25 @@ public enum RoadmapTemplate: CaseIterable { var fontDesign: Font.Design { switch self { - case .playful: - return .rounded - case .classy: - return .serif - case .technical: - return .monospaced - default: - return .default + case .playful: .rounded + case .classy: .serif + case .technical: .monospaced + default: .default } } var titleFont: Font { #if os(macOS) if #available(macOS 13.0, *) { - return Font.system(.headline, design: self.fontDesign, weight: .bold) + .system(.headline, design: self.fontDesign, weight: .bold) } else { - return Font.headline + .headline } #else if #available(iOS 16.0, *) { - return Font.system(.headline, design: self.fontDesign, weight: .bold) + .system(.headline, design: self.fontDesign, weight: .bold) } else { - return Font.system(.headline, design: self.fontDesign).weight(.bold) + .system(.headline, design: self.fontDesign).weight(.bold) } #endif } @@ -79,15 +75,15 @@ public enum RoadmapTemplate: CaseIterable { var numberFont: Font { #if os(macOS) if #available(macOS 13.0, *) { - return Font.system(.body, design: self.fontDesign, weight: .semibold).monospacedDigit() + .system(.body, design: self.fontDesign, weight: .semibold).monospacedDigit() } else { - return Font.body.monospacedDigit() + .body.monospacedDigit() } #else if #available(iOS 16.0, *) { - return Font.system(.body, design: self.fontDesign, weight: .semibold).monospacedDigit() + .system(.body, design: self.fontDesign, weight: .semibold).monospacedDigit() } else { - return Font.system(.body, design: self.fontDesign).weight(.semibold).monospacedDigit() + .system(.body, design: self.fontDesign).weight(.semibold).monospacedDigit() } #endif } @@ -95,15 +91,15 @@ public enum RoadmapTemplate: CaseIterable { var captionFont: Font { #if os(macOS) if #available(macOS 13.0, *) { - return Font.system(.caption, design: self.fontDesign, weight: .bold) + .system(.caption, design: self.fontDesign, weight: .bold) } else { - return Font.caption + .caption } #else if #available(iOS 16.0, *) { - return Font.system(.caption, design: self.fontDesign, weight: .bold) + .system(.caption, design: self.fontDesign, weight: .bold) } else { - return Font.system(.caption, design: self.fontDesign).weight(.bold) + .system(.caption, design: self.fontDesign).weight(.bold) } #endif }