Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
67 commits
Select commit Hold shift + click to select a range
9d86dc9
feat: 필수 과제 구현
hyeminililo Oct 17, 2025
d9f2d6d
#2 feat: 입력 정보 미기재시, Toast 메세지 적용
hyeminililo Oct 17, 2025
446880d
#2 refactor : 불필요한 임포트 삭제
hyeminililo Oct 20, 2025
6cf63e6
#2 feat: 탐구과제 1번 작성
hyeminililo Oct 20, 2025
1ac8a9d
#2 refactor: 폴더 구조 변경
hyeminililo Oct 21, 2025
741dd20
#2 refactor: 리뷰 기반으로 리팩토링
hyeminililo Oct 26, 2025
c436c9a
#2 feat : 탐구과제 3번 작성
hyeminililo Oct 26, 2025
27cfb3e
#2 feat : 탐구과제 3번 수정
hyeminililo Oct 26, 2025
912e9f2
#4 refactor: textField 컴포넌트 분리
hyeminililo Oct 27, 2025
afc9084
#4 feat: 텍스트 필드 컴포넌트 구성
hyeminililo Oct 28, 2025
03bd6b7
#4 feat: 텍스트 및 버튼 컴포넌트 구성
hyeminililo Oct 28, 2025
4bdcd3c
#4 feat: 회원가입 스크린에 컴포넌트 적용
hyeminililo Oct 28, 2025
fb976a0
#4 refactor: commonTextField 이름변경 commonTextField -> CommonInputField
hyeminililo Oct 28, 2025
81e778a
#4 feat: 로그인 스크린에 컴포넌트 적용
hyeminililo Oct 28, 2025
d9d7d31
#4 feat: 입력값 Validator 구현
hyeminililo Oct 28, 2025
57c42fa
#4 refactor: User 객체 생성 및 적용
hyeminililo Oct 30, 2025
19a87b0
#4 feat: Navigator 설정 및 라우터 설정
hyeminililo Oct 31, 2025
97ce311
#4 chore: Navigator 설정 및 라우터 설정
hyeminililo Oct 31, 2025
8310a5e
#4 feat: 마이페이지 구현
hyeminililo Oct 31, 2025
948af71
#4 feat: 홈스크린 화면
hyeminililo Oct 31, 2025
9285ff1
#4 feat: 설정화면 구현
hyeminililo Oct 31, 2025
5525cad
#4 feat: week2 과제 완성
hyeminililo Oct 31, 2025
a5c5b6c
#4 refactor: 필요 없는 파일 삭제
hyeminililo Oct 31, 2025
5a633e1
#4 refactor: 코드리뷰 기반으로 리팩토링
hyeminililo Nov 4, 2025
66ce411
#4 fix: 비밀번호 관련 버그 수정
hyeminililo Nov 4, 2025
3cb5622
#4 design: 화면 스크롤 구현
hyeminililo Nov 4, 2025
dffccb0
#4 refactor: SAA 적용해 리팩토링
hyeminililo Nov 5, 2025
b03f93c
#7 feat: MainViewModel 구현
hyeminililo Nov 5, 2025
59497c1
#7 feat: viewModel 추가 적용
hyeminililo Nov 6, 2025
090d581
#7 feat: 애니메이션 구현
hyeminililo Nov 7, 2025
a238248
#7 refactor: 파일 이름 변경
hyeminililo Nov 7, 2025
c709bd7
#7 refactor: 파일 이름 변경
hyeminililo Nov 7, 2025
3790041
#7 fix: 애니메이션 관련 버그 수정
hyeminililo Nov 12, 2025
b79fe68
#7 refactor: 주요 색상 상수화
hyeminililo Nov 12, 2025
197a372
#7 refactor: 코드리뷰 기반으로 리팩토링
hyeminililo Nov 12, 2025
b50da7d
#7 rename: 폴더명 수정
hyeminililo Nov 12, 2025
c93f437
Merge pull request #8 from 37-dive-sopt-android/week3
hyeminililo Nov 12, 2025
2615659
#9 chore: 인터넷 권한 설정 및 통신 관련 의존성 추가
hyeminililo Nov 13, 2025
6ff34dc
#9 feat: 회원가입 응답, 요청 DTO 구현
hyeminililo Nov 13, 2025
84064aa
#9 feat: 로그인 응답, 요청 DTO 구현
hyeminililo Nov 13, 2025
f9a27e8
#9 rename: responseSignupDto -> responseUserDto 이름 변경
hyeminililo Nov 13, 2025
8c4ce65
#9 feat: 응답시, 에러 상황 DTO 구현
hyeminililo Nov 13, 2025
ac97b36
#9 feat: AuthService, UserService 구현
hyeminililo Nov 13, 2025
ccf5756
#9 feat: API Factory 구현
hyeminililo Nov 13, 2025
b2b91b1
#9 refactor: User 모델 변경
hyeminililo Nov 13, 2025
92e738e
#9 refactor: User 모델 변경
hyeminililo Nov 13, 2025
2105eea
#9 refactor: 변경된 모델에 맞게 화면 변경
hyeminililo Nov 13, 2025
bad0157
#9 feat: User 레포지토리 구현
hyeminililo Nov 13, 2025
d7c1c3e
#9 feat: Auth 레포지토리 구현
hyeminililo Nov 13, 2025
b5ef5ff
#9 build: BASE_URL 변수 수정
hyeminililo Nov 14, 2025
20277b2
#9 fix: api 주소 수정
hyeminililo Nov 14, 2025
e7ebb2c
#9 feat: User 모델 서버 값에 맞게 수정
hyeminililo Nov 14, 2025
d96d89c
#9 feat: API 연동 로직 ViewModel에 추가
hyeminililo Nov 14, 2025
33b6d0c
#9 feat: 서버 모델에 맞춰 변경
hyeminililo Nov 14, 2025
fd033d0
#9 feat: ResponseDto 변경
hyeminililo Nov 14, 2025
44d7479
#9 chore: http 통신 허용을 위한 xml 추가
hyeminililo Nov 14, 2025
5e141b4
#9 delete: 안 쓰는 repository 삭제
hyeminililo Nov 14, 2025
6225039
#9 refactor: 불필요한 공백 및 임포트 정리
hyeminililo Nov 14, 2025
863199e
refactor: 코드리뷰 기반 리팩토링
hyeminililo Nov 27, 2025
3316d52
#11 refactor: 코드 리뷰 기반으로 로그인 로직 수정
hyeminililo Nov 27, 2025
11efdde
#11 refactor: 불필요한 코드 삭제
hyeminililo Nov 27, 2025
7607f5f
#10 #11 mod: Call -> Response 변경
hyeminililo Nov 27, 2025
f8dc07b
#10 #11 refactor: 코드 리팩토링
hyeminililo Nov 27, 2025
bd54daa
#10 #11 merge branch 'dev' into week4
hyeminililo Nov 27, 2025
0b35581
merge week4 -> dev
hyeminililo Nov 27, 2025
d5bb0ba
#11 feat: 기존 코드 코루틴으로 변경
hyeminililo Nov 28, 2025
92b2a94
#11 refactor: 불필요한 코드 및 주석 정리
hyeminililo Nov 28, 2025
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
21 changes: 19 additions & 2 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,12 +1,20 @@
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)
id("kotlin-parcelize")
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

