Skip to content

Commit 12d5df9

Browse files
authored
색상 모드 수동 설정 가능하도록 변경 (#195)
1 parent c5c1cf2 commit 12d5df9

File tree

11 files changed

+143
-27
lines changed

11 files changed

+143
-27
lines changed

SNUTT-2022/SNUTT.xcodeproj/project.pbxproj

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,8 @@
160160
BE98A072288AFC1600C2CE95 /* SNUTTWidgetExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = BE98A061288AFC1500C2CE95 /* SNUTTWidgetExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
161161
BE98A07F288B046400C2CE95 /* TimetableWidget.swift in Sources */ = {isa = PBXBuildFile; fileRef = BE98A07D288B032600C2CE95 /* TimetableWidget.swift */; };
162162
BE98A080288B046900C2CE95 /* TimetableWidgetEntryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BE98A07A288B02DD00C2CE95 /* TimetableWidgetEntryView.swift */; };
163+
BE9C90EB2948EA1800003AA6 /* ColorScheme.swift in Sources */ = {isa = PBXBuildFile; fileRef = BE9C90EA2948EA1800003AA6 /* ColorScheme.swift */; };
164+
BE9C90ED2948F4BE00003AA6 /* ColorSchemeSettingScene.swift in Sources */ = {isa = PBXBuildFile; fileRef = BE9C90EC2948F4BE00003AA6 /* ColorSchemeSettingScene.swift */; };
163165
BEB3B6A228CDB7A400E56062 /* LectureTimePicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = BEB3B6A128CDB7A400E56062 /* LectureTimePicker.swift */; };
164166
BEB3B6A528CDE1FD00E56062 /* TimeUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = BEB3B6A428CDE1FD00E56062 /* TimeUtils.swift */; };
165167
BEB3B6A628CDE8AA00E56062 /* TimeUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = BEB3B6A428CDE1FD00E56062 /* TimeUtils.swift */; };
@@ -398,6 +400,8 @@
398400
BE98A06D288AFC1600C2CE95 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
399401
BE98A07A288B02DD00C2CE95 /* TimetableWidgetEntryView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimetableWidgetEntryView.swift; sourceTree = "<group>"; };
400402
BE98A07D288B032600C2CE95 /* TimetableWidget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimetableWidget.swift; sourceTree = "<group>"; };
403+
BE9C90EA2948EA1800003AA6 /* ColorScheme.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ColorScheme.swift; sourceTree = "<group>"; };
404+
BE9C90EC2948F4BE00003AA6 /* ColorSchemeSettingScene.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ColorSchemeSettingScene.swift; sourceTree = "<group>"; };
401405
BEB3B6A128CDB7A400E56062 /* LectureTimePicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LectureTimePicker.swift; sourceTree = "<group>"; };
402406
BEB3B6A428CDE1FD00E56062 /* TimeUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimeUtils.swift; sourceTree = "<group>"; };
403407
BEB3B6AC28D4D40400E56062 /* EditableFields.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditableFields.swift; sourceTree = "<group>"; };
@@ -517,6 +521,7 @@
517521
children = (
518522
DC29159A2865F95100FE5F9A /* SettingScene.swift */,
519523
B8F40EAA28980D730021A2A9 /* AccountSettingScene.swift */,
524+
BE9C90EC2948F4BE00003AA6 /* ColorSchemeSettingScene.swift */,
520525
B8F40EAC28980D840021A2A9 /* TimetableSettingScene.swift */,
521526
);
522527
path = Settings;
@@ -564,6 +569,7 @@
564569
BEB57C2028B6758200279EFF /* Animation+Custom.swift */,
565570
BE9413D128C2458A00171060 /* DateFormatter+Parse.swift */,
566571
BED04D3228EA963E00937E4C /* FacebookLogin.swift */,
572+
BE9C90EA2948EA1800003AA6 /* ColorScheme.swift */,
567573
);
568574
path = Extensions;
569575
sourceTree = "<group>";
@@ -1185,6 +1191,7 @@
11851191
B8AF8D3E28C72A880056DE62 /* ValidationUtils.swift in Sources */,
11861192
BE8BB3AD285D763B00070A66 /* SearchLectureScene.swift in Sources */,
11871193
BE682C0528881852009EBCB7 /* SearchService.swift in Sources */,
1194+
BE9C90EB2948EA1800003AA6 /* ColorScheme.swift in Sources */,
11881195
BE4B0EC02873BDAA005FE164 /* SearchSceneViewModel.swift in Sources */,
11891196
BEE86519289E287400D3D0E4 /* MenuRenameSheet.swift in Sources */,
11901197
BEDE34DC2879B40100525014 /* AppEnvironment.swift in Sources */,
@@ -1327,6 +1334,7 @@
13271334
BE682BB6287C40AF009EBCB7 /* Theme.swift in Sources */,
13281335
BE779B1C28E72622009960EB /* AnimatedTextField.swift in Sources */,
13291336
B8BC0C9028BE02D2007A1CA8 /* ReviewRepository.swift in Sources */,
1337+
BE9C90ED2948F4BE00003AA6 /* ColorSchemeSettingScene.swift in Sources */,
13301338
BEDF507927F42D7500CDCC13 /* STColor.swift in Sources */,
13311339
BE4B0EB628735005005FE164 /* MenuSheetViewModel.swift in Sources */,
13321340
B87DF6FB291A4303008BB95B /* PopupScene.swift in Sources */,

