Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
5e2ea82
feat: 피드 모듈 생성 #450
edv-Shin Jan 29, 2026
7c9746d
feat: 비즈니스 모델 추가 #450
edv-Shin Jan 29, 2026
7ec30c5
feat: api 연결 준비 #450
edv-Shin Jan 29, 2026
cbde246
feat: 피드 ui 구현 #450
edv-Shin Jan 30, 2026
b1c002d
feat: 이미지 비율 수정 #450
edv-Shin Jan 30, 2026
dd74936
feat: 게시판 선택 ui 구현 #452
edv-Shin Feb 1, 2026
2d22b72
feat: 게시판 선택 시 필터링 적용 #452
edv-Shin Feb 1, 2026
acb46c2
feat: empty 텍스트 추가 #452
edv-Shin Feb 1, 2026
1540544
feat: 피드 생성 구현 #453
edv-Shin Feb 2, 2026
7ffd00e
feat: 스켈레톤 로딩 추가, api response 수정 #453
edv-Shin Feb 2, 2026
c75c87b
feat: 피드 삭제 #454
edv-Shin Feb 3, 2026
2d99a2d
feat: 피드 상세화면 개발 #454
edv-Shin Feb 3, 2026
0a45543
feat: 생성 후 갱신, empty인 경우도 refresh 추가 #462
edv-Shin Feb 4, 2026
b3aa873
feat: 댓글 구현 #463
edv-Shin Feb 9, 2026
85d0e99
feat: 피드/댓글 좋아요 구현 #463
edv-Shin Feb 10, 2026
75d39d2
feat: 피드 수정 구현 #474
edv-Shin Feb 10, 2026
752220c
feat: 이미지 추가 #475
edv-Shin Feb 11, 2026
200b863
feat: 댓글 태그 구현 #465
edv-Shin Feb 17, 2026
0a2f544
feat: 피드/댓글 좋아요 api 연결 #479
edv-Shin Feb 19, 2026
e8bab33
feat: 좋아요 중복 요청 방지 #479
edv-Shin Feb 19, 2026
67f93ec
feat: 이미지 삭제 api 연결 #480
edv-Shin Feb 19, 2026
fcabe57
feat: 댓글 태그 추가
edv-Shin Mar 19, 2026
4f22975
Merge pull request #481 from projects200/feat/like-479
edv-Shin Mar 19, 2026
02ddf4e
fix: ktlint 문법 수정
edv-Shin Mar 19, 2026
e408e5b
Merge remote-tracking branch 'origin/feat/comment-tag-465' into feat/…
edv-Shin Mar 19, 2026
9c57bee
chore: 로그 삭제
edv-Shin Mar 19, 2026
fe1c51e
Merge branch 'dev' into feat/feed
edv-Shin Mar 19, 2026
072e0a3
fix: 함수명 변경
edv-Shin Mar 19, 2026
2b1c493
fix: baseToolbar constraint 오류 수정
edv-Shin Mar 19, 2026
19d95cb
fix: ktlint 문법 수정
edv-Shin Mar 19, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ dependencies {
implementation(projects.feature.exercise)
implementation(projects.feature.timer)
implementation(projects.feature.matching)
implementation(projects.feature.feed)
implementation(projects.feature.chatting)

implementation(libs.androidx.appcompat)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,8 @@ class MainActivity : AppCompatActivity(), BottomNavigationController {
com.project200.undabang.feature.exercise.R.id.exerciseShareEditFragment,
com.project200.undabang.feature.matching.R.id.matchingGuideFragment,
com.project200.undabang.feature.chatting.R.id.chattingRoomFragment,
com.project200.undabang.feature.feed.R.id.feedFormFragment,
com.project200.undabang.feature.feed.R.id.feedDetailFragment,
// ... 필요한 다른 프래그먼트 ID들 추가 ... //
)

Expand Down
9 changes: 9 additions & 0 deletions app/src/main/res/drawable/ic_nav_feed.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="28dp"
android:height="28dp"
android:viewportWidth="28"
android:viewportHeight="28">
<path
android:pathData="M3.5,7.875C3.5,6.715 3.961,5.602 4.781,4.781C5.602,3.961 6.715,3.5 7.875,3.5H20.125C21.285,3.5 22.398,3.961 23.219,4.781C24.039,5.602 24.5,6.715 24.5,7.875V20.125C24.5,21.285 24.039,22.398 23.219,23.219C22.398,24.039 21.285,24.5 20.125,24.5H7.875C6.715,24.5 5.602,24.039 4.781,23.219C3.961,22.398 3.5,21.285 3.5,20.125V7.875ZM7.875,5.25C7.179,5.25 6.511,5.527 6.019,6.019C5.527,6.511 5.25,7.179 5.25,7.875V12.25H15.75V5.25H7.875ZM5.25,14V20.125C5.25,20.821 5.527,21.489 6.019,21.981C6.511,22.473 7.179,22.75 7.875,22.75H15.75V14H5.25ZM17.5,15.75H22.75V12.25H17.5V15.75ZM22.75,17.5H17.5V22.75H20.125C20.821,22.75 21.489,22.473 21.981,21.981C22.473,21.489 22.75,20.821 22.75,20.125V17.5ZM22.75,7.875C22.75,7.179 22.473,6.511 21.981,6.019C21.489,5.527 20.821,5.25 20.125,5.25H17.5V10.5H22.75V7.875Z"
android:fillColor="#9E9E9E"/>
</vector>
12 changes: 8 additions & 4 deletions app/src/main/res/menu/bottom_nav_menu.xml
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,18 @@
android:id="@id/matching_nav_graph"
android:icon="@drawable/ic_nav_matching"
android:title="@string/matching" />
<item
android:id="@id/feed_nav_graph"
android:icon="@drawable/ic_nav_feed"
android:title="@string/feed" />
<item
android:id="@id/chatting_nav_graph"
android:icon="@drawable/ic_chatting"
android:title="@string/chatting"/>
<item
android:id="@id/timer_nav_graph"
android:icon="@drawable/ic_nav_timer"
android:title="@string/timer" />
<!-- <item-->
<!-- android:id="@id/timer_nav_graph"-->
<!-- android:icon="@drawable/ic_nav_timer"-->
<!-- android:title="@string/timer" />-->
<item
android:id="@id/profile_nav_graph"
android:icon="@drawable/ic_nav_mypage"
Expand Down
1 change: 1 addition & 0 deletions app/src/main/res/navigation/bottom_nav_graph.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

<include app:graph="@navigation/exercise_nav_graph" />
<include app:graph="@navigation/matching_nav_graph"/>
<include app:graph="@navigation/feed_nav_graph"/>
<include app:graph="@navigation/chatting_nav_graph"/>
<include app:graph="@navigation/timer_nav_graph" />
<include app:graph="@navigation/profile_nav_graph" />
Expand Down
1 change: 1 addition & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

<string name="exercise_record">기록</string>
<string name="matching">매칭</string>
<string name="feed">피드</string>
<string name="chatting">채팅</string>
<string name="timer">타이머</string>
<string name="profile">MY</string>
Expand Down
100 changes: 100 additions & 0 deletions data/src/main/java/com/project200/data/api/ApiService.kt
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
package com.project200.data.api

import com.project200.data.dto.BaseResponse
import com.project200.data.dto.CommentDTO
import com.project200.data.dto.CreateCommentRequestDTO
import com.project200.data.dto.CreateCommentResponseDTO
import com.project200.data.dto.CreateFeedRequestDTO
import com.project200.data.dto.CustomTimerIdDTO
import com.project200.data.dto.DeletePreferredExerciseDTO
import com.project200.data.dto.EditExercisePlaceDTO
import com.project200.data.dto.ExerciseIdDto
import com.project200.data.dto.ExpectedScoreInfoDTO
import com.project200.data.dto.FeedCreateResultDTO
import com.project200.data.dto.FeedDTO
import com.project200.data.dto.FeedPictureUploadDTO
import com.project200.data.dto.GetBlockedMemberDTO
import com.project200.data.dto.GetChattingMessagesDTO
import com.project200.data.dto.GetChattingRoomsDTO
Expand All @@ -15,6 +22,7 @@ import com.project200.data.dto.GetExerciseCountByRangeDTO
import com.project200.data.dto.GetExercisePlaceDTO
import com.project200.data.dto.GetExerciseRecordData
import com.project200.data.dto.GetExerciseRecordListDto
import com.project200.data.dto.GetFeedsDTO
import com.project200.data.dto.GetIsNicknameDuplicated
import com.project200.data.dto.GetIsRegisteredData
import com.project200.data.dto.GetMatchingMembersDto
Expand All @@ -27,6 +35,7 @@ import com.project200.data.dto.GetProfileDTO
import com.project200.data.dto.GetProfileImageResponseDto
import com.project200.data.dto.GetScoreDTO
import com.project200.data.dto.GetSimpleTimersDTO
import com.project200.data.dto.LikeRequestDTO
import com.project200.data.dto.NotificationStateDTO
import com.project200.data.dto.PatchCustomTimerTitleRequest
import com.project200.data.dto.PatchExerciseRequestDto
Expand All @@ -46,6 +55,7 @@ import com.project200.data.dto.PostSignUpRequest
import com.project200.data.dto.PutProfileRequest
import com.project200.data.dto.SimpleTimerIdDTO
import com.project200.data.dto.SimpleTimerRequest
import com.project200.data.dto.UpdateFeedRequestDTO
import com.project200.data.utils.AccessTokenApi
import com.project200.data.utils.AccessTokenWithFcmApi
import com.project200.data.utils.IdTokenApi
Expand Down Expand Up @@ -474,4 +484,94 @@ interface ApiService {
@Header("X-Fcm-Token") fcmToken: String,
@Body notiRequest: List<NotificationStateDTO>,
): BaseResponse<Unit?>

/** 피드 */
@GET("api/v1/feeds")
@AccessTokenApi
suspend fun getFeeds(
@Query("prevFeedId") prevFeedId: Long?,
@Query("size") size: Int?,
): BaseResponse<GetFeedsDTO?>

@GET("api/v1/feeds/{feedId}")
@AccessTokenApi
suspend fun getFeedDetail(
@Path("feedId") feedId: Long,
): BaseResponse<FeedDTO>

@POST("api/v1/feeds")
@AccessTokenApi
suspend fun postFeed(
@Body createFeedRequest: CreateFeedRequestDTO,
): BaseResponse<FeedCreateResultDTO>

@DELETE("api/v1/feeds/{feedId}")
@AccessTokenApi
suspend fun deleteFeed(
@Path("feedId") feedId: Long,
): BaseResponse<Unit?>

@PATCH("api/v1/feeds/{feedId}")
@AccessTokenApi
suspend fun updateFeed(
@Path("feedId") feedId: Long,
@Body updateFeedRequest: UpdateFeedRequestDTO,
): BaseResponse<Unit?>

// 피드 좋아요
@POST("api/v1/feeds/{feedId}/like")
@AccessTokenApi
suspend fun likeFeed(
@Path("feedId") feedId: Long,
@Body request: LikeRequestDTO,
): BaseResponse<Unit?>

/** 댓글 */
// 댓글 목록 조회
@GET("api/v1/feeds/{feedId}/comments")
@AccessTokenApi
suspend fun getComments(
@Path("feedId") feedId: Long,
): BaseResponse<List<CommentDTO>>

// 댓글 작성
@POST("api/v1/feeds/{feedId}/comments")
@AccessTokenApi
suspend fun createComment(
@Path("feedId") feedId: Long,
@Body request: CreateCommentRequestDTO,
): BaseResponse<CreateCommentResponseDTO>

// 댓글 좋아요
@POST("api/v1/comments/{commentId}/like")
@AccessTokenApi
suspend fun likeComment(
@Path("commentId") commentId: Long,
@Body request: LikeRequestDTO,
): BaseResponse<Unit?>

// 댓글 삭제
@DELETE("api/v1/comments/{commentId}")
@AccessTokenApi
suspend fun deleteComment(
@Path("commentId") commentId: Long,
): BaseResponse<Unit?>

/** 피드 이미지 */
// 피드 이미지 업로드
@Multipart
@POST("api/v1/feeds/{feedId}/pictures")
@AccessTokenApi
suspend fun postFeedImages(
@Path("feedId") feedId: Long,
@Part pictures: List<MultipartBody.Part>,
): BaseResponse<List<FeedPictureUploadDTO>>

// 피드 이미지 삭제
@DELETE("api/v1/feeds/{feedId}/pictures/{pictureId}")
@AccessTokenApi
suspend fun deleteFeedImage(
@Path("feedId") feedId: Long,
@Path("pictureId") pictureId: Long,
): BaseResponse<Unit?>
}
6 changes: 6 additions & 0 deletions data/src/main/java/com/project200/data/di/RepositoryModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import com.project200.data.impl.ChatSocketRepositoryImpl
import com.project200.data.impl.ChattingRepositoryImpl
import com.project200.data.impl.ExerciseRecordRepositoryImpl
import com.project200.data.impl.FcmRepositoryImpl
import com.project200.data.impl.FeedRepositoryImpl
import com.project200.data.impl.MatchingRepositoryImpl
import com.project200.data.impl.MemberRepositoryImpl
import com.project200.data.impl.NotificationRepositoryImpl
Expand All @@ -20,6 +21,7 @@ import com.project200.domain.repository.ChatSocketRepository
import com.project200.domain.repository.ChattingRepository
import com.project200.domain.repository.ExerciseRecordRepository
import com.project200.domain.repository.FcmRepository
import com.project200.domain.repository.FeedRepository
import com.project200.domain.repository.MatchingRepository
import com.project200.domain.repository.MemberRepository
import com.project200.domain.repository.NotificationRepository
Expand Down Expand Up @@ -86,4 +88,8 @@ abstract class RepositoryModule {
@Binds
@Singleton
abstract fun bindNotificationRepository(notificationRepositoryImpl: NotificationRepositoryImpl): NotificationRepository

@Binds
@Singleton
abstract fun bindFeedRepository(feedRepositoryImpl: FeedRepositoryImpl): FeedRepository
}
56 changes: 56 additions & 0 deletions data/src/main/java/com/project200/data/dto/CommentDTO.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package com.project200.data.dto