p2: 현재 방식은 버전을 명시하지 않고 사용하기에 프로젝트 버전 관리를 하기 어려워요 이친구도 versions.toml 에 plugins 에 정의해서 사용해 보는 것두 추천드립니다 ㅎ

kotlin-parcelize = { id = "org.jetbrains.kotlin.plugin.parcelize", version.ref = "kotlinParcelize" }

}

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

android {
namespace = "com.sopt.dive"
compileSdk = 35
compileSdk = 36

defaultConfig {
applicationId = "com.sopt.dive"
Expand All @@ -16,6 +24,7 @@ android {
versionName = "1.0"

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

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

Expand All @@ -56,4 +66,11 @@ dependencies {
androidTestImplementation(libs.androidx.ui.test.junit4)
debugImplementation(libs.androidx.ui.tooling)
debugImplementation(libs.androidx.ui.test.manifest)
}
implementation(libs.androidx.compose.navigation)
implementation(libs.androidx.lifecycle.viewmodel.ktx)
implementation(libs.androidx.lifecycle.viewmodel.compose)
implementation(libs.kotlinx.serialization.json)
implementation(libs.retrofit.core)
implementation(libs.retrofit.kotlin.serialization)
implementation(libs.okhttp.logging)
}
10 changes: 7 additions & 3 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@
<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:usesCleartextTraffic="true"
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
Expand All @@ -16,13 +20,13 @@
android:name=".MainActivity"
android:exported="true"
android:label="@string/app_name"
android:theme="@style/Theme.Dive">
android:theme="@style/Theme.Dive"
android:windowSoftInputMode="adjustResize">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>

</manifest>
</manifest>
35 changes: 5 additions & 30 deletions app/src/main/java/com/sopt/dive/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,45 +3,20 @@ package com.sopt.dive
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import androidx.navigation.compose.rememberNavController
import com.sopt.dive.ui.theme.DiveTheme
import com.sopt.dive.util.Navigator

class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()

setContent {
DiveTheme {
Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
Greeting(
name = "Android",
modifier = Modifier.padding(innerPadding)
)
}
val navController = rememberNavController()
Navigator(navController)
}
}
}
}

