Group tasks feature #3

Merged
javier merged 7 commits from app/group-tasks into main 2026-02-10 02:22:41 +00:00
5 changed files with 215 additions and 2 deletions
Showing only changes of commit fae7a476a1 - Show all commits
+44
View File
@@ -1,6 +1,50 @@
{ {
"sourceLanguage" : "en", "sourceLanguage" : "en",
"strings" : { "strings" : {
"enumeration.todo-group.title.completed" : {
"extractionState" : "manual",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Completed"
}
}
}
},
"enumeration.todo-group.title.overdue" : {
"extractionState" : "manual",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Overdue"
}
}
}
},
"enumeration.todo-group.title.today" : {
"extractionState" : "manual",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Today"
}
}
}
},
"enumeration.todo-group.title.upcoming" : {
"extractionState" : "manual",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Upcoming"
}
}
}
},
"view.new-task.navigation.title" : { "view.new-task.navigation.title" : {
"extractionState" : "manual", "extractionState" : "manual",
"localizations" : { "localizations" : {
+70
View File
@@ -0,0 +1,70 @@
import Foundation
import SwiftUI
/// Categorizes todo tasks into groups based on their due dates and completion status.
///
/// This enumeration provides a semantic grouping mechanism for organizing and filtering todo tasks throughout the application.
/// Each case represents a distinct category that helps users manage their tasks based on temporal relevance and completion state.
enum TodoGroup {
/// Tasks that have been marked as done, regardless of due date.
case completed
/// Tasks with due dates in the past that remain incomplete.
case overdue
/// Tasks due on the current day that are not yet completed.
case today
/// Tasks due in the future that are not yet completed.
case upcoming
}
// MARK: - Computed
extension TodoGroup {
/// The color associated with the task group.
var color: Color {
switch self {
case .completed: .gray
case .overdue: .red
case .today: .blue
case .upcoming: .green
}
}
/// The system icon name for the task group.
var iconName: String {
switch self {
case .completed: "checkmark.circle.fill"
case .overdue: "calendar.badge.exclamationmark"
case .today: "calendar.badge.clock"
case .upcoming: "calendar"
}
}
/// The display title for the task group.
var title: LocalizedStringKey {
switch self {
case .completed: "enumeration.todo-group.title.completed"
case .overdue: "enumeration.todo-group.title.overdue"
case .today: "enumeration.todo-group.title.today"
case .upcoming: "enumeration.todo-group.title.upcoming"
}
}
}
// MARK: - CaseIterable
extension TodoGroup: CaseIterable {
static var allCases: [TodoGroup] { [.today, .upcoming, .overdue, .completed] }
}
// MARK: - Identifiable
extension TodoGroup: Identifiable {
var id: Self { self }
}
@@ -0,0 +1,99 @@
import Foundation
import SwiftUI
import Testing
@testable import Todos
@Suite("TodoGroup enumeration tests")
struct TodoGroupTests {
// MARK: Computed tests
@Test(
"group color match expected values",
arguments: zip(
TodoGroup.allCases,
[Color.blue, .green, .red, .gray]
)
)
func color(
for group: TodoGroup,
expects expectation: Color
) {
// GIVEN
// WHEN
let color = group.color
// THEN
#expect(color == expectation)
}
@Test(
"group icon names match expected values",
arguments: zip(
TodoGroup.allCases,
["calendar.badge.clock", "calendar", "calendar.badge.exclamationmark", "checkmark.circle.fill"]
)
)
func iconName(
for group: TodoGroup,
expects expectation: String
) {
// GIVEN
// WHEN
let iconName = group.iconName
// THEN
#expect(iconName == expectation)
}
@Test(
"group titles match expected values",
arguments: zip(
TodoGroup.allCases,
["today", "upcoming", "overdue", "completed"]
)
)
func title(
for group: TodoGroup,
expects expectation: String
) {
// GIVEN
let key = "enumeration.todo-group.title." + expectation
// WHEN
let title = group.title
// THEN
#expect(title == .init(key))
}
// MARK: Case Iteration Tests
@Test("all cases contains all cases, in correct order")
func allCases() {
// GIVEN
// WHEN
let allCases = TodoGroup.allCases
// THEN
#expect(allCases.count == 4)
#expect(allCases[0] == .today)
#expect(allCases[1] == .upcoming)
#expect(allCases[2] == .overdue)
#expect(allCases[3] == .completed)
}
// MARK: Identifiable Tests
@Test("id returns an identity of a case", arguments: TodoGroup.allCases)
func id(for group: TodoGroup) {
// GIVEN
// WHEN
let id = group.id
// THEN
#expect(id == group)
}
}
@@ -4,7 +4,7 @@ import Testing
@testable import Todos @testable import Todos
@Suite("ContentView.ViewModel Tests") @Suite("ContentView view model tests")
struct ContentViewModelTests { struct ContentViewModelTests {
// MARK: Initialization Tests // MARK: Initialization Tests
@@ -4,7 +4,7 @@ import Testing
@testable import Todos @testable import Todos
@Suite("NewTaskView ViewModel Tests") @Suite("NewTaskView view model tests")
struct NewTaskViewModelTests { struct NewTaskViewModelTests {
// MARK: Initialization tests // MARK: Initialization tests