Skip to content

Commit 90db03f

Browse files
authored
[NL-41]: 마이페이지 viewModel 구현, 푸시 알림 설정 화면 구현 (#21)
* [NL-41]: 뷰모델 초안 * [NL-41]: editButtonTapped * [NL-41]: feedBackButtonTapped * [NL-41]: menuTapped * [NL-41]: Toggle Component 구현 * [NL-41]: 푸시알림 설정 화면 UI 구현 * [NL-41]: 푸시알림 설정 화면 ViewModel 바인딩 * [NL-41]: 코드 정리 * [NL-41]: DIInjector 를 통한 MyPageService 주입 * [NL-41]: 프리뷰에서 DIInjector 가 호출되지 않아 크래시가 발생하는 문제
1 parent c5c1e12 commit 90db03f

19 files changed

+687
-69
lines changed

App/Sources/AppDelegate.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import UIKit
22
import Onboarding
33
import Lib
4+
import Setting
45

56
import DIInjector
67

@@ -27,7 +28,8 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
2728

2829
private func dependencyInjection() {
2930
DependencyInjector.shared.assemble([
30-
CoreLayerAssembly()
31+
CoreLayerAssembly(),
32+
SettingAssembly()
3133
])
3234
}
3335

App/Sources/DIAseembly/CoreLayerAssembly.swift

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,6 @@ import Foundation
1010
import DIInjector
1111
import Lib
1212

13-
import Swinject
14-
1513
public class CoreLayerAssembly : Assembly {
1614
public func assemble(container: Container) {
1715
container.register(AppRouter.self) { _ in
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
//
2+
// Exports.swift
3+
// DIInjector
4+
//
5+
// Created by ttozzi on 8/1/25.
6+
//
7+
8+
@_exported import Swinject

Core/DIInjector/Test/Sources/DependencyInjectorTest.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
//
77

88
import DIInjector
9-
import Swinject
109
import Testing
1110

1211
struct DependencyInjectorTest {

Core/DIInjector/Test/Sources/MockData.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
// Created by 최재혁 on 7/21/25.
66
//
77

8-
import Swinject
8+
import DIInjector
99

1010
public class MockClass {
1111
func mockFunc() -> Bool {
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
//
2+
// Array+.swift
3+
// Extension
4+
//
5+
// Created by ttozzi on 8/1/25.
6+
//
7+
8+
import Foundation
9+
10+
extension Array {
11+
public subscript(safe index: Int) -> Element? {
12+
return (index >= .zero && index < count) ? self[index] : nil
13+
}
14+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
//
2+
// NSObject+.swift
3+
// Extension
4+
//
5+
// Created by ttozzi on 8/1/25.
6+
//
7+
8+
import Foundation
9+
10+
extension NSObject {
11+
public static var typeName: String { String(describing: self) }
12+
}

Core/Extension/Sources/UIView+Combine.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,3 +68,11 @@ extension UIButton {
6868
.eraseToAnyPublisher()
6969
}
7070
}
71+
72+
extension UISwitch {
73+
public var isOnPublisher: AnyPublisher<Bool, Never> {
74+
controlPublisher(for: .valueChanged)
75+
.map { [weak self] _ in self?.isOn ?? false }
76+
.eraseToAnyPublisher()
77+
}
78+
}
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
//
2+
// Toggle.swift
3+
// DesignSystem
4+
//
5+
// Created by ttozzi on 7/31/25.
6+
//
7+
8+
import UIKit
9+
10+
public final class Toggle: UISwitch {
11+
12+
override public var isEnabled: Bool {
13+
didSet {
14+
updateUI(isEnabled)
15+
}
16+
}
17+
18+
public override init(frame: CGRect) {
19+
super.init(frame: frame)
20+
setupUI()
21+
}
22+
23+
required init?(coder: NSCoder) {
24+
fatalError()
25+
}
26+
27+
private func setupUI() {
28+
onTintColor = STColors.primary1.color
29+
snp.makeConstraints { make in
30+
make.width.equalTo(51)
31+
}
32+
}
33+
34+
private func updateUI(_ isEnabled: Bool) {
35+
if isEnabled {
36+
onTintColor = STColors.primary1.color
37+
} else {
38+
onTintColor = STColors.primary9.color
39+
}
40+
}
41+
}
42+
43+
@available(iOS 17.0, *)
44+
#Preview {
45+
let stackView = UIStackView().then {
46+
$0.axis = .vertical
47+
$0.spacing = 20
48+
$0.alignment = .leading
49+
}
50+
let activeStackView = UIStackView().then {
51+
$0.axis = .horizontal
52+
$0.spacing = 20
53+
$0.alignment = .center
54+
}
55+
let activeDefaultLabel = UILabel().then {
56+
$0.text = "Default"
57+
$0.style = Typography.Body_14_M
58+
}
59+
let activeDefaultToggle = Toggle().then {
60+
$0.isOn = true
61+
$0.isEnabled = true
62+
}
63+
let activeDisabledLabel = UILabel().then {
64+
$0.text = "Disabled"
65+
$0.style = Typography.Body_14_M
66+
}
67+
let activeDisabledToggle = Toggle().then {
68+
$0.isOn = true
69+
$0.isEnabled = false
70+
}
71+
activeStackView.addArrangedSubview(activeDefaultLabel)
72+
activeStackView.addArrangedSubview(activeDefaultToggle)
73+
activeStackView.addArrangedSubview(activeDisabledLabel)
74+
activeStackView.addArrangedSubview(activeDisabledToggle)
75+
76+
let inactiveStackView = UIStackView().then {
77+
$0.axis = .horizontal
78+
$0.spacing = 20
79+
$0.alignment = .center
80+
}
81+
let inactiveDefaultLabel = UILabel().then {
82+
$0.text = "Default"
83+
$0.style = Typography.Body_14_M
84+
}
85+
let inactiveDefaultToggle = Toggle().then {
86+
$0.isOn = false
87+
$0.isEnabled = true
88+
}
89+
let inactiveDisabledLabel = UILabel().then {
90+
$0.text = "Disabled"
91+
$0.style = Typography.Body_14_M
92+
}
93+
let inactiveDisabledToggle = Toggle().then {
94+
$0.isOn = false
95+
$0.isEnabled = false
96+
}
97+
98+
inactiveStackView.addArrangedSubview(inactiveDefaultLabel)
99+
inactiveStackView.addArrangedSubview(inactiveDefaultToggle)
100+
inactiveStackView.addArrangedSubview(inactiveDisabledLabel)
101+
inactiveStackView.addArrangedSubview(inactiveDisabledToggle)
102+
103+
let activeTitleLabel = UILabel().then {
104+
$0.text = "Control/Toggle/Active"
105+
$0.style = Typography.Heading_20_B
106+
}
107+
let inactiveTitleLabel = UILabel().then {
108+
$0.text = "Control/Toggle/Inactive"
109+
$0.style = Typography.Heading_20_B
110+
}
111+
stackView.addArrangedSubview(activeTitleLabel)
112+
stackView.addArrangedSubview(activeStackView)
113+
stackView.addArrangedSubview(inactiveTitleLabel)
114+
stackView.addArrangedSubview(inactiveStackView)
115+
116+
return stackView
117+
}

Feature/Setting/Sources/MyPage/Cells/MyProfileInfoCollectionViewCell.swift

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
// Created by ttozzi on 7/26/25.
66
//
77

8+
import Combine
89
import DesignSystem
910
import SnapKit
1011
import Then
@@ -36,7 +37,7 @@ final class MyProfileInfoCollectionViewCell: UICollectionViewCell {
3637
private lazy var nicknameLabel = UILabel().then {
3738
$0.style = Typography.Heading_20_B
3839
}
39-
private lazy var editButton = UIButton().then {
40+
private(set) lazy var editButton = UIButton().then {
4041
let image = STImages.edit2.image.withRenderingMode(.alwaysTemplate)
4142
$0.setImage(image, for: .normal)
4243
$0.tintColor = STColors.gray5.color
@@ -55,6 +56,7 @@ final class MyProfileInfoCollectionViewCell: UICollectionViewCell {
5556
private lazy var birthTimeLabel = UILabel().then {
5657
$0.style = Typography.Caption_12_B
5758
}
59+
var cancellables = Set<AnyCancellable>()
5860

5961
override init(frame: CGRect) {
6062
super.init(frame: frame)
@@ -66,6 +68,11 @@ final class MyProfileInfoCollectionViewCell: UICollectionViewCell {
6668
fatalError("init(coder:) has not been implemented")
6769
}
6870

71+
override func prepareForReuse() {
72+
super.prepareForReuse()
73+
cancellables.removeAll()
74+
}
75+
6976
private func setupUI() {
7077
backgroundColor = .clear
7178
contentStackView.backgroundColor = .clear

0 commit comments

Comments
 (0)