SNUTT-2022/SNUTT/AppState/AppEnvironment.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ extension AppEnvironment {
6868
/// We need to load access token ASAP in order to determine which screen to show first.
6969
/// Note that this should run synchronously on the main thread.
7070
services.authService.loadAccessTokenDuringBootstrap()
71+
services.globalUIService.loadColorSchemeDuringBootstrap()
7172
services.timetableService.loadTimetableConfig()
7273

7374
return .init(container: container)

SNUTT-2022/SNUTT/AppState/States/SystemState.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,11 @@
66
//
77

88
import Combine
9+
import SwiftUI
910
import UIKit
1011

1112
class SystemState: ObservableObject {
1213
@Published var isErrorAlertPresented = false
1314
@Published var error: STError? = nil
15+
@Published var preferredColorScheme: ColorScheme? = nil
1416
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
//
2+
// ColorScheme.swift
3+
// SNUTT
4+
//
5+
// Created by 박신홍 on 2022/12/14.
6+
//
7+
8+
import SwiftUI
9+
10+
extension ColorScheme {
11+
var description: String {
12+
switch self {
13+
case .dark:
14+
return "dark"
15+
case .light:
16+
return "light"
17+
@unknown default:
18+
return "light"
19+
}
20+
}
21+
22+
static func from(description: String?) -> Self? {
23+
if description == "light" {
24+
return .light
25+
}
26+
27+
if description == "dark" {
28+
return .dark
29+
}
30+
31+
return nil
32+
}
33+
}

SNUTT-2022/SNUTT/Repositories/UserDefaultsRepository.swift

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,11 @@ enum STDefaultsKey: String {
1919
case userId
2020
case userDto
2121
case fcmToken
22+
case preferredColorScheme
2223

2324
case currentTimetable
2425
case timetableConfig
2526

26-
case registeredFCMToken
27-
case appVersion
28-
29-
case shouldShowBadge
30-
case shouldDeleteFCMInfos
31-
3227
case popupList
3328
}
3429

SNUTT-2022/SNUTT/Services/GlobalUIService.swift

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,12 @@
66
//
77

88
import Foundation
9+
import SwiftUI
910

1011
protocol GlobalUIServiceProtocol {
12+
func setColorScheme(_ colorScheme: ColorScheme?)
13+
func loadColorSchemeDuringBootstrap()
14+
1115
func setIsMenuOpen(_ value: Bool)
1216

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

44+
func setColorScheme(_ colorScheme: ColorScheme?) {
45+
DispatchQueue.main.async {
46+
appState.system.preferredColorScheme = colorScheme
47+
}
48+
localRepositories.userDefaultsRepository.set(String.self, key: .preferredColorScheme, value: colorScheme?.description)
49+
}
50+
51+
func loadColorSchemeDuringBootstrap() {
52+
let colorSchemeDescription = localRepositories.userDefaultsRepository.get(String.self, key: .preferredColorScheme)
53+
let colorScheme = ColorScheme.from(description: colorSchemeDescription)
54+
appState.system.preferredColorScheme = colorScheme
55+
}
56+
4057
func setIsMenuOpen(_ value: Bool) {
4158
DispatchQueue.main.async {
4259
appState.menu.isOpen = value

SNUTT-2022/SNUTT/ViewModels/SettingViewModel.swift

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,39 @@
88
import Foundation
99
import SwiftUI
1010

11-
class SettingViewModel: BaseViewModel {
11+
class SettingViewModel: BaseViewModel, ObservableObject {
12+
@Published var preferredColorScheme: ColorScheme? = nil
13+
1214
override init(container: DIContainer) {
1315
super.init(container: container)
16+
appState.system.$preferredColorScheme.assign(to: &$preferredColorScheme)
17+
}
18+
19+
func setColorScheme(colorScheme: ColorScheme?) {
20+
services.globalUIService.setColorScheme(colorScheme)
21+
}
22+
23+
var currentColorSchemeSelection: ColorSchemeSelection {
24+
get {
25+
if preferredColorScheme == .light {
26+
return .light
27+
}
28+
if preferredColorScheme == .dark {
29+
return .dark
30+
}
31+
return .automatic
32+
}
33+
34+
set {
35+
switch newValue {
36+
case .automatic:
37+
setColorScheme(colorScheme: nil)
38+
case .light:
39+
setColorScheme(colorScheme: .light)
40+
case .dark:
41+
setColorScheme(colorScheme: .dark)
42+
}
43+
}
1444
}
1545

1646
func logout() async {

SNUTT-2022/SNUTT/Views/Components/WebViews/ReviewWebView.swift

Lines changed: 1 addition & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ struct ReviewWebView: WebView {
7979
case .reload:
8080
self?.parent.reloadWebView()
8181
case let .colorSchemeChange(to: colorScheme):
82-
self?.parent.webView.evaluateJavaScript("changeTheme(\(colorScheme.descriptionWithQuotes))")
82+
self?.parent.webView.evaluateJavaScript("changeTheme('\(colorScheme.description)')")
8383
}
8484
}.store(in: &bag)
8585
}
@@ -103,20 +103,3 @@ struct ReviewWebView: WebView {
103103
}
104104
}
105105
}
106-
107-
private extension ColorScheme {
108-
var description: String {
109-
switch self {
110-
case .dark:
111-
return "dark"
112-
case .light:
113-
return "light"
114-
@unknown default:
115-
return "light"
116-
}
117-
}
118-
119-
var descriptionWithQuotes: String {
120-
"'\(description)'"
121-
}
122-
}

SNUTT-2022/SNUTT/Views/SNUTTView.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ struct SNUTTView: View {
6767
LectureTimeSheetScene(viewModel: .init(container: viewModel.container))
6868
}
6969
.animation(.easeOut, value: viewModel.accessToken)
70+
.preferredColorScheme(viewModel.preferredColorScheme)
7071
.accentColor(Color(UIColor.label))
7172
.alert(viewModel.errorTitle, isPresented: $viewModel.isErrorAlertPresented, actions: {}) {
7273
Text(viewModel.errorMessage)
@@ -100,6 +101,8 @@ extension SNUTTView {
100101
class ViewModel: BaseViewModel, ObservableObject {
101102
@Published var isErrorAlertPresented = false
102103
@Published var accessToken: String? = nil
104+
@Published var preferredColorScheme: ColorScheme? = nil
105+
103106
@Published private var error: STError? = nil
104107
var reviewEventSignal = PassthroughSubject<WebViewEventType, Never>()
105108

@@ -113,6 +116,7 @@ extension SNUTTView {
113116
appState.system.$error.assign(to: &$error)
114117
appState.system.$isErrorAlertPresented.assign(to: &$isErrorAlertPresented)
115118
appState.user.$accessToken.assign(to: &$accessToken)
119+
appState.system.$preferredColorScheme.assign(to: &$preferredColorScheme)
116120
}
117121

118122
var errorTitle: String {
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
//
2+
// ColorSchemeSettingScene.swift
3+
// SNUTT
4+
//
5+
// Created by 박신홍 on 2022/12/14.
6+
//
7+
8+
import SwiftUI
9+
10+
struct ColorSchemeSettingScene: View {
11+
@Binding var selection: ColorSchemeSelection
12+
13+
var body: some View {
14+
List {
15+
ForEach(ColorSchemeSelection.allCases, id: \.self) { scheme in
16+
Button {
17+
withAnimation {
18+
selection = scheme
19+
}
20+
} label: {
21+
HStack {
22+
Text(scheme.rawValue)
23+
Spacer()
24+
if selection == scheme {
25+
Image(systemName: "checkmark")
26+
}
27+
}
28+
}
29+
}
30+
}
31+
.listStyle(.insetGrouped)
32+
.navigationTitle("색상 모드")
33+
}
34+
}

0 commit comments

Comments
 (0)