Skip to content

Commit

Permalink
Merge pull request #92 from team-JMT/upgrade/restaurant_detail
Browse files Browse the repository at this point in the history
�레스토랑 디테일 페이지 구현
dogdduddy authored Mar 5, 2024
2 parents 6487cf7 + 304fb18 commit 04964e5
Showing 44 changed files with 1,578 additions and 5 deletions.
8 changes: 8 additions & 0 deletions data/src/main/java/org/gdsc/data/database/ReviewPaging.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package org.gdsc.data.database

import org.gdsc.domain.model.Review

data class ReviewPaging(
val page: Page,
val reviewList: List<Review>
)
Original file line number Diff line number Diff line change
@@ -3,6 +3,7 @@ package org.gdsc.data.datasource
import androidx.paging.PagingData
import kotlinx.coroutines.flow.Flow
import org.gdsc.data.database.RegisteredRestaurant
import org.gdsc.data.database.ReviewPaging
import org.gdsc.data.model.RegisteredRestaurantResponse
import org.gdsc.domain.DrinkPossibility
import org.gdsc.domain.FoodCategory
@@ -41,4 +42,6 @@ interface RestaurantDataSource {
userLocation: Location?, startLocation: Location?, endLocation: Location?, sortType: SortType, foodCategory: FoodCategory?, drinkPossibility: DrinkPossibility?
): Flow<PagingData<RegisteredRestaurantResponse>>

suspend fun getRestaurantReviews(restaurantId: Int): ReviewPaging

}
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
package org.gdsc.data.datasource

import android.util.Log
import androidx.lifecycle.asFlow
import androidx.paging.ExperimentalPagingApi
import androidx.paging.Pager
import androidx.paging.PagingConfig
import androidx.paging.PagingData
import androidx.paging.cachedIn
import androidx.paging.liveData
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.Flow
@@ -17,6 +15,7 @@ import org.gdsc.data.database.RegisteredRestaurant
import org.gdsc.data.database.RestaurantByMapPagingSource
import org.gdsc.data.database.RestaurantDatabase
import org.gdsc.data.database.RestaurantMediator
import org.gdsc.data.database.ReviewPaging
import org.gdsc.data.model.RegisteredRestaurantResponse
import org.gdsc.data.network.RestaurantAPI
import org.gdsc.domain.DrinkPossibility
@@ -205,4 +204,8 @@ class RestaurantDataSourceImpl @Inject constructor(
}.flow.cachedIn(coroutineScope)
}

override suspend fun getRestaurantReviews(restaurantId: Int): ReviewPaging {
return restaurantAPI.getRestaurantReviews(restaurantId).data
}

}
2 changes: 2 additions & 0 deletions data/src/main/java/org/gdsc/data/datasource/UserDataSource.kt
Original file line number Diff line number Diff line change
@@ -18,6 +18,8 @@ interface UserDataSource {

suspend fun getUserInfo(): UserInfo

suspend fun getOtherUserInfo(id: Int): UserInfo

suspend fun postUserLogout(refreshToken: String): String

suspend fun postUserSignout(): String
Original file line number Diff line number Diff line change
@@ -58,6 +58,10 @@ class UserDataSourceImpl @Inject constructor(
return UserInfo()
}

override suspend fun getOtherUserInfo(id: Int): UserInfo {
return userAPI.getOtherUserInfo(id).data
}

override suspend fun postUserLogout(refreshToken: String): String {
return userAPI.postUserLogOut(LogoutRequest(refreshToken)).code
}
6 changes: 6 additions & 0 deletions data/src/main/java/org/gdsc/data/network/RestaurantAPI.kt
Original file line number Diff line number Diff line change
@@ -3,6 +3,7 @@ package org.gdsc.data.network
import okhttp3.MultipartBody
import okhttp3.RequestBody
import org.gdsc.data.database.RegisteredRestaurantPaging
import org.gdsc.data.database.ReviewPaging
import org.gdsc.data.model.Response
import org.gdsc.domain.model.RestaurantLocationInfo
import org.gdsc.domain.model.UserLocation
@@ -75,4 +76,9 @@ interface RestaurantAPI {
@Body restaurantSearchMapRequest: RestaurantSearchMapRequest,
): Response<RegisteredRestaurantPaging>

@GET("/api/v1/restaurant/{recommendRestaurantId}/review")
suspend fun getRestaurantReviews(
@Path("recommendRestaurantId") recommendRestaurantId: Int,
): Response<ReviewPaging>

}
5 changes: 4 additions & 1 deletion data/src/main/java/org/gdsc/data/network/UserAPI.kt
Original file line number Diff line number Diff line change
@@ -33,7 +33,10 @@ interface UserAPI {
@GET("api/v1/user/info")
suspend fun getUserInfo(): Response<UserInfo>

@HTTP(method="DELETE", path="api/v1/auth/user", hasBody = true)
@GET("api/v1/user/info/{id}")
suspend fun getOtherUserInfo(@Path(value = "id") id: Int): Response<UserInfo>

@HTTP(method = "DELETE", path = "api/v1/auth/user", hasBody = true)
suspend fun postUserLogOut(
@Body request: LogoutRequest
): Response<String>
Original file line number Diff line number Diff line change
@@ -12,6 +12,7 @@ import org.gdsc.domain.model.Location
import org.gdsc.domain.model.PagingResult
import org.gdsc.domain.model.RegisteredRestaurant
import org.gdsc.domain.model.RestaurantLocationInfo
import org.gdsc.domain.model.Review
import org.gdsc.domain.model.UserLocation
import org.gdsc.domain.model.request.ModifyRestaurantInfoRequest
import org.gdsc.domain.model.request.RestaurantRegistrationRequest
@@ -120,4 +121,8 @@ class RestaurantRepositoryImpl @Inject constructor(
}
}
}

