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

[WEEK06 조영서] 스타일 가이드와 디자인 패턴 #57

Open
wants to merge 2 commits into
base: jjwm10625
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
136 changes: 65 additions & 71 deletions app/src/main/java/com/gdg/android/presentation/LoginPage.kt
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
// LoginPage.kt
// app/src/main/java/com/gdg/android/presentation/LoginPage.kt
package com.gdg.android.presentation

import android.widget.Toast
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
Expand All @@ -14,110 +13,105 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.lifecycle.lifecycleScope
import androidx.navigation.NavController
import kotlinx.coroutines.launch
import bodyLarge
import bodyMedium
import buttontext
import com.gdg.android.ui.theme.BackgroundBox

@Composable
fun LoginPage(navController: NavController? = null) {
fun LoginPage(
navController: NavController? = null,
mainViewModel: MainViewModel
) {
val context = LocalContext.current

val majorTextValue = remember { mutableStateOf("") }
val nameTextValue = remember { mutableStateOf("") }
var majorError by remember { mutableStateOf("") }
var nameError by remember { mutableStateOf("") }

Column(
modifier = Modifier
.fillMaxSize()
.background(Color.White)
.padding(30.dp),
horizontalAlignment = Alignment.Start,
verticalArrangement = Arrangement.Center
) {
Text(
text = "안녕하세요, 여러분",
fontSize = 24.sp,
fontWeight = FontWeight.Bold,
modifier = Modifier.fillMaxWidth(),
textAlign = TextAlign.Start
)

Spacer(modifier = Modifier.height(20.dp))

// 학부 입력
TextFieldSection(label = "학부", textValue = majorTextValue, errorText = majorError)
BackgroundBox {
Column(
modifier = Modifier
.fillMaxSize()
.padding(30.dp),
horizontalAlignment = Alignment.Start,
verticalArrangement = Arrangement.Center
) {
Text(
text = "안녕하세요, 여러분",
fontSize = 24.sp,
fontWeight = FontWeight.Bold,
modifier = Modifier.fillMaxWidth(),
textAlign = TextAlign.Start
)

Spacer(modifier = Modifier.height(16.dp))
Spacer(modifier = Modifier.height(20.dp))

// 이름 입력
TextFieldSection(label = "이름", textValue = nameTextValue, errorText = nameError)
// 학부 입력
TextFieldSection(label = "학부", textValue = majorTextValue, errorText = majorError)

Spacer(modifier = Modifier.height(30.dp))
Spacer(modifier = Modifier.height(16.dp))

Button(
onClick = {
majorError = if (majorTextValue.value.isEmpty()) "학부를 입력해주세요." else ""
nameError = if (nameTextValue.value.isEmpty()) "이름을 입력해주세요." else ""
// 이름 입력
TextFieldSection(label = "이름", textValue = nameTextValue, errorText = nameError)

(context as? MainActivity)?.lifecycleScope?.launch {
(context as? MainActivity)?.saveAutoLoginState(context, true)
}
Spacer(modifier = Modifier.height(30.dp))

if (majorTextValue.value.isNotEmpty() && nameTextValue.value.isNotEmpty()) {
Toast.makeText(context, "로그인에 성공했습니다", Toast.LENGTH_SHORT).show()
navController?.navigate("profile") {
popUpTo(navController.graph.startDestinationId) { inclusive = true }
Button(
onClick = {
majorError = if (majorTextValue.value.isEmpty()) "학부를 입력해주세요." else ""
nameError = if (nameTextValue.value.isEmpty()) "이름을 입력해주세요." else ""

if (majorTextValue.value.isNotEmpty() && nameTextValue.value.isNotEmpty()) {
Toast.makeText(context, "로그인에 성공했습니다", Toast.LENGTH_SHORT).show()
navController?.let {
it.navigate("main") {
popUpTo(it.graph.startDestinationId) { inclusive = true }
}
mainViewModel.saveAutoLoginState(context, true)
}
}
}
},
modifier = Modifier
.padding(top = 20.dp)
.width(320.dp)
.align(Alignment.CenterHorizontally),
colors = ButtonDefaults.buttonColors(
containerColor = Color(0xFF313131),
contentColor = Color.White
)
) {
Text(
text = "LOGIN",
fontWeight = FontWeight.Bold,
fontSize = 16.sp,
style = TextStyle(
letterSpacing = 5.sp
},
modifier = Modifier
.padding(top = 20.dp)
.width(320.dp)
.align(Alignment.CenterHorizontally),
colors = ButtonDefaults.buttonColors(
containerColor = Color(0xFF313131)
)
)
) {
Text(
text = "LOGIN",
style = buttontext
)
}

Spacer(modifier = Modifier.height(12.dp))
}
}
}

@Composable
fun TextFieldSection(label: String, textValue: MutableState<String>, errorText: String) {
// label에 따라 올바른 조사를 선택
val placeholderText = if (label.endsWith("이름")) "${label}을 입력해주세요" else "${label}를 입력해주세요"

Column(modifier = Modifier.fillMaxWidth()) {
Text(
text = label,
fontSize = 16.sp,
color = Color(0xFF1C1C1C),
modifier = Modifier
.padding(top = 10.dp)
.fillMaxWidth()
style = bodyLarge
)

TextField(
value = textValue.value,
onValueChange = { textValue.value = it },
label = { Text(placeholderText, color = Color.Black) }, // 변경된 placeholderText 사용
label = { Text(placeholderText, color = Color.Black) },
colors = TextFieldDefaults.colors(
focusedContainerColor = Color(0xFFC4C4C4),
unfocusedContainerColor = Color(0xFFE0E0E0),
Expand All @@ -136,17 +130,17 @@ fun TextFieldSection(label: String, textValue: MutableState<String>, errorText:
if (errorText.isNotEmpty()) {
Text(
text = errorText,
color = Color.Red,
fontSize = 12.sp,
modifier = Modifier.padding(top = 4.dp)
style = bodyMedium,
color = Color.Red
)
} else {
Spacer(modifier = Modifier.height(20.dp)) // 오류 메시지가 없을 때 공간 유지
}
}
}


@Preview(showBackground = true)
@Composable
fun LoginPagePreview() {
LoginPage(navController = null)
LoginPage(navController = null, mainViewModel = MainViewModel())
}
39 changes: 11 additions & 28 deletions app/src/main/java/com/gdg/android/presentation/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import androidx.datastore.preferences.core.Preferences
import androidx.datastore.preferences.core.booleanPreferencesKey
import androidx.datastore.preferences.core.edit
import androidx.datastore.preferences.preferencesDataStore
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.first
Expand All @@ -22,47 +23,29 @@ import kotlinx.coroutines.launch
val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = "auto_login")

class MainActivity : ComponentActivity() {

// 키 생성
private val AUTO_LOGIN_KEY = booleanPreferencesKey("auto_login")

// 자동 로그인 상태 저장 함수
suspend fun saveAutoLoginState(context: Context, isLoggedIn: Boolean) {
context.dataStore.edit { preferences ->
preferences[AUTO_LOGIN_KEY] = isLoggedIn
}
}

// 자동 로그인 상태 불러오기 함수
fun getAutoLoginState(context: Context): Flow<Boolean> {
return context.dataStore.data
.map { preferences ->
preferences[AUTO_LOGIN_KEY] ?: false // 기본값은 false
}
}

private lateinit var mainViewModel: MainViewModel // mainViewModel 변수를 미리 생성
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
lifecycleScope.launch {
val isLoggedIn = getAutoLoginState(applicationContext).first() // 자동 로그인 상태 확인

mainViewModel = ViewModelProvider(this)[MainViewModel::class.java] // mainViewModel 변수 정의

lifecycleScope.launch {
val isLoggedIn =
mainViewModel.getAutoLoginState(applicationContext).first() // 자동 로그인 상태 확인
setContent {
val navController = rememberNavController()

// NavHost 설정
NavHost(
navController = navController,
startDestination = if (isLoggedIn) "main" else "login" // 자동 로그인 여부에 따라 시작 화면 설정
) {
composable("login") {
LoginPage(navController)
LoginPage(navController, mainViewModel)
}
composable("profile") {
ProfileScreen(navController)
composable("main") {
ProfileScreen(navController, mainViewModel)
}
composable("user") {
UserScreen(navController)
UserScreen(navController, mainViewModel)
}
composable("userCreate") {
UserCreateScreen(navController)
Comment on lines 36 to 51
Copy link
Contributor

Choose a reason for hiding this comment

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

이 코드 바깥을 GDGAndroidTheme으로 감싸야 테마가 적용될거에요!!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

이 코드 바깥을 GDGAndroidTheme으로 감싸야 테마가 적용될거에요!!

헉 그렇군요 !!

Expand Down
29 changes: 29 additions & 0 deletions app/src/main/java/com/gdg/android/presentation/MainViewModel.kt
Original file line number Diff line number Diff line change
@@ -1,18 +1,47 @@
package com.gdg.android.presentation

import android.content.Context
import android.util.Log
import androidx.datastore.core.DataStore
import androidx.datastore.preferences.core.Preferences
import androidx.datastore.preferences.core.booleanPreferencesKey
import androidx.datastore.preferences.core.edit
import androidx.datastore.preferences.preferencesDataStore
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.gdg.android.api.ServicePool
import com.gdg.android.api.User
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch

class MainViewModel : ViewModel() {
private val _users = MutableLiveData<List<User>>() // 내부에서 수정 가능한 데이터
val users: LiveData<List<User>> get() = _users // 외부에서 읽기만 가능한 데이터

val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = "auto_login")
// 키 생성
private val AUTO_LOGIN_KEY = booleanPreferencesKey("auto_login")

// 자동 로그인 상태 저장 함수
fun saveAutoLoginState(context: Context, isLoggedIn: Boolean) {
viewModelScope.launch {
context.dataStore.edit { preferences ->
preferences[AUTO_LOGIN_KEY] = isLoggedIn
}
}
}

// 자동 로그인 상태 불러오기 함수
fun getAutoLoginState(context: Context): Flow<Boolean> {
return context.dataStore.data
.map { preferences ->
preferences[AUTO_LOGIN_KEY] ?: false // 기본값은 false
}
}

fun getUsers() {
viewModelScope.launch {
runCatching { ServicePool.userService.getUsers(page = 2) }
Expand Down
Loading