Skip to content

[#160] TodoListView에서 정렬 및 필터 옵션을 스티키 헤더로 재구성하고 description에 있는 데로 옵션을 수정한다#165

Merged
opficdev merged 2 commits intodevelopfrom
feat/#160-Sort&Filter
Mar 3, 2026
Merged

[#160] TodoListView에서 정렬 및 필터 옵션을 스티키 헤더로 재구성하고 description에 있는 데로 옵션을 수정한다#165
opficdev merged 2 commits intodevelopfrom
feat/#160-Sort&Filter

Conversation

@opficdev
Copy link
Owner

@opficdev opficdev commented Mar 3, 2026

@opficdev opficdev self-assigned this Mar 3, 2026
@gemini-code-assist
Copy link

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly refactors the Todo list functionality to introduce a more robust and flexible querying system. It consolidates various todo fetching use cases into a single, comprehensive FetchTodosUseCase and enhances the TodoQuery model to support dynamic sorting and filtering based on multiple criteria. The user interface for the Todo list has been updated with a sticky header containing interactive menus for sorting by creation/update date and order, and filtering by pinned status and completion status, significantly improving user control over todo display.

Highlights

  • Todo fetching logic consolidated: Multiple specific FetchTodoBy...UseCase implementations have been replaced by a single, more flexible FetchTodosUseCase, simplifying the domain layer and enabling dynamic querying.
  • Enhanced TodoQuery model: The TodoQuery struct now includes SortTarget, SortOrder, and CompletionFilter enums, providing richer sorting (by creation/update date, latest/oldest) and filtering (by completion status) capabilities.
  • Dynamic sorting and filtering UI: The TodoListView now features a sticky header with interactive menus for sorting by creation/update date and order, and filtering by pinned status and completion status, significantly improving user control.
  • Refactored data layer for flexibility: The TodoCursorDTO and TodoCursor entities were updated to use orderedAt for dynamic sorting, and the TodoService was modified to apply sorting and filtering based on the new TodoQuery parameters.
  • Updated ViewModel dependencies: HomeViewModel, ProfileViewModel, and SearchViewModel have been updated to utilize the new FetchTodosUseCase, streamlining their data fetching mechanisms.
Changelog
  • DevLog/App/Assembler/DomainAssembler.swift
    • Removed registrations for specific todo fetch use cases (FetchPinnedTodosUseCase, FetchTodosByKindUseCase, FetchTodosByDateRangeUseCase, FetchTodosByKeywordUseCase).
    • Added registration for the new FetchTodosUseCase.
  • DevLog/Data/DTO/TodoCursorDTO.swift
    • Renamed createdAt property to orderedAt.
  • DevLog/Data/Mapper/TodoMapping.swift
    • Updated TodoCursorDTO mapping to use orderedAt instead of createdAt.
  • DevLog/Domain/Entity/TodoCursor.swift
    • Renamed createdAt property to orderedAt.
  • DevLog/Domain/Entity/TodoQuery.swift
    • Refactored TodoQuery to include SortTarget, SortOrder, and CompletionFilter enums.
    • Updated properties and initializer to use new enums for flexible querying.
  • DevLog/Domain/UseCase/Todo/Fetch/FetchPinnedTodosUseCase.swift
    • Removed file.
  • DevLog/Domain/UseCase/Todo/Fetch/FetchPinnedTodosUseCaseImpl.swift
    • Removed file.
  • DevLog/Domain/UseCase/Todo/Fetch/FetchTodosByKeywordUseCase.swift
    • Removed file.
  • DevLog/Domain/UseCase/Todo/Fetch/FetchTodosByKeywordUseCaseImpl.swift
    • Removed file.
  • DevLog/Domain/UseCase/Todo/Fetch/FetchTodosUseCase.swift
    • Added new protocol FetchTodosUseCase.
  • DevLog/Domain/UseCase/Todo/Fetch/FetchTodosUseCaseImpl.swift
    • Added new implementation for FetchTodosUseCase.
  • DevLog/Domain/UseCase/UserData/Fetch/Todo/FetchTodosByDateRangeUseCase.swift
    • Removed file.
  • DevLog/Domain/UseCase/UserData/Fetch/Todo/FetchTodosByDateRangeUseCaseImpl.swift
    • Removed file.
  • DevLog/Domain/UseCase/UserData/Fetch/Todo/FetchTodosByKindUseCase.swift
    • Removed file.
  • DevLog/Domain/UseCase/UserData/Fetch/Todo/FetchTodosByKindUseCaseImpl.swift
    • Removed file.
  • DevLog/Infra/Service/TodoService.swift
    • Updated fetchTodos method to use new TodoQuery properties for dynamic sorting and filtering.
    • Adjusted cursor handling to use orderedAt and dynamic orderField.
  • DevLog/Presentation/Structure/TodoListItem.swift
    • Added createdAt and updatedAt properties.
  • DevLog/Presentation/ViewModel/HomeViewModel.swift
    • Replaced fetchPinnedTodosUseCase with fetchTodosUseCase and updated its usage.
  • DevLog/Presentation/ViewModel/ProfileViewModel.swift
    • Replaced fetchTodosByDateRangeUseCase with fetchTodosUseCase and updated its usage.
  • DevLog/Presentation/ViewModel/SearchViewModel.swift
    • Replaced fetchTodosByKeywordUseCase with fetchTodosUseCase and updated its usage.
  • DevLog/Presentation/ViewModel/TodoListViewModel.swift
    • Refactored state to use TodoQuery directly and removed FilterOption enum.
    • Added new actions for setting sort target, sort order, toggling pinned, setting completion filter, and resetting filters.
    • Updated reduce method to handle new actions and use fetchTodosUseCase with state.query.
    • Added computed property appliedFilterCount and extensions for TodoQuery.SortTarget, SortOrder, CompletionFilter to provide titles.
    • Updated todo.updatedAt when toggling pinned status.
  • DevLog/Resource/Localizable.xcstrings
    • Removed unused localization keys ('생성', '어제', '지난달', '지난주', '작년').
    • Added new localization keys for '완료 상태', '정렬 기준', '정렬 순서', and a new format string '정렬: %@ / %@'.
  • DevLog/UI/Common/MainView.swift
    • Updated HomeViewModel and ProfileViewModel initializations to pass the new fetchTodosUseCase.
  • DevLog/UI/Home/HomeView.swift
    • Updated TodoListViewModel and SearchViewModel initializations to pass the new fetchTodosUseCase.
  • DevLog/UI/Home/TodoListView.swift
    • Reworked the UI to remove the old filter menu and introduce a sticky header with new sortMenu and filterMenu components.
    • Added filterBadge and selectionLabel helper views.
    • Changed the list structure to use Section for the header.
    • Moved LoadingView to overlay the entire view.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This PR impressively integrates multiple Fetch...UseCase into a single FetchTodosUseCase and introduces TodoQuery to improve data fetching logic, reducing code duplication and enhancing flexibility and scalability. Additionally, the TodoListView's filter and sort options have been reconfigured into sticky headers, improving user experience. However, a critical security concern has been identified in TodoService.swift. Keyword-based searches are executing unbounded Firestore queries, which could lead to resource exhaustion or denial of service for users with large datasets. It is strongly recommended to apply a reasonable limit to these queries or implement a more scalable search solution. Further suggestions for improvement are detailed in the specific comments.

Comment on lines +94 to 101
var appliedFilterCount: Int {
var count = 0
if state.query.sortTarget != .createdAt { count += 1 }
if state.query.sortOrder != .latest { count += 1 }
if state.query.isPinned != nil { count += 1 }
if state.query.completionFilter != .all { count += 1 }
return count
}

Choose a reason for hiding this comment

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

medium

appliedFilterCount의 현재 구현은 동작에는 문제가 없지만, 각 조건을 배열로 만들고 filtercount를 사용하는 방식으로 더 간결하고 선언적으로 개선할 수 있습니다. 이렇게 하면 가독성이 향상되고 의도를 더 명확하게 표현할 수 있습니다.

Suggested change
var appliedFilterCount: Int {
var count = 0
if state.query.sortTarget != .createdAt { count += 1 }
if state.query.sortOrder != .latest { count += 1 }
if state.query.isPinned != nil { count += 1 }
if state.query.completionFilter != .all { count += 1 }
return count
}
var appliedFilterCount: Int {
[
state.query.sortTarget != .createdAt,
state.query.sortOrder != .latest,
state.query.isPinned != nil,
state.query.completionFilter != .all
].filter { $0 }.count
}

Comment on lines +346 to +379
extension TodoQuery.SortTarget {
var title: String {
switch self {
case .createdAt:
return "생성"
case .updatedAt:
return "수정"
}
}
}

extension TodoQuery.SortOrder {
var title: String {
switch self {
case .latest:
return "최신순"
case .oldest:
return "예전순"
}
}
}

extension TodoQuery.CompletionFilter {
var title: String {
switch self {
case .all:
return "완료 + 미완료"
case .incomplete:
return "미완료"
case .completed:
return "완료"
}
}
}

Choose a reason for hiding this comment

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

medium

TodoQueryenum들에 대한 title 연산 프로퍼티 확장은 UI 표현과 관련된 로직입니다. 현재 ViewModel 파일에 위치해 있는데, 이는 Domain 계층의 모델이 Presentation 계층의 구체적인 내용(UI에 표시될 문자열)을 알게 되는 구조입니다. Clean Architecture 원칙에 따라 이러한 UI 관련 확장은 실제 사용되는 View 파일(이 경우 TodoListView.swift) 내부로 옮겨 private extension으로 관리하거나, Presentation 계층의 별도 파일로 분리하는 것이 좋습니다. 이렇게 하면 계층 간의 의존성을 줄이고 코드의 관심사를 명확히 분리할 수 있습니다.

Comment on lines +258 to +271
private var filterBadge: some View {
let isDark = colorScheme == .dark
let blue = Color(uiColor: .systemBlue)
let textColor: Color = isDark ? blue : .white
let backgroundColor: Color = isDark ? .white : blue

return Text("\(viewModel.appliedFilterCount)")
.font(.caption2.weight(.bold))
.foregroundColor(textColor)
.lineLimit(1)
.minimumScaleFactor(0.6)
.frame(width: 20, height: 20)
.background(Circle().fill(backgroundColor))
}

Choose a reason for hiding this comment

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

medium

다크 모드에서 필터 뱃지 배경이 흰색으로 설정되어 있어 시각적으로 너무 두드러져 보일 수 있습니다. 라이트 모드와 일관성을 유지하기 위해, 다크 모드에서도 파란색 배경에 흰색 텍스트를 사용하도록 수정하는 것을 제안합니다. 이렇게 하면 colorScheme에 따라 분기하는 로직을 제거하여 코드를 더 간결하게 만들 수 있습니다.

    private var filterBadge: some View {
        let blue = Color(uiColor: .systemBlue)

        return Text("\(viewModel.appliedFilterCount)")
            .font(.caption2.weight(.bold))
            .foregroundColor(.white)
            .lineLimit(1)
            .minimumScaleFactor(0.6)
            .frame(width: 20, height: 20)
            .background(Circle().fill(blue))
    }

@opficdev opficdev merged commit a9d8480 into develop Mar 3, 2026
1 check passed
@opficdev opficdev deleted the feat/#160-Sort&Filter branch March 3, 2026 02:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

TodoListView에서 정렬 및 필터 옵션을 스티키 헤더로 재구성하고 description에 있는 데로 옵션을 수정한다

1 participant