From 07308ef1953afe50a4f1f514c528f64f2ffedb1f Mon Sep 17 00:00:00 2001 From: Arturo Carretero Calvo <10163049+ArtCC@users.noreply.github.com> Date: Sun, 2 Nov 2025 11:08:07 +0100 Subject: [PATCH 1/6] Update version from 1.0.17 to 1.0.18 across project - Bump votice-sdk package dependency version to 1.0.18 in README.md - Update _version property to "1.0.18" in ConfigurationManager.swift - Modify version expectations to "1.0.18" in ConfigurationManagerTests.swift test cases no message --- README.md | 2 +- Sources/Votice/Core/Managers/ConfigurationManager.swift | 2 +- Tests/VoticeTests/Managers/ConfigurationManagerTests.swift | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 22ed2fa..f4c5c87 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,7 @@ The Votice management app for handling suggestions or issues and apps is availab Add this line to your `Package.swift` dependencies: ```swift -.package(url: "https://github.com/artcc/votice-sdk", from: "1.0.17"), +.package(url: "https://github.com/artcc/votice-sdk", from: "1.0.18"), ``` Or via Xcode: diff --git a/Sources/Votice/Core/Managers/ConfigurationManager.swift b/Sources/Votice/Core/Managers/ConfigurationManager.swift index a99185f..fd873fc 100644 --- a/Sources/Votice/Core/Managers/ConfigurationManager.swift +++ b/Sources/Votice/Core/Managers/ConfigurationManager.swift @@ -51,7 +51,7 @@ final class ConfigurationManager: ConfigurationManagerProtocol, @unchecked Senda private let lock = NSLock() private let _baseURL = "https://api.votice.app/api" private let _configurationId = UUID().uuidString - private let _version = "1.0.17" + private let _version = "1.0.18" private let _buildNumber = "1" // MARK: - Public properties diff --git a/Tests/VoticeTests/Managers/ConfigurationManagerTests.swift b/Tests/VoticeTests/Managers/ConfigurationManagerTests.swift index 5294625..ab9d93b 100644 --- a/Tests/VoticeTests/Managers/ConfigurationManagerTests.swift +++ b/Tests/VoticeTests/Managers/ConfigurationManagerTests.swift @@ -32,7 +32,7 @@ struct ConfigurationManagerTests { #expect(manager.showCompletedSeparately == false) #expect(manager.user.isPremium == false) #expect(manager.optionalVisibleStatuses == [.accepted, .blocked, .rejected]) - #expect(manager.version == "1.0.17") + #expect(manager.version == "1.0.18") #expect(manager.buildNumber == "1") } @@ -138,7 +138,7 @@ struct ConfigurationManagerTests { // ConfigurationId, version, and buildNumber should remain unchanged #expect(!manager.configurationId.isEmpty) - #expect(manager.version == "1.0.17") + #expect(manager.version == "1.0.18") #expect(manager.buildNumber == "1") } @@ -325,7 +325,7 @@ struct ConfigurationManagerTests { // Test immutable properties #expect(manager.baseURL == "https://api.votice.app/api") - #expect(manager.version == "1.0.17") + #expect(manager.version == "1.0.18") #expect(manager.buildNumber == "1") // Configuration ID should be consistent for same instance From 6b19347afe33f1f4ef2ab39ba41d69fcd782661f Mon Sep 17 00:00:00 2001 From: Arturo Carretero Calvo <10163049+ArtCC@users.noreply.github.com> Date: Mon, 3 Nov 2025 11:10:38 +0100 Subject: [PATCH 2/6] Update SwiftLintPlugins dependency to version 0.62.2 - Bump SwiftLintPlugins revision to ecafb5b056cb7995324f0d310a61f30661d00cad - Update SwiftLintPlugins version from 0.62.1 to 0.62.2 in Package.resolved file no message --- .../project.xcworkspace/xcshareddata/swiftpm/Package.resolved | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Example/VoticeDemo/VoticeDemo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Example/VoticeDemo/VoticeDemo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 81af845..fd1dc09 100644 --- a/Example/VoticeDemo/VoticeDemo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/Example/VoticeDemo/VoticeDemo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -6,8 +6,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/SimplyDanny/SwiftLintPlugins", "state" : { - "revision" : "ef264ee3ccea175f5c9efc8b814ccb48cd3fdaac", - "version" : "0.62.1" + "revision" : "ecafb5b056cb7995324f0d310a61f30661d00cad", + "version" : "0.62.2" } } ], From b15252971404967f82e872c49f4b9f4bdae2ed0b Mon Sep 17 00:00:00 2001 From: Arturo Carretero Calvo <10163049+ArtCC@users.noreply.github.com> Date: Fri, 7 Nov 2025 11:17:22 +0100 Subject: [PATCH 3/6] Add progress parameter to StatusBadge and update its usage in multiple views - Add optional progress property to StatusBadge component - Adjust padding order in StatusBadge text styling - Pass suggestion.progress to StatusBadge in SuggestionCard - Pass suggestion.progress to StatusBadge in TVOSSuggestionCard - Pass currentSuggestion.progress to StatusBadge in SuggestionDetailView+tvOS - Pass suggestion.progress to StatusBadge in SuggestionDetailView and update padding accordingly no message --- Sources/Votice/UI/Components/StatusBadge.swift | 3 ++- Sources/Votice/UI/Components/SuggestionCard.swift | 8 ++++++-- Sources/Votice/UI/Components/TVOSSuggestionCard.swift | 6 +++++- .../SuggestionDetail/SuggestionDetailView+tvOS.swift | 6 +++++- .../UI/Views/SuggestionDetail/SuggestionDetailView.swift | 8 ++++++-- 5 files changed, 24 insertions(+), 7 deletions(-) diff --git a/Sources/Votice/UI/Components/StatusBadge.swift b/Sources/Votice/UI/Components/StatusBadge.swift index d2fa954..8de501e 100644 --- a/Sources/Votice/UI/Components/StatusBadge.swift +++ b/Sources/Votice/UI/Components/StatusBadge.swift @@ -49,6 +49,7 @@ struct StatusBadge: View { } let status: SuggestionStatusEntity + let progress: Int? let useLiquidGlass: Bool // MARK: - View @@ -57,8 +58,8 @@ struct StatusBadge: View { Text(statusText) .font(theme.typography.caption) .foregroundColor(.white) - .padding(.horizontal, theme.spacing.sm) .padding(.vertical, theme.spacing.xs) + .padding(.horizontal, theme.spacing.sm) .adaptiveGlassBackground( useLiquidGlass: useLiquidGlass, cornerRadius: theme.cornerRadius.sm, diff --git a/Sources/Votice/UI/Components/SuggestionCard.swift b/Sources/Votice/UI/Components/SuggestionCard.swift index 85d0a5f..15ee9f5 100644 --- a/Sources/Votice/UI/Components/SuggestionCard.swift +++ b/Sources/Votice/UI/Components/SuggestionCard.swift @@ -81,8 +81,12 @@ struct SuggestionCard: View { ) ) .scaleEffect(isPressed ? 1.005 : 1.0) - StatusBadge(status: suggestion.status ?? .pending, useLiquidGlass: useLiquidGlass) - .padding(theme.spacing.sm) + StatusBadge( + status: suggestion.status ?? .pending, + progress: suggestion.progress, + useLiquidGlass: useLiquidGlass + ) + .padding(theme.spacing.sm) } .onTapGesture { isPressed = true diff --git a/Sources/Votice/UI/Components/TVOSSuggestionCard.swift b/Sources/Votice/UI/Components/TVOSSuggestionCard.swift index c7460ef..360a100 100644 --- a/Sources/Votice/UI/Components/TVOSSuggestionCard.swift +++ b/Sources/Votice/UI/Components/TVOSSuggestionCard.swift @@ -70,7 +70,11 @@ struct TVOSSuggestionCard: View { } .frame(maxWidth: .infinity, alignment: .leading) VStack { - StatusBadge(status: suggestion.status ?? .pending, useLiquidGlass: useLiquidGlass) + StatusBadge( + status: suggestion.status ?? .pending, + progress: suggestion.progress, + useLiquidGlass: useLiquidGlass + ) Spacer() } } diff --git a/Sources/Votice/UI/Views/SuggestionDetail/SuggestionDetailView+tvOS.swift b/Sources/Votice/UI/Views/SuggestionDetail/SuggestionDetailView+tvOS.swift index 374a179..b96bb72 100644 --- a/Sources/Votice/UI/Views/SuggestionDetail/SuggestionDetailView+tvOS.swift +++ b/Sources/Votice/UI/Views/SuggestionDetail/SuggestionDetailView+tvOS.swift @@ -66,7 +66,11 @@ extension SuggestionDetailView { .foregroundColor(theme.colors.onSurface) .multilineTextAlignment(.leading) Spacer() - StatusBadge(status: currentSuggestion.status ?? .pending, useLiquidGlass: false) + StatusBadge( + status: currentSuggestion.status ?? .pending, + progress: currentSuggestion.progress, + useLiquidGlass: false) + } if let description = currentSuggestion.description, description != currentSuggestion.title { Text(description) diff --git a/Sources/Votice/UI/Views/SuggestionDetail/SuggestionDetailView.swift b/Sources/Votice/UI/Views/SuggestionDetail/SuggestionDetailView.swift index 48c125e..123660c 100644 --- a/Sources/Votice/UI/Views/SuggestionDetail/SuggestionDetailView.swift +++ b/Sources/Votice/UI/Views/SuggestionDetail/SuggestionDetailView.swift @@ -248,8 +248,12 @@ private extension SuggestionDetailView { .fill(theme.colors.surface) .shadow(color: .black.opacity(0.1), radius: 2, x: 0, y: 1) ) - StatusBadge(status: currentSuggestion.status ?? .pending, useLiquidGlass: viewModel.liquidGlassEnabled) - .padding(theme.spacing.sm) + StatusBadge( + status: currentSuggestion.status ?? .pending, + progress: suggestion.progress, + useLiquidGlass: viewModel.liquidGlassEnabled + ) + .padding(theme.spacing.sm) } } From dd3100866290d42414840b24e458c6e924914e3e Mon Sep 17 00:00:00 2001 From: Arturo Carretero Calvo <10163049+ArtCC@users.noreply.github.com> Date: Fri, 7 Nov 2025 11:58:33 +0100 Subject: [PATCH 4/6] Refactor StatusBadge view to support progress display with gradient and adaptive backgrounds - Add status, progress, and useLiquidGlass properties to StatusBadge - Implement conditional body view to show progress with gradient fill when status is inProgress and progress is available - Use GeometryReader and ZStack to create progress bar with rounded corners and gradient fill - Display status text with progress percentage when applicable - Apply adaptiveGlassBackground for non-progress statuses with configurable liquid glass effect - Extract statusColor and statusText as computed properties in a private extension - Add backgroundView computed property with @ViewBuilder to provide background visuals based on status and progress no message --- .../Votice/UI/Components/StatusBadge.swift | 93 +++++++++++++++---- 1 file changed, 74 insertions(+), 19 deletions(-) diff --git a/Sources/Votice/UI/Components/StatusBadge.swift b/Sources/Votice/UI/Components/StatusBadge.swift index 8de501e..f0c0f08 100644 --- a/Sources/Votice/UI/Components/StatusBadge.swift +++ b/Sources/Votice/UI/Components/StatusBadge.swift @@ -13,7 +13,58 @@ struct StatusBadge: View { @Environment(\.voticeTheme) private var theme - private var statusColor: Color { + let status: SuggestionStatusEntity + let progress: Int? + let useLiquidGlass: Bool + + // MARK: - View + + var body: some View { + if status == .inProgress, let progress { + Text(statusText) + .font(theme.typography.caption) + .foregroundColor(.white) + .padding(.vertical, theme.spacing.xs) + .padding(.horizontal, theme.spacing.sm) + .background { + GeometryReader { geometry in + ZStack(alignment: .leading) { + RoundedRectangle(cornerRadius: theme.cornerRadius.sm) + .fill(statusColor.opacity(0.3)) + RoundedRectangle(cornerRadius: theme.cornerRadius.sm) + .fill( + LinearGradient( + gradient: Gradient(colors: [ + statusColor, + statusColor.opacity(0.7) + ]), + startPoint: .leading, + endPoint: .trailing + ) + ) + .frame(width: geometry.size.width * CGFloat(progress) / 100.0) + } + } + } + } else { + Text(statusText) + .font(theme.typography.caption) + .foregroundColor(.white) + .padding(.vertical, theme.spacing.xs) + .padding(.horizontal, theme.spacing.sm) + .adaptiveGlassBackground( + useLiquidGlass: useLiquidGlass, + cornerRadius: theme.cornerRadius.sm, + fillColor: statusColor + ) + } + } +} + +// MARK: - Private + +private extension StatusBadge { + var statusColor: Color { switch status { case .accepted: return theme.colors.accepted @@ -29,7 +80,8 @@ struct StatusBadge: View { return theme.colors.rejected } } - private var statusText: String { + + var statusText: String { let texts = TextManager.shared.texts switch status { @@ -40,6 +92,10 @@ struct StatusBadge: View { case .completed: return texts.completed case .inProgress: + if let progress { + return "\(texts.inProgress) \(progress)%" + } + return texts.inProgress case .pending: return texts.pending @@ -48,22 +104,21 @@ struct StatusBadge: View { } } - let status: SuggestionStatusEntity - let progress: Int? - let useLiquidGlass: Bool - - // MARK: - View - - var body: some View { - Text(statusText) - .font(theme.typography.caption) - .foregroundColor(.white) - .padding(.vertical, theme.spacing.xs) - .padding(.horizontal, theme.spacing.sm) - .adaptiveGlassBackground( - useLiquidGlass: useLiquidGlass, - cornerRadius: theme.cornerRadius.sm, - fillColor: statusColor - ) + @ViewBuilder + var backgroundView: some View { + if status == .inProgress, let progress { + GeometryReader { geometry in + ZStack(alignment: .leading) { + RoundedRectangle(cornerRadius: theme.cornerRadius.sm) + .fill(statusColor.opacity(0.3)) + RoundedRectangle(cornerRadius: theme.cornerRadius.sm) + .fill(statusColor) + .frame(width: geometry.size.width * CGFloat(progress) / 100.0) + } + } + } else { + RoundedRectangle(cornerRadius: theme.cornerRadius.sm) + .fill(statusColor) + } } } From 64780853041b75ee5d45ddf43c70444364275b16 Mon Sep 17 00:00:00 2001 From: Arturo Carretero Calvo <10163049+ArtCC@users.noreply.github.com> Date: Fri, 7 Nov 2025 12:14:36 +0100 Subject: [PATCH 5/6] Refactor StatusBadge view to improve in-progress status display - Extract default tag view into a computed property `defaultTagView` - Create `inProgressTagView(with:)` function to handle in-progress status rendering - Update in-progress text to show completed and remaining parts with different foreground styles - Replace inline view builder code with calls to `inProgressTagView` and `defaultTagView` - Remove unused `backgroundView` computed property - Add MARK comments for properties and functions sections in private extension no message --- .../Votice/UI/Components/StatusBadge.swift | 93 +++++++++---------- 1 file changed, 44 insertions(+), 49 deletions(-) diff --git a/Sources/Votice/UI/Components/StatusBadge.swift b/Sources/Votice/UI/Components/StatusBadge.swift index f0c0f08..4240d69 100644 --- a/Sources/Votice/UI/Components/StatusBadge.swift +++ b/Sources/Votice/UI/Components/StatusBadge.swift @@ -21,42 +21,9 @@ struct StatusBadge: View { var body: some View { if status == .inProgress, let progress { - Text(statusText) - .font(theme.typography.caption) - .foregroundColor(.white) - .padding(.vertical, theme.spacing.xs) - .padding(.horizontal, theme.spacing.sm) - .background { - GeometryReader { geometry in - ZStack(alignment: .leading) { - RoundedRectangle(cornerRadius: theme.cornerRadius.sm) - .fill(statusColor.opacity(0.3)) - RoundedRectangle(cornerRadius: theme.cornerRadius.sm) - .fill( - LinearGradient( - gradient: Gradient(colors: [ - statusColor, - statusColor.opacity(0.7) - ]), - startPoint: .leading, - endPoint: .trailing - ) - ) - .frame(width: geometry.size.width * CGFloat(progress) / 100.0) - } - } - } + inProgressTagView(with: progress) } else { - Text(statusText) - .font(theme.typography.caption) - .foregroundColor(.white) - .padding(.vertical, theme.spacing.xs) - .padding(.horizontal, theme.spacing.sm) - .adaptiveGlassBackground( - useLiquidGlass: useLiquidGlass, - cornerRadius: theme.cornerRadius.sm, - fillColor: statusColor - ) + defaultTagView } } } @@ -64,6 +31,8 @@ struct StatusBadge: View { // MARK: - Private private extension StatusBadge { + // MARK: - Properties + var statusColor: Color { switch status { case .accepted: @@ -104,21 +73,47 @@ private extension StatusBadge { } } - @ViewBuilder - var backgroundView: some View { - if status == .inProgress, let progress { - GeometryReader { geometry in - ZStack(alignment: .leading) { - RoundedRectangle(cornerRadius: theme.cornerRadius.sm) - .fill(statusColor.opacity(0.3)) - RoundedRectangle(cornerRadius: theme.cornerRadius.sm) - .fill(statusColor) - .frame(width: geometry.size.width * CGFloat(progress) / 100.0) + var defaultTagView: some View { + Text(statusText) + .font(theme.typography.caption) + .foregroundColor(.white) + .padding(.vertical, theme.spacing.xs) + .padding(.horizontal, theme.spacing.sm) + .adaptiveGlassBackground( + useLiquidGlass: useLiquidGlass, + cornerRadius: theme.cornerRadius.sm, + fillColor: statusColor + ) + } + + // MARK: - Functions + + func inProgressTagView(with progress: Int) -> some View { + let fullText = statusText + let splitIndex = Int(Double(fullText.count) * Double(progress) / 100.0) + let completedPart = String(fullText.prefix(splitIndex)) + let remainingPart = String(fullText.dropFirst(splitIndex)) + + return Text("\(Text(completedPart).foregroundStyle(.white))\(Text(remainingPart).foregroundStyle(statusColor))") + .font(theme.typography.caption) + .padding(.vertical, theme.spacing.xs) + .padding(.horizontal, theme.spacing.sm) + .background { + GeometryReader { geometry in + ZStack(alignment: .leading) { + RoundedRectangle(cornerRadius: theme.cornerRadius.sm) + .fill(statusColor.opacity(0.3)) + RoundedRectangle(cornerRadius: theme.cornerRadius.sm) + .fill( + LinearGradient( + gradient: Gradient(colors: [statusColor, statusColor.opacity(0.7)]), + startPoint: .leading, + endPoint: .trailing + ) + ) + .frame(width: geometry.size.width * CGFloat(progress) / 100.0) + } } } - } else { - RoundedRectangle(cornerRadius: theme.cornerRadius.sm) - .fill(statusColor) - } } } From d7352689dc03265629fa7c0fe167d63f343a1dcc Mon Sep 17 00:00:00 2001 From: Arturo Carretero Calvo <10163049+ArtCC@users.noreply.github.com> Date: Fri, 7 Nov 2025 13:49:17 +0100 Subject: [PATCH 6/6] Adjust progress calculation in inProgressTagView to include next character - Modify splitIndex calculation by adding 1 to include an additional character in the completed part of the status text based on progress percentage. no message --- Sources/Votice/UI/Components/StatusBadge.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/Votice/UI/Components/StatusBadge.swift b/Sources/Votice/UI/Components/StatusBadge.swift index 4240d69..61135c2 100644 --- a/Sources/Votice/UI/Components/StatusBadge.swift +++ b/Sources/Votice/UI/Components/StatusBadge.swift @@ -90,7 +90,7 @@ private extension StatusBadge { func inProgressTagView(with progress: Int) -> some View { let fullText = statusText - let splitIndex = Int(Double(fullText.count) * Double(progress) / 100.0) + let splitIndex = Int(Double(fullText.count) * Double(progress) / 100.0) + 1 let completedPart = String(fullText.prefix(splitIndex)) let remainingPart = String(fullText.dropFirst(splitIndex))