Skip to content

Commit

Permalink
색상 모드 수동 설정 가능하도록 변경 (#195)
Browse files Browse the repository at this point in the history
  • Loading branch information
shp7724 authored Dec 17, 2022
1 parent c5c1cf2 commit 12d5df9
Show file tree
Hide file tree
Showing 11 changed files with 143 additions and 27 deletions.
8 changes: 8 additions & 0 deletions SNUTT-2022/SNUTT.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,8 @@
BE98A072288AFC1600C2CE95 /* SNUTTWidgetExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = BE98A061288AFC1500C2CE95 /* SNUTTWidgetExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
BE98A07F288B046400C2CE95 /* TimetableWidget.swift in Sources */ = {isa = PBXBuildFile; fileRef = BE98A07D288B032600C2CE95 /* TimetableWidget.swift */; };
BE98A080288B046900C2CE95 /* TimetableWidgetEntryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BE98A07A288B02DD00C2CE95 /* TimetableWidgetEntryView.swift */; };
BE9C90EB2948EA1800003AA6 /* ColorScheme.swift in Sources */ = {isa = PBXBuildFile; fileRef = BE9C90EA2948EA1800003AA6 /* ColorScheme.swift */; };
BE9C90ED2948F4BE00003AA6 /* ColorSchemeSettingScene.swift in Sources */ = {isa = PBXBuildFile; fileRef = BE9C90EC2948F4BE00003AA6 /* ColorSchemeSettingScene.swift */; };
BEB3B6A228CDB7A400E56062 /* LectureTimePicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = BEB3B6A128CDB7A400E56062 /* LectureTimePicker.swift */; };
BEB3B6A528CDE1FD00E56062 /* TimeUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = BEB3B6A428CDE1FD00E56062 /* TimeUtils.swift */; };
BEB3B6A628CDE8AA00E56062 /* TimeUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = BEB3B6A428CDE1FD00E56062 /* TimeUtils.swift */; };
Expand Down Expand Up @@ -398,6 +400,8 @@
BE98A06D288AFC1600C2CE95 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
BE98A07A288B02DD00C2CE95 /* TimetableWidgetEntryView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimetableWidgetEntryView.swift; sourceTree = "<group>"; };
BE98A07D288B032600C2CE95 /* TimetableWidget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimetableWidget.swift; sourceTree = "<group>"; };
BE9C90EA2948EA1800003AA6 /* ColorScheme.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ColorScheme.swift; sourceTree = "<group>"; };
BE9C90EC2948F4BE00003AA6 /* ColorSchemeSettingScene.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ColorSchemeSettingScene.swift; sourceTree = "<group>"; };
BEB3B6A128CDB7A400E56062 /* LectureTimePicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LectureTimePicker.swift; sourceTree = "<group>"; };
BEB3B6A428CDE1FD00E56062 /* TimeUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimeUtils.swift; sourceTree = "<group>"; };
BEB3B6AC28D4D40400E56062 /* EditableFields.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditableFields.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -517,6 +521,7 @@
children = (
DC29159A2865F95100FE5F9A /* SettingScene.swift */,
B8F40EAA28980D730021A2A9 /* AccountSettingScene.swift */,
BE9C90EC2948F4BE00003AA6 /* ColorSchemeSettingScene.swift */,
B8F40EAC28980D840021A2A9 /* TimetableSettingScene.swift */,
);
path = Settings;
Expand Down Expand Up @@ -564,6 +569,7 @@
BEB57C2028B6758200279EFF /* Animation+Custom.swift */,
BE9413D128C2458A00171060 /* DateFormatter+Parse.swift */,
BED04D3228EA963E00937E4C /* FacebookLogin.swift */,
BE9C90EA2948EA1800003AA6 /* ColorScheme.swift */,
);
path = Extensions;
sourceTree = "<group>";
Expand Down Expand Up @@ -1185,6 +1191,7 @@
B8AF8D3E28C72A880056DE62 /* ValidationUtils.swift in Sources */,
BE8BB3AD285D763B00070A66 /* SearchLectureScene.swift in Sources */,
BE682C0528881852009EBCB7 /* SearchService.swift in Sources */,
BE9C90EB2948EA1800003AA6 /* ColorScheme.swift in Sources */,
BE4B0EC02873BDAA005FE164 /* SearchSceneViewModel.swift in Sources */,
BEE86519289E287400D3D0E4 /* MenuRenameSheet.swift in Sources */,
BEDE34DC2879B40100525014 /* AppEnvironment.swift in Sources */,
Expand Down Expand Up @@ -1327,6 +1334,7 @@
BE682BB6287C40AF009EBCB7 /* Theme.swift in Sources */,
BE779B1C28E72622009960EB /* AnimatedTextField.swift in Sources */,
B8BC0C9028BE02D2007A1CA8 /* ReviewRepository.swift in Sources */,
BE9C90ED2948F4BE00003AA6 /* ColorSchemeSettingScene.swift in Sources */,
BEDF507927F42D7500CDCC13 /* STColor.swift in Sources */,
BE4B0EB628735005005FE164 /* MenuSheetViewModel.swift in Sources */,
B87DF6FB291A4303008BB95B /* PopupScene.swift in Sources */,
Expand Down
1 change: 1 addition & 0 deletions SNUTT-2022/SNUTT/AppState/AppEnvironment.swift
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ extension AppEnvironment {
/// We need to load access token ASAP in order to determine which screen to show first.
/// Note that this should run synchronously on the main thread.
services.authService.loadAccessTokenDuringBootstrap()
services.globalUIService.loadColorSchemeDuringBootstrap()
services.timetableService.loadTimetableConfig()

return .init(container: container)
Expand Down
2 changes: 2 additions & 0 deletions SNUTT-2022/SNUTT/AppState/States/SystemState.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@
//

import Combine
import SwiftUI
import UIKit

class SystemState: ObservableObject {
@Published var isErrorAlertPresented = false
@Published var error: STError? = nil
@Published var preferredColorScheme: ColorScheme? = nil
}
33 changes: 33 additions & 0 deletions SNUTT-2022/SNUTT/Extensions/ColorScheme.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
//
// ColorScheme.swift
// SNUTT
//
// Created by 박신홍 on 2022/12/14.
//

import SwiftUI

extension ColorScheme {
var description: String {
switch self {
case .dark:
return "dark"
case .light:
return "light"
@unknown default:
return "light"
}
}

static func from(description: String?) -> Self? {
if description == "light" {
return .light
}

if description == "dark" {
return .dark
}

return nil
}
}
7 changes: 1 addition & 6 deletions SNUTT-2022/SNUTT/Repositories/UserDefaultsRepository.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,11 @@ enum STDefaultsKey: String {
case userId
case userDto
case fcmToken
case preferredColorScheme

case currentTimetable
case timetableConfig

case registeredFCMToken
case appVersion

case shouldShowBadge
case shouldDeleteFCMInfos

case popupList
}

Expand Down
17 changes: 17 additions & 0 deletions SNUTT-2022/SNUTT/Services/GlobalUIService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,12 @@
//

import Foundation
import SwiftUI

protocol GlobalUIServiceProtocol {
func setColorScheme(_ colorScheme: ColorScheme?)
func loadColorSchemeDuringBootstrap()

func setIsMenuOpen(_ value: Bool)

func openEllipsis(for timetable: TimetableMetadata)
Expand Down Expand Up @@ -37,6 +41,19 @@ struct GlobalUIService: GlobalUIServiceProtocol, UserAuthHandler {
var appState: AppState
var localRepositories: AppEnvironment.LocalRepositories

func setColorScheme(_ colorScheme: ColorScheme?) {
DispatchQueue.main.async {
appState.system.preferredColorScheme = colorScheme
}
localRepositories.userDefaultsRepository.set(String.self, key: .preferredColorScheme, value: colorScheme?.description)
}

func loadColorSchemeDuringBootstrap() {
let colorSchemeDescription = localRepositories.userDefaultsRepository.get(String.self, key: .preferredColorScheme)
let colorScheme = ColorScheme.from(description: colorSchemeDescription)
appState.system.preferredColorScheme = colorScheme
}

func setIsMenuOpen(_ value: Bool) {
DispatchQueue.main.async {
appState.menu.isOpen = value
Expand Down
32 changes: 31 additions & 1 deletion SNUTT-2022/SNUTT/ViewModels/SettingViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,39 @@
import Foundation
import SwiftUI

class SettingViewModel: BaseViewModel {
class SettingViewModel: BaseViewModel, ObservableObject {
@Published var preferredColorScheme: ColorScheme? = nil

override init(container: DIContainer) {
super.init(container: container)
appState.system.$preferredColorScheme.assign(to: &$preferredColorScheme)
}

func setColorScheme(colorScheme: ColorScheme?) {
services.globalUIService.setColorScheme(colorScheme)
}

var currentColorSchemeSelection: ColorSchemeSelection {
get {
if preferredColorScheme == .light {
return .light
}
if preferredColorScheme == .dark {
return .dark
}
return .automatic
}

set {
switch newValue {
case .automatic:
setColorScheme(colorScheme: nil)
case .light:
setColorScheme(colorScheme: .light)
case .dark:
setColorScheme(colorScheme: .dark)
}
}
}

func logout() async {
Expand Down
19 changes: 1 addition & 18 deletions SNUTT-2022/SNUTT/Views/Components/WebViews/ReviewWebView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ struct ReviewWebView: WebView {
case .reload:
self?.parent.reloadWebView()
case let .colorSchemeChange(to: colorScheme):
self?.parent.webView.evaluateJavaScript("changeTheme(\(colorScheme.descriptionWithQuotes))")
self?.parent.webView.evaluateJavaScript("changeTheme('\(colorScheme.description)')")
}
}.store(in: &bag)
}
Expand All @@ -103,20 +103,3 @@ struct ReviewWebView: WebView {
}
}
}

private extension ColorScheme {
var description: String {
switch self {
case .dark:
return "dark"
case .light:
return "light"
@unknown default:
return "light"
}
}

var descriptionWithQuotes: String {
"'\(description)'"
}
}
4 changes: 4 additions & 0 deletions SNUTT-2022/SNUTT/Views/SNUTTView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ struct SNUTTView: View {
LectureTimeSheetScene(viewModel: .init(container: viewModel.container))
}
.animation(.easeOut, value: viewModel.accessToken)
.preferredColorScheme(viewModel.preferredColorScheme)
.accentColor(Color(UIColor.label))
.alert(viewModel.errorTitle, isPresented: $viewModel.isErrorAlertPresented, actions: {}) {
Text(viewModel.errorMessage)
Expand Down Expand Up @@ -100,6 +101,8 @@ extension SNUTTView {
class ViewModel: BaseViewModel, ObservableObject {
@Published var isErrorAlertPresented = false
@Published var accessToken: String? = nil
@Published var preferredColorScheme: ColorScheme? = nil

@Published private var error: STError? = nil
var reviewEventSignal = PassthroughSubject<WebViewEventType, Never>()

Expand All @@ -113,6 +116,7 @@ extension SNUTTView {
appState.system.$error.assign(to: &$error)
appState.system.$isErrorAlertPresented.assign(to: &$isErrorAlertPresented)
appState.user.$accessToken.assign(to: &$accessToken)
appState.system.$preferredColorScheme.assign(to: &$preferredColorScheme)
}

var errorTitle: String {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
//
// ColorSchemeSettingScene.swift
// SNUTT
//
// Created by 박신홍 on 2022/12/14.
//

import SwiftUI

struct ColorSchemeSettingScene: View {
@Binding var selection: ColorSchemeSelection

var body: some View {
List {
ForEach(ColorSchemeSelection.allCases, id: \.self) { scheme in
Button {
withAnimation {
selection = scheme
}
} label: {
HStack {
Text(scheme.rawValue)
Spacer()
if selection == scheme {
Image(systemName: "checkmark")
}
}
}
}
}
.listStyle(.insetGrouped)
.navigationTitle("색상 모드")
}
}
13 changes: 11 additions & 2 deletions SNUTT-2022/SNUTT/Views/Scenes/Settings/SettingScene.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@
import SwiftUI

struct SettingScene: View {
let viewModel: SettingViewModel

@ObservedObject var viewModel: SettingViewModel
@State private var isLogoutAlertPresented: Bool = false

var body: some View {
Expand All @@ -22,6 +21,10 @@ struct SettingScene: View {
SettingsLinkItem(title: "시간표 설정") {
TimetableSettingScene(viewModel: .init(container: viewModel.container))
}

SettingsLinkItem(title: "색상 모드", detail: viewModel.currentColorSchemeSelection.rawValue) {
ColorSchemeSettingScene(selection: $viewModel.currentColorSchemeSelection)
}
}

Section {
Expand Down Expand Up @@ -73,6 +76,12 @@ struct SettingScene: View {
}
}

enum ColorSchemeSelection: String, CaseIterable {
case automatic = "자동"
case light = "라이트 모드"
case dark = "다크 모드"
}

#if DEBUG
struct SettingScene_Previews: PreviewProvider {
static var previews: some View {
Expand Down

0 comments on commit 12d5df9

Please sign in to comment.