override suspend fun getRestaurantReviews(restaurantId: Int): List<Review> {
return restaurantDataSource.getRestaurantReviews(restaurantId).reviewList
}
}
Original file line number Diff line number Diff line change
@@ -32,6 +32,10 @@ class UserRepositoryImpl @Inject constructor(
return userDataSource.getUserInfo()
}

override suspend fun getOtherUserInfo(id: Int): UserInfo {
return userDataSource.getOtherUserInfo(id)
}

override suspend fun postUserLogout(refreshToken: String): String {
return userDataSource.postUserLogout(refreshToken)
}
10 changes: 10 additions & 0 deletions domain/src/main/java/org/gdsc/domain/model/Review.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package org.gdsc.domain.model

data class Review(
val recommendRestaurantId: Int,
val reviewContent: String,
val reviewId: Int,
val reviewImages: List<String>,
val reviewerImageUrl: String,
val userName: String
)
Original file line number Diff line number Diff line change
@@ -16,5 +16,6 @@ data class RestaurantInfoResponse(
val userNickName: String,
val userProfileImageUrl: String,
val x: Double,
val y: Double
val y: Double,
val differenceInDistance: String
)
Original file line number Diff line number Diff line change
@@ -9,6 +9,7 @@ import org.gdsc.domain.model.Location
import org.gdsc.domain.model.PagingResult
import org.gdsc.domain.model.RegisteredRestaurant
import org.gdsc.domain.model.RestaurantLocationInfo
import org.gdsc.domain.model.Review
import org.gdsc.domain.model.UserLocation
import org.gdsc.domain.model.request.ModifyRestaurantInfoRequest
import org.gdsc.domain.model.request.RestaurantRegistrationRequest
@@ -40,4 +41,6 @@ interface RestaurantRepository {
userLocation: Location?, startLocation: Location?, endLocation: Location?, sortType: SortType, foodCategory: FoodCategory?, drinkPossibility: DrinkPossibility?
): Flow<PagingData<RegisteredRestaurant>>