import com.squareup.moshi.JsonClass
import java.time.LocalDateTime

@JsonClass(generateAdapter = true)
data class GetCommentsDTO(
val comments: List<CommentDTO>,
)

@JsonClass(generateAdapter = true)
data class CommentDTO(
val commentId: Long,
val memberId: String,
val memberNickname: String,
val memberProfileImageUrl: String?,
val memberThumbnailUrl: String?,
val content: String,
val likesCount: Int,
val taggedMember: TaggedMemberDTO,
val commentIsLiked: Boolean = false,
val createdAt: LocalDateTime,
val children: List<ReplyDTO>,
)

@JsonClass(generateAdapter = true)
data class TaggedMemberDTO(
val memberId: String?,
val memberNickname: String?,
)

@JsonClass(generateAdapter = true)
data class ReplyDTO(
val commentId: Long,
val memberId: String,
val memberNickname: String,
val memberProfileImageUrl: String?,
val memberThumbnailUrl: String?,
val content: String,
val likesCount: Int,
val commentIsLiked: Boolean = false,
val createdAt: LocalDateTime,
val taggedMember: TaggedMemberDTO? = null,
)

@JsonClass(generateAdapter = true)
data class CreateCommentRequestDTO(
val content: String,
val parentCommentId: Long?,
val taggedMemberId: String? = null,
)

