From eed9ce30073a963733a8995796e92c6570603c4c Mon Sep 17 00:00:00 2001
From: Mustafa Merza <mustafa.merza95@gmail.com>
Date: Wed, 17 Jul 2024 15:55:58 +0300
Subject: [PATCH] - Added use cases to handle app's color scheme.

---
 MiniScanner.xcodeproj/project.pbxproj         | 20 ++++++++++
 .../Common/DI/DependencyManager.swift         |  3 ++
 .../Data/DataSources/SettingsDataSource.swift | 20 ++++++++++
 .../Data/Model/SupportedColorScheme.swift     | 27 +++++++++++++
 .../Repositories/SettingsRepository.swift     | 38 +++++++++++++++++++
 .../SettingsRepositoryProtocol.swift          |  3 ++
 .../ChangeColorSchemeUseCase.swift            | 22 +++++++++++
 .../ColorScheme/GetColorSchemeUseCase.swift   | 22 +++++++++++
 .../UserDefaults/UserDefaultsKeys.swift       |  1 +
 9 files changed, 156 insertions(+)
 create mode 100644 MiniScanner/Features/Common/Data/Model/SupportedColorScheme.swift
 create mode 100644 MiniScanner/Features/Common/Domain/UseCases/ColorScheme/ChangeColorSchemeUseCase.swift
 create mode 100644 MiniScanner/Features/Common/Domain/UseCases/ColorScheme/GetColorSchemeUseCase.swift

diff --git a/MiniScanner.xcodeproj/project.pbxproj b/MiniScanner.xcodeproj/project.pbxproj
index df35133..0f7ada4 100644
--- a/MiniScanner.xcodeproj/project.pbxproj
+++ b/MiniScanner.xcodeproj/project.pbxproj
@@ -186,6 +186,9 @@
 		672C46C92C47E98A00497EF0 /* SupportedLanguage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 672C46C02C47E98A00497EF0 /* SupportedLanguage.swift */; };
 		672C46CA2C47E98A00497EF0 /* SettingsRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 672C46C22C47E98A00497EF0 /* SettingsRepository.swift */; };
 		672C46CC2C47E9AB00497EF0 /* GetLanguageUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 672C46CB2C47E9AB00497EF0 /* GetLanguageUseCase.swift */; };
+		672C46CF2C47EA6D00497EF0 /* GetColorSchemeUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 672C46CE2C47EA6D00497EF0 /* GetColorSchemeUseCase.swift */; };
+		672C46D12C47EA7400497EF0 /* ChangeColorSchemeUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 672C46D02C47EA7400497EF0 /* ChangeColorSchemeUseCase.swift */; };
+		672C46D32C47EA8F00497EF0 /* SupportedColorScheme.swift in Sources */ = {isa = PBXBuildFile; fileRef = 672C46D22C47EA8F00497EF0 /* SupportedColorScheme.swift */; };
 		B827E5196CC419E773B843E1 /* Pods_MiniScanner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E9A37DC9F9A8E3AF632DFB98 /* Pods_MiniScanner.framework */; };
 		EC0CF1FE254D8BBF00888722 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC0CF1FD254D8BBF00888722 /* AppDelegate.swift */; };
 		EC0CF200254D8BBF00888722 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC0CF1FF254D8BBF00888722 /* SceneDelegate.swift */; };