suspend fun getRestaurantReviews(restaurantId: Int): List<Review>

}
Original file line number Diff line number Diff line change
@@ -18,6 +18,8 @@ interface UserRepository {

suspend fun getUserInfo(): UserInfo

suspend fun getOtherUserInfo(id: Int): UserInfo

suspend fun postUserLogout(refreshToken: String): String

suspend fun postUserSignout(): String
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package org.gdsc.domain.usecase

import org.gdsc.domain.repository.RestaurantRepository
import javax.inject.Inject

class GetRestaurantReviewsUseCase @Inject constructor(
private val restaurantRepository: RestaurantRepository
) {
suspend operator fun invoke(recommendRestaurantId: Int) = restaurantRepository.getRestaurantReviews(recommendRestaurantId)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package org.gdsc.domain.usecase.user

import org.gdsc.domain.repository.UserRepository
import javax.inject.Inject

class GetOtherUserInfoUseCase @Inject constructor(
private val userRepository: UserRepository
) {

suspend operator fun invoke(id: Int) = userRepository.getOtherUserInfo(id)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package org.gdsc.presentation.model

data class RestaurantPhotoItem(
val photoUrl: String,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package org.gdsc.presentation.view.mypage.adapter

import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.Glide
import org.gdsc.presentation.databinding.ItemImagePageBinding

data class ImagePagerItem(
val imageUrl: String
)

class ImagePager(
private val onItemSelected: () -> Unit
) :
ListAdapter<ImagePagerItem, ImagePager.ImagePagerViewHolder>(
diffUtil
) {

inner class ImagePagerViewHolder(private val binding: ItemImagePageBinding) :
RecyclerView.ViewHolder(binding.root) {
fun bind(item: ImagePagerItem, position: Int) {
with(binding) {
Glide.with(root)
.load(item.imageUrl)
.into(imageView)

tvSequence.text = "$position / $itemCount"
}
}
}

companion object {
private val diffUtil = object : DiffUtil.ItemCallback<ImagePagerItem>() {
override fun areItemsTheSame(
oldItem: ImagePagerItem,
newItem: ImagePagerItem
) = oldItem === newItem

override fun areContentsTheSame(
oldItem: ImagePagerItem,
newItem: ImagePagerItem
) = oldItem == newItem

}

}

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ImagePagerViewHolder {
val inflater = LayoutInflater.from(parent.context)
return ImagePagerViewHolder(
ItemImagePageBinding.inflate(
inflater,
parent,
false
)
)

}

override fun onBindViewHolder(holder: ImagePagerViewHolder, position: Int) {
val item = getItem(position)
holder.bind(item, position + 1)
holder.itemView.setOnClickListener {
onItemSelected()
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package org.gdsc.presentation.view.mypage.adapter

import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.Glide
import org.gdsc.presentation.databinding.ItemImageSlideBinding

data class ImageSliderItem(
val imageUrl: String
)

class ImageSlider(
private val onItemSelected: () -> Unit = {}
) :
ListAdapter<ImageSliderItem, ImageSlider.ImageSliderViewHolder>(
diffUtil
) {

inner class ImageSliderViewHolder(private val binding: ItemImageSlideBinding) :
RecyclerView.ViewHolder(binding.root) {
fun bind(item: ImageSliderItem) {
with(binding) {
Glide.with(root)
.load(item.imageUrl)
.into(imageView)
}
}
}

companion object {
private val diffUtil = object : DiffUtil.ItemCallback<ImageSliderItem>() {
override fun areItemsTheSame(
oldItem: ImageSliderItem,
newItem: ImageSliderItem
) = oldItem === newItem

override fun areContentsTheSame(
oldItem: ImageSliderItem,
newItem: ImageSliderItem
) = oldItem == newItem

}

}

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ImageSliderViewHolder {
val inflater = LayoutInflater.from(parent.context)
return ImageSliderViewHolder(
ItemImageSlideBinding.inflate(
inflater,
parent,
false
)
)
}

override fun onBindViewHolder(holder: ImageSliderViewHolder, position: Int) {
val item = getItem(position)
holder.bind(item)
holder.itemView.setOnClickListener {
onItemSelected()
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package org.gdsc.presentation.view.mypage.adapter

import androidx.fragment.app.Fragment
import androidx.viewpager2.adapter.FragmentStateAdapter
import org.gdsc.presentation.view.mypage.restaurantdetail.RestaurantInfoFragment
import org.gdsc.presentation.view.mypage.restaurantdetail.RestaurantPhotoFragment
import org.gdsc.presentation.view.mypage.restaurantdetail.RestaurantReviewFragment

class RestaurantDetailPagerAdapter(fragment: Fragment) : FragmentStateAdapter(fragment) {

override fun getItemCount() = RESTAURANT_DETAIL_PAGER_SIZE

override fun createFragment(position: Int): Fragment {
return when (position) {
RESTAURANT_INFO -> RestaurantInfoFragment()
PHOTO -> RestaurantPhotoFragment()
else -> RestaurantReviewFragment()
}
}

companion object {
private const val RESTAURANT_DETAIL_PAGER_SIZE = 3

const val RESTAURANT_INFO = 0
const val PHOTO = 1
const val REVIEW = 2
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package org.gdsc.presentation.view.mypage.adapter

import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.Glide
import org.gdsc.presentation.databinding.ItemPhotoRestaurantBinding
import org.gdsc.presentation.model.RestaurantPhotoItem

class RestaurantPhotoAdapter(
private val onItemSelected: () -> Unit
) :
ListAdapter<RestaurantPhotoItem, RestaurantPhotoAdapter.RestaurantPhotoViewHolder>(
diffUtil
) {

private var width = 0
private var height = 0

inner class RestaurantPhotoViewHolder(private val binding: ItemPhotoRestaurantBinding) :
RecyclerView.ViewHolder(binding.root) {
fun bind(item: RestaurantPhotoItem) {
with(binding) {
Glide.with(root)
.load(item.photoUrl)
.into(ivPhoto)
}
}
}

companion object {
private val diffUtil = object : DiffUtil.ItemCallback<RestaurantPhotoItem>() {
override fun areItemsTheSame(
oldItem: RestaurantPhotoItem,
newItem: RestaurantPhotoItem
) = oldItem === newItem

override fun areContentsTheSame(
oldItem: RestaurantPhotoItem,
newItem: RestaurantPhotoItem
) = oldItem == newItem

}

}

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RestaurantPhotoViewHolder {
val inflater = LayoutInflater.from(parent.context)
return RestaurantPhotoViewHolder(
ItemPhotoRestaurantBinding.inflate(
inflater,
parent,
false
)
)
}

override fun onBindViewHolder(holder: RestaurantPhotoViewHolder, position: Int) {
val item = getItem(position)
holder.bind(item)
holder.itemView.setOnClickListener {
onItemSelected()
}
holder.itemView.layoutParams.width = width
holder.itemView.layoutParams.height = height
}

fun setSize(width: Int, height: Int) {
this.width = width
this.height = height
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package org.gdsc.presentation.view.mypage.adapter

import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.Glide
import org.gdsc.domain.model.Review
import org.gdsc.presentation.databinding.ItemReviewRestaurantBinding

class RestaurantReviewAdapter(
private val onItemSelected: () -> Unit
) :
ListAdapter<Review, RestaurantReviewAdapter.RestaurantReviewViewHolder>(
diffUtil
) {

inner class RestaurantReviewViewHolder(private val binding: ItemReviewRestaurantBinding) :
RecyclerView.ViewHolder(binding.root) {
fun bind(item: Review) {
with(binding) {
Glide.with(root)
.load(item.reviewerImageUrl)
.into(ivProfile)

tvNickname.text = item.userName
tvContent.text = item.reviewContent
}
}
}

companion object {
private val diffUtil = object : DiffUtil.ItemCallback<Review>() {
override fun areItemsTheSame(
oldItem: Review,
newItem: Review
) = oldItem.reviewId == newItem.reviewId

override fun areContentsTheSame(
oldItem: Review,
newItem: Review
) = oldItem == newItem

}

}

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RestaurantReviewViewHolder {
val inflater = LayoutInflater.from(parent.context)
return RestaurantReviewViewHolder(
ItemReviewRestaurantBinding.inflate(
inflater,
parent,
false
)
)
}

override fun onBindViewHolder(holder: RestaurantReviewViewHolder, position: Int) {
val item = getItem(position)
holder.bind(item)
holder.itemView.setOnClickListener {
onItemSelected()
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
package org.gdsc.presentation.view.mypage.restaurantdetail

import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.lifecycleScope
import com.bumptech.glide.Glide
import com.google.android.material.tabs.TabLayoutMediator
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.launch
import org.gdsc.presentation.R
import org.gdsc.presentation.databinding.FragmentRestaurantDetailBinding
import org.gdsc.presentation.utils.CalculatorUtils
import org.gdsc.presentation.view.mypage.adapter.RestaurantDetailPagerAdapter
import org.gdsc.presentation.view.mypage.viewmodel.RestaurantDetailViewModel

@AndroidEntryPoint
class RestaurantDetailFragment : Fragment() {

private var _binding: FragmentRestaurantDetailBinding? = null
private val binding get() = _binding!!

private val viewModel: RestaurantDetailViewModel by activityViewModels()

override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
_binding = FragmentRestaurantDetailBinding.inflate(inflater, container, false)
return binding.root
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
setButtons()
setTabLayout()
observeData()
}

private fun setButtons() {
binding.tvCopy.setOnClickListener {

val clipboardManager =
requireContext().getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager

val clipData = ClipData.newPlainText("address", binding.tvAddress.text)
clipboardManager.setPrimaryClip(clipData)

}
}

private fun observeData() {
viewLifecycleOwner.lifecycleScope.launch {
viewModel.restaurantInfo.collect {
it?.let { notNullRestaurantInfo ->

notNullRestaurantInfo.apply {
binding.tvRestaurantName.text = name
binding.tvDistance.text = requireContext().getString(
R.string.distance_from_current_location,
CalculatorUtils.getDistanceWithLength(it.differenceInDistance.toInt())
)
binding.tvAddress.text = address
binding.tvCategory.text = category
}
}
}
}

viewLifecycleOwner.lifecycleScope.launch {
viewModel.authorInfo.collect {
it?.let { notNullAuthorInfo ->

notNullAuthorInfo.apply {
binding.tvNickname.text = nickname
Glide.with(binding.root)
.load(profileImg)
.into(binding.ivProfile)
}
}
}
}
}

private fun setTabLayout() {

binding.restaurantDetailPager.adapter = RestaurantDetailPagerAdapter(this)
binding.restaurantDetailPager.isUserInputEnabled = false

TabLayoutMediator(binding.tabLayout, binding.restaurantDetailPager) { tab, position ->
when (position) {
RestaurantDetailPagerAdapter.RESTAURANT_INFO -> tab.text = "식당 정보"
RestaurantDetailPagerAdapter.PHOTO -> tab.text = "사진"
RestaurantDetailPagerAdapter.REVIEW -> tab.text = "후기"
}
}.attach()

}

fun changeCategory(category: Int) {
binding.restaurantDetailPager.currentItem = category
}


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
package org.gdsc.presentation.view.mypage.restaurantdetail

import android.graphics.Rect
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.ViewTreeObserver
import androidx.core.content.ContextCompat
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.chip.Chip
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.launch
import org.gdsc.presentation.R
import org.gdsc.presentation.databinding.FragmentRestaurantInfoBinding
import org.gdsc.presentation.model.RestaurantPhotoItem
import org.gdsc.presentation.utils.toPx
import org.gdsc.presentation.view.mypage.adapter.ImagePager
import org.gdsc.presentation.view.mypage.adapter.ImagePagerItem
import org.gdsc.presentation.view.mypage.adapter.RestaurantDetailPagerAdapter
import org.gdsc.presentation.view.mypage.adapter.RestaurantPhotoAdapter
import org.gdsc.presentation.view.mypage.adapter.RestaurantReviewAdapter
import org.gdsc.presentation.view.mypage.viewmodel.RestaurantDetailViewModel

@AndroidEntryPoint
class RestaurantInfoFragment : Fragment() {

private var _binding: FragmentRestaurantInfoBinding? = null
private val binding get() = _binding!!

private val viewModel: RestaurantDetailViewModel by activityViewModels()

private val photoAdapter = ImagePager {

}

private val restaurantReviewAdapter = RestaurantReviewAdapter {

}

private val restaurantPhotoAdapter = RestaurantPhotoAdapter {

}

override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
_binding = FragmentRestaurantInfoBinding.inflate(inflater, container, false)
return binding.root
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
setButtons()
setAdapter()
observeData()

}

private fun setButtons() {
binding.tvMoreReviews.setOnClickListener {
(parentFragment as RestaurantDetailFragment).changeCategory(RestaurantDetailPagerAdapter.REVIEW)
}
}

private fun observeData() {
viewLifecycleOwner.lifecycleScope.launch {
viewModel.restaurantInfo.collect { it ->
it?.let { notNullRestaurantInfo ->

notNullRestaurantInfo.apply {
recommendMenu.split("#").forEach {
if (it.isNotBlank()) {
binding.cgRecommendMenu.addView(newChip(it))
}
}

goWellWithLiquor.split("#").forEach {
if (it.isNotBlank()) {
binding.cgRecommendDrink.addView(newChip(it))
}
}
}
}
}
}

viewLifecycleOwner.lifecycleScope.launch {
viewModel.reviews.collect {
restaurantReviewAdapter.submitList(it.take(2))
}
}

viewLifecycleOwner.lifecycleScope.launch {
viewModel.restaurantInfo.collect {
it?.let { notNullRestaurantInfo ->
restaurantPhotoAdapter.submitList(
notNullRestaurantInfo.pictures.map { imageUrl ->
(RestaurantPhotoItem(imageUrl))
})
}
}
}
}

private fun setAdapter() {

binding.pagerPhotos.adapter = photoAdapter

photoAdapter.submitList(
listOf(
ImagePagerItem("https://picsum.photos/200/200"),
ImagePagerItem("https://picsum.photos/200/200"),
ImagePagerItem("https://picsum.photos/200/200"),
ImagePagerItem("https://picsum.photos/200/200"),
ImagePagerItem("https://picsum.photos/200/200"),
ImagePagerItem("https://picsum.photos/200/200"),
)
)

binding.rvReviews.adapter = restaurantReviewAdapter
binding.rvReviews.layoutManager = LinearLayoutManager(context)

val spanCount = 3

binding.rvPhotos.adapter = restaurantPhotoAdapter
binding.rvPhotos.layoutManager = GridLayoutManager(context, spanCount)
binding.rvPhotos.addItemDecoration(object : RecyclerView.ItemDecoration() {
override fun getItemOffsets(
outRect: Rect,
view: View,
parent: RecyclerView,
state: RecyclerView.State
) {
val margin = 4.toPx
outRect.bottom = margin
}
})


binding.root.viewTreeObserver.addOnGlobalLayoutListener(object :
ViewTreeObserver.OnGlobalLayoutListener {
override fun onGlobalLayout() {
binding.root.viewTreeObserver.removeOnGlobalLayoutListener(this)
val width = binding.root.width / 3
restaurantPhotoAdapter.setSize(width, width)
restaurantPhotoAdapter.notifyDataSetChanged()
}
})

}

private fun newChip(text: String): Chip {
return Chip(requireContext()).apply {
this.text = text

chipBackgroundColor = ContextCompat.getColorStateList(
requireContext(),
R.color.white
)
chipStrokeColor = ContextCompat.getColorStateList(
requireContext(),
R.color.grey200
)
chipStrokeWidth = 1f

this.isCheckable = false

}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package org.gdsc.presentation.view.mypage.restaurantdetail

import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.lifecycleScope
import androidx.viewpager2.widget.ViewPager2
import com.bumptech.glide.Glide
import kotlinx.coroutines.launch
import org.gdsc.domain.Empty
import org.gdsc.presentation.databinding.FragmentRestaurantPhotoDetailBinding
import org.gdsc.presentation.view.MainActivity
import org.gdsc.presentation.view.mypage.adapter.ImageSlider
import org.gdsc.presentation.view.mypage.adapter.ImageSliderItem
import org.gdsc.presentation.view.mypage.viewmodel.RestaurantDetailViewModel

class RestaurantPhotoDetailFragment : Fragment() {

private var _binding: FragmentRestaurantPhotoDetailBinding? = null
private val binding get() = _binding!!

private val viewModel: RestaurantDetailViewModel by activityViewModels()

private val parentActivity by lazy { activity as MainActivity }

private val imageSlider = ImageSlider(

)

override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
_binding = FragmentRestaurantPhotoDetailBinding.inflate(inflater, container, false)
return binding.root
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)

setAdapter()
observeData()

}

private fun observeData() {
viewLifecycleOwner.lifecycleScope.launch {
viewModel.reviews.collect { reviewList ->
if (reviewList.isNotEmpty()) {

// TODO: to be dynamic
val firstReview = reviewList.first()
with(binding.reviewItem) {
Glide.with(root)
.load(firstReview.reviewerImageUrl)
.into(ivProfile)

tvNickname.text = firstReview.userName
tvContent.text = firstReview.reviewContent
}
}
}
}
}

private fun setAdapter() {
binding.imageSlider.adapter = imageSlider

viewModel.restaurantInfo.value?.let { restaurantInfo ->

binding.imageSlider.registerOnPageChangeCallback(object :
ViewPager2.OnPageChangeCallback() {
override fun onPageSelected(position: Int) {
super.onPageSelected(position)
parentActivity.changeToolbarTitle("${position + 1} / ${restaurantInfo.pictures.size}")
}
})

imageSlider.submitList(restaurantInfo.pictures.map {
ImageSliderItem(it)
})
}
}

override fun onDestroyView() {
super.onDestroyView()
parentActivity.changeToolbarTitle(String.Empty)
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package org.gdsc.presentation.view.mypage.restaurantdetail

import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.ViewTreeObserver
import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.GridLayoutManager
import dagger.hilt.android.AndroidEntryPoint
import org.gdsc.presentation.databinding.FragmentRestaurantPhotoBinding
import org.gdsc.presentation.model.RestaurantPhotoItem
import org.gdsc.presentation.view.mypage.adapter.RestaurantPhotoAdapter

@AndroidEntryPoint
class RestaurantPhotoFragment : Fragment() {

private var _binding: FragmentRestaurantPhotoBinding? = null
private val binding get() = _binding!!

override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
_binding = FragmentRestaurantPhotoBinding.inflate(inflater, container, false)
return binding.root
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
setAdapter()
}

private fun setAdapter() {
val restaurantPhotoAdapter = RestaurantPhotoAdapter {
findNavController().navigate(RestaurantDetailFragmentDirections.actionRestaurantDetailFragmentToRestaurantPhotoDetailFragment())
}

val spanCount = 3

binding.rvPhotos.adapter = restaurantPhotoAdapter
binding.rvPhotos.layoutManager = GridLayoutManager(context, spanCount)

binding.root.viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
override fun onGlobalLayout() {
binding.root.viewTreeObserver.removeOnGlobalLayoutListener(this)
val width = binding.root.width / 3
restaurantPhotoAdapter.setSize(width, width)
restaurantPhotoAdapter.notifyDataSetChanged()
}
})


// TODO: supposed to be real data
restaurantPhotoAdapter.submitList(
listOf(
RestaurantPhotoItem("https://gdsc-jmt.s3.ap-northeast-2.amazonaws.com/profileImg/defaultImg/Default+image.png"),
RestaurantPhotoItem("https://gdsc-jmt.s3.ap-northeast-2.amazonaws.com/profileImg/defaultImg/Default+image.png"),
RestaurantPhotoItem("https://gdsc-jmt.s3.ap-northeast-2.amazonaws.com/profileImg/defaultImg/Default+image.png"),
RestaurantPhotoItem("https://gdsc-jmt.s3.ap-northeast-2.amazonaws.com/profileImg/defaultImg/Default+image.png"),
RestaurantPhotoItem("https://gdsc-jmt.s3.ap-northeast-2.amazonaws.com/profileImg/defaultImg/Default+image.png"),
RestaurantPhotoItem("https://gdsc-jmt.s3.ap-northeast-2.amazonaws.com/profileImg/defaultImg/Default+image.png"),
RestaurantPhotoItem("https://gdsc-jmt.s3.ap-northeast-2.amazonaws.com/profileImg/defaultImg/Default+image.png"),
RestaurantPhotoItem("https://gdsc-jmt.s3.ap-northeast-2.amazonaws.com/profileImg/defaultImg/Default+image.png"),
RestaurantPhotoItem("https://gdsc-jmt.s3.ap-northeast-2.amazonaws.com/profileImg/defaultImg/Default+image.png"),
RestaurantPhotoItem("https://gdsc-jmt.s3.ap-northeast-2.amazonaws.com/profileImg/defaultImg/Default+image.png"),
RestaurantPhotoItem("https://gdsc-jmt.s3.ap-northeast-2.amazonaws.com/profileImg/defaultImg/Default+image.png"),
RestaurantPhotoItem("https://gdsc-jmt.s3.ap-northeast-2.amazonaws.com/profileImg/defaultImg/Default+image.png"),
RestaurantPhotoItem("https://gdsc-jmt.s3.ap-northeast-2.amazonaws.com/profileImg/defaultImg/Default+image.png"),
RestaurantPhotoItem("https://gdsc-jmt.s3.ap-northeast-2.amazonaws.com/profileImg/defaultImg/Default+image.png"),
RestaurantPhotoItem("https://gdsc-jmt.s3.ap-northeast-2.amazonaws.com/profileImg/defaultImg/Default+image.png"),
RestaurantPhotoItem("https://gdsc-jmt.s3.ap-northeast-2.amazonaws.com/profileImg/defaultImg/Default+image.png"),
)
)
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package org.gdsc.presentation.view.mypage.restaurantdetail

import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.LinearLayoutManager
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.launch
import org.gdsc.presentation.databinding.FragmentRestaurantReviewBinding
import org.gdsc.presentation.view.mypage.adapter.RestaurantReviewAdapter
import org.gdsc.presentation.view.mypage.viewmodel.RestaurantDetailViewModel

@AndroidEntryPoint
class RestaurantReviewFragment : Fragment() {

private var _binding: FragmentRestaurantReviewBinding? = null
private val binding get() = _binding!!

private val viewModel: RestaurantDetailViewModel by activityViewModels()

private val restaurantReviewAdapter = RestaurantReviewAdapter {

}

override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
_binding = FragmentRestaurantReviewBinding.inflate(inflater, container, false)
return binding.root
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
setAdapter()
observeData()
}

private fun observeData() {
viewLifecycleOwner.lifecycleScope.launch {
viewModel.reviews.collect {
restaurantReviewAdapter.submitList(it)
}
}
}

private fun setAdapter() {

binding.rvReviews.adapter = restaurantReviewAdapter
binding.rvReviews.layoutManager = LinearLayoutManager(context)

}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package org.gdsc.presentation.view.mypage.viewmodel

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.launch
import org.gdsc.domain.model.Review
import org.gdsc.domain.model.UserInfo
import org.gdsc.domain.model.response.RestaurantInfoResponse
import org.gdsc.domain.usecase.GetRestaurantInfoUseCase
import org.gdsc.domain.usecase.GetRestaurantReviewsUseCase
import org.gdsc.domain.usecase.user.GetOtherUserInfoUseCase
import org.gdsc.presentation.JmtLocationManager
import javax.inject.Inject

@HiltViewModel
class RestaurantDetailViewModel
@Inject constructor(
private val jmtLocationManager: JmtLocationManager,
private val getRestaurantInfoUseCase: GetRestaurantInfoUseCase,
private val getOtherUserInfoUseCase: GetOtherUserInfoUseCase,
private val getRestaurantReviewsUseCase: GetRestaurantReviewsUseCase
): ViewModel() {

private var _restaurantInfo: MutableStateFlow<RestaurantInfoResponse?> = MutableStateFlow(null)
val restaurantInfo: StateFlow<RestaurantInfoResponse?>
get() = _restaurantInfo

private var _authorInfo: MutableStateFlow<UserInfo?> = MutableStateFlow(null)
val authorInfo: StateFlow<UserInfo?>
get() = _authorInfo

private var _reviews: MutableStateFlow<List<Review>> = MutableStateFlow(emptyList())
val reviews: StateFlow<List<Review>>
get() = _reviews


init {
viewModelScope.launch {

val currentLocation = jmtLocationManager.getCurrentLocation()
val restaurantInfo = getRestaurantInfoUseCase(1, currentLocation?.longitude.toString(), currentLocation?.latitude.toString())
_restaurantInfo.value = restaurantInfo

val userInfo = getOtherUserInfoUseCase(restaurantInfo.userId)
_authorInfo.value = userInfo

val reviews = getRestaurantReviewsUseCase(1)
_reviews.value = reviews

}

}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<selector >
<item xmlns:android="http://schemas.android.com/apk/res/android">
<shape android:shape="rectangle">
<solid android:color="@color/grey100" />
<corners android:radius="12dp" />
</shape>
</item>
</selector>
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<selector >
<item xmlns:android="http://schemas.android.com/apk/res/android">
<shape android:shape="rectangle">
<solid android:color="@color/grey100" />
<corners android:radius="4dp" />
</shape>
</item>
</selector>
15 changes: 15 additions & 0 deletions presentation/src/main/res/drawable/bg_selected_tab_item.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:bottom="4dp"
android:left="4dp"
android:right="4dp"
android:top="4dp">

<shape android:shape="rectangle">
<solid android:color="@color/white" />
<corners android:radius="6dp" />
</shape>

</item>
</layer-list>
4 changes: 4 additions & 0 deletions presentation/src/main/res/drawable/bg_tab_item.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/bg_selected_tab_item" android:state_selected="true"/>
</selector>
Binary file added presentation/src/main/res/drawable/ic_thumb_up.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
192 changes: 192 additions & 0 deletions presentation/src/main/res/layout/fragment_restaurant_detail.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto">

<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginHorizontal="20dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="@id/ct_review_foam"
android:layout_marginBottom="22dp">

<TextView
android:id="@+id/tv_restaurant_name"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
style="@style/title_small_bold"
android:textColor="@color/grey900"
tools:text="용용선생 노원점"
/>

<LinearLayout
android:id="@+id/ct_distance_and_category"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_restaurant_name"
android:layout_marginTop="4dp">

<TextView
android:id="@+id/tv_distance"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/text_large_medium"
android:textColor="@color/grey900"
tools:text="위치에서 300m" />

<View
android:layout_width="1dp"
android:layout_height="12dp"
android:layout_gravity="center_vertical"
android:background="@color/grey200"
android:layout_marginHorizontal="12dp"
/>

<TextView
android:id="@+id/tv_category"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/text_large_medium"
android:textColor="@color/grey900"
tools:text="중식"/>

</LinearLayout>

<LinearLayout
android:id="@+id/ct_address"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/ct_distance_and_category"
android:layout_marginTop="4dp">

<TextView
android:id="@+id/tv_address"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/text_medium_medium"
android:textColor="@color/grey700"
tools:text="서울시 노원구 동일로 32-1길, 101호" />

<TextView
android:id="@+id/tv_copy"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="주소복사"
android:layout_marginStart="16dp"
style="@style/text_small_medium"
android:textColor="@color/main300"
/>

</LinearLayout>

<ImageView
android:id="@+id/iv_profile"
android:src="@drawable/mock_profile"
android:layout_width="20dp"
android:layout_height="20dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/ct_address"
android:layout_marginTop="16dp"
android:contentDescription="profile" />

<TextView
android:id="@+id/tv_nickname"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintStart_toEndOf="@id/iv_profile"
app:layout_constraintTop_toTopOf="@id/iv_profile"
app:layout_constraintBottom_toBottomOf="@id/iv_profile"
android:layout_marginStart="4dp"
style="@style/text_medium_medium"
android:textColor="@color/grey900"
tools:text="Blaire"/>

<com.google.android.material.tabs.TabLayout
android:id="@+id/tab_layout"
android:layout_width="0dp"
android:layout_height="48dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_nickname"
android:background="@drawable/bg_rounded_border_4_grey100"
app:tabRippleColor="@null"
app:tabTextColor="@color/grey400"
app:tabSelectedTextColor="@color/main500"
app:tabIndicator="@null"
app:tabTextAppearance="@style/text_medium_bold"
app:tabBackground="@drawable/bg_tab_item"
android:animateLayoutChanges="true"
android:layout_marginTop="16dp">

</com.google.android.material.tabs.TabLayout>

<androidx.viewpager2.widget.ViewPager2
android:id="@+id/restaurant_detail_pager"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/tab_layout"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_marginTop="16dp"
/>

</androidx.constraintlayout.widget.ConstraintLayout>

<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/ct_review_foam"
android:layout_width="0dp"
android:layout_height="88dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent">

<View
android:layout_width="0dp"
android:layout_height="1dp"
android:background="@color/grey100"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"/>

<org.gdsc.presentation.view.custom.JmtEditText
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toStartOf="@id/btn_write_review"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_marginStart="20dp"
android:layout_marginEnd="4dp"
android:layout_marginTop="14dp"
android:layout_marginBottom="24dp"
app:jmtEditTextHint="방문 후기를 작성해 보세요!"
/>

<androidx.appcompat.widget.AppCompatButton
android:id="@+id/btn_write_review"
android:text="등록"
android:layout_width="60dp"
android:layout_height="50dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginTop="14dp"
android:layout_marginEnd="20dp"
style="@style/JmtButtonMain"
android:textAppearance="@style/text_medium_medium"/>

</androidx.constraintlayout.widget.ConstraintLayout>

</androidx.constraintlayout.widget.ConstraintLayout>
143 changes: 143 additions & 0 deletions presentation/src/main/res/layout/fragment_restaurant_info.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto">

<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">

<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">

<androidx.viewpager2.widget.ViewPager2
android:id="@+id/pager_photos"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />

<TextView
android:id="@+id/tv_menu"
android:text="메인메뉴"
android:layout_width="0dp"
android:layout_height="wrap_content"
style="@style/text_medium_medium"
android:textColor="@color/grey700"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/pager_photos"
android:layout_marginTop="24dp" />

<com.google.android.material.chip.ChipGroup
android:id="@+id/cg_recommend_menu"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_menu">
</com.google.android.material.chip.ChipGroup>

<TextView
android:id="@+id/tv_drink"
android:text="술과 함께 즐길 수 있어요 🍻"
android:layout_width="0dp"
android:layout_height="wrap_content"
style="@style/text_medium_medium"
android:textColor="@color/grey700"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/cg_recommend_menu"
android:layout_marginTop="20dp" />

<com.google.android.material.chip.ChipGroup
android:id="@+id/cg_recommend_drink"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_drink">
</com.google.android.material.chip.ChipGroup>

<View
android:id="@+id/dv_first"
android:layout_width="0dp"
android:layout_height="8dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/cg_recommend_drink"
android:layout_marginTop="24dp"
android:background="@color/grey100"/>

<TextView
android:id="@+id/tv_reviews"
android:text="멤버의 추천 한마디 ✍️"
android:layout_width="0dp"
android:layout_height="wrap_content"
style="@style/text_medium_medium"
android:textColor="@color/grey700"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/dv_first"
android:layout_marginTop="20dp" />

<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_reviews"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_reviews" />

<TextView
android:id="@+id/tv_more_reviews"
android:text="멤버 후기 더보기+"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/rv_reviews"
android:layout_marginTop="24dp"
android:textColor="@color/main400"
style="@style/text_medium_medium"/>

<View
android:id="@+id/dv_second"
android:layout_width="0dp"
android:layout_height="8dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_more_reviews"
android:layout_marginTop="20dp"
android:background="@color/grey100"/>

<TextView
android:id="@+id/tv_photos"
android:text="맛집 사진"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/dv_second"
android:layout_marginTop="24dp"/>

<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_photos"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_photos"
android:layout_marginTop="16dp"/>


</androidx.constraintlayout.widget.ConstraintLayout>

</androidx.core.widget.NestedScrollView>

</androidx.constraintlayout.widget.ConstraintLayout>
27 changes: 27 additions & 0 deletions presentation/src/main/res/layout/fragment_restaurant_photo.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
tools:context=".view.mypage.restaurantdetail.RestaurantPhotoFragment">

<TextView
android:id="@+id/tv_photos"
android:text="맛집 사진"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />

<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_photos"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_photos"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_marginTop="16dp"/>

</androidx.constraintlayout.widget.ConstraintLayout>
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
tools:context=".view.mypage.restaurantdetail.RestaurantPhotoDetailFragment">

<androidx.viewpager2.widget.ViewPager2
android:id="@+id/image_slider"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginTop="108dp"/>

<include
android:id="@+id/review_item"
layout="@layout/item_review_restaurant"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/image_slider"
android:layout_marginHorizontal="20dp"
android:layout_marginTop="20dp"/>

</androidx.constraintlayout.widget.ConstraintLayout>
29 changes: 29 additions & 0 deletions presentation/src/main/res/layout/fragment_restaurant_review.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
tools:context=".view.mypage.restaurantdetail.RestaurantReviewFragment">

<TextView
android:id="@+id/tv_reviews"
android:text="멤버의 추천 한마디 ✍️"
android:layout_width="0dp"
android:layout_height="wrap_content"
style="@style/text_medium_medium"
android:textColor="@color/grey700"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"/>

<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_reviews"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_reviews"
app:layout_constraintBottom_toBottomOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>
32 changes: 32 additions & 0 deletions presentation/src/main/res/layout/item_image_page.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">

<org.gdsc.presentation.view.custom.FlexibleCornerImageView
android:id="@+id/image_view"
android:layout_width="350dp"
android:layout_height="350dp"
android:scaleType="center"
app:all_corner_radius="10dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"/>

<TextView
android:id="@+id/tv_sequence"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="@id/image_view"
app:layout_constraintBottom_toBottomOf="@id/image_view"
android:layout_marginEnd="14dp"
android:layout_marginBottom="14dp"
android:textColor="@color/grey200"
style="@style/text_small_medium"
tools:text="1/10"
/>

</androidx.constraintlayout.widget.ConstraintLayout>
12 changes: 12 additions & 0 deletions presentation/src/main/res/layout/item_image_slide.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<ImageView
android:id="@+id/image_view"
xmlns:android="http://schemas.android.com/apk/res/android"
android:scaleType="centerCrop"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintDimensionRatio="1:1"
xmlns:app="http://schemas.android.com/apk/res-auto">


</ImageView>
20 changes: 20 additions & 0 deletions presentation/src/main/res/layout/item_photo_restaurant.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto">

<org.gdsc.presentation.view.custom.FlexibleCornerImageView
android:id="@+id/iv_photo"
android:layout_width="110dp"
android:layout_height="110dp"
android:scaleType="centerCrop"
android:background="@drawable/bg_rounded_border_8_grey200"
app:all_corner_radius="5dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>
69 changes: 69 additions & 0 deletions presentation/src/main/res/layout/item_review_restaurant.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:background="@drawable/bg_rounded_border_12_grey200"
android:padding="16dp"
android:layout_marginTop="16dp">

<ImageView
android:id="@+id/iv_profile"
android:layout_width="20dp"
android:layout_height="20dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:src="@drawable/mock_profile"/>

<TextView
android:id="@+id/tv_nickname"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintStart_toEndOf="@id/iv_profile"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginStart="6dp"
style="@style/text_medium_medium"
android:textColor="@color/grey900"
tools:text="권나무방구뿡뿡"/>

<TextView
android:id="@+id/tv_content"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/iv_profile"
android:layout_marginTop="6dp"
style="@style/text_medium_medium"
android:textColor="@color/grey900"
tools:text="와 정말 맛있더군요 여기 안가면 바보입니다 하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하"/>


<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintEnd_toStartOf="@id/iv_thumb_up"
app:layout_constraintTop_toBottomOf="@id/tv_content"
app:layout_constraintBottom_toBottomOf="parent"
android:text="리뷰가 도움이 됐어요"
android:layout_marginEnd="4dp"
android:layout_marginTop="8dp"
style="@style/text_small_medium"
android:textColor="@color/grey500"
/>

<ImageView
android:id="@+id/iv_thumb_up"
android:src="@drawable/ic_thumb_up"
android:layout_width="16dp"
android:layout_height="16dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_content"
android:layout_marginTop="8dp"
/>




</androidx.constraintlayout.widget.ConstraintLayout>
17 changes: 17 additions & 0 deletions presentation/src/main/res/navigation/main_nav_graph.xml
Original file line number Diff line number Diff line change
@@ -38,6 +38,9 @@
<action
android:id="@+id/action_myPageFragment_to_settingsFragment"
app:destination="@id/settings_fragment" />
<action
android:id="@+id/action_my_page_fragment_to_restaurantDetailFragment"
app:destination="@id/restaurantDetailFragment" />
</fragment>
<fragment
android:id="@+id/search_restaurant_location_info_fragment"
@@ -162,5 +165,19 @@
android:name="url"
app:argType="string" />
</fragment>
<fragment
android:id="@+id/restaurantDetailFragment"
android:name="org.gdsc.presentation.view.mypage.restaurantdetail.RestaurantDetailFragment"
android:label="fragment_restaurant_detail"
tools:layout="@layout/fragment_restaurant_detail" >
<action
android:id="@+id/action_restaurantDetailFragment_to_restaurantPhotoDetailFragment"
app:destination="@id/restaurantPhotoDetailFragment" />
</fragment>
<fragment
android:id="@+id/restaurantPhotoDetailFragment"
android:name="org.gdsc.presentation.view.mypage.restaurantdetail.RestaurantPhotoDetailFragment"
android:label="fragment_restaurant_photo_detail"
tools:layout="@layout/fragment_restaurant_photo_detail" />

</navigation>
2 changes: 1 addition & 1 deletion presentation/src/main/res/values/colors.xml
Original file line number Diff line number Diff line change
@@ -18,7 +18,7 @@
<color name="main800">#802000</color>
<color name="main900">#4D1300</color>

<color name="grey100">#F1F3F4</color>
<color name="grey100">#F6F8F8</color>
<color name="grey200">#D4DADE</color>
<color name="grey300">#B7C1C8</color>
<color name="grey400">#9AA9B2</color>

0 comments on commit 04964e5

Please sign in to comment.