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/#9: week4 compose 과제 구현 #12

Open
wants to merge 21 commits into
base: develop-compose
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
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
28 changes: 28 additions & 0 deletions app/build.gradle
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
plugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.android'
id 'org.jetbrains.kotlin.plugin.serialization' version '1.9.0'
id 'kotlin-parcelize'
}

Properties properties = new Properties()
properties.load(project.rootProject.file('local.properties').newDataInputStream())

android {
namespace 'com.sopt.now.compose'
compileSdk 34
Expand All @@ -15,6 +20,8 @@ android {
versionName "1.0"

testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
buildConfigField "String", "AUTH_BASE_URL", properties["auth.base.url"]

vectorDrawables {
useSupportLibrary true
}
Expand All @@ -36,6 +43,7 @@ android {
buildFeatures {
compose true
viewBinding true
buildConfig true
}
composeOptions {
kotlinCompilerExtensionVersion '1.5.1'
Expand Down Expand Up @@ -69,4 +77,24 @@ dependencies {
androidTestImplementation 'androidx.compose.ui:ui-test-junit4'
debugImplementation 'androidx.compose.ui:ui-tooling'
debugImplementation 'androidx.compose.ui:ui-test-manifest'

//Gson
implementation "com.google.code.gson:gson:2.8.9"

// Glide
implementation("com.github.bumptech.glide:compose:1.0.0-beta01")

// retrofit2
implementation("com.squareup.retrofit2:retrofit:2.11.0")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.0")
implementation("com.jakewharton.retrofit:retrofit2-kotlinx-serialization-converter:1.0.0")
implementation("androidx.lifecycle:lifecycle-livedata-ktx:2.4.0")

// define a BOM and its version
implementation(platform("com.squareup.okhttp3:okhttp-bom:4.10.0"))
implementation ("androidx.compose.runtime:runtime-livedata:1.0.5")

// define any required OkHttp artifacts without version
implementation("com.squareup.okhttp3:okhttp")
implementation("com.squareup.okhttp3:logging-interceptor")
}
9 changes: 6 additions & 3 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">

<uses-permission android:name="android.permission.INTERNET" />

<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
Expand All @@ -11,16 +13,17 @@
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.NOWSOPTAndroid"
android:usesCleartextTraffic="true"
tools:targetApi="31">
<activity
android:name=".MainActivity"
android:name=".presentation.MainActivity"
android:exported="false"/>

<activity
android:name=".SignUpActivity"
android:name=".presentation.SignUpActivity"
android:exported="false"/>

<activity android:name=".LoginActivity"
<activity android:name=".presentation.LoginActivity"
android:exported="true"
android:label="@string/app_name"
android:theme="@style/Theme.NOWSOPTAndroid">
Expand Down
57 changes: 57 additions & 0 deletions app/src/main/java/com/sopt/now/compose/data/ApiFactory.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package com.sopt.now.compose.data

import android.util.Log
import com.jakewharton.retrofit2.converter.kotlinx.serialization.asConverterFactory
import com.sopt.now.BuildConfig
import kotlinx.serialization.json.Json
import okhttp3.Interceptor
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.OkHttpClient
import okhttp3.Response
import retrofit2.Retrofit
import java.io.IOException

object ApiFactory {
private const val BASE_URL: String = BuildConfig.AUTH_BASE_URL
lateinit var userPreference: UserPreference

Choose a reason for hiding this comment

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

ApiFactory가 userPreferences를 가지고 있어야 하는 이유가 무엇일까요? ApiFactory라는 클래스(오브젝트)는 어떤 역할을 수행하고 있을까요?

var isInitialized = false
private set

fun initializeUserPreference(userPreference: UserPreference) {
ApiFactory.userPreference = userPreference
}

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

private fun provideOkHttpClient(): OkHttpClient = OkHttpClient.Builder()
.addInterceptor(HeaderInterceptor())
.build()

class HeaderInterceptor : Interceptor {
@Throws(IOException::class)
override fun intercept(chain: Interceptor.Chain): Response {
if (!ApiFactory::userPreference.isInitialized) {

Choose a reason for hiding this comment

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

오 isInitialized 사용은 좋습니다! 👍🏻

throw IllegalStateException("UserPreference is not initialized")
}

val newRequest = chain.request().newBuilder()
.addHeader("memberId", userPreference.getUserId().toString())
.build()
Log.d("userPreference API", "${userPreference.getUserId().toString()}")
return chain.proceed(newRequest)
}
}

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

object ServicePool {
val authService = ApiFactory.create<AuthService>()
val userService = ApiFactory.create<UserService>()
}
20 changes: 20 additions & 0 deletions app/src/main/java/com/sopt/now/compose/data/AuthService.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.sopt.now.compose.data

import com.sopt.now.compose.data.dto.request.RequestLoginDto
import com.sopt.now.compose.data.dto.request.RequestSignUpDto
import com.sopt.now.compose.data.dto.response.ResponseAuthDto
import retrofit2.Call
import retrofit2.http.Body
import retrofit2.http.POST

interface AuthService {
@POST("member/join")
fun signUp(
@Body request: RequestSignUpDto,
): Call<ResponseAuthDto>

@POST("member/login")
fun login(
@Body request: RequestLoginDto,
): Call<ResponseAuthDto>
}
12 changes: 12 additions & 0 deletions app/src/main/java/com/sopt/now/compose/data/BaseState.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.sopt.now.compose.data

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

@Serializable
data class BaseState(
@SerialName("isSuccess")
val isSuccess: Boolean,
@SerialName("message")
val message: String
)
Comment on lines +6 to +12

Choose a reason for hiding this comment

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

해당 데이터는 UI에서 사용되는 것으로 알고 있는데 이 데이터 클래스에 Serializable 붙인 이유를 알 수 있을까요?

14 changes: 14 additions & 0 deletions app/src/main/java/com/sopt/now/compose/data/Friend.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.sopt.now.compose.data

import androidx.annotation.DrawableRes

data class Friend(
@DrawableRes val profileImage: Int,
val name: String,
val phone: String,
) {
companion object {
const val TYPE_USER = 0
const val TYPE_FRIEND = 1
}
}
55 changes: 55 additions & 0 deletions app/src/main/java/com/sopt/now/compose/data/UserPreference.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package com.sopt.now.compose.data

import android.content.Context

import androidx.core.content.edit
import com.sopt.now.compose.data.UserPreference.UserPreferenceKeys.KEY_USER_ID
import com.sopt.now.compose.data.UserPreference.UserPreferenceKeys.KEY_USER_NAME
import com.sopt.now.compose.data.UserPreference.UserPreferenceKeys.KEY_USER_PHONE
import com.sopt.now.compose.data.UserPreference.UserPreferenceKeys.PREF_USER_DATA

class UserPreference(context: Context) {
private val sharedPreferences = context.applicationContext.getSharedPreferences(PREF_USER_DATA, Context.MODE_PRIVATE)

// 사용자 아이디 저장
fun saveUserId(userId: String) {
sharedPreferences.edit {
putString(KEY_USER_ID, userId)
}
}

// 사용자 아이디 가져오기
fun getUserId(): String? {
return sharedPreferences.getString(KEY_USER_ID, null)
}

// 사용자 데이터 저장
fun saveUserData(userData: UserData) {
sharedPreferences.edit {
putString(KEY_USER_ID, userData.userId)
putString(KEY_USER_NAME, userData.userName)
putString(KEY_USER_PHONE, userData.userPhone)
}
}

// 사용자 데이터 가져오기
fun getUserData(): UserData? {
with(sharedPreferences){
val userId = getString("userId", null)
val userName = getString("userName", null)
val userPhone = getString("userPhone", null)
Comment on lines +38 to +40
Copy link
Member

Choose a reason for hiding this comment

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

이런 상수들도 따로 빼둔다면 추후 수정이 용이해집니당


return if (userId != null && userName != null && userPhone != null) {
UserData(userId, userName, userPhone)
} else {
null
}
}
}
object UserPreferenceKeys {
const val PREF_USER_DATA = "userData"
const val KEY_USER_ID = "userId"
const val KEY_USER_NAME = "userName"
const val KEY_USER_PHONE = "userPhone"
}
}
11 changes: 11 additions & 0 deletions app/src/main/java/com/sopt/now/compose/data/UserService.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.sopt.now.compose.data

import com.sopt.now.compose.data.dto.response.ResponseUserInfoDto
import retrofit2.Call
import retrofit2.http.GET

interface UserService {
@GET("member/info")
fun userInfo(
): Call<ResponseUserInfoDto>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.sopt.now.compose.data.dto.request

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

@Serializable
data class RequestLoginDto(
@SerialName("authenticationId")
val authenticationId: String,
@SerialName("password")
val password: String
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.sopt.now.compose.data.dto.request

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

@Serializable
data class RequestSignUpDto(
@SerialName("authenticationId")
val authenticationId: String,
@SerialName("password")
val password: String,
@SerialName("nickname")
val nickname: String,
@SerialName("phone")
val phone: String,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.sopt.now.compose.data.dto.response

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

@Serializable
data class ResponseAuthDto(
@SerialName("code")
val code: Int,
@SerialName("message")
val message: String,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.sopt.now.compose.data.dto.response

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

@Serializable
data class ResponseUserInfoDto(
@SerialName("code")
val code: Int,
@SerialName("message")
val message: String,
@SerialName("data")
val data: UserInfo
)

@Serializable
data class UserInfo(
@SerialName("authenticationId")
val authenticationId: String,
@SerialName("nickname")
val nickname: String,
@SerialName("phone")
val phone: String
)
12 changes: 12 additions & 0 deletions app/src/main/java/com/sopt/now/compose/data/userData.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.sopt.now.compose.data

import android.os.Parcelable
import kotlinx.android.parcel.Parcelize
import kotlinx.serialization.Serializable

@Serializable
data class UserData(
val userId: String,
val userName: String,
val userPhone: String
)
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.sopt.now.compose
package com.sopt.now.compose.presentation

import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
Expand All @@ -8,16 +8,17 @@ import com.sopt.now.compose.item.FriendItem
import com.sopt.now.compose.item.Profile
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import com.sopt.now.compose.R
import com.sopt.now.compose.item.UserItem
import com.sopt.now.compose.ui.theme.NOWSOPTAndroidTheme

@Composable
fun HomeView() {
fun HomeView(userName: String, userPhone: String) {
LazyColumn(
modifier = Modifier.fillMaxSize()
) {
item {
UserItem(friendList.first())
UserItem(Profile(R.drawable.iv_user_profile, userName, userPhone))
}

// 첫 번째 요소는 건너뛰고 적용
Expand Down Expand Up @@ -101,6 +102,6 @@ val friendList = listOf(
@Composable
fun HomePreview() {
NOWSOPTAndroidTheme {
HomeView()
HomeView("","")
}
}
Loading