@JsonClass(generateAdapter = true)
data class CreateCommentResponseDTO(
val commentId: Long,
)
63 changes: 63 additions & 0 deletions data/src/main/java/com/project200/data/dto/FeedDTO.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package com.project200.data.dto

import com.squareup.moshi.JsonClass
import java.time.LocalDateTime

@JsonClass(generateAdapter = true)
data class GetFeedsDTO(
val hasNext: Boolean,
val feeds: List<FeedDTO>,
)

@JsonClass(generateAdapter = true)
data class FeedDTO(
val feedId: Long,
val feedContent: String,
val feedLikesCount: Int,
val feedCommentsCount: Int,
val feedTypeId: Long?,
val feedTypeName: String?,
val feedTypeDesc: String?,
val feedCreatedAt: LocalDateTime,
val feedIsLiked: Boolean,
val feedHasCommented: Boolean,
val memberId: String,
val nickname: String,
val profileUrl: String?,
val thumbnailUrl: String?,
val feedPictures: List<FeedPictureDTO>,
)

@JsonClass(generateAdapter = true)
data class FeedPictureDTO(
val feedPictureId: Long,
val feedPictureUrl: String,
)

@JsonClass(generateAdapter = true)
data class CreateFeedRequestDTO(
val feedContent: String,
val feedTypeId: Long?,
)

@JsonClass(generateAdapter = true)
data class FeedCreateResultDTO(
val feedId: Long,
)

@JsonClass(generateAdapter = true)
data class UpdateFeedRequestDTO(
val feedContent: String,
val feedTypeId: Long?,
)

@JsonClass(generateAdapter = true)
data class FeedPictureUploadDTO(
val pictureId: Long,
val pictureUrl: String,
)

@JsonClass(generateAdapter = true)
data class LikeRequestDTO(
val liked: Boolean,
)
Loading
Loading