Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

관심강좌 버튼 이동 #271

Merged
merged 6 commits into from
Dec 30, 2023
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
46 changes: 27 additions & 19 deletions SNUTT-2022/SNUTT.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions SNUTT-2022/SNUTT/AppState/DeepLinkHandler.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ struct DeepLinkHandler {

extension DeepLinkHandler {
private func handleNotification(parameters _: Parameters?) {
appState.system.selectedTab = .settings
appState.routing.settingScene.pushToNotification = true
appState.system.selectedTab = .timetable
appState.routing.timetableScene.pushToNotification = true
}

private func handleVacancy(parameters _: Parameters?) {
Expand Down
8 changes: 7 additions & 1 deletion SNUTT-2022/SNUTT/AppState/States/RoutingState.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,17 @@ import Foundation
@MainActor
class ViewRoutingState {
@Published var settingScene = SettingScene.RoutingState()
@Published var timetableScene = TimetableScene.RoutingState()
}

extension SettingScene {
struct RoutingState {
var pushToNotification = false
var pushToVacancy = false
}
}

extension TimetableScene {
struct RoutingState {
var pushToNotification = false
}
}
1 change: 1 addition & 0 deletions SNUTT-2022/SNUTT/AppState/States/SearchState.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ class SearchState {
@Published var isFilterOpen = false
@Published var searchTagList: SearchTagList?
@Published var selectedTagList: [SearchTag] = []
@Published var displayMode: SearchDisplayMode = .search

/// If `nil`, the user had never started searching.
/// If empty, the server returned an empty search result.
Expand Down
5 changes: 4 additions & 1 deletion SNUTT-2022/SNUTT/Models/Lecture.swift
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,10 @@ struct Lecture: Identifiable {
}

func isEquivalent(with lecture: Lecture) -> Bool {
return !isCustom && courseNumber == lecture.courseNumber && lectureNumber == lecture.lectureNumber
if isCustom {
return id == lecture.id
}
return courseNumber == lecture.courseNumber && lectureNumber == lecture.lectureNumber
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
//
// InteractiveDismissKeyboardModifier.swift
// SNUTT
//
// Created by 박신홍 on 2023/12/18.
//

import SwiftUI

struct InteractiveDismissesKeyboardModifier: ViewModifier {
func body(content: Content) -> some View {
if #available(iOS 16.0, *) {
content
.scrollDismissesKeyboard(.interactively)
} else {
content
}
}
}

extension View {
func scrollDismissesKeyboardInteractively() -> some View {
modifier(InteractiveDismissesKeyboardModifier())
}
}
12 changes: 7 additions & 5 deletions SNUTT-2022/SNUTT/Services/SearchService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ protocol SearchServiceProtocol: Sendable {
func setSelectedLecture(_ value: Lecture?)
func initializeSearchState()
func getBookmark() async throws
func setSearchDisplayMode(_ mode: SearchDisplayMode)
}

struct SearchService: SearchServiceProtocol {
Expand Down Expand Up @@ -47,6 +48,7 @@ struct SearchService: SearchServiceProtocol {
searchState.selectedTagList = []
searchState.searchResult = nil
searchState.searchText = ""
searchState.displayMode = .search
}

func fetchTags(quarter: Quarter) async throws {
Expand Down Expand Up @@ -108,6 +110,10 @@ struct SearchService: SearchServiceProtocol {
searchState.isFilterOpen = value
}

func setSearchDisplayMode(_ mode: SearchDisplayMode) {
searchState.displayMode = mode
}

func setSelectedLecture(_ value: Lecture?) {
searchState.selectedLecture = value
}
Expand All @@ -117,11 +123,6 @@ struct SearchService: SearchServiceProtocol {
}

func getBookmark() async throws {
setLoading(true)
defer {
setLoading(false)
}
searchState.pageNum = 0
try await _getBookmark()
}

Expand Down Expand Up @@ -149,4 +150,5 @@ class FakeSearchService: SearchServiceProtocol {
func setSelectedLecture(_: Lecture?) {}
func initializeSearchState() {}
func getBookmark() async throws {}
func setSearchDisplayMode(_: SearchDisplayMode) {}
}
1 change: 0 additions & 1 deletion SNUTT-2022/SNUTT/Services/TimetableService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -159,5 +159,4 @@ struct FakeTimetableService: TimetableServiceProtocol {
func selectTimetableTheme(theme _: Theme) {}
func createTimetable(title _: String, quarter _: Quarter) async throws {}
func setTimetableConfig(config _: TimetableConfiguration) {}
func setBookmark(lectures _: [Lecture]) {}
}
7 changes: 5 additions & 2 deletions SNUTT-2022/SNUTT/ViewModels/LectureDetailViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,9 @@ extension LectureDetailScene {
}

func findLectureInCurrentTimetable(_ lecture: Lecture) -> Lecture? {
guard let lecture = appState.timetable.current?.lectures.first(where: { $0.id == lecture.id }) else {
guard let lecture = appState.timetable.current?.lectures
.first(where: { $0.isEquivalent(with: lecture) })
else {
return nil
}
return lecture
Expand Down Expand Up @@ -185,7 +187,8 @@ extension LectureDetailScene {
}

func isBookmarked(lecture: Lecture) -> Bool {
return (appState.timetable.bookmark?.lectures.first(where: { $0.id == lecture.lectureId ?? lecture.id })) != nil
appState.timetable.bookmark?.lectures
.contains(where: { $0.isEquivalent(with: lecture) }) ?? false
}

func addVacancyLecture(lecture: Lecture) async {
Expand Down
103 changes: 103 additions & 0 deletions SNUTT-2022/SNUTT/ViewModels/SearchLectureSceneViewModel.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
//
// SearchLectureSceneViewModel.swift
// SNUTT
//
// Created by 박신홍 on 2023/12/18.
//

import Foundation

class SearchLectureSceneViewModel: BaseViewModel, ObservableObject {
@Published private var _selectedLecture: Lecture?
@Published private var _currentTimetable: Timetable?
@Published private var _timetableConfig: TimetableConfiguration = .init()
@Published private var _searchText: String = ""
@Published private var _isFilterOpen: Bool = false
@Published private var _displayMode: SearchDisplayMode = .search

@Published var searchResult: [Lecture]? = nil
@Published var selectedTagList: [SearchTag] = []
@Published var isLoading: Bool = false

var searchText: String {
get { _searchText }
set { services.searchService.setSearchText(newValue) }
}

var isFilterOpen: Bool {
get { _isFilterOpen }
set { services.searchService.setIsFilterOpen(newValue) }
}

var displayMode: SearchDisplayMode {
get { _displayMode }
set { services.searchService.setSearchDisplayMode(newValue) }
}

override init(container: DIContainer) {
super.init(container: container)

appState.timetable.$current.assign(to: &$_currentTimetable)
appState.timetable.$configuration.assign(to: &$_timetableConfig)
appState.search.$selectedLecture.assign(to: &$_selectedLecture)
appState.search.$isFilterOpen.assign(to: &$_isFilterOpen)
appState.search.$searchText.assign(to: &$_searchText)
appState.search.$isLoading.assign(to: &$isLoading)
appState.search.$searchResult.assign(to: &$searchResult)
appState.search.$selectedTagList.assign(to: &$selectedTagList)
appState.search.$displayMode.assign(to: &$_displayMode)
}

var selectedLecture: Lecture? {
get { _selectedLecture }
set { services.searchService.setSelectedLecture(newValue) }
}

var currentTimetableWithSelection: Timetable? {
_currentTimetable?.withSelectedLecture(_selectedLecture)
}

var timetableConfigWithAutoFit: TimetableConfiguration {
_timetableConfig.withAutoFitEnabled()
}

func fetchTags() async {
if appState.search.searchTagList != nil {
return
}
guard let currentTimetable = appState.timetable.current else { return }
do {
try await services.searchService.fetchTags(quarter: currentTimetable.quarter)
} catch {
services.globalUIService.presentErrorAlert(error: error)
}
}

func deselectTag(_ tag: SearchTag) {
services.searchService.deselectTag(tag)
}

func fetchInitialSearchResult() async {
do {
try await services.searchService.fetchInitialSearchResult()
} catch {
services.globalUIService.presentErrorAlert(error: error)
}
}

func getBookmark() async {
do {
try await services.searchService.getBookmark()
} catch {
services.globalUIService.presentErrorAlert(error: error)
}
}

func fetchMoreSearchResult() async {
do {
try await services.searchService.fetchMoreSearchResult()
} catch {
services.globalUIService.presentErrorAlert(error: error)
}
}
}
71 changes: 0 additions & 71 deletions SNUTT-2022/SNUTT/ViewModels/SearchSceneViewModel.swift

This file was deleted.

32 changes: 2 additions & 30 deletions SNUTT-2022/SNUTT/ViewModels/SettingViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,8 @@ import Foundation
import SwiftUI

class SettingViewModel: BaseViewModel, ObservableObject {
@Published var currentUser: User?
@Published var preferredColorScheme: ColorScheme? = nil
@Published var notifications: [STNotification] = []
@Published var unreadCount: Int = 0
@Published private(set) var currentUser: User?
@Published private(set) var preferredColorScheme: ColorScheme? = nil

@Published var _routingState: SettingScene.RoutingState = .init()
var routingState: SettingScene.RoutingState {
Expand All @@ -26,39 +24,13 @@ class SettingViewModel: BaseViewModel, ObservableObject {
super.init(container: container)
appState.user.$current.assign(to: &$currentUser)
appState.system.$preferredColorScheme.assign(to: &$preferredColorScheme)
appState.notification.$notifications.assign(to: &$notifications)
appState.notification.$unreadCount.assign(to: &$unreadCount)
appState.routing.$settingScene.assign(to: &$_routingState)
}

var userEmail: String? {
appState.user.current?.email
}

func fetchInitialNotifications(updateLastRead: Bool) async {
do {
try await services.notificationService.fetchInitialNotifications(updateLastRead: updateLastRead)
} catch {
services.globalUIService.presentErrorAlert(error: error)
}
}

func fetchMoreNotifications() async {
do {
try await services.notificationService.fetchMoreNotifications()
} catch {
services.globalUIService.presentErrorAlert(error: error)
}
}

func fetchNotificationsCount() async {
do {
try await services.notificationService.fetchUnreadNotificationCount()
} catch {
services.globalUIService.presentErrorAlert(error: error)
}
}

func hasNewBadge(settingName: String) -> Bool {
services.globalUIService.hasNewBadge(settingName: settingName)
}
Expand Down
Loading