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

[FEAT] 4주차 과제 완료 #8

Open
wants to merge 7 commits into
base: develop
Choose a base branch
from
Open
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
16 changes: 16 additions & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
import java.util.Properties

plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.kotlin.android)
alias(libs.plugins.kotlin.compose)
alias(libs.plugins.kotlin.serialization)
}

val properties = Properties().apply{
load(project.rootProject.file("local.properties").inputStream())
}

android {
Expand All @@ -16,6 +23,7 @@ android {
versionName = "1.0"

testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
buildConfigField("String","BASE_URL", properties["base.url"].toString())
}

buildTypes {
Expand All @@ -36,6 +44,7 @@ android {
}
buildFeatures {
compose = true
buildConfig = true
}
}

Expand All @@ -61,4 +70,11 @@ dependencies {
androidTestImplementation(libs.androidx.ui.test.junit4)
debugImplementation(libs.androidx.ui.tooling)
debugImplementation(libs.androidx.ui.test.manifest)
// Network
implementation(platform(libs.okhttp.bom))
implementation(libs.okhttp)
implementation(libs.okhttp.logging.interceptor)
implementation(libs.retrofit)
implementation(libs.retrofit.kotlin.serialization.converter)
implementation(libs.kotlinx.serialization.json)
}
1 change: 1 addition & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.ANDANDROID"
android:usesCleartextTraffic="true"
tools:targetApi="31">
<activity
android:name=".MainActivity"
Expand Down
40 changes: 40 additions & 0 deletions app/src/main/java/org/sopt/and/api/ApiFactory.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package org.sopt.and.api

import com.jakewharton.retrofit2.converter.kotlinx.serialization.asConverterFactory
import kotlinx.serialization.json.Json
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import org.sopt.and.BuildConfig
import org.sopt.and.api.service.HobbyService
import org.sopt.and.api.service.LoginService
import org.sopt.and.api.service.UserService
import retrofit2.Retrofit

object ApiFactory {
private const val BASE_URL: String = BuildConfig.BASE_URL

Choose a reason for hiding this comment

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

BASE_URL을 바로 사용하지 않고 value로 저장하신 이유가 무엇인가요?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

value로 저장하고 쓰는게 습관이 되어서 .. 보니까 저장 안하고도 쓸 수 있었군요 🥲
수정하겠습니다 !


private val loggingInterceptor = HttpLoggingInterceptor().apply {
level = HttpLoggingInterceptor.Level.BODY
}

private val client = OkHttpClient.Builder()
.addInterceptor(loggingInterceptor)
.build()

val retrofit: Retrofit by lazy {
Retrofit.Builder()
.baseUrl(BASE_URL)
.client(client)
.addConverterFactory(Json.asConverterFactory("application/json".toMediaType()))
.build()
}

inline fun <reified T> create(): T = retrofit.create(T::class.java)
}

object ServicePool {
val userService = ApiFactory.create<UserService>()
val loginService = ApiFactory.create<LoginService>()
val hobbyService = ApiFactory.create<HobbyService>()
}
10 changes: 10 additions & 0 deletions app/src/main/java/org/sopt/and/api/dto/ErrorDto.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package org.sopt.and.api.dto

import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable

@Serializable
data class ResponseErrorDto(
@SerialName("code")
val code: String
)
16 changes: 16 additions & 0 deletions app/src/main/java/org/sopt/and/api/dto/HobbyDto.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package org.sopt.and.api.dto

import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable

@Serializable
data class ResponseHobbySuccessDto(
@SerialName("result")

Choose a reason for hiding this comment

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

다른 api들에서도 response가 result로 감싸져서 오기 때문에 BaseReposne를 만들어서 사용하는 것도 고려해보면 좋을 것 같아요!

val result: HobbyData
)

@Serializable
data class HobbyData(
@SerialName("hobby")
val hobby: String
)
24 changes: 24 additions & 0 deletions app/src/main/java/org/sopt/and/api/dto/LoginDto.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package org.sopt.and.api.dto

import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable

@Serializable
data class ResponseLoginSuccessDto(

Choose a reason for hiding this comment

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

response와 request를 같은 파일에서 관리하시는데 저는 따로 파일을 만들었거든요!! 나중에 어떤게 더 좋을지 이야기해보는 것도 좋을 것 같네요😊

Copy link
Contributor Author

Choose a reason for hiding this comment

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

분리하는게 더 좋을 것 같아요 ㅎㅎ .. 수정하겠습니다 !

@SerialName("result")
val result: LoginData
)

@Serializable
data class LoginData(
@SerialName("token")
val token: String
)

@Serializable
data class RequestLoginDto(
@SerialName("username")
val username: String,
@SerialName("password")
val password: String
)
26 changes: 26 additions & 0 deletions app/src/main/java/org/sopt/and/api/dto/UserDto.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package org.sopt.and.api.dto

import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable

@Serializable
data class ResponseUserSuccessDto(
@SerialName("result")
val result: UserData
)

@Serializable
data class UserData(
@SerialName("no")
val no: Int
Copy link
Contributor

Choose a reason for hiding this comment

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

더 직관적인 이름을 사용해도 좋을 것 같아요!
단순히 no라고만 네이밍 하면 어떤 것을 의미하는지 모호해지니까요!
꼭 서버에서 내려오는 이름이랑 동일하게 가져가야할 필요는 없습니다.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

무조건 서버에서 내려오는 이름이랑 동일하게만 사용했었는데 .. 직관적인 네이밍을 해도 되는거였군요 ! 수정해보겠습니다 !!

)

@Serializable
data class RequestUserDto(
@SerialName("username")
val username: String,
@SerialName("password")
val password: String,
@SerialName("hobby")
val hobby: String
)
13 changes: 13 additions & 0 deletions app/src/main/java/org/sopt/and/api/service/HobbyService.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package org.sopt.and.api.service

import okhttp3.ResponseBody
import retrofit2.Call
import retrofit2.http.GET
import retrofit2.http.Header

interface HobbyService {
Copy link
Contributor

Choose a reason for hiding this comment

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

Service를 나누시는 기준이 무엇인지 궁금합니다.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

저는 보통 기능별로 나누는 편입니다 !
userService는 사용자 관련 데이터, loginService는 로그인 관련 데이터, .. 이렇게 쓰다보니 hobby는 사용자 관련 데이터니까 userService에 넣는게 맞았던 것 같네요 🥲
수정하겠습니다 !!

@GET("/user/my-hobby")
fun getMyHobby(
@Header("token") token: String
): Call<ResponseBody>
}
14 changes: 14 additions & 0 deletions app/src/main/java/org/sopt/and/api/service/LoginService.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package org.sopt.and.api.service

import okhttp3.ResponseBody
import org.sopt.and.api.dto.RequestLoginDto
import retrofit2.Call
import retrofit2.http.Body
import retrofit2.http.POST

interface LoginService {
@POST("/login")
fun postLogin(
@Body requestLogin: RequestLoginDto
): Call<ResponseBody>
}
14 changes: 14 additions & 0 deletions app/src/main/java/org/sopt/and/api/service/UserService.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package org.sopt.and.api.service

import okhttp3.ResponseBody
import org.sopt.and.api.dto.RequestUserDto
import retrofit2.Call
import retrofit2.http.Body
import retrofit2.http.POST

interface UserService {
@POST("/user")
fun postUser(
@Body requestUser: RequestUserDto
): Call<ResponseBody>
}
2 changes: 1 addition & 1 deletion app/src/main/java/org/sopt/and/component/BuyTextButton.kt
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import org.sopt.and.R
@Composable
fun BuyTextButton(
labelText: String,
onClick: ()->Unit
onClick: () -> Unit
) {
Column {
Text(
Expand Down
2 changes: 1 addition & 1 deletion app/src/main/java/org/sopt/and/component/MyPageItem.kt
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ fun MyPageItem(
.padding(bottom = 80.dp)
.fillMaxWidth(),
horizontalAlignment = Alignment.CenterHorizontally
){
) {
Image(
painter = icon,
contentDescription = "",
Expand Down
5 changes: 2 additions & 3 deletions app/src/main/java/org/sopt/and/component/bar/BottomBar.kt
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ import androidx.compose.ui.unit.TextUnit
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.navigation.NavHostController
import org.sopt.and.navigate.Routes
import org.sopt.and.navigate.ScreenTab

@Composable
Expand Down Expand Up @@ -55,8 +54,8 @@ fun BottomBar(

BottomTab(
onClick = {
navController.navigate(tab.route){
popUpTo(tab.route){
navController.navigate(tab.route) {
popUpTo(tab.route) {
inclusive = true
}
}
Expand Down
2 changes: 1 addition & 1 deletion app/src/main/java/org/sopt/and/component/bar/TopBar.kt
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ fun TopBar(modifier: Modifier = Modifier) {
modifier = Modifier.width(100.dp)
)

Row{
Row {
Image(
painter = painterResource(R.drawable.outline_cast_connected_24),
contentDescription = "",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ fun IDTextField(
onValueChange: (String) -> Unit,
placeholder: String,
modifier: Modifier = Modifier
){
) {
TextField(
value = value,
onValueChange = onValueChange,
Expand Down
33 changes: 27 additions & 6 deletions app/src/main/java/org/sopt/and/navigate/NavGraph.kt
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,19 @@ import androidx.navigation.compose.composable
import androidx.navigation.compose.currentBackStackEntryAsState
import org.sopt.and.component.bar.BottomBar
import org.sopt.and.ui.home.HomeScreen
import org.sopt.and.ui.home.HomeViewModel
import org.sopt.and.ui.my.MyScreen
import org.sopt.and.ui.my.MyViewModel
import org.sopt.and.ui.search.SearchScreen
import org.sopt.and.ui.signin.SignInScreen
import org.sopt.and.ui.signin.SignInViewModel
import org.sopt.and.ui.signup.SignUpScreen
import org.sopt.and.ui.signup.SignUpViewModel

@Composable
fun NavGraph(navController: NavHostController){
fun NavGraph(navController: NavHostController) {
val signUpViewModel: SignUpViewModel = viewModel()
val signInViewModel: SignInViewModel = viewModel()
val myViewModel: MyViewModel = viewModel()

Choose a reason for hiding this comment

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

뷰모델을 navGraph에서 관리하시는 이유가 있나요? 각 뷰에서 관리하는게 더 좋을 것 같다는 생각이 드는데 혹시 다른 이유가 있으신지 궁금합니다!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

전에 데이터를 넘기는 방법으로 한 뷰에서 두개의 viewmodel을 부른 적이 있었는데 그때 navgraph에서 뷰모델을 관리했었어요 ! 근데 이제 데이터를 넘기는 로직을 변경했으니 viewmodel 로직도 각 뷰에서 관리하는 방법으로 변경해야겠네요 감사합니다 !!


val navBackStackEntry by navController.currentBackStackEntryAsState()
val currentRoute = navBackStackEntry?.destination?.route
Expand All @@ -37,7 +38,12 @@ fun NavGraph(navController: NavHostController){
val selectedScreen = ScreenTab.entries.find { it.route == currentRoute }
if (selectedScreen != null) {
BottomBar(selected = selectedScreen, navController = navController)
}else if (currentRoute in listOf(Routes.Home.route, Routes.My.route, Routes.Search.route)) {
} else if (currentRoute in listOf(
Routes.Home.route,
Routes.My.route,
Routes.Search.route
)
) {
BottomBar(selected = null, navController = navController)
}
}
Expand All @@ -49,9 +55,24 @@ fun NavGraph(navController: NavHostController){
.padding(paddingValues)
) {
NavHost(navController = navController, startDestination = Routes.SignIn.route) {
composable(Routes.SignIn.route) { SignInScreen(navController, signInViewModel = signInViewModel) }
composable(Routes.SignUp.route) { SignUpScreen(navController, signUpViewModel = signUpViewModel) }
composable(Routes.My.route) { MyScreen(navController, signInViewModel = signInViewModel) }
composable(Routes.SignIn.route) {
SignInScreen(
navController,
signInViewModel = signInViewModel
)
}
composable(Routes.SignUp.route) {
SignUpScreen(
navController,
signUpViewModel = signUpViewModel
)
}
composable(Routes.My.route) {
MyScreen(
navController,
myViewModel = myViewModel
)
}
composable(Routes.Search.route) { SearchScreen(navController) }
composable(Routes.Home.route) { HomeScreen(navController) }
}
Expand Down
Loading