Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
2 changes: 1 addition & 1 deletion Sources/Votice/Core/Managers/ConfigurationManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
69 changes: 60 additions & 9 deletions Sources/Votice/UI/Components/StatusBadge.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,27 @@ 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 {
inProgressTagView(with: progress)
} else {
defaultTagView
}
}
}

// MARK: - Private

private extension StatusBadge {
// MARK: - Properties

var statusColor: Color {
switch status {
case .accepted:
return theme.colors.accepted
Expand All @@ -29,7 +49,8 @@ struct StatusBadge: View {
return theme.colors.rejected
}
}
private var statusText: String {

var statusText: String {
let texts = TextManager.shared.texts

switch status {
Expand All @@ -40,6 +61,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
Expand All @@ -48,21 +73,47 @@ struct StatusBadge: View {
}
}

let status: SuggestionStatusEntity
let useLiquidGlass: Bool

// MARK: - View

var body: some View {
var defaultTagView: some 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,
fillColor: statusColor
)
}

// MARK: - Functions

func inProgressTagView(with progress: Int) -> some View {
let fullText = statusText
let splitIndex = Int(Double(fullText.count) * Double(progress) / 100.0) + 1

Copilot AI Nov 7, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The + 1 in the splitIndex calculation causes at least one character to always be displayed as completed, even when progress is 0. This means at 0% progress, the first character of the text will be shown in white (completed color), which may not be the intended behavior.

Consider removing the + 1 to make the progress indicator more accurate:

let splitIndex = Int(Double(fullText.count) * Double(progress) / 100.0)

Additionally, consider adding input validation to ensure progress is within the expected 0-100 range.

Copilot uses AI. Check for mistakes.
let completedPart = String(fullText.prefix(splitIndex))
let remainingPart = String(fullText.dropFirst(splitIndex))
Comment on lines +91 to +95

Copilot AI Nov 7, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The inProgressTagView function has a parameter progress that shadows the struct property progress. This creates potential confusion since statusText (line 92) uses the struct's progress property via the computed property defined at line 53. While functionally they should have the same value (due to the check on line 23), this reduces code clarity.

Consider either:

  1. Using self.progress explicitly in the statusText computation, or
  2. Removing the function parameter and using the struct property directly since inProgressTagView is only called when progress is non-nil

Copilot uses AI. Check for mistakes.

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)
}
}
}
}
}
8 changes: 6 additions & 2 deletions Sources/Votice/UI/Components/SuggestionCard.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
6 changes: 5 additions & 1 deletion Sources/Votice/UI/Components/TVOSSuggestionCard.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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()
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Copilot AI Nov 7, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inconsistent code formatting. The closing parenthesis should be on its own line without an extra blank line after it, to maintain consistency with the formatting style used in other files (see SuggestionDetailView.swift lines 251-256 and TVOSSuggestionCard.swift lines 73-77).

Suggested formatting:

StatusBadge(
    status: currentSuggestion.status ?? .pending,
    progress: currentSuggestion.progress,
    useLiquidGlass: false
)
Suggested change

Copilot uses AI. Check for mistakes.
}
if let description = currentSuggestion.description, description != currentSuggestion.title {
Text(description)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}

Expand Down
6 changes: 3 additions & 3 deletions Tests/VoticeTests/Managers/ConfigurationManagerTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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")
}

Expand Down Expand Up @@ -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")
}

Expand Down Expand Up @@ -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
Expand Down