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

Fix [#80] 소식 탭 오류 수정 및 배지 구현, 알림 탭 프로필 이동 구현 #91

Merged
merged 8 commits into from
Jan 18, 2025
248 changes: 184 additions & 64 deletions Wable-iOS.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions Wable-iOS/Global/Literals/StringLiterals.swift
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,7 @@ enum StringLiterals {
static let getTeamRank = "v1/information/rank"
static let getNews = "v1/information/news"
static let getNotice = "v1/information/notice"
static let getInfoCount = "v1/information/number"
}

enum Notification {
Expand Down
34 changes: 34 additions & 0 deletions Wable-iOS/Global/Shared/UserDefaults/CodableSerializable.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
//
// CodableSerializable.swift
// Wable-iOS
//
// Created by 김진웅 on 1/7/25.
//

import Foundation

protocol Serializable {
func serialize(_ value: Encodable) throws -> Data
}

protocol Deserializable {
func deserialize<T: Decodable>(_ type: T.Type, from data: Data) throws -> T
}

typealias CodableSerializable = Serializable & Deserializable


// MARK: - JSONSerializer

struct JSONSerializer: CodableSerializable {
private let encoder = JSONEncoder()
private let decoder = JSONDecoder()

func serialize(_ value: any Encodable) throws -> Data {
try encoder.encode(value)
}

func deserialize<T: Decodable>(_ type: T.Type, from data: Data) throws -> T {
try decoder.decode(type, from: data)
}
Comment on lines +27 to +33
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

제가 이해한 바로는 UserDefault에 구조체를 저장할 수 있게끔 만들어주신 것 같은데 맞을 까요?! 너무 고생 많으셨습니다!!👍🏻👍🏻

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

네 맞습니다.

}
28 changes: 28 additions & 0 deletions Wable-iOS/Global/Shared/UserDefaults/UserDefaultsKey.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
//
// UserDefaultsKey.swift
// Wable-iOS
//
// Created by 김진웅 on 1/7/25.
//

import Foundation

/// UserDefaults에 접근하기 위한 Key의 타입을 정의하는 프로토콜
///
/// 아래와 같이, 열거형으로 구현한다.
///
/// ```swift
/// enum UserDefaultsKeys: UserDefaultsKey {
/// case userInfo
///
/// var value: String {
/// switch self{
/// case .userInfo:
/// return "userInfo"
/// }
/// }
/// }
/// ```
protocol UserDefaultsKey: Hashable, CaseIterable {
var value: String { get }
}
71 changes: 71 additions & 0 deletions Wable-iOS/Global/Shared/UserDefaults/UserDefaultsManager.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
//
// UserDefaultsManager.swift
// Wable-iOS
//
// Created by 김진웅 on 1/7/25.
//

import Foundation

protocol UserDefaultsManager {
func save<T: Codable>(_ value: T, forKey key: any UserDefaultsKey)
func load<T: Codable>(forKey key: any UserDefaultsKey, as type: T.Type) -> T?
func remove(forKey keys: any UserDefaultsKey...)
func removeAll()
}

final class UserDefaultsManagerImpl: UserDefaultsManager {
private let serializer: CodableSerializable
private let userDefaults = UserDefaults.standard

init(serializer: CodableSerializable = JSONSerializer()) {
self.serializer = serializer
}

func save<T: Codable>(_ value: T, forKey key: any UserDefaultsKey) {
if isPrimitiveType(T.self) {
userDefaults.set(value, forKey: key.value)
return
}

do {
let data = try serializer.serialize(value)
userDefaults.set(data, forKey: key.value)
} catch {
print("Failed to encode data for key \(key.value): \(error)")
}
}

func load<T: Codable>(forKey key: any UserDefaultsKey, as type: T.Type) -> T? {
if isPrimitiveType(T.self) {
return userDefaults.object(forKey: key.value) as? T
}

guard let data = userDefaults.data(forKey: key.value) else {
return nil
}

do {
return try serializer.deserialize(type, from: data)
} catch {
print("Failed to decode data for key \(key.value): \(error)")
return nil
}
}

/// 특정 키 삭제
func remove(forKey keys: any UserDefaultsKey...) {
keys.forEach { self.userDefaults.removeObject(forKey: $0.value) }
}

/// 모든 데이터 삭제
func removeAll() {
userDefaults.dictionaryRepresentation().forEach { (key, _) in
userDefaults.removeObject(forKey: key)
}
}

private func isPrimitiveType<T>(_ type: T.Type) -> Bool {
return type is Int.Type || type is Double.Type || type is Float.Type || type is Bool.Type || type is String.Type
}
}
9 changes: 9 additions & 0 deletions Wable-iOS/Network/Info/InfoAPI.swift
Original file line number Diff line number Diff line change
Expand Up @@ -64,4 +64,13 @@ extension InfoAPI {
.mapError { $0 as? WableNetworkError ?? .unknownError($0.localizedDescription) }
.eraseToAnyPublisher()
}

func getInfoCount() -> AnyPublisher<InfoCountDTO?, WableNetworkError> {
infoProvider.requestPublisher(.getInfoCount)
.tryMap { [weak self] response -> InfoCountDTO? in
return try self?.parseResponse(statusCode: response.statusCode, data: response.data)
}
.mapError { $0 as? WableNetworkError ?? .unknownError($0.localizedDescription) }
.eraseToAnyPublisher()
}
}
7 changes: 5 additions & 2 deletions Wable-iOS/Network/Info/InfoRouter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ enum InfoRouter {
case getTeamRank
case getNews(param: Int)
case getNotice(param: Int)
case getInfoCount
}

extension InfoRouter: BaseTargetType {
Expand All @@ -30,19 +31,21 @@ extension InfoRouter: BaseTargetType {
return StringLiterals.Endpoint.Info.getNews
case .getNotice:
return StringLiterals.Endpoint.Info.getNotice
case .getInfoCount:
return StringLiterals.Endpoint.Info.getInfoCount
}
}

var method: Moya.Method {
switch self {
case .getMatchInfo, .getGameType, .getTeamRank, .getNews, .getNotice:
case .getMatchInfo, .getGameType, .getTeamRank, .getNews, .getNotice, .getInfoCount:
return .get
}
}

var task: Moya.Task {
switch self {
case .getMatchInfo, .getGameType, .getTeamRank:
case .getMatchInfo, .getGameType, .getTeamRank, .getInfoCount:
return .requestPlain
case .getNews(let cursor), .getNotice(let cursor):
return .requestParameters(parameters: ["cursor": cursor], encoding: URLEncoding.queryString)
Expand Down
18 changes: 18 additions & 0 deletions Wable-iOS/Network/Info/ResponseDTO/InfoCountDTO.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
//
// InfoCountDTO.swift
// Wable-iOS
//
// Created by 김진웅 on 1/7/25.
//

import Foundation

struct InfoCountDTO: Codable {
let newsCount: Int
let noticeCount: Int

enum CodingKeys: String, CodingKey {
case newsCount = "newsNumber"
case noticeCount = "noticeNumber"
}
}
5 changes: 5 additions & 0 deletions Wable-iOS/Presentation/Info/Notice/View/Cell/NoticeCell.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ final class NoticeCell: UICollectionViewCell {
let label = UILabel()
label.font = .caption4
label.textColor = .gray500
label.textAlignment = .right
return label
}()

Expand Down Expand Up @@ -71,12 +72,16 @@ private extension NoticeCell {
titleLabel.snp.makeConstraints { make in
make.top.equalToSuperview().offset(12)
make.leading.equalToSuperview().offset(20)
make.trailing.equalTo(timeLabel.snp.leading).offset(-4)
}

titleLabel.setContentHuggingPriority(.defaultLow, for: .vertical)

timeLabel.snp.makeConstraints { make in
make.centerY.equalTo(titleLabel)
make.leading.greaterThanOrEqualTo(titleLabel.snp.trailing).offset(10)
make.trailing.equalToSuperview().offset(-20)
make.width.equalTo(52.adjusted)
}

bodyLabel.snp.makeConstraints { make in
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//
// InfoView.swift
// InfoPageView.swift
// Wable-iOS
//
// Created by 변상우 on 8/18/24.
Expand All @@ -10,7 +10,7 @@ import UIKit
import SnapKit
import Lottie

final class InfoView: UIView {
final class InfoPageView: UIView {

// MARK: - UI Component

Expand Down Expand Up @@ -64,7 +64,7 @@ final class InfoView: UIView {

// MARK: - Private Method

private extension InfoView {
private extension InfoPageView {
func setupView() {
backgroundColor = .wableWhite

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//
// InfoLogoView.swift
// InfoPageLogoView.swift
// Wable-iOS
//
// Created by 박윤빈 on 8/20/24.
Expand All @@ -9,7 +9,7 @@ import UIKit

import SnapKit

final class InfoLogoView: UIView {
final class InfoPageLogoView: UIView {
private let imageView: UIImageView = {
let imageView = UIImageView()
imageView.image = ImageLiterals.Icon.icInfoPurple
Expand Down Expand Up @@ -40,7 +40,7 @@ final class InfoLogoView: UIView {

// MARK: - Private Method

private extension InfoLogoView {
private extension InfoPageLogoView {
func setupView() {
backgroundColor = .wableBlack

Expand Down
Loading