@Composable
fun Greeting(name: String, modifier: Modifier = Modifier) {
Text(
text = "Hello $name!",
modifier = modifier
)
}

@Preview(showBackground = true)
@Composable
fun GreetingPreview() {
DiveTheme {
Greeting("Android")
}
}
37 changes: 37 additions & 0 deletions app/src/main/java/com/sopt/dive/data/ApiFactory.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package com.sopt.dive.data

import com.jakewharton.retrofit2.converter.kotlinx.serialization.asConverterFactory
import com.sopt.dive.BuildConfig
import kotlinx.serialization.json.Json
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit

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

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

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

private val json = Json {
explicitNulls = false
}

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)
}
14 changes: 14 additions & 0 deletions app/src/main/java/com/sopt/dive/data/ServicePool.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.sopt.dive.data

import com.sopt.dive.data.api.AuthService
import com.sopt.dive.data.api.UserService

object ServicePool {
val userService: UserService by lazy {
ApiFactory.create<UserService>()
}

val authService: AuthService by lazy {
ApiFactory.create<AuthService>()
}
}
15 changes: 15 additions & 0 deletions app/src/main/java/com/sopt/dive/data/api/AuthService.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.sopt.dive.data.api

import com.sopt.dive.data.dto.LoginDataDto
import com.sopt.dive.data.dto.RequestLoginDto
import com.sopt.dive.data.dto.ResponseSuccessDto
import retrofit2.Response
import retrofit2.http.Body
import retrofit2.http.POST

interface AuthService {
@POST("api/v1/auth/login")
suspend fun login(
@Body request: RequestLoginDto
): Response<ResponseSuccessDto<LoginDataDto>>
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

이번 합세에서 배웠을 지 모르겠지만 BaseResponse 를 사용해 봅시다~ wrapping이 너무 많이 되어있네요!

}
22 changes: 22 additions & 0 deletions app/src/main/java/com/sopt/dive/data/api/UserService.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.sopt.dive.data.api

import com.sopt.dive.data.dto.RequestSignupDto
import com.sopt.dive.data.dto.ResponseSuccessDto
import com.sopt.dive.data.dto.ResponseUserDto
import retrofit2.Response
import retrofit2.http.Body
import retrofit2.http.GET
import retrofit2.http.POST
import retrofit2.http.Path

