Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
131 commits
Select commit Hold shift + click to select a range
0001563
Merge pull request #85 from Nexters/release/0.2.0
DongChyeon Apr 12, 2026
b21e748
refactor/#86: UploadScreen을 Route-Screen νŒ¨ν„΄μœΌλ‘œ 뢄리 및 Preview μΆ”κ°€
DongChyeon Apr 12, 2026
fdcf1be
feat/#86: UploadScreen에 제λͺ© μž…λ ₯ ν•„λ“œ μΆ”κ°€
DongChyeon Apr 12, 2026
98c03f9
feat/#86: 링크 μž…λ ₯ ν•„λ“œ 및 μœ νš¨μ„± 검사 μΆ”κ°€
DongChyeon Apr 12, 2026
59b978c
fix/#86: 링크 μœ νš¨μ„± κ²€μ‚¬μ—μ„œ ν•œκΈ€ 및 곡백 차단 쑰건 μˆ˜μ •
DongChyeon Apr 12, 2026
f7301f0
chore/#86: ic_link μ•„μ΄μ½˜ μΆ”κ°€
DongChyeon Apr 12, 2026
3e574f5
feat/#86: 사진 닀쀑 선택 및 νˆ¬ν‘œ κ²Œμ‹œ μ‹œ ν‚€λ³΄λ“œ dismiss 처리
DongChyeon Apr 12, 2026
7ea9bfa
feat/#86: FeedCard에 제λͺ© ν‘œμ‹œ μ˜μ—­ μΆ”κ°€
DongChyeon Apr 12, 2026
be5ce9a
feat/#86: FeedCard 이미지 닀쀑 선택 및 carousel peek μŠ€μ™€μ΄ν”„ κ΅¬ν˜„
DongChyeon Apr 12, 2026
551c807
refactor/#86: FeedCard μ»΄ν¬λ„ŒνŠΈ 뢄리도 κ°œμ„ 
DongChyeon Apr 12, 2026
81e28ac
feat/#86: FeedCard title 및 닀쀑 이미지 지원을 μœ„ν•œ 데이터 λͺ¨λΈ μ—…λ°μ΄νŠΈ
DongChyeon Apr 12, 2026
cca18ce
feat/#86: 이미지 νƒ­ 전체화면 및 μƒν’ˆ 링크 λ²„νŠΌ μΆ”κ°€
DongChyeon Apr 12, 2026
b42dc76
feat/#86: FeedCard 툴팁 μ»΄ν¬λ„ŒνŠΈ 및 상단 ν™”μ‚΄ν‘œ 버블 λͺ¨μ–‘ μΆ”κ°€
DongChyeon Apr 12, 2026
9643a64
feat/#86: FeedCard LinkButton 툴팁 연동 λ ˆμ΄μ•„μ›ƒ κ°œμ„ 
DongChyeon Apr 12, 2026
44e32f4
feat/#86: 링크 μžˆλŠ” μ΅œμƒλ‹¨ FeedCard에 툴팁 λ…ΈμΆœ κΈ°λŠ₯ μΆ”κ°€
DongChyeon Apr 12, 2026
00973e8
feat/#86: LinkButton ν„°μΉ˜ μ˜μ—­ μœ μ§€ν•˜λ©° 툴팁 μ‹œκ°μ  λ²„νŠΌ κΈ°μ€€ 배치
DongChyeon Apr 12, 2026
de2d203
docs/#86: FilterChipRow μΉ΄ν…Œκ³ λ¦¬ ν•„ν„° + νˆ¬ν‘œ μƒνƒœ μ •λ ¬ 섀계 λ¬Έμ„œ μΆ”κ°€
DongChyeon Apr 13, 2026
d25c65e
docs/#86: FilterChipRow μΉ΄ν…Œκ³ λ¦¬ ν•„ν„° + νˆ¬ν‘œ μƒνƒœ μ •λ ¬ κ΅¬ν˜„ ν”Œλžœ μΆ”κ°€
DongChyeon Apr 13, 2026
d991ef8
feat/#86: BuyOrNotIcons에 Sort μ•„μ΄μ½˜ μΆ”κ°€
DongChyeon Apr 13, 2026
c92c1eb
feat/#86: Sort μ•„μ΄μ½˜ μ•‘μ…˜ μ•„μ΄μ½˜ 그룹으둜 μ •λ ¬
DongChyeon Apr 13, 2026
a024af0
feat/#86: HomeContract에 μΉ΄ν…Œκ³ λ¦¬ ν•„ν„° State/Intent μΆ”κ°€
DongChyeon Apr 13, 2026
e773970
feat/#86: handleCategoryToggled 단일 updateState λžŒλ‹€λ‘œ κ°œμ„ 
DongChyeon Apr 13, 2026
4c7c5d6
feat/#86: HomeViewModel μΉ΄ν…Œκ³ λ¦¬ 둜컬 필터링 둜직 μΆ”κ°€
DongChyeon Apr 13, 2026
442983a
feat/#86: μ‚­μ œ/차단 μ‹œ allFeeds도 λ™κΈ°ν™”ν•˜μ—¬ μΉ΄ν…Œκ³ λ¦¬ ν•„ν„° μ •ν•©μ„± 보μž₯
DongChyeon Apr 13, 2026
1df01ad
feat/#86: FilterChipRow μΉ΄ν…Œκ³ λ¦¬ μΉ© + νˆ¬ν‘œ μƒνƒœ OptionSheet κ΅¬ν˜„
DongChyeon Apr 13, 2026
e3163ae
feat/#86: FilterChipRow ν„°μΉ˜ μ˜μ—­ 및 recomposition μ΅œμ ν™”
DongChyeon Apr 13, 2026
8c027e0
feat/#86: νˆ¬ν‘œ μ—…λ°μ΄νŠΈ/λ‘€λ°± μ‹œ allFeeds λ™κΈ°ν™”ν•˜μ—¬ μΉ΄ν…Œκ³ λ¦¬ ν•„ν„° μ •ν•©μ„± 보μž₯
DongChyeon Apr 13, 2026
4dd292e
feat/#86: HomeTopBar/Tab κ³ μ • 헀더화 및 OptionSheet dim 처리λ₯Ό ViewModel State…
DongChyeon Apr 14, 2026
13641e4
feat/#86: OptionSheet 슀크둀 κ°€λŠ₯ν•  λ•Œλ§Œ ν•˜λ‹¨ μ—¬λ°±κ³Ό κ·ΈλΌλ””μ–ΈνŠΈ ν‘œμ‹œ
DongChyeon Apr 14, 2026
52762f8
feat/#86: Feed API v2 λ§ˆμ΄κ·Έλ ˆμ΄μ…˜ 및 닀쀑 이미지/동적 aspect ratio 지원
DongChyeon Apr 14, 2026
508da4a
feat/#86: FilterChipRow 전체 μΉ© μΆ”κ°€ 및 μΉ΄ν…Œκ³ λ¦¬ API 필터링 적용
DongChyeon Apr 15, 2026
15778b8
feat/#86: FilterChipRow μΉ© 선택 μ‹œ 선택 μ•„μ΄ν…œ 쀑앙 슀크둀 적용
DongChyeon Apr 15, 2026
513bb2e
feat/#86: FeedCard 빈 제λͺ©μΌ λ•Œ 제λͺ© 및 ν•˜λ‹¨ μ—¬λ°± λ―Έλ…ΈμΆœ 처리
DongChyeon Apr 15, 2026
3f60899
feat/#86: 이미지 선택 μ‹œ 쀑볡 URI 필터링 처리
DongChyeon Apr 15, 2026
a655e49
feat/#86: 이미지 피컀λ₯Ό PickMultipleVisualMedia둜 ꡐ체 및 쀑볡/초과 선택 μ‹œ μŠ€λ‚΅λ°” μ•ˆλ‚΄
DongChyeon Apr 15, 2026
e645d08
feat/#86: FeedCard 툴팁 아무 μ˜μ—­ νƒ­ μ‹œ dismiss 처리
DongChyeon Apr 15, 2026
7e7d4cc
feat/#86: λ‚΄ ν”Όλ“œ 빈 ν™”λ©΄ UI κ΅¬ν˜„ 및 empty μƒνƒœμ—μ„œ FAB μˆ¨κΉ€ 처리
DongChyeon Apr 15, 2026
370af91
chore/#86: ktlint ν¬λ§·νŒ…
github-actions[bot] Apr 15, 2026
54a0909
feat/#86: λ‚΄ ν”Όλ“œ 빈 ν™”λ©΄ 이미지 크기 μ‘°μ • (240x180dp)
DongChyeon Apr 15, 2026
dc1b548
chore/#86: ktlint ν¬λ§·νŒ…
github-actions[bot] Apr 15, 2026
5cae650
fix/#86: FeedCard 이미지 νŽ˜μ΄μ§€λ³„ aspect ratio 독립 적용
DongChyeon Apr 17, 2026
f6c7b7f
fix/#86: FeedCard 빈 μƒν’ˆ 링크 λ¬Έμžμ—΄ 필터링 처리
DongChyeon Apr 17, 2026
f2bfbe1
fix/#86: TopArrowBubbleShape ν™”μ‚΄ν‘œ 쀑심 μ’Œν‘œ 경계 λ‚΄ clamp 처리
DongChyeon Apr 17, 2026
e4cc79b
fix/#86: 이미지 선택 배치 λ‚΄ 쀑볡 URI 필터링 처리
DongChyeon Apr 17, 2026
3596750
fix/#86: ν”Όλ“œ 제좜 μ‹œ title/link μŠ€λƒ…μƒ· κ³ μ •μœΌλ‘œ race condition λ°©μ§€
DongChyeon Apr 17, 2026
fb14dac
chore/#86: ktlint ν¬λ§·νŒ…
github-actions[bot] Apr 17, 2026
adc9315
fix/#86: 툴팁 클릭 μ‹œμ—λ§Œ λ‹«νžˆλ„λ‘ dismiss λ™μž‘ λ³€κ²½
DongChyeon Apr 18, 2026
dcac4e8
fix/#86: ν”Όλ“œ 제좜 μ‹œ title/link μ•žλ’€ 곡백 trim 처리
DongChyeon Apr 18, 2026
d26c4bb
chore/#86: 프리뷰 productLink 더미 κ°’ μˆ˜μ •
DongChyeon Apr 18, 2026
5a7d6b8
fix/#86: 이미지 차원 읽기 μ‹€νŒ¨ μ‹œ S3 μ—…λ‘œλ“œ μ „ early return 처리
DongChyeon Apr 18, 2026
a62e6b2
feat/#86: getFeedList category νŒŒλΌλ―Έν„°λ₯Ό List<String>?으둜 λ³€κ²½
DongChyeon Apr 21, 2026
9633fc5
fix/#86: getMyFeeds μ—”λ“œν¬μΈνŠΈλ₯Ό v1μ—μ„œ v2둜 λ³€κ²½
DongChyeon Apr 21, 2026
e67c588
fix/#86: ν™ˆ ν™”λ©΄ 빈 μƒνƒœ 상단 νŒ¨λ”© μ‘°μ •
DongChyeon Apr 21, 2026
38aa6a1
chore/#86: gray950 색상 토큰 μΆ”κ°€ 및 전체 μ»΄ν¬λ„ŒνŠΈ 적용
DongChyeon Apr 21, 2026
cccdcb9
chore/#86: ktlint ν¬λ§·νŒ…
github-actions[bot] Apr 21, 2026
ac2e772
feat/#86: ThemePreview μ—…λ°μ΄νŠΈ
DongChyeon Apr 22, 2026
129d77a
Merge pull request #88 from Nexters/feature/#86-feed-improvement
DongChyeon Apr 22, 2026
5e7e151
feat/#89: 탭별 빈 μƒνƒœ EmptyView λΆ„κΈ° 처리
DongChyeon Apr 23, 2026
816a4bf
fix/#89: OptionSheet ν•˜λ‹¨ νŒ¨λ”© μ‘°μ •
DongChyeon Apr 23, 2026
6c8a44d
fix/#89: μƒν’ˆ 링크 WebView 타이틀 제거
DongChyeon Apr 23, 2026
f251f2f
fix/#89: 첫 번째 μ΄λ―Έμ§€μ—μ„œλ§Œ 가격 ν‘œμ‹œ
DongChyeon Apr 25, 2026
5423418
refactor/#89: nonRippleClickable μœ ν‹Έ 뢄리 및 νˆ΄νŒμ— 적용
DongChyeon Apr 25, 2026
2354bab
docs: ν™ˆ 슀크둀 연동 헀더 섀계 λ¬Έμ„œ μΆ”κ°€
DongChyeon Apr 25, 2026
3e4bd4b
docs: ν™ˆ 슀크둀 헀더 κ΅¬ν˜„ κ³„νš μΆ”κ°€
DongChyeon Apr 25, 2026
e2a92e8
feat/#89: 슀크둀 연동 헀더 β€” TopBar/FilterRow 슀크둀, Tab sticky κ³ μ •
DongChyeon Apr 25, 2026
4034155
fix/#89: λ‘œλ”© μŠ€ν”Όλ„ˆ fillParentMaxSize 적용
DongChyeon Apr 25, 2026
6a8eb3e
feat/#89: μœ„λ‘œ 슀크둀 μ‹œ TopBar/FilterRow μ¦‰μ‹œ ν‘œμ‹œ (AnimatedVisibility + λ°©ν–₯ 감지)
DongChyeon Apr 25, 2026
1a7db98
feat/#89: TopBar β†’ Tab(κ³ μ •) β†’ FilterRow μˆœμ„œ, μŠ¬λΌμ΄λ“œ+νŽ˜μ΄λ“œ μ• λ‹ˆλ©”μ΄μ…˜ 뢄리
DongChyeon Apr 25, 2026
73fe9ba
feat/#89: 헀더 μ• λ‹ˆλ©”μ΄μ…˜ tween + easing 적용 (300ms EaseOutCubic λ“±μž₯, 200ms Ea…
DongChyeon Apr 25, 2026
4a5c6cf
feat/#89: 헀더 μ• λ‹ˆλ©”μ΄μ…˜ expandVertically둜 λ³€κ²½ β€” 곡간과 μ½˜ν…μΈ  ν•¨κ»˜ ν™•μž₯
DongChyeon Apr 25, 2026
78e0fb2
chore/#89: docs/superpowers κΉƒ 좔적 μ œμ™Έ
DongChyeon Apr 25, 2026
c6ad93d
chore/#89: BuyOrNotChip을 CircleShape둜 μˆ˜μ •
DongChyeon Apr 25, 2026
8b9e612
feat/#89: FilterChipRow μ •λ ¬ λ²„νŠΌμ„ BuyOrNotIconChip으둜 ꡐ체
DongChyeon Apr 25, 2026
80c5ade
feat/#89: BuyOrNotChip 미선택 border μΆ”κ°€ 및 μ •λ ¬ μ•„μ΄μ½˜ κ³ μ • 배치
DongChyeon Apr 25, 2026
a067ce4
fix/#89: ν”Όλ“œ μΉ΄λ“œ 이미지 μ˜€λ²„λ ˆμ΄ 투λͺ…도 μ‘°μ • (0.3 β†’ 0.4)
DongChyeon Apr 25, 2026
55d4902
feat/#89: Sort μ•„μ΄μ½˜κ³Ό κ²ΉμΉ˜λŠ” FilterChip에 BlendMode νŽ˜μ΄λ“œ 효과 적용
DongChyeon Apr 25, 2026
7eb6a5b
feat/#89: ν”Όλ“œ μΉ΄λ“œ 가격 ν…μŠ€νŠΈμ— λ“œλ‘­ μ„€λ„μš° 적용
DongChyeon Apr 25, 2026
edc3985
refactor/#89: νˆ¬ν‘œ λΆˆκ°€ 쑰건 병합
DongChyeon Apr 25, 2026
0a0eb70
fix/#89: μ—…λ‘œλ“œ ν™”λ©΄ 이미지 선택 μ•„μ΄μ½˜ 클릭 μ˜μ—­ μΆ”κ°€
DongChyeon Apr 25, 2026
d700bdf
feat/#89: 링크 μž…λ ₯ 힌트의 (선택) ν…μŠ€νŠΈ μŠ€νƒ€μΌ 뢄리
DongChyeon Apr 25, 2026
051d3c6
feat/#89: 사진 선택 ν›„ ν‚€λ³΄λ“œ μžλ™ λ‹«κΈ°, 쀑볡 이미지 체크 제거, 링크 힌트 Row λ ˆμ΄μ•„μ›ƒμœΌλ‘œ λ³€κ²½
DongChyeon Apr 25, 2026
cc9483a
refactor/#89: NotificationItem 래퍼 제거 및 feedTitle ν•„λ“œ μΆ”κ°€
DongChyeon Apr 25, 2026
e5b1f20
chore/#89: μ•Œλ¦Ό 리슀트 ν•˜λ‹¨ ν‘Έν„° μŠ€νƒ€μΌ 및 Divider λ…ΈμΆœ 쑰건 μˆ˜μ •
DongChyeon Apr 25, 2026
0f4ff5f
chore/#89: ν™ˆ ν”Όλ“œ Divider padding 제거
DongChyeon Apr 25, 2026
995af49
feat/#89: 이미지 전체화면 λ·°μ–΄λ₯Ό 별도 λ„€λΉ„κ²Œμ΄μ…˜ ν™”λ©΄μœΌλ‘œ 뢄리
DongChyeon Apr 25, 2026
deb826c
feat/#89: computeMaxOffset 순수 ν•¨μˆ˜ μΆ”μΆœ 및 λ‹¨μœ„ ν…ŒμŠ€νŠΈ μΆ”κ°€
DongChyeon Apr 25, 2026
4ea1912
test/#89: computeMaxOffset μ—£μ§€ μΌ€μ΄μŠ€ ν…ŒμŠ€νŠΈ μΆ”κ°€
DongChyeon Apr 25, 2026
86d0e4a
feat/#89: 이미지 λ·°μ–΄ λ“œλž˜κ·Έ 경계 μ œν•œ 및 ν•€μΉ˜ 쀌 볡귀 κ΅¬ν˜„
DongChyeon Apr 25, 2026
eecebb1
refactor/#89: 쀌 볡귀 μ• λ‹ˆλ©”μ΄μ…˜ ν•¨μˆ˜ μΆ”μΆœ 및 더블탭 쀌인 μ‹œ offset μ΄ˆκΈ°ν™”
DongChyeon Apr 25, 2026
d2a2557
test/#89: 음수/0 이미지 크기 μ—£μ§€ μΌ€μ΄μŠ€ ν…ŒμŠ€νŠΈ μΆ”κ°€
DongChyeon Apr 25, 2026
ed8ffee
feat/#89: computeFocalOffset 순수 ν•¨μˆ˜ μΆ”μΆœ 및 λ‹¨μœ„ ν…ŒμŠ€νŠΈ μΆ”κ°€
DongChyeon Apr 25, 2026
cb63d97
test/#89: computeFocalOffset 경계값 ν…ŒμŠ€νŠΈ μΆ”κ°€
DongChyeon Apr 25, 2026
f7e26c2
feat/#89: ν•€μΉ˜ 쀌 focal point 적용 (손가락 μœ„μΉ˜ κΈ°μ€€ ν™•λŒ€)
DongChyeon Apr 25, 2026
fa437c3
fix/#89: scale 1f μƒνƒœμ—μ„œ pan 이벀트 μ†ŒλΉ„ν•˜μ§€ μ•Šλ„λ‘ μˆ˜μ • (νŽ˜μ΄μ € μŠ€μ™€μ΄ν”„ 볡원)
DongChyeon Apr 25, 2026
c919edf
feat/#89: μ˜€λ„ˆ ν”Όλ“œμ—μ„œ νˆ¬ν‘œ μ§„ν–‰λ₯  항상 ν‘œμ‹œ
DongChyeon Apr 26, 2026
42efb20
feat/#89: 동λ₯  μƒνƒœμ—μ„œ νˆ¬ν‘œ μ§„ν–‰λ₯  ν…μŠ€νŠΈ 색상 μˆ˜μ •
DongChyeon Apr 26, 2026
3c7683b
fix/#89: 동λ₯  νˆ¬ν‘œ μ‹œ maybe λ°” 배경색 gray950으둜 톡일
DongChyeon Apr 26, 2026
05b464a
fix/#89: 동λ₯  νˆ¬ν‘œ μ‹œ maybe λ°” percentageText gray950으둜 톡일
DongChyeon Apr 26, 2026
8189cb1
chore/#89: ImageViewerNavigation 디버그 둜그 제거
DongChyeon Apr 26, 2026
c90f3ec
Merge pull request #90 from Nexters/feature/#89-empty-view-filter
DongChyeon Apr 26, 2026
3e39cad
Merge pull request #90 from Nexters/feature/#89-empty-view-filter
DongChyeon Apr 26, 2026
58e09c0
chore/#29: serialization ν”ŒλŸ¬κ·ΈμΈ μΆ”κ°€ (feature convention + core:ui)
DongChyeon Apr 26, 2026
dbf2d0b
chore/#29: kotlin.serialization ν”ŒλŸ¬κ·ΈμΈ 루트 build.gradle.kts에 μΆ”κ°€
DongChyeon Apr 26, 2026
58ee4ba
refactor/#29: WebViewRoute 래퍼 ν•¨μˆ˜ 제거 (WebViewNavigation으둜 이동)
DongChyeon Apr 26, 2026
9555e87
refactor/#29: WebViewNavigation KClass 기반 λΌμš°νŒ…μœΌλ‘œ λ³€ν™˜
DongChyeon Apr 26, 2026
a2d68fc
refactor/#29: ImageViewerNavigation KClass 기반 λΌμš°νŒ…μœΌλ‘œ λ³€ν™˜
DongChyeon Apr 26, 2026
0b085c0
refactor/#29: AuthNavigation KClass 기반 λΌμš°νŒ…μœΌλ‘œ λ³€ν™˜
DongChyeon Apr 26, 2026
04c92b1
refactor/#29: HomeNavigation KClass 기반 λΌμš°νŒ…μœΌλ‘œ λ³€ν™˜
DongChyeon Apr 26, 2026
0c79c59
refactor/#29: UploadNavigation KClass 기반 λΌμš°νŒ…μœΌλ‘œ λ³€ν™˜
DongChyeon Apr 26, 2026
de5a27f
refactor/#29: NotificationNavigation KClass 기반 λΌμš°νŒ…μœΌλ‘œ λ³€ν™˜
DongChyeon Apr 26, 2026
e4e82a2
refactor/#29: MyPageNavigation KClass 기반 λΌμš°νŒ…μœΌλ‘œ λ³€ν™˜
DongChyeon Apr 26, 2026
1a4e19f
refactor/#29: BuyOrNotNavHost KClass 기반 λΌμš°νŒ…μœΌλ‘œ λ³€ν™˜
DongChyeon Apr 26, 2026
610b888
refactor/#29: BuyOrNotApp λ¬Έμžμ—΄ 라우트 μ°Έμ‘°λ₯Ό KClass 기반으둜 λ³€ν™˜
DongChyeon Apr 26, 2026
46432c3
refactor/#29: BuyOrNotApp λ¬Έμžμ—΄ 라우트 μ°Έμ‘°λ₯Ό KClass 기반으둜 λ³€ν™˜
DongChyeon Apr 26, 2026
4acdf78
Merge pull request #91 from Nexters/refactor/#29-kclass-route
DongChyeon Apr 26, 2026
47962d0
feat/#94: 이미지 λ·°μ–΄ 쒌우 이동 ν™”μ‚΄ν‘œ λ²„νŠΌ μΆ”κ°€
DongChyeon Apr 26, 2026
4a9a8ef
feat/#94: ImageViewerλ₯Ό FullScreen Dialog둜 μ „ν™˜
DongChyeon Apr 26, 2026
be5c786
feat/#94: ImageViewerScreen μ‹œμŠ€ν…œ λ°” νŒ¨λ”© 적용
DongChyeon Apr 26, 2026
4573bfb
Merge pull request #96 from Nexters/feat/#94-image-viewer-navigation-…
DongChyeon Apr 26, 2026
04cb82d
feat/#95: Gallery μ•„μ΄μ½˜ μΆ”κ°€
DongChyeon Apr 26, 2026
7803e47
feat/#95: ActionSheet μ»΄ν¬λ„ŒνŠΈ μΆ”κ°€
DongChyeon Apr 26, 2026
8772d96
docs/#95: ActionSheet 및 ActionItem 곡용 API KDoc μΆ”κ°€
DongChyeon Apr 26, 2026
7d7e94f
fix/#95: ic_gallery μ•„μ΄μ½˜ λ‚΄λΆ€ 흰색 μ˜μ—­ 투λͺ… 클리핑 처리
DongChyeon Apr 26, 2026
7886bec
feat/#95: UploadContract에 PhotoPicker μ‹œνŠΈ μƒνƒœ μΆ”κ°€
DongChyeon Apr 26, 2026
c365190
feat/#95: FileProvider μ„€μ • μΆ”κ°€ (카메라 촬영 URI용)
DongChyeon Apr 26, 2026
9a1207d
feat/#95: 카메라 μ•„μ΄μ½˜ ν„°μΉ˜ μ‹œ ActionSheet둜 사진 선택 방법 λΆ„κΈ°
DongChyeon Apr 26, 2026
8de4dd0
fix/#95: 카메라 촬영 파일λͺ… κ³ μœ ν™” 및 κΆŒν•œ μƒμˆ˜ μˆ˜μ •
DongChyeon Apr 26, 2026
4faeec5
refactor/#95: 카메라 μ €μž₯ 방식을 FileProvider β†’ MediaStore둜 μ „ν™˜
DongChyeon Apr 26, 2026
92e0552
feat/#95: 카메라 κΆŒν•œ κ±°λΆ€ μ‹œ μŠ€λ‚΅λ°” λ©”μ‹œμ§€ λ…ΈμΆœ
DongChyeon Apr 26, 2026
227f05d
Merge pull request #97 from Nexters/feature/#95-upload-photo-camera-g…
DongChyeon Apr 26, 2026
fd8ec7d
chore: 0.2.0 (5) -> 0.3.0 (6)
DongChyeon Apr 26, 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 .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -84,3 +84,4 @@ lint/tmp/
@gemini-skills/
.gemini/logs/
.gemini/cache/
docs/superpowers/
5 changes: 3 additions & 2 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import java.util.Properties
plugins {
id("buyornot.android.application")
alias(libs.plugins.kotlin.compose)
alias(libs.plugins.kotlin.serialization)
alias(libs.plugins.hilt)
alias(libs.plugins.ksp)
alias(libs.plugins.google.services)
Expand All @@ -29,8 +30,8 @@ android {

defaultConfig {
applicationId = "com.sseotdabwa.buyornot"
versionCode = 5
versionName = "0.2.0"
versionCode = 6
versionName = "0.3.0"

buildConfigField("String", "KAKAO_NATIVE_APP_KEY", "\"${localProperties.getProperty("kakao.nativeAppKey", "")}\"")
manifestPlaceholders["NATIVE_APP_KEY"] = localProperties.getProperty("kakao.nativeAppKey", "")
Expand Down
1 change: 1 addition & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="com.google.android.gms.permission.AD_ID" />

<application
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,15 @@ import androidx.navigation.compose.NavHost
import com.sseotdabwa.buyornot.BuildConfig
import com.sseotdabwa.buyornot.core.network.AuthEvent
import com.sseotdabwa.buyornot.core.network.AuthEventBus
import com.sseotdabwa.buyornot.core.ui.imageviewer.imageViewerScreen
import com.sseotdabwa.buyornot.core.ui.imageviewer.navigateToImageViewer
import com.sseotdabwa.buyornot.core.ui.snackbar.LocalSnackbarState
import com.sseotdabwa.buyornot.core.ui.webview.navigateToPrivacyPolicy
import com.sseotdabwa.buyornot.core.ui.webview.navigateToTerms
import com.sseotdabwa.buyornot.core.ui.webview.navigateToWebView
import com.sseotdabwa.buyornot.core.ui.webview.webViewScreen
import com.sseotdabwa.buyornot.feature.auth.navigation.AUTH_ROUTE
import com.sseotdabwa.buyornot.feature.auth.navigation.SPLASH_ROUTE
import com.sseotdabwa.buyornot.feature.auth.navigation.AuthRoute
import com.sseotdabwa.buyornot.feature.auth.navigation.SplashRoute
import com.sseotdabwa.buyornot.feature.auth.navigation.authScreen
import com.sseotdabwa.buyornot.feature.auth.navigation.navigateForceToLogin
import com.sseotdabwa.buyornot.feature.auth.navigation.navigateToLogin
Expand All @@ -27,17 +30,10 @@ import com.sseotdabwa.buyornot.feature.mypage.navigation.navigateToMyPage
import com.sseotdabwa.buyornot.feature.notification.navigation.navigateToNotification
import com.sseotdabwa.buyornot.feature.notification.navigation.navigateToNotificationDetail
import com.sseotdabwa.buyornot.feature.notification.navigation.notificationGraph
import com.sseotdabwa.buyornot.feature.upload.navigation.UPLOAD_ROUTE
import com.sseotdabwa.buyornot.feature.upload.navigation.UploadRoute
import com.sseotdabwa.buyornot.feature.upload.navigation.navigateToUpload
import com.sseotdabwa.buyornot.feature.upload.navigation.uploadScreen

/**
* BuyOrNot μ•±μ˜ 메인 λ„€λΉ„κ²Œμ΄μ…˜ 호슀트
*
* @param navController λ„€λΉ„κ²Œμ΄μ…˜ 컨트둀러
* @param authEventBus 인증 κ΄€λ ¨ κΈ€λ‘œλ²Œ 이벀트λ₯Ό μˆ˜μ‹ ν•˜λŠ” λ²„μŠ€
* @param modifier λ ˆμ΄μ•„μ›ƒ μˆ˜μ •μž
*/
@Composable
fun BuyOrNotNavHost(
navController: NavHostController,
Expand All @@ -47,7 +43,6 @@ fun BuyOrNotNavHost(
) {
val snackbarState = LocalSnackbarState.current

// κ°•μ œ λ‘œκ·Έμ•„μ›ƒ 이벀트 처리
LaunchedEffect(authEventBus) {
authEventBus.events.collect { event ->
if (event == AuthEvent.FORCE_LOGOUT) {
Expand All @@ -61,7 +56,7 @@ fun BuyOrNotNavHost(

NavHost(
navController = navController,
startDestination = SPLASH_ROUTE,
startDestination = SplashRoute,
modifier = modifier,
) {
splashScreen(
Expand All @@ -70,7 +65,7 @@ fun BuyOrNotNavHost(
navController.navigateToHome(
navOptions =
androidx.navigation.navOptions {
popUpTo(SPLASH_ROUTE) { inclusive = true }
popUpTo<SplashRoute> { inclusive = true }
launchSingleTop = true
},
)
Expand All @@ -83,7 +78,7 @@ fun BuyOrNotNavHost(
navController.navigateToHome(
navOptions =
androidx.navigation.navOptions {
popUpTo(AUTH_ROUTE) { inclusive = true }
popUpTo<AuthRoute> { inclusive = true }
launchSingleTop = true
},
)
Expand All @@ -97,10 +92,14 @@ fun BuyOrNotNavHost(
onNotificationClick = navController::navigateToNotification,
onProfileClick = navController::navigateToMyPage,
onUploadClick = navController::navigateToUpload,
onLinkClick = { url -> navController.navigateToWebView("", url) },
onImageClick = { urls, page -> navController.navigateToImageViewer(urls, page) },
)
notificationGraph(
onBackClick = navController::popBackStack,
onNotificationClick = navController::navigateToNotificationDetail,
onLinkClick = { url -> navController.navigateToWebView("", url) },
onImageClick = { urls, page -> navController.navigateToImageViewer(urls, page) },
)
uploadScreen(
onNavigateBack = navController::popBackStack,
Expand All @@ -109,7 +108,7 @@ fun BuyOrNotNavHost(
tab = HomeTab.MY_FEED,
navOptions =
androidx.navigation.navOptions {
popUpTo(UPLOAD_ROUTE) {
popUpTo<UploadRoute> {
inclusive = true
}
launchSingleTop = true
Expand All @@ -122,6 +121,9 @@ fun BuyOrNotNavHost(
versionName = BuildConfig.VERSION_NAME,
onNavigateToLogin = navController::navigateForceToLogin,
)
imageViewerScreen(
onBackClick = navController::popBackStack,
)
webViewScreen(
onBackClick = navController::popBackStack,
)
Expand Down
46 changes: 12 additions & 34 deletions app/src/main/java/com/sseotdabwa/buyornot/ui/BuyOrNotApp.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.navigation.NavDestination
import androidx.navigation.compose.currentBackStackEntryAsState
import androidx.navigation.compose.rememberNavController
import com.sseotdabwa.buyornot.core.designsystem.components.BuyOrNotSnackBarHost
Expand All @@ -21,25 +20,11 @@ import com.sseotdabwa.buyornot.core.network.AuthEventBus
import com.sseotdabwa.buyornot.core.ui.permission.rememberNotificationPermission
import com.sseotdabwa.buyornot.core.ui.snackbar.LocalSnackbarState
import com.sseotdabwa.buyornot.core.ui.snackbar.rememberBuyOrNotSnackbarState
import com.sseotdabwa.buyornot.feature.auth.navigation.AUTH_ROUTE
import com.sseotdabwa.buyornot.feature.auth.navigation.SPLASH_ROUTE
import com.sseotdabwa.buyornot.feature.home.navigation.HOME_ROUTE
import com.sseotdabwa.buyornot.feature.auth.navigation.AuthRoute
import com.sseotdabwa.buyornot.feature.auth.navigation.SplashRoute
import com.sseotdabwa.buyornot.feature.home.navigation.HomeRoute
import com.sseotdabwa.buyornot.navigation.BuyOrNotNavHost

/**
* BuyOrNot μ•±μ˜ 메인 컴포저블
*
* λ„€λΉ„κ²Œμ΄μ…˜κ³Ό ν•˜λ‹¨ λ„€λΉ„κ²Œμ΄μ…˜ λ°”λ₯Ό ν¬ν•¨ν•œ μ•±μ˜ 전체 ꡬ쑰λ₯Ό μ •μ˜ν•©λ‹ˆλ‹€.
* μŠ€ν”Œλž˜μ‹œ 및 둜그인 ν™”λ©΄μ—μ„œλŠ” ν•˜λ‹¨ λ°”κ°€ ν‘œμ‹œλ˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.
*
* 전체 화면이 ν•„μš”ν•˜λ©΄ β†’ bottomBarPadding() ν•¨μˆ˜μ˜ λ¦¬μŠ€νŠΈμ— 라우트 μΆ”κ°€
* 일반 화면이면 β†’ 아무 것도 ν•˜μ§€ μ•Šμ•„λ„ μžλ™μœΌλ‘œ νŒ¨λ”© 적용
*
* @param authEventBus 인증 κ΄€λ ¨ 이벀트 λ²„μŠ€
* @param onBackPressed ν™ˆ ν™”λ©΄μ—μ„œ λ’€λ‘œκ°€κΈ° μ‹œ μ•± μ’…λ£Œλ₯Ό μœ„ν•œ 콜백
* @param onFinish μ•± μ’…λ£Œ 콜백 (κ°•μ œ μ—…λ°μ΄νŠΈ μ‹œ "μ’…λ£Œ" λ²„νŠΌ)
* @param viewModel μ•± 곡톡 ViewModel
*/
@Composable
fun BuyOrNotApp(
authEventBus: AuthEventBus,
Expand All @@ -54,12 +39,10 @@ fun BuyOrNotApp(

val isFirstRun by viewModel.isFirstRun.collectAsStateWithLifecycle()

// ν™ˆ ν™”λ©΄μ—μ„œ λ’€λ‘œκ°€κΈ° μ‹œ μ•± μ’…λ£Œ
BackHandler(enabled = currentDestination?.route == HOME_ROUTE) {
BackHandler(enabled = currentDestination?.route?.startsWith(HomeRoute::class.qualifiedName ?: "") == true) {
onBackPressed()
}

// μ•± μ§„μž… μ‹œ 졜초 1회만 μ•Œλ¦Ό κΆŒν•œ μžλ™ μš”μ²­
val (hasNotificationPermission, requestNotificationPermission) = rememberNotificationPermission()

LaunchedEffect(isFirstRun) {
Expand All @@ -71,6 +54,11 @@ fun BuyOrNotApp(
}
}

val isFullscreen =
currentDestination?.route.let { route ->
route == SplashRoute::class.qualifiedName || route == AuthRoute::class.qualifiedName
}

CompositionLocalProvider(LocalSnackbarState provides snackbarState) {
Scaffold(
containerColor = BuyOrNotTheme.colors.gray0,
Expand All @@ -83,27 +71,17 @@ fun BuyOrNotApp(
modifier =
Modifier
.consumeWindowInsets(innerPadding)
.bottomBarPadding(currentDestination, innerPadding),
.bottomBarPadding(isFullscreen, innerPadding),
)
}
}
}

/**
* νŠΉμ • ν™”λ©΄(μŠ€ν”Œλž˜μ‹œ, 둜그인)μ—μ„œλŠ” μ‹œμŠ€ν…œ νŒ¨λ”©μ„ μ œκ±°ν•˜λŠ” ν™•μž₯ ν•¨μˆ˜
*
* NavHost에 μ μš©λ˜μ–΄, 전체 화면이 ν•„μš”ν•œ μŠ€ν”Œλž˜μ‹œ/둜그인 ν™”λ©΄μ—μ„œλŠ”
* μ‹œμŠ€ν…œ λ°” μ˜μ—­κΉŒμ§€ ν™•μž₯되고, 일반 ν™”λ©΄μ—μ„œλŠ” ν•˜λ‹¨ λ°” νŒ¨λ”©μ„ μ μš©ν•©λ‹ˆλ‹€.
*
* @param currentDestination ν˜„μž¬ λ„€λΉ„κ²Œμ΄μ…˜ λͺ©μ μ§€
* @param padding Scaffold의 innerPadding (ν•˜λ‹¨ λ°” 높이 포함)
* @return 쑰건에 따라 νŒ¨λ”©μ΄ μ μš©λ˜κ±°λ‚˜ 제거된 Modifier
*/
private fun Modifier.bottomBarPadding(
currentDestination: NavDestination?,
isFullscreen: Boolean,
padding: PaddingValues,
): Modifier =
if (currentDestination?.route in listOf(SPLASH_ROUTE, AUTH_ROUTE)) {
if (isFullscreen) {
this
} else {
this.padding(padding)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ class AndroidFeatureConventionPlugin : Plugin<Project> {
apply("com.android.library")
apply("org.jetbrains.kotlin.android")
apply("org.jetbrains.kotlin.plugin.compose")
apply("org.jetbrains.kotlin.plugin.serialization")
}

extensions.configure<LibraryExtension> {
Expand All @@ -30,7 +31,6 @@ class AndroidFeatureConventionPlugin : Plugin<Project> {
add("implementation", libs.findLibrary("androidx.lifecycle.runtime.compose").get())
add("implementation", libs.findLibrary("androidx.navigation.compose").get())
add("implementation", libs.findLibrary("hilt.navigation.compose").get())

}
}
}
Expand Down
1 change: 1 addition & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ plugins {
alias(libs.plugins.android.library) apply false
alias(libs.plugins.kotlin.android) apply false
alias(libs.plugins.kotlin.compose) apply false
alias(libs.plugins.kotlin.serialization) apply false
alias(libs.plugins.hilt) apply false
alias(libs.plugins.ksp) apply false
alias(libs.plugins.ktlint) apply false
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
package com.sseotdabwa.buyornot.core.data.repository

import com.sseotdabwa.buyornot.core.network.api.FeedApiService
import com.sseotdabwa.buyornot.core.network.dto.request.FeedImageRequest
import com.sseotdabwa.buyornot.core.network.dto.request.FeedRequest
import com.sseotdabwa.buyornot.core.network.dto.request.PresignedUrlRequest
import com.sseotdabwa.buyornot.core.network.dto.request.VoteRequest
import com.sseotdabwa.buyornot.core.network.dto.response.AuthorDto
import com.sseotdabwa.buyornot.core.network.dto.response.FeedImageDto
import com.sseotdabwa.buyornot.core.network.dto.response.FeedItemDto
import com.sseotdabwa.buyornot.core.network.dto.response.FeedListResponse
import com.sseotdabwa.buyornot.core.network.dto.response.VoteResponse
import com.sseotdabwa.buyornot.core.network.dto.response.getOrThrow
import com.sseotdabwa.buyornot.domain.model.Author
import com.sseotdabwa.buyornot.domain.model.Feed
import com.sseotdabwa.buyornot.domain.model.FeedCategory
import com.sseotdabwa.buyornot.domain.model.FeedImage
import com.sseotdabwa.buyornot.domain.model.FeedStatus
import com.sseotdabwa.buyornot.domain.model.UploadInfo
import com.sseotdabwa.buyornot.domain.model.VoteChoice
Expand All @@ -29,9 +32,10 @@ class FeedRepositoryImpl @Inject constructor(
cursor: Long?,
size: Int,
feedStatus: String?,
category: List<String>?,
): FeedList =
feedApiService
.getFeedList(cursor, size, feedStatus)
.getFeedList(cursor, size, feedStatus, category)
.getOrThrow()
.toDomain()

Expand Down Expand Up @@ -87,19 +91,26 @@ class FeedRepositoryImpl @Inject constructor(
category: FeedCategory,
price: Int,
content: String,
s3ObjectKey: String,
imageWidth: Int,
imageHeight: Int,
images: List<FeedImage>,
title: String?,
link: String?,
): Long =
feedApiService
.createFeed(
FeedRequest(
category = category.name,
price = price,
content = content,
s3ObjectKey = s3ObjectKey,
imageWidth = imageWidth,
imageHeight = imageHeight,
images =
images.map { image ->
FeedImageRequest(
s3ObjectKey = image.s3ObjectKey,
imageWidth = image.imageWidth,
imageHeight = image.imageHeight,
)
},
title = title,
link = link,
),
).getOrThrow()
.feedId
Expand Down Expand Up @@ -149,21 +160,28 @@ private fun FeedListResponse.toDomain(): FeedList =
private fun FeedItemDto.toDomain(): Feed =
Feed(
feedId = feedId,
title = title ?: "",
content = content,
price = String.format(java.util.Locale.KOREA, "%,d", price),
category = category.toFeedCategory(),
yesCount = yesCount,
noCount = noCount,
totalCount = totalCount,
feedStatus = feedStatus.toFeedStatus(),
s3ObjectKey = s3ObjectKey,
viewUrl = viewUrl,
imageWidth = imageWidth,
imageHeight = imageHeight,
images = images.map { it.toDomain() },
author = author.toDomain(),
createdAt = createdAt,
hasVoted = hasVoted ?: false,
myVoteChoice = myVoteChoice?.toVoteChoice(),
productLink = link,
)

private fun FeedImageDto.toDomain(): FeedImage =
FeedImage(
s3ObjectKey = s3ObjectKey,
imageUrl = imageUrl,
imageWidth = imageWidth,
imageHeight = imageHeight,
)

private fun String.toFeedCategory(): FeedCategory =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,6 @@ class NotificationRepositoryImpl @Inject constructor(
resultPercent = resultPercent,
resultLabel = resultLabel,
viewUrl = viewUrl,
feedTitle = feedTitle.orEmpty(),
)
}
Loading
Loading