Skip to content
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
15 changes: 13 additions & 2 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
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 {
namespace = "org.sopt.at"
compileSdk = 35
Expand All @@ -17,6 +23,7 @@ android {
versionName = "1.0"

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

buildTypes {
Expand All @@ -37,11 +44,11 @@ android {
}
buildFeatures {
compose = true
buildConfig = true
}
}

dependencies {

implementation(libs.androidx.core.ktx)
implementation(libs.androidx.lifecycle.runtime.ktx)
implementation(libs.androidx.activity.compose)
Expand All @@ -60,6 +67,10 @@ dependencies {

// Compose
implementation(libs.androidx.compose.navigation)
implementation(libs.kotlinx.serialization.json)
implementation(libs.kotlinx.collections.immutable)
// NetWorking
implementation(libs.kotlinx.serialization.json)
implementation(libs.retrofit.core)
implementation(libs.retrofit.kotlin.serialization)
implementation(libs.okhttp.logging)
}
3 changes: 3 additions & 0 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,6 +13,7 @@
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.ATSOPTANDROID"
android:usesCleartextTraffic="true"
tools:targetApi="31">
<activity
android:name=".ui.MainActivity"
Expand Down
16 changes: 16 additions & 0 deletions app/src/main/java/org/sopt/at/data/model/BaseResponseDto.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package org.sopt.at.data.model

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

@Serializable
data class BaseResponseDto<T>(
@SerialName("success")
val success: Boolean,
@SerialName("code")
val code: String,
@SerialName("message")
val message: String,
@SerialName("data")
val data: T?,
)
18 changes: 18 additions & 0 deletions app/src/main/java/org/sopt/at/data/model/SignInDto.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package org.sopt.at.data.model

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

@Serializable
data class SignInRequestDto(
@SerialName("loginId")
val loginId: String,
@SerialName("password")
val password: String,
)

@Serializable
data class SignInResponseDto(
@SerialName("userId")
val userId: Int,
)
22 changes: 22 additions & 0 deletions app/src/main/java/org/sopt/at/data/model/SignUpDto.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package org.sopt.at.data.model

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

@Serializable
data class SignUpRequestDto(
@SerialName("loginId")
val loginId: String,
@SerialName("password")
val password: String,
@SerialName("nickname")
val nickname: String,
)

@Serializable
data class SignUpResponseDto(
@SerialName("userId")
val userId: Int,
@SerialName("nickname")
val nickname: String,
)
10 changes: 10 additions & 0 deletions app/src/main/java/org/sopt/at/data/model/UsersDto.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package org.sopt.at.data.model

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

@Serializable
data class UserNickNameResponseDto(
@SerialName("nickname")
val nickname: String,
)
40 changes: 40 additions & 0 deletions app/src/main/java/org/sopt/at/data/service/ApiFactory.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package org.sopt.at.data.service

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.at.BuildConfig
import retrofit2.Retrofit

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

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 authService: AuthService by lazy {
ApiFactory.create<AuthService>()
}
val userService: UserService by lazy {
ApiFactory.create<UserService>()
}
}
24 changes: 24 additions & 0 deletions app/src/main/java/org/sopt/at/data/service/AuthService.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package org.sopt.at.data.service

import org.sopt.at.data.model.BaseResponseDto
import org.sopt.at.data.model.SignInRequestDto
import org.sopt.at.data.model.SignInResponseDto
import org.sopt.at.data.model.SignUpRequestDto
import org.sopt.at.data.model.SignUpResponseDto
import retrofit2.Call
import retrofit2.http.Body
import retrofit2.http.GET
import retrofit2.http.Header
import retrofit2.http.POST

interface AuthService {
@POST("/api/v1/auth/signup")
fun signup(
@Body request: SignUpRequestDto
): Call<BaseResponseDto<SignUpResponseDto>>

@POST("/api/v1/auth/signin")
fun signin(
@Body request: SignInRequestDto
): Call<BaseResponseDto<SignInResponseDto>>
}
14 changes: 14 additions & 0 deletions app/src/main/java/org/sopt/at/data/service/UserService.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package org.sopt.at.data.service

import org.sopt.at.data.model.BaseResponseDto
import org.sopt.at.data.model.UserNickNameResponseDto
import retrofit2.Call
import retrofit2.http.GET
import retrofit2.http.Header

interface UserService {
@GET("/api/v1/users/me")
fun getUserInfo(
@Header("userId") userId: Int
): Call<BaseResponseDto<UserNickNameResponseDto>>
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,46 +3,41 @@ package org.sopt.at.navigation
import androidx.annotation.DrawableRes
import androidx.annotation.StringRes
import org.sopt.at.R
import org.sopt.at.navigation.MainNavRoute.History
import org.sopt.at.navigation.MainNavRoute.Home
import org.sopt.at.navigation.MainNavRoute.Live
import org.sopt.at.navigation.MainNavRoute.Search
import org.sopt.at.navigation.MainNavRoute.Shorts

internal enum class MainNavItem(
internal enum class MainBottomNavItem(
@DrawableRes val activeIcon: Int,
@DrawableRes val inactiveIcon: Int,
@StringRes val labelId: Int,
val screenRoute: MainNavRoute,
val route: MainBottomNavRoute,
) {
HOME(
activeIcon = R.drawable.ic_home_active,
inactiveIcon = R.drawable.ic_home_inactive,
labelId = R.string.home_title,
screenRoute = Home,
route = MainBottomNavRoute.Home,
),
SHORTS(
activeIcon = R.drawable.ic_shorts_active,
inactiveIcon = R.drawable.ic_shorts_inactive,
labelId = R.string.shorts_title,
screenRoute = Shorts,
route = MainBottomNavRoute.Shorts,
),
LIVE(
activeIcon = R.drawable.ic_live_active,
inactiveIcon = R.drawable.ic_live_inactive,
labelId = R.string.live_title,
screenRoute = Live,
route = MainBottomNavRoute.Live,
),
SEARCH(
activeIcon = R.drawable.ic_search_active,
inactiveIcon = R.drawable.ic_search_inactive,
labelId = R.string.search_title,
screenRoute = Search,
route = MainBottomNavRoute.Search,
),
HISTORY(
activeIcon = R.drawable.ic_history_active,
inactiveIcon = R.drawable.ic_history_inactive,
labelId = R.string.history_title,
screenRoute = History,
route = MainBottomNavRoute.History,
),
}
42 changes: 17 additions & 25 deletions app/src/main/java/org/sopt/at/navigation/MainNavHost.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,11 @@ import androidx.compose.ui.Modifier
import androidx.navigation.NavHostController
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import org.sopt.at.navigation.MainNavRoute.History
import org.sopt.at.navigation.MainNavRoute.Home
import org.sopt.at.navigation.MainNavRoute.Live
import org.sopt.at.navigation.MainNavRoute.My
import org.sopt.at.navigation.MainNavRoute.Search
import org.sopt.at.navigation.MainNavRoute.Shorts
import org.sopt.at.navigation.MainNavRoute.SignIn
import org.sopt.at.navigation.MainNavRoute.SignUp
import org.sopt.at.ui.history.HistoryScreen
import org.sopt.at.ui.home.HomeScreen
import org.sopt.at.ui.live.LiveScreen
import org.sopt.at.ui.login.SignInScreen
import org.sopt.at.ui.login.SignUpScreen
import org.sopt.at.ui.login.signin.SignInScreen
import org.sopt.at.ui.login.signup.SignUpScreen
import org.sopt.at.ui.my.MyScreen
import org.sopt.at.ui.search.SearchScreen
import org.sopt.at.ui.shorts.ShortsScreen
Expand All @@ -29,34 +21,34 @@ import org.sopt.at.ui.shorts.ShortsScreen
fun MainNavHost(
navController: NavHostController,
paddingValues: PaddingValues,
startDestination: String,
startDestination: Route,
) {
NavHost(
navController = navController,
startDestination = startDestination,
modifier = Modifier.padding(paddingValues),
) {
composable(Home.route) {
composable<MainBottomNavRoute.Home> {
HomeScreen(
navigateToMyScreen = { navController.navigateAddTo(My.route) }
navigateToMyScreen = { navController.navigateAddTo(Route.My) }
)
}
composable(Shorts.route) { ShortsScreen() }
composable(Live.route) { LiveScreen() }
composable(Search.route) { SearchScreen() }
composable(History.route) { HistoryScreen() }
composable(My.route) { MyScreen() }
composable(SignIn.route) {
composable<MainBottomNavRoute.Shorts> { ShortsScreen() }
composable<MainBottomNavRoute.Live> { LiveScreen() }
composable<MainBottomNavRoute.Search> { SearchScreen() }
composable<MainBottomNavRoute.History> { HistoryScreen() }
composable<Route.My> { MyScreen() }
composable<Route.SignIn> {
SignInScreen(
navigateToHomeScreen = { navController.navigateReplaceTo(route = Home.route) },
navigateToSignUpScreen = { navController.navigateAddTo(SignUp.route) },
navigateToHomeScreen = { navController.navigateReplaceTo(route = MainBottomNavRoute.Home) },
navigateToSignUpScreen = { navController.navigateAddTo(Route.SignUp) },
navController = navController,
)
}
composable(SignUp.route) {
composable<Route.SignUp> {
SignUpScreen(
navigateToSignInScreen = {
navController.navigateReplaceTo(SignIn.route)
navController.navigateReplaceTo(Route.SignIn)
navController.currentBackStackEntry?.savedStateHandle?.set(
"signUpSuccess",
true
Expand All @@ -69,7 +61,7 @@ fun MainNavHost(
}

fun NavHostController.navigateAddTo(
route: String,
route: Route,
) {
this.navigate(route) {
popUpTo(route) {
Expand All @@ -81,7 +73,7 @@ fun NavHostController.navigateAddTo(
}

fun NavHostController.navigateReplaceTo(
route: String,
route: Route,
) {
val currentRoute = this.currentBackStackEntry?.destination?.route ?: return
this.navigate(route) {
Expand Down
Loading