@@ -422,6 +425,9 @@
 		672C46C02C47E98A00497EF0 /* SupportedLanguage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SupportedLanguage.swift; sourceTree = "<group>"; };
 		672C46C22C47E98A00497EF0 /* SettingsRepository.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsRepository.swift; sourceTree = "<group>"; };
 		672C46CB2C47E9AB00497EF0 /* GetLanguageUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GetLanguageUseCase.swift; sourceTree = "<group>"; };
+		672C46CE2C47EA6D00497EF0 /* GetColorSchemeUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GetColorSchemeUseCase.swift; sourceTree = "<group>"; };
+		672C46D02C47EA7400497EF0 /* ChangeColorSchemeUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChangeColorSchemeUseCase.swift; sourceTree = "<group>"; };
+		672C46D22C47EA8F00497EF0 /* SupportedColorScheme.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SupportedColorScheme.swift; sourceTree = "<group>"; };
 		E8AF4FB39674DF589D719DCF /* Pods-MiniScanner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MiniScanner.release.xcconfig"; path = "Target Support Files/Pods-MiniScanner/Pods-MiniScanner.release.xcconfig"; sourceTree = "<group>"; };
 		E9A37DC9F9A8E3AF632DFB98 /* Pods_MiniScanner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_MiniScanner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
 		EC0CF1FA254D8BBF00888722 /* MiniScanner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MiniScanner.app; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -1017,6 +1023,7 @@
 		672C46BC2C47E98900497EF0 /* UseCases */ = {
 			isa = PBXGroup;
 			children = (
+				672C46CD2C47EA2A00497EF0 /* ColorScheme */,
 				672C46BB2C47E98900497EF0 /* Language */,
 			);
 			path = UseCases;
@@ -1043,6 +1050,7 @@
 			isa = PBXGroup;
 			children = (
 				672C46C02C47E98A00497EF0 /* SupportedLanguage.swift */,
+				672C46D22C47EA8F00497EF0 /* SupportedColorScheme.swift */,
 			);
 			path = Model;
 			sourceTree = "<group>";
@@ -1065,6 +1073,15 @@
 			path = Data;
 			sourceTree = "<group>";
 		};
+		672C46CD2C47EA2A00497EF0 /* ColorScheme */ = {
+			isa = PBXGroup;
+			children = (
+				672C46CE2C47EA6D00497EF0 /* GetColorSchemeUseCase.swift */,
+				672C46D02C47EA7400497EF0 /* ChangeColorSchemeUseCase.swift */,
+			);
+			path = ColorScheme;
+			sourceTree = "<group>";
+		};
 		98E49D3F46C8E62718825860 /* Pods */ = {
 			isa = PBXGroup;
 			children = (
@@ -1480,7 +1497,9 @@
 				539996A22C27130000671340 /* ConstraintDirectionalInsets.swift in Sources */,
 				53E7D3352C1B00880025A1D3 /* FSPagerView.swift in Sources */,
 				672C46B32C47E8D700497EF0 /* DependencyManager.swift in Sources */,
+				672C46D32C47EA8F00497EF0 /* SupportedColorScheme.swift in Sources */,
 				53014F912C11A8E80071CE39 /* ShutterButton.swift in Sources */,
+				672C46CF2C47EA6D00497EF0 /* GetColorSchemeUseCase.swift in Sources */,
 				53F21F8B2C1246AF00172BFC /* AllFolderTableViewCell.swift in Sources */,
 				53014FBD2C11A8E80071CE39 /* CaptureSession+Focus.swift in Sources */,
 				5399969C2C27130000671340 /* ConstraintItem.swift in Sources */,
@@ -1508,6 +1527,7 @@
 				53E7D3372C1B00880025A1D3 /* FSPagerViewCell.swift in Sources */,
 				53014F9B2C11A8E80071CE39 /* CGAffineTransform+Utils.swift in Sources */,
 				53014FBC2C11A8E80071CE39 /* CaptureSession.swift in Sources */,
+				672C46D12C47EA7400497EF0 /* ChangeColorSchemeUseCase.swift in Sources */,
 				539996852C27130000671340 /* ConstraintViewDSL.swift in Sources */,
 				EC702542254E1E7500BE1958 /* ClassicWalkthroughViewController.swift in Sources */,
 				539996882C27130000671340 /* ConstraintMakerFinalizable.swift in Sources */,
diff --git a/MiniScanner/Features/Common/DI/DependencyManager.swift b/MiniScanner/Features/Common/DI/DependencyManager.swift
index 9631b29..43a708a 100644
--- a/MiniScanner/Features/Common/DI/DependencyManager.swift
+++ b/MiniScanner/Features/Common/DI/DependencyManager.swift
@@ -29,5 +29,8 @@ final class DependencyManager {
         @Provide var getLanguagesUseCase = GetLanguagesUseCase(repository: repository)
         @Provide var getLanguageUseCase = GetLanguageUseCase(repository: repository)
         @Provide var changeLanguageUseCase = ChangeLanguageUseCase(repository: repository)
+        
+        @Provide var getColorSchemeUseCase = GetColorSchemeUseCase(repository: repository)
+        @Provide var changeColorSchemeUseCase = ChangeColorSchemeUseCase(repository: repository)
     }
 }
diff --git a/MiniScanner/Features/Common/Data/DataSources/SettingsDataSource.swift b/MiniScanner/Features/Common/Data/DataSources/SettingsDataSource.swift
index 0751c0b..469ed75 100644
--- a/MiniScanner/Features/Common/Data/DataSources/SettingsDataSource.swift
+++ b/MiniScanner/Features/Common/Data/DataSources/SettingsDataSource.swift
@@ -13,6 +13,9 @@ protocol SettingsDataSourceProtocol {
     func getLanguages() -> [SupportedLanguage]
     func getLanguage() -> SupportedLanguage
     func changeLanguage(to language: SupportedLanguage)
+    
+    func getColorScheme() -> SupportedColorScheme
+    func changeColorScheme(to colorScheme: SupportedColorScheme)
 }
 
 class SettingsDataSource: SettingsDataSourceProtocol {
@@ -30,6 +33,15 @@ class SettingsDataSource: SettingsDataSourceProtocol {
         }
     }
     
+    private var colorShceme: SupportedColorScheme {
+        get {
+            .from(codeName: userDefaultsManager.string(key: .appColorScheme) ?? SupportedColorScheme.device.codeName)
+        }
+        set {
+            userDefaultsManager.set(value: newValue.codeName, key: .appColorScheme)
+        }
+    }
+    
     init(userDefaultsManager: UserDefaultsManagerProtocol) {
         self.userDefaultsManager = userDefaultsManager
     }
@@ -48,4 +60,12 @@ class SettingsDataSource: SettingsDataSourceProtocol {
         languageManager.setLanguage(language: language.language)
         languageManager.defaultLanguage = language.language
     }
+    
+    func getColorScheme() -> SupportedColorScheme {
+        colorShceme
+    }
+    
+    func changeColorScheme(to colorScheme: SupportedColorScheme) {
+        self.colorShceme = colorScheme
+    }
 }
