Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[feature/#763] hot post #778

Merged
merged 7 commits into from
Jul 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package org.sopt.official.data.model.home

import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import org.sopt.official.domain.entity.home.HotPostEntity

@Serializable
data class HotPostResponse(
@SerialName("title")
val title: String,
@SerialName("content")
val content: String,
@SerialName("url")
val url: String
) {
fun toEntity(): HotPostEntity = HotPostEntity(
title = this.title,
content = this.content,
url = this.url
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,13 @@
*/
package org.sopt.official.data.repository.home

import javax.inject.Inject
import org.sopt.official.data.service.home.HomeService
import org.sopt.official.domain.entity.home.AppService
import org.sopt.official.domain.entity.home.HomeSection
import org.sopt.official.domain.entity.home.HotPostEntity
import org.sopt.official.domain.entity.home.SoptUser
import org.sopt.official.domain.repository.home.HomeRepository
import javax.inject.Inject

class DefaultHomeRepository @Inject constructor(
private val homeService: HomeService,
Expand All @@ -51,4 +52,10 @@ class DefaultHomeRepository @Inject constructor(
homeService.getAppService().map { it.toEntity() }
}
}

override suspend fun getHotPost(): Result<HotPostEntity> {
return runCatching {
homeService.getHotPost().toEntity()
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ package org.sopt.official.data.service.home
import org.sopt.official.data.model.home.AppServiceResponse
import org.sopt.official.data.model.home.DescriptionViewResponse
import org.sopt.official.data.model.home.HomeResponse
import org.sopt.official.data.model.home.HotPostResponse
import retrofit2.http.GET

interface HomeService {
Expand All @@ -38,4 +39,7 @@ interface HomeService {

@GET("user/app-service")
suspend fun getAppService(): List<AppServiceResponse>

@GET("user/playground/hot-post")
suspend fun getHotPost(): HotPostResponse
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package org.sopt.official.domain.entity.home

data class HotPostEntity(
val title: String = "",
val content: String = "",
val url: String = ""
)
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,12 @@ package org.sopt.official.domain.repository.home

import org.sopt.official.domain.entity.home.AppService
import org.sopt.official.domain.entity.home.HomeSection
import org.sopt.official.domain.entity.home.HotPostEntity
import org.sopt.official.domain.entity.home.SoptUser

interface HomeRepository {
suspend fun getMainView(): Result<SoptUser>
suspend fun getMainDescription(): Result<HomeSection>
suspend fun getAppService(): Result<List<AppService>>
suspend fun getHotPost(): Result<HotPostEntity>
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,6 @@ import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import dagger.hilt.android.AndroidEntryPoint
import java.io.Serializable
import javax.inject.Inject
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
Expand Down Expand Up @@ -81,6 +79,8 @@ import org.sopt.official.feature.poke.util.showPokeToast
import org.sopt.official.stamp.SoptampActivity
import org.sopt.official.util.AlertDialogOneButton
import org.sopt.official.webview.view.WebViewActivity
import java.io.Serializable
import javax.inject.Inject

@AndroidEntryPoint
class HomeActivity : AppCompatActivity() {
Expand Down Expand Up @@ -249,6 +249,7 @@ class HomeActivity : AppCompatActivity() {

viewModel.appServiceUiState.flowWithLifecycle(lifecycle).onEach {
with(binding) {
hotPost.isVisible = it.showHotboard
bottomDescription.isVisible = it.showPoke || it.showSoptamp
contentSoptamp.root.isVisible = it.showSoptamp
contentPoke.root.isVisible = it.showPoke
Expand All @@ -273,6 +274,18 @@ class HomeActivity : AppCompatActivity() {
}

private fun initBlock() {
viewModel.hotPost.flowWithLifecycle(lifecycle).onEach { hotPost ->
binding.hotTitle.text = hotPost.title
binding.hotContent.text = hotPost.content
binding.hotPost.setOnSingleClickListener {
tracker.track(type = EventType.CLICK, name = "hotpost", properties = mapOf("view_type" to args?.userStatus?.value))
val intent = Intent(this@HomeActivity, WebViewActivity::class.java).apply {
putExtra(WebViewActivity.INTENT_URL, hotPost.url)
}
startActivity(intent)
}
}.launchIn(lifecycleScope)

binding.smallBlockList.apply {
adapter = SmallBlockAdapter()
addItemDecoration(object : RecyclerView.ItemDecoration() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.google.firebase.messaging.FirebaseMessaging
import dagger.hilt.android.lifecycle.HiltViewModel
import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
Expand All @@ -48,6 +47,7 @@ import org.sopt.official.common.util.calculateGenerationStartDate
import org.sopt.official.common.util.systemNow
import org.sopt.official.common.util.toDefaultLocalDate
import org.sopt.official.domain.entity.home.HomeSection
import org.sopt.official.domain.entity.home.HotPostEntity
import org.sopt.official.domain.entity.home.SoptActiveGeneration
import org.sopt.official.domain.entity.home.SoptActiveRecord
import org.sopt.official.domain.entity.home.SoptUser
Expand All @@ -69,6 +69,7 @@ import org.sopt.official.feature.home.model.UserUiState
import org.sopt.official.feature.poke.UiState
import retrofit2.HttpException
import timber.log.Timber
import javax.inject.Inject

@HiltViewModel
class HomeViewModel @Inject constructor(
Expand Down Expand Up @@ -205,6 +206,10 @@ class HomeViewModel @Inject constructor(
val appServiceUiState: StateFlow<AppServiceUiState>
get() = _appServiceUiState

private val _hotPost = MutableStateFlow(HotPostEntity())
val hotPost
get() = _hotPost.asStateFlow()

fun initHomeUi(userStatus: UserStatus) {
viewModelScope.launch {
if (userStatus != UserStatus.UNAUTHENTICATED) {
Expand Down Expand Up @@ -252,12 +257,24 @@ class HomeViewModel @Inject constructor(
)
}

AppServiceEnum.HOTBOARD.name -> {
appService = appService.copy(
showHotboard = showActiveUser || showInactiveUser
)
}

else -> {}
}
}

_appServiceUiState.value = appService
}

homeRepository.getHotPost()
.onSuccess {
_hotPost.value = it
}
.onFailure(Timber::e)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ package org.sopt.official.feature.home.model

data class AppServiceUiState(
val showSoptamp: Boolean = false,
val showPoke: Boolean = false
val showPoke: Boolean = false,
val showHotboard: Boolean = false
)

enum class AppServiceEnum {
SOPTAMP,
POKE
POKE,
HOTBOARD
}
9 changes: 9 additions & 0 deletions app/src/main/res/drawable/ic_hot.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="12dp"
android:height="12dp"
android:viewportWidth="12"
android:viewportHeight="12">
<path
android:pathData="M10.5,6.99C10.5,5.514 9.243,3.482 8.743,2.565C8.665,2.422 8.455,2.427 8.384,2.572C8.26,2.829 8.081,3.199 7.878,3.574C7.823,3.677 7.674,3.686 7.606,3.591C7.013,2.758 6.416,1.834 6.02,1.105C5.952,0.98 5.776,0.963 5.685,1.073C4.029,3.083 2,5.161 2,7.354C2,9.198 3.125,10.511 4.77,10.995C4.883,11.028 4.97,10.897 4.891,10.812C4.597,10.495 4.427,10.071 4.427,9.605C4.427,8.89 5.346,7.564 5.903,6.901C6.083,6.688 6.416,6.688 6.596,6.901C7.154,7.564 8.073,8.89 8.073,9.605C8.073,10.055 7.914,10.465 7.64,10.778C7.562,10.866 7.652,10.997 7.765,10.959C9.39,10.413 10.499,8.989 10.499,7.159C10.499,7.143 10.498,7.127 10.498,7.111C10.499,7.071 10.499,7.031 10.499,6.991L10.5,6.99Z"
android:fillColor="#F77234"/>
</vector>
80 changes: 77 additions & 3 deletions app/src/main/res/layout/activity_sopt_main.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
<?xml version="1.0" encoding="utf-8"?><!--
MIT License

Copyright (c) 2023-2024 SOPT Makers
Expand Down Expand Up @@ -159,6 +158,81 @@
app:layout_constraintTop_toBottomOf="@id/tag_member_state"
tools:text="@string/main_subtitle_member" />

<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/hot_post"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="20dp"
android:background="@drawable/rectangle_radius_15"
android:backgroundTint="@color/mds_gray_800"
android:padding="16dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/subtitle">

<ImageView
android:id="@+id/hot_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="icon"
android:src="@drawable/ic_hot"
app:layout_constraintBottom_toBottomOf="@id/hot_mark"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@id/hot_mark" />

<TextView
android:id="@+id/hot_mark"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/suit_bold"
android:text="HOT"
android:textColor="@color/mds_secondary"
app:layout_constraintStart_toEndOf="@id/hot_icon"
app:layout_constraintTop_toTopOf="parent" />

<TextView
android:id="@+id/hot_title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="4dp"
android:layout_marginEnd="4dp"
android:ellipsize="end"
android:singleLine="true"
android:fontFamily="@font/suit_semibold"
android:textColor="@color/white"
app:layout_constraintEnd_toStartOf="@id/hot_arrow"
app:layout_constraintStart_toEndOf="@id/hot_mark"
app:layout_constraintTop_toTopOf="@id/hot_mark"
tools:text="핫게시물 제목" />

<TextView
android:id="@+id/hot_content"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="2dp"
android:layout_marginEnd="4dp"
android:ellipsize="end"
android:fontFamily="@font/suit_semibold"
android:singleLine="true"
android:textColor="@color/mds_gray_300"
app:layout_constraintEnd_toStartOf="@id/hot_arrow"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/hot_mark"
tools:text="핫게시물 본문 내용입니다.핫게시물 본문 내용입니다.핫게시물 본문 내용입니다." />

<ImageView
android:id="@+id/hot_arrow"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="icon"
android:src="@drawable/arrow_right"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:tint="@color/mds_gray_300" />

</androidx.constraintlayout.widget.ConstraintLayout>

<include
android:id="@+id/large_block"
layout="@layout/item_main_large"
Expand All @@ -169,7 +243,7 @@
android:layout_marginEnd="12dp"
app:layout_constraintEnd_toStartOf="@id/small_block_1"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/subtitle" />
app:layout_constraintTop_toBottomOf="@id/hot_post" />

<include
android:id="@+id/small_block_1"
Expand Down
2 changes: 1 addition & 1 deletion app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@
<string name="main_active_small_block_crew">모임/스터디</string>
<string name="main_active_small_block_crew_description">지금 열린 모임은?</string>
<string name="main_active_small_block_playground">Playground</string>
<string name="main_active_small_block_playground_description">지금 Hot한 글은?</string>
<string name="main_active_small_block_playground_description">모두와 연결되는 공간</string>
<string name="main_active_small_block_member">멤버</string>
<string name="main_active_small_block_member_description">궁금한 사람 찾아보기</string>
<string name="main_active_small_block_project">프로젝트</string>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ class AuthInterceptor @Inject constructor(
}

private fun isAccessTokenUsed(originalRequest: Request) = when {
originalRequest.url.encodedPath.contains("playground") -> false
originalRequest.url.encodedPath.contains("auth/playground") -> false
Copy link
Member Author

@chattymin chattymin Jul 24, 2024

Choose a reason for hiding this comment

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

playground가 들어가면 header를 넣지 않는 코드였습니다. 이 코드로 인해 403에러가 발생하고 있었습니다.
이번에 구현한 api에 playground가 들어가지만, header가 필요해 수정했습니다.
api명세서를 전부 뒤져보니 playground가 들어가는 api가 auth/playground 만 존재하여 해당 방법으로 수정했습니다.

originalRequest.url.encodedPath.contains("availability") -> false
else -> true
}
Expand Down