interface UserService {
@POST("api/v1/users")
suspend fun signup(
@Body request: RequestSignupDto
): Response<ResponseSuccessDto<ResponseUserDto>>

@GET("api/v1/users/{id}")
fun fetchUserInfo(
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

suspend 키워드 빠진 거 같아요!

@Path("id") id: Int,
): Response<ResponseSuccessDto<ResponseUserDto>>
}
13 changes: 13 additions & 0 deletions app/src/main/java/com/sopt/dive/data/dto/RequestLoginDto.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.sopt.dive.data.dto

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

@Serializable
data class RequestLoginDto(
@SerialName("username")
val username: String,

@SerialName("password")
val password: String
)
22 changes: 22 additions & 0 deletions app/src/main/java/com/sopt/dive/data/dto/RequestSignupDto.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.sopt.dive.data.dto

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

@Serializable
data class RequestSignupDto(
@SerialName("username")
val username: String,

@SerialName("password")
val password: String,

@SerialName("name")
val name: String,

@SerialName("email")
val email: String,

@SerialName("age")
val age: Int
)
49 changes: 49 additions & 0 deletions app/src/main/java/com/sopt/dive/data/dto/ResponseErrorDto.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package com.sopt.dive.data.dto

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

@Serializable
data class ResponseErrorDto(

@SerialName("success")
val success: Boolean = false,

@SerialName("code")
val code: String,

@SerialName("message")
val message: String,

@SerialName("data")
val data: ErrorDataDto?

)

@Serializable
data class ErrorDataDto(

@SerialName("code")
val code: String,

@SerialName("message")
val message: String,

@SerialName("errors")
val errors: List<FieldErrorDto>?

)

@Serializable
data class FieldErrorDto(

@SerialName("field")
val field: String,

@SerialName("value")
val value: String,

@SerialName("reason")
val reason: String

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

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


@Serializable
data class LoginDataDto(
@SerialName("userId")
val userId: Int,

@SerialName("message")
val message: String
)
13 changes: 13 additions & 0 deletions app/src/main/java/com/sopt/dive/data/dto/ResponseSuccessDto.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.sopt.dive.data.dto

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


@Serializable
data class ResponseSuccessDto<T>(
@SerialName("success") val success: Boolean,
@SerialName("code") val code: String,
@SerialName("message") val message: String,
@SerialName("data") val data: T?
)
27 changes: 27 additions & 0 deletions app/src/main/java/com/sopt/dive/data/dto/ResponseUserDto.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.sopt.dive.data.dto

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

enum class Status { ACTIVE }
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

혹시 따로 이렇게 1개의 status를 data에서 만들어 준 이유가 있을까요?
이런 상태는 ui에서 사용될 거 같아요
서버에서 받은 내용을 가공하여 내려주는 역할은 dto가 아닌것 같습니다!
7차 세미나에서 배운대로 간단 변환의 책임이나 가공은 어디가 좋을 지 생각해보시면 좋을 것 같아요!


@Serializable
data class ResponseUserDto(
@SerialName("id")
val id: Long,

@SerialName("username")
val username: String,

@SerialName("name")
val name: String,

@SerialName("email")
val email: String,

@SerialName("age")
val age: Int,

@SerialName("status")
val status: Status
)
11 changes: 11 additions & 0 deletions app/src/main/java/com/sopt/dive/model/HomeProfileInfo.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.sopt.dive.model

import android.os.Parcelable
import kotlinx.parcelize.Parcelize

@Parcelize
data class HomeProfileInfo(
val userName: String,
val title: String,
val content: String
) : Parcelable
13 changes: 13 additions & 0 deletions app/src/main/java/com/sopt/dive/model/User.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.sopt.dive.model

import android.os.Parcelable
import kotlinx.parcelize.Parcelize

@Parcelize
data class User(
val id: String,
val pw: String,
val name: String,
val email: String,
val age: Int
) : Parcelable
Loading