diff --git a/MiniScanner/Features/Common/Data/Model/SupportedColorScheme.swift b/MiniScanner/Features/Common/Data/Model/SupportedColorScheme.swift
new file mode 100644
index 0000000..25773e7
--- /dev/null
+++ b/MiniScanner/Features/Common/Data/Model/SupportedColorScheme.swift
@@ -0,0 +1,27 @@
+//
+//  SupportedColorScheme.swift
+//  MiniScanner
+//
+//  Created by Mustafa Merza on 7/17/24.
+//  Copyright © 2024 AppsNectar. All rights reserved.
+//
+
+import Foundation
+
+enum SupportedColorScheme: String, CaseIterable {
+    
+    case device
+    case light
+    case dark
+}
+
+extension SupportedColorScheme {
+    
+    static func from(codeName: String) -> SupportedColorScheme {
+        SupportedColorScheme(rawValue: codeName) ?? .device
+    }
+    
+    var codeName: String {
+        rawValue
+    }
+}
diff --git a/MiniScanner/Features/Common/Data/Repositories/SettingsRepository.swift b/MiniScanner/Features/Common/Data/Repositories/SettingsRepository.swift
index 35932a2..1b99dea 100644
--- a/MiniScanner/Features/Common/Data/Repositories/SettingsRepository.swift
+++ b/MiniScanner/Features/Common/Data/Repositories/SettingsRepository.swift
@@ -31,6 +31,20 @@ class SettingsRepository: SettingsRepositoryProtocol {
             dataSource.changeLanguage(to: language)
         }
     }
