From 05ad4cb6f95dcf84fdead8788529a4c99ca03499 Mon Sep 17 00:00:00 2001 From: kangddong Date: Mon, 12 Jan 2026 19:03:44 +0900 Subject: [PATCH 1/3] =?UTF-8?q?feat:=20=EB=A7=88=EC=9D=B4=ED=8E=98?= =?UTF-8?q?=EC=9D=B4=EC=A7=80=20=ED=99=9C=EB=8F=99=EB=82=B4=EC=97=AD=20?= =?UTF-8?q?=ED=94=BC=EC=B2=98=20=EA=B0=9C=EB=B0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../DesignSystem/AsyncThumbnailImage.swift | 48 +++ .../Contents.json | 0 .../community_comment.png | Bin Hambug/ContentView.swift | 3 +- .../community_comment.png | Bin 339 -> 658 bytes .../Contents.json | 21 ++ .../community_comment_fill.png | Bin 0 -> 550 bytes .../Request/CursorPagingQuery.swift | 24 ++ MyPage/Package.swift | 18 +- MyPage/Sources/DI/MyPageDIContainer.swift | 41 ++- MyPage/Sources/Data/DTO/MyActivitiesDTO.swift | 106 ++++++ MyPage/Sources/Data/MyPageEndpoint.swift | 14 +- .../Repositories/MyPageRepositoryImpl.swift | 45 ++- .../Domain/Entities/MyCommentActivity.swift | 66 ++++ .../Repositories/MyPageRepository.swift | 6 +- .../Domain/UseCases/GetMyBoardsUseCase.swift | 27 ++ .../UseCases/GetMyCommentsUseCase.swift | 26 ++ .../Domain/UseCases/MyPageUseCase.swift | 1 - .../Presentation/MyActivitiesView.swift | 328 +++++++++++++++++- .../Presentation/MyActivitiesViewModel.swift | 162 +++++++++ .../Presentation/MyPage/MyPageView.swift | 35 +- .../Presentation/MyPage/MyPageViewModel.swift | 113 ++---- 22 files changed, 968 insertions(+), 116 deletions(-) create mode 100644 Common/Sources/DesignSystem/AsyncThumbnailImage.swift rename Community/Sources/Presentation/Assets.xcassets/{community_comment.imageset => community_comment_fill.imageset}/Contents.json (100%) rename Community/Sources/Presentation/Assets.xcassets/{community_comment.imageset => community_comment_fill.imageset}/community_comment.png (100%) create mode 100644 Hambug/Resources/Assets.xcassets/community_comment_fill.imageset/Contents.json create mode 100644 Hambug/Resources/Assets.xcassets/community_comment_fill.imageset/community_comment_fill.png create mode 100644 Infrastructure/Sources/NetworkInterface/Request/CursorPagingQuery.swift create mode 100644 MyPage/Sources/Data/DTO/MyActivitiesDTO.swift create mode 100644 MyPage/Sources/Domain/Entities/MyCommentActivity.swift create mode 100644 MyPage/Sources/Domain/UseCases/GetMyBoardsUseCase.swift create mode 100644 MyPage/Sources/Domain/UseCases/GetMyCommentsUseCase.swift create mode 100644 MyPage/Sources/Presentation/MyActivitiesViewModel.swift diff --git a/Common/Sources/DesignSystem/AsyncThumbnailImage.swift b/Common/Sources/DesignSystem/AsyncThumbnailImage.swift new file mode 100644 index 0000000..7826fb0 --- /dev/null +++ b/Common/Sources/DesignSystem/AsyncThumbnailImage.swift @@ -0,0 +1,48 @@ +// +// AsyncThumbnailImage.swift +// Common +// +// Created by 강동영 on 1/12/26. +// + +import SwiftUI + +public struct AsyncThumbnailImage: View { + private let imageURL: String? + private let width: CGFloat? + private let height: CGFloat? + private let cornerRadius: CGFloat + + public init( + imageURL: String?, + width: CGFloat? = nil, + height: CGFloat? = nil, + cornerRadius: CGFloat = 8 + ) { + self.imageURL = imageURL + self.width = width + self.height = height + self.cornerRadius = cornerRadius + } + + public var body: some View { + content + .frame(width: width, height: height) + .clipShape(RoundedRectangle(cornerRadius: cornerRadius)) + } + + @ViewBuilder + private var content: some View { + if let imageURL = imageURL, + !imageURL.isEmpty, + let url = URL(string: imageURL) { + AsyncImage(url: url) { phase in + if case .success(let image) = phase { + image + .resizable() + .aspectRatio(contentMode: .fill) + } + } + } + } +} diff --git a/Community/Sources/Presentation/Assets.xcassets/community_comment.imageset/Contents.json b/Community/Sources/Presentation/Assets.xcassets/community_comment_fill.imageset/Contents.json similarity index 100% rename from Community/Sources/Presentation/Assets.xcassets/community_comment.imageset/Contents.json rename to Community/Sources/Presentation/Assets.xcassets/community_comment_fill.imageset/Contents.json diff --git a/Community/Sources/Presentation/Assets.xcassets/community_comment.imageset/community_comment.png b/Community/Sources/Presentation/Assets.xcassets/community_comment_fill.imageset/community_comment.png similarity index 100% rename from Community/Sources/Presentation/Assets.xcassets/community_comment.imageset/community_comment.png rename to Community/Sources/Presentation/Assets.xcassets/community_comment_fill.imageset/community_comment.png diff --git a/Hambug/ContentView.swift b/Hambug/ContentView.swift index 11c4b4f..cd56345 100644 --- a/Hambug/ContentView.swift +++ b/Hambug/ContentView.swift @@ -54,7 +54,8 @@ struct ContentView: View { NavigationStack { MyPageView( - viewModel: mypageDIContainer.makeMyPageViewModel() + viewModel: mypageDIContainer.makeMyPageViewModel(), + activitesFactory: mypageDIContainer ) } .tag(2) diff --git a/Hambug/Resources/Assets.xcassets/community_comment.imageset/community_comment.png b/Hambug/Resources/Assets.xcassets/community_comment.imageset/community_comment.png index ee596d5ad2a6d30f5c732bfa766b9547b3177af5..59bd984fe249b33fe57656df59761088ce1bb9f1 100644 GIT binary patch delta 640 zcmV-`0)PF}0+IzbiBL{Q4GJ0x0000DNk~Le0000O0000O2nGNE0N{5$_y7O^32;bR za{vGqB>(^xB>_oNB=C_oAAbTTNklP3slfcLgf(DVdOPhj65K0=l@Kx;COwDN;wQwj0_futbuy_tC&GL<0t z(P?weMwHdod=61vpquzxjVJdxxFB>dHFu2C`D*}3_)zl(s2&574j_ajmv@#iXah;qp` z)#-N#(Qgm7MdBlf))&R*A0*xydYWZ-8j;cIM2Pl??TEG@a_U9CU;*XWfCA8z*tk>@ zwPA`%0##t#jCmYVw0{B+qV*cMMb0Oc1ghebpUH%3BObd!s9i~*d2~)_+IUVi@ffi` zE2RX*BsBNCaCX|gDkXRg661>t_xZJHiHJGtb!M>hn+ddnuDEC+7@N*jyg=Gl&iZd4 zfLa#uEhTSUVsL5J7UB<}7})n!1PEVS#b1BWp4%Jq2m7w+xPLYQl&{!Mz5BE;ZPdTO zjUV`klV11M*{q?B?f3AeO7Swb`)J`f^-lSYj+*p3f-%+~CTfEV4QHw^OI0t)B3wOB zvJuAPX5Q$9SerL&nNCi;veJ*R5!~@#Ij;Lzd8B0#FufBBg5V;fxUTcoL=XW|s9pCK zmr`AlAOh|EsX=cC>NX`xPP?P?pVil8Ap*4vuEEo*lEN{lU1WcMTSWA+X!S4QTLlf& aZRtG`;|bu;O!Hv?0000DCaza*MV_(BctbNe9sS#2_D^3x5GJp{D(CXcH%L+KYy5Pv%t4PFJ!9W5Wz zI4(2OUZf_v_aWJDGT*rTVsH!66z1^ZRG+|nY@I?@K0@lmLb_i-hvjKn+qesj0@R&5 z(LjamxmD(8A6}Rt<K!7FRt)eEcjI(vV8n}NkM>L(`#M;}a9*bl#C QPyhe`07*qoM6N<$g6ETc4FCWD diff --git a/Hambug/Resources/Assets.xcassets/community_comment_fill.imageset/Contents.json b/Hambug/Resources/Assets.xcassets/community_comment_fill.imageset/Contents.json new file mode 100644 index 0000000..2825e92 --- /dev/null +++ b/Hambug/Resources/Assets.xcassets/community_comment_fill.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "community_comment_fill.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Hambug/Resources/Assets.xcassets/community_comment_fill.imageset/community_comment_fill.png b/Hambug/Resources/Assets.xcassets/community_comment_fill.imageset/community_comment_fill.png new file mode 100644 index 0000000000000000000000000000000000000000..df96e079e59ab55466ea9876735e3806b0ca6244 GIT binary patch literal 550 zcmV+>0@?kEP)FGIN5hBnyu}bJ;g$PUlD#-s3U_giiM0&Wq>GUBXaPg*T+xdy` zxD8yL=WDMu% zpq)8^+;Vx!MI|EJsaqfNIx_+(A@ZCUUP;|^+b3%DvucrVoU6oyl{qOtiPW_81c>)? zlhr;E?ftM#!AwcOq8C;VVM~75D?&N_H+iV2&aq|wsa}B!f(<>;1-E653?*`>_I?q3 zh}EM&P3xA+7gZ%*(M}^ihHQV~5$U(wKzE$_Axnhs#>LGEbRl0T3a`ET!<3LfF3p&$ zMDb;YqgaB3$R%+aqu1o4#>qh!iN=s MyPageViewModel { return container.resolve(MyPageViewModel.self) } - + public func resolve(_ type: T.Type) -> T { return container.resolve(type) } } + +extension MyPageDIContainer: ActivitesFactory { + public func makeMyActivitiesViewModel() -> MyActivitiesViewModel { + return container.resolve(MyActivitiesViewModel.self) + } +} diff --git a/MyPage/Sources/Data/DTO/MyActivitiesDTO.swift b/MyPage/Sources/Data/DTO/MyActivitiesDTO.swift new file mode 100644 index 0000000..8175244 --- /dev/null +++ b/MyPage/Sources/Data/DTO/MyActivitiesDTO.swift @@ -0,0 +1,106 @@ +// +// MyActivitiesDTO.swift +// MyPage +// +// Created by Claude on 1/12/26. +// + +import Foundation +import CommunityDomain +import MyPageDomain +import Util + +// MARK: - MyBoards Response DTOs +public struct MyBoardsResponseDTO: Decodable, Sendable { + public let content: [MyBoardItemDTO] + public let nextCursorId: Int? + public let nextPage: Bool +} + +public struct MyBoardItemDTO: Decodable, Sendable { + public let id: Int64 + public let title: String + public let content: String + public let authorNickname: String + public let viewCount: Int64 + public let commentCount: Int64 + public let likeCount: Int64 + public let category: String + public let imageUrls: [String] + public let createAt: String +} + +// MARK: - MyComments Response DTOs +public struct MyCommentsResponseDTO: Decodable, Sendable { + public let content: [MyCommentItemDTO] + public let nextCursorId: Int? + public let nextPage: Bool +} + +public struct MyCommentItemDTO: Decodable, Sendable { + public let boardId: Int64 + public let title: String + public let commentId: Int64 + public let content: String + public let createdAt: String +} + +// MARK: - MyBoardsResponseDTO to Domain Mapping +extension MyBoardsResponseDTO { + func toDomain() -> BoardListData { + return BoardListData( + content: content.map { $0.toDomain() }, + nextCursorId: nextCursorId, + hasNextPage: nextPage + ) + } +} + +extension MyBoardItemDTO { + func toDomain() -> Board { + let dateFormatter = DateFormatter.iso8601WithMicroseconds + let createdDate = dateFormatter.date(from: createAt) ?? Date() + + return Board( + id: Int(id), + title: title, + content: content, + category: BoardCategory(rawValue: category) ?? .freeTalk, + imageUrls: imageUrls, + authorNickname: authorNickname, // API 미제공 + authorId: nil, + createdAt: createdDate, + updatedAt: createdDate, + viewCount: Int(viewCount), + likeCount: Int(likeCount), + commentCount: Int(commentCount), + isLiked: false + ) + } +} + +// MARK: - MyCommentsResponseDTO to Domain Mapping +extension MyCommentsResponseDTO { + func toDomain() -> MyCommentActivityListData { + return MyCommentActivityListData( + content: content.map { $0.toDomain() }, + nextCursorId: nextCursorId, + hasNextPage: nextPage + ) + } +} + +extension MyCommentItemDTO { + func toDomain() -> MyCommentActivity { + let dateFormatter = DateFormatter.iso8601WithMicroseconds + let createdDate = dateFormatter.date(from: createdAt) ?? Date() + + return MyCommentActivity( + commentId: commentId, + boardId: boardId, + boardTitle: title, + content: content, + createdAt: createdDate + ) + } +} diff --git a/MyPage/Sources/Data/MyPageEndpoint.swift b/MyPage/Sources/Data/MyPageEndpoint.swift index cf1c16e..54dfe9b 100644 --- a/MyPage/Sources/Data/MyPageEndpoint.swift +++ b/MyPage/Sources/Data/MyPageEndpoint.swift @@ -17,6 +17,9 @@ enum MyPageEndpoint: Endpoint { case logout case deleteAccount(provider: String) + case getMyBoards(query: CursorPagingQuery) + case getMyComments(query: CursorPagingQuery) + var baseURL: String { NetworkConfig.baseURL } @@ -33,12 +36,17 @@ enum MyPageEndpoint: Endpoint { return "/api/v1/auth/logout" case let .deleteAccount(provider): return "/api/v1/auth/unlink/\(provider)" + + case .getMyBoards: + return "/api/v1/my-pages/boards" + case .getMyComments: + return "/api/v1/my-pages/comments" } } var method: HTTPMethod { switch self { - case .authMe: + case .authMe, .getMyBoards, .getMyComments: return .GET case .updateProfile, .updateNickname: return .PUT @@ -49,13 +57,13 @@ enum MyPageEndpoint: Endpoint { var headers: [String: String] { var headers: [String: String] = [:] - // TODO: Add Authorization header when auth is implemented - // headers["Authorization"] = "Bearer \(token)" return headers } var queryParameters: [String: Any] { switch self { + case let .getMyBoards(dto), let .getMyComments(dto): + return queryEncoder.encode(dto) default: return [:] } diff --git a/MyPage/Sources/Data/Repositories/MyPageRepositoryImpl.swift b/MyPage/Sources/Data/Repositories/MyPageRepositoryImpl.swift index 61398bf..935cf0a 100644 --- a/MyPage/Sources/Data/Repositories/MyPageRepositoryImpl.swift +++ b/MyPage/Sources/Data/Repositories/MyPageRepositoryImpl.swift @@ -6,11 +6,11 @@ // import Foundation -import Combine import UIKit import MyPageDomain import NetworkInterface import SharedDomain +import CommunityDomain // MARK: - MyPage Repository Implementation public final class MyPageRepositoryImpl: MyPageRepository { @@ -45,12 +45,10 @@ public final class MyPageRepositoryImpl: MyPageRepository { let endpoint = MyPageEndpoint.updateNickname(userID: userId, nickname: nickName) do { - return try await networkService.request( + _ = try await networkService.request( endpoint, responseType: SuccessResponse.self ) - .map { _ in () } - .catch { _ in Just(()) } .async() } catch { @@ -104,12 +102,10 @@ public final class MyPageRepositoryImpl: MyPageRepository { public func logout() async { let endpoint = MyPageEndpoint.logout do { - return try await networkService.request( + _ = try await networkService.request( endpoint, responseType: SuccessResponse.self ) - .map { _ in () } - .catch { _ in Just(()) } .async() } catch { @@ -120,18 +116,41 @@ public final class MyPageRepositoryImpl: MyPageRepository { public func deleteAccount(provider: String) async { let endpoint = MyPageEndpoint.deleteAccount(provider: provider) do { - return try await networkService.request( + _ = try await networkService.request( endpoint, responseType: SuccessResponse.self ) - .map { _ in () } - .catch { _ in Just(()) } .async() } catch { - + } - + } - + + // MARK: - Activities + public func fetchMyBoards(lastId: Int?, limit: Int, order: String) async throws -> BoardListData { + let query = CursorPagingQuery(lastId: lastId, limit: limit, order: order) + let endpoint = MyPageEndpoint.getMyBoards(query: query) + + let response = try await networkService.request( + endpoint, + responseType: SuccessResponse.self + ).async() + + return response.data.toDomain() + } + + public func fetchMyComments(lastId: Int?, limit: Int, order: String) async throws -> MyCommentActivityListData { + let query = CursorPagingQuery(lastId: lastId, limit: limit, order: order) + let endpoint = MyPageEndpoint.getMyComments(query: query) + + let response = try await networkService.request( + endpoint, + responseType: SuccessResponse.self + ).async() + + return response.data.toDomain() + } + private var currentUserId: Int? } diff --git a/MyPage/Sources/Domain/Entities/MyCommentActivity.swift b/MyPage/Sources/Domain/Entities/MyCommentActivity.swift new file mode 100644 index 0000000..b04da5e --- /dev/null +++ b/MyPage/Sources/Domain/Entities/MyCommentActivity.swift @@ -0,0 +1,66 @@ +// +// MyCommentActivity.swift +// MyPage +// +// Created by Claude on 1/12/26. +// + +import Foundation + +// MARK: - MyCommentActivity Entity +public struct MyCommentActivity: Identifiable, Equatable, Sendable { + public let id: Int64 // commentId + public let boardId: Int64 + public let boardTitle: String + public let content: String + public let createdAt: String + + public init( + commentId: Int64, + boardId: Int64, + boardTitle: String, + content: String, + createdAt: Date + ) { + self.id = commentId + self.boardId = boardId + self.boardTitle = boardTitle + self.content = content + self.createdAt = Self.timeAgoDisplay(createdAt) + } + + private static func timeAgoDisplay(_ date: Date) -> String { + let now = Date() + let timeInterval = now.timeIntervalSince(date) + + if timeInterval < 60 { + return "방금 전" + } else if timeInterval < 3600 { + let minutes = Int(timeInterval / 60) + return "\(minutes)분 전" + } else if timeInterval < 86400 { + let hours = Int(timeInterval / 3600) + return "\(hours)시간 전" + } else if timeInterval < 604800 { + let days = Int(timeInterval / 86400) + return "\(days)일 전" + } else { + let formatter = DateFormatter() + formatter.dateFormat = "MM.dd" + return formatter.string(from: date) + } + } +} + +// MARK: - MyCommentActivity List Data (Pagination) +public struct MyCommentActivityListData: Sendable { + public let content: [MyCommentActivity] + public let nextCursorId: Int? + public let hasNextPage: Bool + + public init(content: [MyCommentActivity], nextCursorId: Int?, hasNextPage: Bool) { + self.content = content + self.nextCursorId = nextCursorId + self.hasNextPage = hasNextPage + } +} diff --git a/MyPage/Sources/Domain/Repositories/MyPageRepository.swift b/MyPage/Sources/Domain/Repositories/MyPageRepository.swift index 953a9e5..d8949d3 100644 --- a/MyPage/Sources/Domain/Repositories/MyPageRepository.swift +++ b/MyPage/Sources/Domain/Repositories/MyPageRepository.swift @@ -6,9 +6,9 @@ // import Foundation -import Combine import UIKit import SharedDomain +import CommunityDomain // MARK: - MyPage Repository Interface public protocol MyPageRepository { @@ -21,4 +21,8 @@ public protocol MyPageRepository { func logout() async func deleteAccount(provider: String) async + + // Activities + func fetchMyBoards(lastId: Int?, limit: Int, order: String) async throws -> BoardListData + func fetchMyComments(lastId: Int?, limit: Int, order: String) async throws -> MyCommentActivityListData } diff --git a/MyPage/Sources/Domain/UseCases/GetMyBoardsUseCase.swift b/MyPage/Sources/Domain/UseCases/GetMyBoardsUseCase.swift new file mode 100644 index 0000000..6d97355 --- /dev/null +++ b/MyPage/Sources/Domain/UseCases/GetMyBoardsUseCase.swift @@ -0,0 +1,27 @@ +// +// GetMyBoardsUseCase.swift +// MyPage +// +// Created by Claude on 1/12/26. +// + +import Foundation +import CommunityDomain + +// MARK: - GetMyBoardsUseCase Protocol +public protocol GetMyBoardsUseCase: Sendable { + func execute(lastId: Int?, limit: Int, order: String) async throws -> BoardListData +} + +// MARK: - GetMyBoardsUseCase Implementation +public final class GetMyBoardsUseCaseImpl: GetMyBoardsUseCase { + private let repository: MyPageRepository + + public init(repository: MyPageRepository) { + self.repository = repository + } + + public func execute(lastId: Int?, limit: Int, order: String) async throws -> BoardListData { + return try await repository.fetchMyBoards(lastId: lastId, limit: limit, order: order) + } +} diff --git a/MyPage/Sources/Domain/UseCases/GetMyCommentsUseCase.swift b/MyPage/Sources/Domain/UseCases/GetMyCommentsUseCase.swift new file mode 100644 index 0000000..76a8d20 --- /dev/null +++ b/MyPage/Sources/Domain/UseCases/GetMyCommentsUseCase.swift @@ -0,0 +1,26 @@ +// +// GetMyCommentsUseCase.swift +// MyPage +// +// Created by Claude on 1/12/26. +// + +import Foundation + +// MARK: - GetMyCommentsUseCase Protocol +public protocol GetMyCommentsUseCase: Sendable { + func execute(lastId: Int?, limit: Int, order: String) async throws -> MyCommentActivityListData +} + +// MARK: - GetMyCommentsUseCase Implementation +public final class GetMyCommentsUseCaseImpl: GetMyCommentsUseCase { + private let repository: MyPageRepository + + public init(repository: MyPageRepository) { + self.repository = repository + } + + public func execute(lastId: Int?, limit: Int, order: String) async throws -> MyCommentActivityListData { + return try await repository.fetchMyComments(lastId: lastId, limit: limit, order: order) + } +} diff --git a/MyPage/Sources/Domain/UseCases/MyPageUseCase.swift b/MyPage/Sources/Domain/UseCases/MyPageUseCase.swift index 331a6be..a7c429d 100644 --- a/MyPage/Sources/Domain/UseCases/MyPageUseCase.swift +++ b/MyPage/Sources/Domain/UseCases/MyPageUseCase.swift @@ -6,7 +6,6 @@ // import Foundation -import Combine import UIKit import SharedDomain import Util diff --git a/MyPage/Sources/Presentation/MyActivitiesView.swift b/MyPage/Sources/Presentation/MyActivitiesView.swift index 5a1c3d9..ab24dca 100644 --- a/MyPage/Sources/Presentation/MyActivitiesView.swift +++ b/MyPage/Sources/Presentation/MyActivitiesView.swift @@ -6,9 +6,333 @@ // import SwiftUI +import DesignSystem +import CommunityDomain +import MyPageDomain +import SharedUI + +public struct MyActivitiesView: View { + @State private var viewModel: MyActivitiesViewModel + + public init(viewModel: MyActivitiesViewModel) { + self._viewModel = State(initialValue: viewModel) + } + + public var body: some View { + NavigationStack { + VStack(spacing: 0) { + navigationBar + tabBar + contentView + } + .background(Color.bgG75) + } + .navigationBarHidden(true) + .refreshable { + viewModel.refreshCurrentTab() + } + } + + private var navigationBar: some View { + HambugNavigationView() { + Text("활동내역") + .pretendard(.title(.t2)) + .foregroundStyle(Color.textG900) + .padding(.leading, 8) + } + } + + private var tabBar: some View { + HStack(spacing: 0) { + TabButton( + title: "게시글", + isSelected: viewModel.selectedTab == .posts, + action: { viewModel.selectedTab = .posts } + ) + + TabButton( + title: "댓글", + isSelected: viewModel.selectedTab == .comments, + action: { viewModel.selectedTab = .comments } + ) + } + .padding(.horizontal, 16) + } + + @ViewBuilder + private var contentView: some View { + if viewModel.selectedTab == .posts { + MyBoardsListView( + boards: viewModel.myBoards, + isLoadingMore: viewModel.isLoadingMoreBoards, + onLoadMore: { index in + if index >= viewModel.myBoards.count - 3 { + Task { await viewModel.loadMoreBoards() } + } + } + ) + .padding(.horizontal, 20) + .padding(.vertical, 12) + } else { + MyCommentsListView( + comments: viewModel.myComments, + isLoadingMore: viewModel.isLoadingMoreComments, + onLoadMore: { index in + if index >= viewModel.myComments.count - 3 { + Task { await viewModel.loadMoreComments() } + } + } + ) + .padding(.horizontal, 20) + .padding(.vertical, 12) + } + } +} + +// MARK: - MyActivitiesView's ActivityTab +extension MyActivitiesView { + enum ActivityTab { + case posts + case comments + } +} + +// MARK: - Tab Button +struct TabButton: View { + let title: String + let isSelected: Bool + let action: () -> Void -struct MyActivitiesView: View { var body: some View { - Text("MyActivities") + Button(action: action) { + VStack(spacing: 8) { + Text(title) + .pretendard(.body(.base)) + .foregroundColor(isSelected ? .primaryHambugRed : .textG600) + + Rectangle() + .frame(height: 2) + .foregroundColor(isSelected ? .primaryHambugRed : .borderG400) + } + } + .frame(maxWidth: .infinity) + .padding(.vertical, 12) + } +} + +// MARK: - 게시글 리스트 뷰 +struct MyBoardsListView: View { + let boards: [Board] + let isLoadingMore: Bool + let onLoadMore: (Int) -> Void + + var body: some View { + ScrollView { + LazyVStack(spacing: 0) { + ForEach(Array(boards.enumerated()), id: \.element.id) { index, board in + NavigationLink(destination: Text("Board Detail \(board.id)")) { + MyBoardListCard(board: board) + } + .buttonStyle(PlainButtonStyle()) + .onAppear { onLoadMore(index) } + } + + if isLoadingMore { + HStack { + Spacer() + ProgressView() + Spacer() + } + .padding(.vertical, 16) + } + } + } + .background( + RoundedRectangle(cornerRadius: 8) + .fill(Color.white) + .shadow(color: Color.black.opacity(0.1), radius: 4.5, x: 0, y: 0) + ) + } +} + +// MARK: - 게시글 카드 +fileprivate struct MyBoardListCard: View { + let board: Board + + var body: some View { + VStack(spacing: 0) { + HStack(alignment: .top, spacing: 12) { + VStack(alignment: .leading, spacing: 6) { + HStack { + Text(board.title) + .pretendard(.body(.base)) + .foregroundColor(Color.textG800) + .lineLimit(1) + .truncationMode(.tail) + .padding(.trailing, 8) + + Text(board.createdAt) + .pretendard(.caption(.base)) + .foregroundColor(Color.textG600) + + Spacer() + } + + HStack(spacing: 4) { + Text(board.authorNickname ?? "authorNickname nil") + .pretendard(.caption(.base)) + .foregroundColor(Color.textG800) + + HStack(spacing: 4) { + Image(systemName: "heart.fill") + .foregroundColor(Color.textR100) + .font(.system(size: 12)) + + Text("\(board.likeCount)") + .pretendard(.caption(.base)) + .foregroundColor(Color.textG600) + + Image("community_comment_fill", bundle: .main) + .resizable() + .frame(width: 12, height: 12) + + Text("\(board.commentCount)") + .pretendard(.caption(.base)) + .foregroundColor(Color.textG600) + } + } + } + + AsyncThumbnailImage( + imageURL: board.imageUrls.first ?? "", + width: 50, + height: 50, + cornerRadius: 8 + ) + + } + .padding(16) + .background(Color.white) + } + } +} + +// MARK: - 댓글 리스트 뷰 +struct MyCommentsListView: View { + let comments: [MyCommentActivity] + let isLoadingMore: Bool + let onLoadMore: (Int) -> Void + + var body: some View { + ScrollView { + LazyVStack(spacing: 0) { + ForEach(Array(comments.enumerated()), id: \.element.id) { index, comment in + NavigationLink(destination: Text("Board Detail \(comment.boardId)")) { + MyCommentActivityCard(comment: comment) + } + .buttonStyle(PlainButtonStyle()) + .onAppear { onLoadMore(index) } + } + + if isLoadingMore { + HStack { + Spacer() + ProgressView() + Spacer() + } + .padding(.vertical, 16) + } + } + } + .background( + RoundedRectangle(cornerRadius: 8) + .fill(Color.white) + .shadow(color: Color.black.opacity(0.1), radius: 4.5, x: 0, y: 0) + ) + } +} + +// MARK: - 댓글 카드 +fileprivate struct MyCommentActivityCard: View { + let comment: MyCommentActivity + + var body: some View { + VStack(alignment: .leading, spacing: 6) { + HStack { + Text(comment.boardTitle) + .pretendard(.body(.base)) + .foregroundColor(Color.textG800) + .lineLimit(1) + .truncationMode(.tail) + + Spacer() + + Text(comment.createdAt) + .pretendard(.caption(.base)) + .foregroundColor(Color.textG600) + } + + HStack(spacing: 4) { + Image("community_commnet", bundle: .main) + .foregroundColor(Color.textG600) + .font(.system(size: 12)) + + Text(comment.content) + .pretendard(.caption(.base)) + .foregroundColor(Color.textG600) + .lineLimit(2) + .truncationMode(.tail) + } + } + .padding(.horizontal, 16) + .padding(.vertical, 16) + .background(Color.white) + } +} + +// MARK: - Hambug Navigation View +struct HambugNavigationView: View { + @Environment(\.presentationMode) var presentationMode + @ViewBuilder var content: () -> Content + + var body: some View { + HStack { + Button(action: { + presentationMode.wrappedValue.dismiss() + }) { + Image(systemName: "chevron.left") + .foregroundColor(.textG900) + .frame(width: 24, height: 24) + } + .padding(.leading, 16) + + content() + + Spacer() + } + .padding(.vertical, 12) + } +} + +#Preview { + // Preview requires mocked dependencies + MyActivitiesView( + viewModel: MyActivitiesViewModel( + getMyBoardsUseCase: MockGetMyBoardsUseCase(), + getMyCommentsUseCase: MockGetMyCommentsUseCase() + ) + ) +} + +// MARK: - Mock UseCases for Preview +private final class MockGetMyBoardsUseCase: GetMyBoardsUseCase { + func execute(lastId: Int?, limit: Int, order: String) async throws -> BoardListData { + return BoardListData(content: [], nextCursorId: nil, hasNextPage: false) + } +} + +private final class MockGetMyCommentsUseCase: GetMyCommentsUseCase { + func execute(lastId: Int?, limit: Int, order: String) async throws -> MyCommentActivityListData { + return MyCommentActivityListData(content: [], nextCursorId: nil, hasNextPage: false) } } diff --git a/MyPage/Sources/Presentation/MyActivitiesViewModel.swift b/MyPage/Sources/Presentation/MyActivitiesViewModel.swift new file mode 100644 index 0000000..1e3e35f --- /dev/null +++ b/MyPage/Sources/Presentation/MyActivitiesViewModel.swift @@ -0,0 +1,162 @@ +// +// MyActivitiesViewModel.swift +// MyPage +// +// Created by 강동영 on 12/19/25. +// + +import Foundation +import CommunityDomain +import MyPageDomain + +@MainActor +@Observable +public final class MyActivitiesViewModel { + + // MARK: - Published Properties + public var myBoards: [Board] = [] + public var myComments: [MyCommentActivity] = [] + + public var isLoadingBoards: Bool = false + public var isLoadingMoreBoards: Bool = false + + public var isLoadingComments: Bool = false + public var isLoadingMoreComments: Bool = false + + public var errorMessage: String? = nil + public var selectedTab: ActivityTab = .posts + + // MARK: - Dependencies + private let getMyBoardsUseCase: GetMyBoardsUseCase + private let getMyCommentsUseCase: GetMyCommentsUseCase + + // MARK: - Private Properties + private var boardsCurrentPage: Int? = nil + private var boardsHasNextPage: Bool = true + private let pageSize: Int = 10 + + private var commentsCurrentPage: Int? = nil + private var commentsHasNextPage: Bool = true + + // MARK: - Initialization + public init( + getMyBoardsUseCase: GetMyBoardsUseCase, + getMyCommentsUseCase: GetMyCommentsUseCase + ) { + self.getMyBoardsUseCase = getMyBoardsUseCase + self.getMyCommentsUseCase = getMyCommentsUseCase + + Task { + await loadBoards() + await loadComments() + } + } + + // MARK: - Public Methods - Boards + public func loadBoards() async { + guard !isLoadingBoards else { return } + isLoadingBoards = true + errorMessage = nil + boardsCurrentPage = nil + boardsHasNextPage = true + + do { + let boardListData = try await getMyBoardsUseCase.execute( + lastId: boardsCurrentPage, + limit: pageSize, + order: "DESC" + ) + + myBoards = boardListData.content + boardsHasNextPage = boardListData.hasNextPage + boardsCurrentPage = boardListData.nextCursorId + } catch { + errorMessage = error.localizedDescription + } + + isLoadingBoards = false + } + + public func loadMoreBoards() async { + guard !isLoadingMoreBoards && boardsHasNextPage else { return } + isLoadingMoreBoards = true + + do { + let boardListData = try await getMyBoardsUseCase.execute( + lastId: boardsCurrentPage, + limit: pageSize, + order: "DESC" + ) + + myBoards.append(contentsOf: boardListData.content) + boardsHasNextPage = boardListData.hasNextPage + boardsCurrentPage = boardListData.nextCursorId + } catch { + print("❌ Load more boards error: \(error)") + } + + isLoadingMoreBoards = false + } + + // MARK: - Public Methods - Comments + public func loadComments() async { + guard !isLoadingComments else { return } + isLoadingComments = true + errorMessage = nil + commentsCurrentPage = nil + commentsHasNextPage = true + + do { + let commentListData = try await getMyCommentsUseCase.execute( + lastId: commentsCurrentPage, + limit: pageSize, + order: "DESC" + ) + + myComments = commentListData.content + commentsHasNextPage = commentListData.hasNextPage + commentsCurrentPage = commentListData.nextCursorId + } catch { + errorMessage = error.localizedDescription + } + + isLoadingComments = false + } + + public func loadMoreComments() async { + guard !isLoadingMoreComments && commentsHasNextPage else { return } + isLoadingMoreComments = true + + do { + let commentListData = try await getMyCommentsUseCase.execute( + lastId: commentsCurrentPage, + limit: pageSize, + order: "DESC" + ) + + myComments.append(contentsOf: commentListData.content) + commentsHasNextPage = commentListData.hasNextPage + commentsCurrentPage = commentListData.nextCursorId + } catch { + print("❌ Load more comments error: \(error)") + } + + isLoadingMoreComments = false + } + + public func refreshCurrentTab() { + Task { + if selectedTab == .posts { + await loadBoards() + } else { + await loadComments() + } + } + } + + // MARK: - ActivityTab Enum + public enum ActivityTab { + case posts + case comments + } +} diff --git a/MyPage/Sources/Presentation/MyPage/MyPageView.swift b/MyPage/Sources/Presentation/MyPage/MyPageView.swift index 0430ca5..f13b613 100644 --- a/MyPage/Sources/Presentation/MyPage/MyPageView.swift +++ b/MyPage/Sources/Presentation/MyPage/MyPageView.swift @@ -10,6 +10,10 @@ import PhotosUI import DesignSystem import Util +public protocol ActivitesFactory { + func makeMyActivitiesViewModel() -> MyActivitiesViewModel +} + public struct MyPageView: View { @Bindable var viewModel: MyPageViewModel @State private var showMyActivitiesView: Bool = false @@ -23,8 +27,14 @@ public struct MyPageView: View { @State private var selectedImageData: Data? @State private var showPhotoPicker: Bool = false - public init(viewModel: MyPageViewModel) { + private let activitesFactory: ActivitesFactory + + public init( + viewModel: MyPageViewModel, + activitesFactory: ActivitesFactory + ) { self._viewModel = Bindable(viewModel) + self.activitesFactory = activitesFactory } public var body: some View { @@ -41,7 +51,7 @@ public struct MyPageView: View { Spacer() } .navigationDestination(isPresented: $showMyActivitiesView, destination: { - MyActivitiesView() + MyActivitiesView(viewModel: activitesFactory.makeMyActivitiesViewModel()) }) } .confirmationDialog("프로필 편집", isPresented: $showInfoActionSheet, actions: { @@ -49,8 +59,10 @@ public struct MyPageView: View { showPhotoPicker = true } Button(Strings.ActionSheetTitle.defaultImage) { - viewModel.applyDefaultImage() - popupState = .none + Task { + await viewModel.applyDefaultImage() + popupState = .none + } } Button(Strings.ActionSheetTitle.changeNickname) { popupState = .changeNickname @@ -80,8 +92,9 @@ public struct MyPageView: View { if let processedData = ImageProcessor.process(image) { // 처리 성공 - 압축된 이미지로 업로드 selectedImageData = processedData - viewModel.changeProfileImage(processedData) + await viewModel.changeProfileImage(processedData) popupState = .none + } else { // 처리 실패 - 알림 표시 viewModel.showImageSizeAlert = true @@ -89,7 +102,7 @@ public struct MyPageView: View { } else { // 크기가 괜찮으면 원본 데이터로 업로드 selectedImageData = imageData - viewModel.changeProfileImage(imageData) + await viewModel.changeProfileImage(imageData) popupState = .none } } @@ -127,7 +140,9 @@ public struct MyPageView: View { } .navigationBarHidden(true) .onAppear { - viewModel.fetchProfile() + Task { + await viewModel.fetchProfile() + } } .onChange(of: viewModel.shouldNavigateToLogin) { _, shouldNavigate in if shouldNavigate { @@ -257,7 +272,7 @@ public struct MyPageView: View { }, primaryButton: AlertButton(.save) { print("저장") - viewModel.updateNickname() + Task { await viewModel.updateNickname() } } ) } @@ -284,7 +299,7 @@ public struct MyPageView: View { }, primaryButton: AlertButton(.ok) { print("확인") - viewModel.logout() + Task { await viewModel.logout() } } ) } @@ -318,7 +333,7 @@ public struct MyPageView: View { }, primaryButton: .init(.accountDelete) { print("탈퇴") - viewModel.deleteAccount() + Task { await viewModel.deleteAccount() } } ) } diff --git a/MyPage/Sources/Presentation/MyPage/MyPageViewModel.swift b/MyPage/Sources/Presentation/MyPage/MyPageViewModel.swift index 9518e25..e6d8b2d 100644 --- a/MyPage/Sources/Presentation/MyPage/MyPageViewModel.swift +++ b/MyPage/Sources/Presentation/MyPage/MyPageViewModel.swift @@ -5,7 +5,6 @@ // Created by 강동영 on 10/28/25. // -import Combine import Foundation import Observation import UIKit @@ -15,7 +14,6 @@ import SharedDomain @Observable public final class MyPageViewModel { private let usecase: MyPageUseCase - private var cancellables: Set = [] var currentNickName: String = "" var profileNickName: String = "" @@ -32,19 +30,19 @@ public final class MyPageViewModel { self.usecase = usecase } - func fetchProfile() { + func fetchProfile() async { isLoading = true - usecase.fetchProfile() - .receive(on: DispatchQueue.main) - .sink { [weak self] user in - self?.isLoading = false - self?.user = user - self?.profileNickName = user.nickname - } - .store(in: &cancellables) + do { + let response = try await usecase.fetchProfile() + isLoading = false + user = user + profileNickName = response.nickname + } catch { + + } } - func updateNickname() { + func updateNickname() async { let trimmed = currentNickName.trimmingCharacters(in: .whitespacesAndNewlines) guard !trimmed.isEmpty else { isCorrectedNickName = false @@ -53,16 +51,13 @@ public final class MyPageViewModel { isCorrectedNickName = true isLoading = true - usecase.updateNickname(trimmed) - .receive(on: DispatchQueue.main) - .sink { [weak self] in - self?.isLoading = false - self?.profileNickName = trimmed - } - .store(in: &cancellables) + + await usecase.updateNickname(trimmed) + isLoading = false + profileNickName = trimmed } - func changeProfileImage(_ imageData: Data) { + func changeProfileImage(_ imageData: Data) async { guard let image = UIImage(data: imageData) else { errorMessage = "이미지를 불러올 수 없습니다." showError = true @@ -70,71 +65,39 @@ public final class MyPageViewModel { } isLoading = true - usecase.changeProfileImage(image) - .receive(on: DispatchQueue.main) - .sink( - receiveCompletion: { [weak self] completion in - self?.isLoading = false - - switch completion { - case .failure: - self?.errorMessage = "이미지 변경에 실패했습니다. 다시 시도해 주세요." - self?.showError = true - case .finished: -// self?.fetchProfile() - break - } - }, - receiveValue: { [weak self] in - self?.user?.profileImageURL = $0 - } - ) - .store(in: &cancellables) + + do { + let profileURL = try await usecase.changeProfileImage(image) + user?.profileImageURL = profileURL + } catch { + errorMessage = "이미지 변경에 실패했습니다. 다시 시도해 주세요." + showError = true + } + + isLoading = false } - func applyDefaultImage() { + func applyDefaultImage() async { isLoading = true - usecase.applyDefaultImage() - .receive(on: DispatchQueue.main) - .sink( - receiveCompletion: { [weak self] completion in - self?.isLoading = false - - switch completion { - case .failure: - self?.errorMessage = "이미지 변경에 실패했습니다. 다시 시도해 주세요." - self?.showError = true - case .finished: -// self?.fetchProfile() - self?.user?.profileImageURL = "" - } - }, - receiveValue: {} - ) - .store(in: &cancellables) + await usecase.applyDefaultImage() + isLoading = false + user?.profileImageURL = "" } - func logout() { + func logout() async { isLoading = true - usecase.logout() - .receive(on: DispatchQueue.main) - .sink { [weak self] in - self?.isLoading = false - self?.shouldNavigateToLogin = true - } - .store(in: &cancellables) + await usecase.logout() + + isLoading = false + shouldNavigateToLogin = true } - func deleteAccount() { + func deleteAccount() async { guard let provider = user?.loginType.lowercased(), !provider.isEmpty else { return } isLoading = true - usecase.deleteAccount(provider: provider) - .receive(on: DispatchQueue.main) - .sink { [weak self] in - self?.isLoading = false - self?.shouldNavigateToLogin = true - } - .store(in: &cancellables) + await usecase.deleteAccount(provider: provider) + isLoading = false + shouldNavigateToLogin = true } } From 510b85afc7e36b266338dc3027840e30223284d6 Mon Sep 17 00:00:00 2001 From: kangddong Date: Mon, 12 Jan 2026 19:49:23 +0900 Subject: [PATCH 2/3] =?UTF-8?q?chore:=20Domain=20=EB=9D=BC=EC=9D=B4?= =?UTF-8?q?=EB=B8=8C=EB=9F=AC=EB=A6=AC=20=EC=B6=94=EA=B0=80=20=EB=B0=8F=20?= =?UTF-8?q?=EC=9D=B4=EB=AF=B8=EC=A7=80=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Community/Package.swift | 4 ++ .../Community/CommunityView.swift | 44 ++----------------- .../Presentation/Detail/CommunityDetail.swift | 2 +- 3 files changed, 8 insertions(+), 42 deletions(-) diff --git a/Community/Package.swift b/Community/Package.swift index d2afff7..9b1c01c 100644 --- a/Community/Package.swift +++ b/Community/Package.swift @@ -28,6 +28,10 @@ let package = Package( name: Config.name, targets: Config.allCases.map(\.name) ), + .library( + name: "CommunityDomain", + targets: ["CommunityDomain"] + ), ], dependencies: [ .package(name: "DI", path: "../DI"), diff --git a/Community/Sources/Presentation/Community/CommunityView.swift b/Community/Sources/Presentation/Community/CommunityView.swift index fcddd8e..8410842 100644 --- a/Community/Sources/Presentation/Community/CommunityView.swift +++ b/Community/Sources/Presentation/Community/CommunityView.swift @@ -353,7 +353,7 @@ fileprivate struct CommunityPostListCard: View { .pretendard(.caption(.base)) .foregroundColor(Color.textG600) - Image(.communityComment) + Image(.communityCommentFill) .resizable() .frame(width: 12, height: 12) @@ -419,7 +419,7 @@ fileprivate struct CommunityPostFeedCard: View { .pretendard(.caption(.base)) .foregroundColor(Color.textG600) - Image(.communityComment) + Image(.communityCommentFill) .resizable() .frame(width: 12, height: 12) @@ -443,42 +443,4 @@ fileprivate struct CommunityPostFeedCard: View { } } -struct AsyncThumbnailImage: View { - private let imageURL: String? - private let width: CGFloat? - private let height: CGFloat? - private let cornerRadius: CGFloat - - init( - imageURL: String?, - width: CGFloat? = nil, - height: CGFloat? = nil, - cornerRadius: CGFloat = 8 - ) { - self.imageURL = imageURL - self.width = width - self.height = height - self.cornerRadius = cornerRadius - } - - var body: some View { - content - .frame(width: width, height: height) - .clipShape(RoundedRectangle(cornerRadius: cornerRadius)) - } - - @ViewBuilder - private var content: some View { - if let imageURL = imageURL, - !imageURL.isEmpty, - let url = URL(string: imageURL) { - AsyncImage(url: url) { phase in - if case .success(let image) = phase { - image - .resizable() - .aspectRatio(contentMode: .fill) - } - } - } - } -} + diff --git a/Community/Sources/Presentation/Detail/CommunityDetail.swift b/Community/Sources/Presentation/Detail/CommunityDetail.swift index 42ce982..6a756a0 100644 --- a/Community/Sources/Presentation/Detail/CommunityDetail.swift +++ b/Community/Sources/Presentation/Detail/CommunityDetail.swift @@ -312,7 +312,7 @@ public struct CommunityDetailView: View { } HStack(spacing: 4) { - Image(.communityComment) + Image(.communityCommentFill) .resizable() .frame(width: 20, height: 20) From 9db71c6d121f0f67e0558b8ceed977d7d04fd88d Mon Sep 17 00:00:00 2001 From: kangddong Date: Mon, 12 Jan 2026 22:58:27 +0900 Subject: [PATCH 3/3] =?UTF-8?q?chore:=201.0.0=20=EC=B6=9C=EC=8B=9C=20?= =?UTF-8?q?=EC=A4=80=EB=B9=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Sources/DI/CommunityDIContainer.swift | 11 --- Hambug.xcodeproj/project.pbxproj | 4 + .../AppIcon.appiconset/Contents.json | 73 +----------------- .../app_icon-1024x1024 2.png | Bin 0 -> 55315 bytes .../Data/DTO/TrendingPostResponse.swift | 3 +- .../Domain/Entities/TrendingPost.swift | 39 +++++----- Home/Sources/Presentation/HomeViewModel.swift | 11 +-- Home/Sources/Presentation/PostView.swift | 6 +- .../Sources/NetworkImpl/NetworkLogger.swift | 8 +- .../NetworkImpl/NetworkServiceImpl.swift | 6 +- MyPage/Package.swift | 1 + 11 files changed, 42 insertions(+), 120 deletions(-) create mode 100644 Hambug/Resources/Assets.xcassets/AppIcon.appiconset/app_icon-1024x1024 2.png diff --git a/Community/Sources/DI/CommunityDIContainer.swift b/Community/Sources/DI/CommunityDIContainer.swift index 5bb4adc..1d5a7f1 100644 --- a/Community/Sources/DI/CommunityDIContainer.swift +++ b/Community/Sources/DI/CommunityDIContainer.swift @@ -34,17 +34,6 @@ struct CommunityWriteAssembly: Assembly { struct CommunityAssembly: Assembly { func assemble(container: GenericDIContainer) { - // NetworkService registration (only for mock mode) - // In normal mode, NetworkService comes from parent container -// if isMock { -// container.register(NetworkServiceInterface.self) { _ in -// let config = URLSessionConfiguration.ephemeral -// config.protocolClasses = [CommunityURLProtocol.self] -// setupURLProtocol() -// return NetworkServiceImpl(configuration: config) -// } -// } - // APIClient registration container.register(CommunityAPIClientInterface.self) { resolver in // if self.isMock { diff --git a/Hambug.xcodeproj/project.pbxproj b/Hambug.xcodeproj/project.pbxproj index e9e8ccd..0e25409 100644 --- a/Hambug.xcodeproj/project.pbxproj +++ b/Hambug.xcodeproj/project.pbxproj @@ -502,6 +502,8 @@ ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = Hambug/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = "햄버그"; + INFOPLIST_KEY_ITSAppUsesNonExemptEncryption = NO; "INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphoneos*]" = YES; "INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphonesimulator*]" = YES; "INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents[sdk=iphoneos*]" = YES; @@ -543,6 +545,8 @@ ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = Hambug/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = "햄버그"; + INFOPLIST_KEY_ITSAppUsesNonExemptEncryption = NO; "INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphoneos*]" = YES; "INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphonesimulator*]" = YES; "INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents[sdk=iphoneos*]" = YES; diff --git a/Hambug/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json b/Hambug/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json index ffdfe15..b257683 100644 --- a/Hambug/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json +++ b/Hambug/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -1,81 +1,10 @@ { "images" : [ { + "filename" : "app_icon-1024x1024 2.png", "idiom" : "universal", "platform" : "ios", "size" : "1024x1024" - }, - { - "appearances" : [ - { - "appearance" : "luminosity", - "value" : "dark" - } - ], - "idiom" : "universal", - "platform" : "ios", - "size" : "1024x1024" - }, - { - "appearances" : [ - { - "appearance" : "luminosity", - "value" : "tinted" - } - ], - "idiom" : "universal", - "platform" : "ios", - "size" : "1024x1024" - }, - { - "idiom" : "mac", - "scale" : "1x", - "size" : "16x16" - }, - { - "idiom" : "mac", - "scale" : "2x", - "size" : "16x16" - }, - { - "idiom" : "mac", - "scale" : "1x", - "size" : "32x32" - }, - { - "idiom" : "mac", - "scale" : "2x", - "size" : "32x32" - }, - { - "idiom" : "mac", - "scale" : "1x", - "size" : "128x128" - }, - { - "idiom" : "mac", - "scale" : "2x", - "size" : "128x128" - }, - { - "idiom" : "mac", - "scale" : "1x", - "size" : "256x256" - }, - { - "idiom" : "mac", - "scale" : "2x", - "size" : "256x256" - }, - { - "idiom" : "mac", - "scale" : "1x", - "size" : "512x512" - }, - { - "idiom" : "mac", - "scale" : "2x", - "size" : "512x512" } ], "info" : { diff --git a/Hambug/Resources/Assets.xcassets/AppIcon.appiconset/app_icon-1024x1024 2.png b/Hambug/Resources/Assets.xcassets/AppIcon.appiconset/app_icon-1024x1024 2.png new file mode 100644 index 0000000000000000000000000000000000000000..b919df040c68168411a4d6820a395015492405ef GIT binary patch literal 55315 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