+    
+    func getColorScheme() -> SupportedColorScheme {
+        dataSource.getColorScheme()
+    }
+    
+    func changeColorScheme(to colorScheme: SupportedColorScheme) {
+        
+        if shouldChangeColorScheme(to: colorScheme) {
+            
+            dataSource.changeColorScheme(to: colorScheme)
+            
+            changeAppColorScheme(to: colorScheme)
+        }
+    }
 }
 
 extension SettingsRepository {
@@ -38,4 +52,28 @@ extension SettingsRepository {
     private func shouldChangeLanguage(to language: SupportedLanguage) -> Bool {
         dataSource.getLanguage() != language
     }
+    
+    private func shouldChangeColorScheme(to colorScheme: SupportedColorScheme) -> Bool {
+        dataSource.getColorScheme() != colorScheme
+    }
+    
+    private func changeAppColorScheme(to colorScheme: SupportedColorScheme) {
+        switch colorScheme {
+        case .device:
+            changeUserInterfaceStyle(to: .unspecified)
+        case .light:
+            changeUserInterfaceStyle(to: .light)
+        case .dark:
+            changeUserInterfaceStyle(to: .dark)
+        }
+    }
+    
+    private func changeUserInterfaceStyle(to userInterfaceStyle: UIUserInterfaceStyle) {
+        
+        let window = UIApplication.shared.connectedScenes
+            .flatMap { ($0 as? UIWindowScene)?.windows ?? [] }
+            .first { $0.isKeyWindow }
+        
+        window?.overrideUserInterfaceStyle = userInterfaceStyle
+    }
 }
diff --git a/MiniScanner/Features/Common/Domain/Repositories/SettingsRepositoryProtocol.swift b/MiniScanner/Features/Common/Domain/Repositories/SettingsRepositoryProtocol.swift
index 99d7566..453e045 100644
--- a/MiniScanner/Features/Common/Domain/Repositories/SettingsRepositoryProtocol.swift
+++ b/MiniScanner/Features/Common/Domain/Repositories/SettingsRepositoryProtocol.swift
@@ -13,4 +13,7 @@ protocol SettingsRepositoryProtocol {
     func getLanguages() -> [SupportedLanguage]
     func getLanguage() -> SupportedLanguage
     func changeLanguage(to language: SupportedLanguage)
+    
+    func getColorScheme() -> SupportedColorScheme
+    func changeColorScheme(to colorScheme: SupportedColorScheme)
 }
diff --git a/MiniScanner/Features/Common/Domain/UseCases/ColorScheme/ChangeColorSchemeUseCase.swift b/MiniScanner/Features/Common/Domain/UseCases/ColorScheme/ChangeColorSchemeUseCase.swift
new file mode 100644
index 0000000..ad31029
--- /dev/null
+++ b/MiniScanner/Features/Common/Domain/UseCases/ColorScheme/ChangeColorSchemeUseCase.swift
@@ -0,0 +1,22 @@
+//
+//  ChangeColorSchemeUseCase.swift
+//  MiniScanner
+//
+//  Created by Mustafa Merza on 7/17/24.
+//  Copyright © 2024 AppsNectar. All rights reserved.
+//
+
+import Foundation
+
+class ChangeColorSchemeUseCase {
+    
+    private let repository: SettingsRepositoryProtocol
+    
+    init(repository: SettingsRepositoryProtocol) {
+        self.repository = repository
+    }
+    
+    func execute(to colorScheme: SupportedColorScheme) {
+        repository.changeColorScheme(to: colorScheme)
+    }
+}
diff --git a/MiniScanner/Features/Common/Domain/UseCases/ColorScheme/GetColorSchemeUseCase.swift b/MiniScanner/Features/Common/Domain/UseCases/ColorScheme/GetColorSchemeUseCase.swift
new file mode 100644
index 0000000..468f1ba
--- /dev/null
+++ b/MiniScanner/Features/Common/Domain/UseCases/ColorScheme/GetColorSchemeUseCase.swift
@@ -0,0 +1,22 @@
+//
+//  GetColorSchemeUseCase.swift
+//  MiniScanner
+//
+//  Created by Mustafa Merza on 7/17/24.
+//  Copyright © 2024 AppsNectar. All rights reserved.
+//
+
+import Foundation
+
+class GetColorSchemeUseCase {
+    
+    private let repository: SettingsRepositoryProtocol
+    
+    init(repository: SettingsRepositoryProtocol) {
+        self.repository = repository
+    }
+    
+    func execute() -> SupportedColorScheme {
+        repository.getColorScheme()
+    }
+}
diff --git a/MiniScanner/Managers/UserDefaults/UserDefaultsKeys.swift b/MiniScanner/Managers/UserDefaults/UserDefaultsKeys.swift
index 55662fb..8e0bc31 100644
--- a/MiniScanner/Managers/UserDefaults/UserDefaultsKeys.swift
+++ b/MiniScanner/Managers/UserDefaults/UserDefaultsKeys.swift
@@ -11,4 +11,5 @@ import Foundation
 enum UserDefaultsKeys: String {
     
     case appLanguage = "app_language"
+    case appColorScheme = "app_color_scheme"
 }
-- 
GitLab