diff --git a/app/build.gradle b/app/build.gradle
index fb2c926..9c4bc74 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -7,7 +7,7 @@ plugins {
Properties properties = new Properties()
-properties.load(project.rootProject. file ('local.properties').newDataInputStream())
+properties.load(project.rootProject.file('local.properties').newDataInputStream())
android {
namespace 'org.android.go.sopt'
@@ -46,6 +46,9 @@ android {
}
dependencies {
+ implementation 'com.jakewharton.timber:timber:4.7.1'
+ implementation 'androidx.activity:activity-ktx:1.4.0'
+ implementation 'androidx.fragment:fragment-ktx:1.4.0'
implementation 'androidx.core:core-ktx:1.9.0'
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'com.google.android.material:material:1.8.0'
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index b85d997..1366046 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -7,6 +7,7 @@
()
val image: LiveData
get() = _image
@@ -21,7 +20,7 @@ class GalleryViewModel: ViewModel() {
fun uploadProfileImage() {
if (image.value == null) { /* 아직 사진이 등록되지 않았다는 로직 처리 */
} else {
- imageService.uploadImage(image.value!!.toFormData()).enqueue(
+ service.uploadImage(image.value!!.toFormData()).enqueue(
object : Callback {
override fun onResponse(call: Call, response: Response) {
if (response.isSuccessful)
diff --git a/app/src/main/java/org/android/go/sopt/home/HomeFragment.kt b/app/src/main/java/org/android/go/sopt/home/HomeFragment.kt
index e1f2795..628a588 100644
--- a/app/src/main/java/org/android/go/sopt/home/HomeFragment.kt
+++ b/app/src/main/java/org/android/go/sopt/home/HomeFragment.kt
@@ -5,24 +5,24 @@ import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
-import android.widget.Toast
+import androidx.activity.viewModels
import androidx.fragment.app.Fragment
+import androidx.fragment.app.viewModels
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.ConcatAdapter
import androidx.recyclerview.widget.LinearLayoutManager
import kotlinx.coroutines.launch
import org.android.go.sopt.HomeServicePool
-import org.android.go.sopt.R
+import org.android.go.sopt.SoptServicePool
import org.android.go.sopt.databinding.FragmentHomeBinding
-import org.android.go.sopt.model.ResponseHome
-import retrofit2.Call
-import retrofit2.Response
+import org.android.go.sopt.sign.LoginViewModel
class HomeFragment : Fragment() {
private var _binding: FragmentHomeBinding? = null
private val binding: FragmentHomeBinding
get() = requireNotNull(_binding) { "앗 binding이 null 이다!" }
- private val homeService = HomeServicePool.homeService
+
+ private val viewModel: HomeViewModel by viewModels()
override fun onCreateView(
@@ -40,40 +40,10 @@ class HomeFragment : Fragment() {
binding.rvHome.adapter = adapter
binding.rvHome.layoutManager = LinearLayoutManager(context)
-
-
- lifecycleScope.launch {
- kotlin.runCatching {
- homeService.listuser()
- }.fold(
- {
- homeadapter.submitList(it)
- }, {
- Log.d("aaa", "서버통신 실패")
- }
- )
+ viewModel.followList.observe(viewLifecycleOwner){followList ->
+ homeadapter.submitList(followList)
}
-
-//
-// homeService.listuser().enqueue(object : retrofit2.Callback {
-// override fun onResponse(
-// call: Call,
-// response: Response,
-// ) {
-// if (response.isSuccessful) {
-// response.body()?.data?.let {
-// homeadapter.submitList(it)
-// Log.d("listlist", it.toString())
-// }
-// }
-// }
-//
-// override fun onFailure(call: Call, t: Throwable) {
-//
-// }
-//
-// })
}
override fun onDestroyView() {
diff --git a/app/src/main/java/org/android/go/sopt/home/HomeViewModel.kt b/app/src/main/java/org/android/go/sopt/home/HomeViewModel.kt
new file mode 100644
index 0000000..5a61e41
--- /dev/null
+++ b/app/src/main/java/org/android/go/sopt/home/HomeViewModel.kt
@@ -0,0 +1,37 @@
+package org.android.go.sopt.home
+
+import android.util.Log
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.viewModelScope
+import kotlinx.coroutines.launch
+import org.android.go.sopt.HomeServicePool.homeService
+import org.android.go.sopt.model.ResponseHome
+import timber.log.Timber
+
+class HomeViewModel : ViewModel() {
+
+ private val _followList = MutableLiveData>()
+ val followList: LiveData> = _followList
+
+ init {
+ fetchFollowList()
+ }
+
+ private fun fetchFollowList() {
+ viewModelScope.launch {
+ kotlin.runCatching {
+ homeService.listuser()
+ }.fold(
+ {
+ _followList.value = it.data.toList()
+ }, {
+ Timber.e(it.message)
+
+ }
+ )
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/org/android/go/sopt/remote/SignApiFactory.kt b/app/src/main/java/org/android/go/sopt/remote/ApiFactory.kt
similarity index 65%
rename from app/src/main/java/org/android/go/sopt/remote/SignApiFactory.kt
rename to app/src/main/java/org/android/go/sopt/remote/ApiFactory.kt
index b3bde27..ef1e296 100644
--- a/app/src/main/java/org/android/go/sopt/remote/SignApiFactory.kt
+++ b/app/src/main/java/org/android/go/sopt/remote/ApiFactory.kt
@@ -10,27 +10,21 @@ import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import org.json.JSONArray
import org.json.JSONObject
-import org.android.go.sopt.remote.AuthInterceptor
import retrofit2.Retrofit
-object SignApiFactory {
+object ApiFactory {
- private val client by lazy {
- OkHttpClient.Builder().addInterceptor(HttpLoggingInterceptor().apply {
- level =
- if (BuildConfig.DEBUG) HttpLoggingInterceptor.Level.BODY else HttpLoggingInterceptor.Level.NONE
- }).addInterceptor(AuthInterceptor()).build()
-
- OkHttpClient.Builder()
- .addInterceptor(AuthInterceptor())
- .addInterceptor(
- HttpLoggingInterceptor().apply {
- level =
- if (BuildConfig.DEBUG) HttpLoggingInterceptor.Level.BODY else HttpLoggingInterceptor.Level.NONE
- }
- ).build()
-
- }
+// private val client by lazy {
+// OkHttpClient.Builder()
+// .addInterceptor(AuthInterceptor())
+// .addInterceptor(
+// HttpLoggingInterceptor().apply {
+// level =
+// if (BuildConfig.DEBUG) HttpLoggingInterceptor.Level.BODY else HttpLoggingInterceptor.Level.NONE
+// }
+// ).build()
+//
+// }
val retrofit: Retrofit by lazy {
Retrofit.Builder()
@@ -45,8 +39,10 @@ object SignApiFactory {
when {
message.isJsonObject() ->
Log.d("Retrofit2", JSONObject(message).toString(4))
+
message.isJsonArray() ->
Log.d("Retrofit2", JSONArray(message).toString(4))
+
else -> {
Log.d("Retrofit2", "CONNECTION INFO -> $message")
}
@@ -66,8 +62,7 @@ object SignApiFactory {
inline fun create(): T = retrofit.create(T::class.java)
}
-object SignServicePool {
- val signService = SignApiFactory.create()
-
- val imageService = SignApiFactory.create()
+object SoptServicePool {
+ val signService = ApiFactory.create()
+ val imageService = ApiFactory.create()
}
diff --git a/app/src/main/java/org/android/go/sopt/remote/AuthInterceptor.kt b/app/src/main/java/org/android/go/sopt/remote/AuthInterceptor.kt
index d4a7d71..158d9b8 100644
--- a/app/src/main/java/org/android/go/sopt/remote/AuthInterceptor.kt
+++ b/app/src/main/java/org/android/go/sopt/remote/AuthInterceptor.kt
@@ -1,7 +1,13 @@
package org.android.go.sopt.remote
+import android.util.Log
import okhttp3.Interceptor
import okhttp3.Response
+import okhttp3.logging.HttpLoggingInterceptor
+import org.android.go.sopt.ApiFactory.isJsonArray
+import org.android.go.sopt.ApiFactory.isJsonObject
+import org.json.JSONArray
+import org.json.JSONObject
class AuthInterceptor : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
@@ -11,4 +17,7 @@ class AuthInterceptor : Interceptor {
.build()
return chain.proceed(headerRequest)
}
+
+
}
+
diff --git a/app/src/main/java/org/android/go/sopt/remote/HomeApiFactory.kt b/app/src/main/java/org/android/go/sopt/remote/HomeApiFactory.kt
index 23a5999..0064e27 100644
--- a/app/src/main/java/org/android/go/sopt/remote/HomeApiFactory.kt
+++ b/app/src/main/java/org/android/go/sopt/remote/HomeApiFactory.kt
@@ -4,6 +4,7 @@ package org.android.go.sopt
import android.util.Log
import com.jakewharton.retrofit2.converter.kotlinx.serialization.asConverterFactory
import kotlinx.serialization.json.Json
+import okhttp3.Interceptor
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
@@ -14,32 +15,41 @@ import retrofit2.Retrofit
object HomeApiFactory {
-// private val client by lazy {
-// OkHttpClient.Builder().addInterceptor(HttpLoggingInterceptor().apply {
-// level =
-// if (BuildConfig.DEBUG) HttpLoggingInterceptor.Level.BODY else HttpLoggingInterceptor.Level.NONE
-// }).addInterceptor(AuthInterceptor()).build()
-//
-// OkHttpClient.Builder()
-// .addInterceptor(AuthInterceptor())
-// .addInterceptor(
-// HttpLoggingInterceptor().apply {
-// level =
-// if (BuildConfig.DEBUG) HttpLoggingInterceptor.Level.BODY else HttpLoggingInterceptor.Level.NONE
-// }
-// ).build()
-// }
-
val retrofit: Retrofit by lazy {
Retrofit.Builder()
.baseUrl(BuildConfig.REQRES_BASE_URL)
.addConverterFactory(Json.asConverterFactory("application/json".toMediaType()))
+ .client(client)
.build()
+ }
+ private fun getLogOkHttpClient(): Interceptor {
+
+ val interceptor = HttpLoggingInterceptor { message ->
+ when {
+ message.isJsonObject() ->
+ Log.d("Retrofit2", JSONObject(message).toString(4))
+ message.isJsonArray() ->
+ Log.d("Retrofit2", JSONArray(message).toString(4))
+ else -> {
+ Log.d("Retrofit2", "CONNECTION INFO -> $message")
+ }
+ }
+ }
+ interceptor.level = HttpLoggingInterceptor.Level.BODY
+ return interceptor
}
+ fun String?.isJsonObject(): Boolean = this?.startsWith("{") == true && this.endsWith("}")
+ fun String?.isJsonArray(): Boolean = this?.startsWith("[") == true && this.endsWith("]")
+
+ private val client = OkHttpClient.Builder()
+ .addInterceptor(getLogOkHttpClient())
+ .build()
+
inline fun create(): T = retrofit.create(T::class.java)
+
}
object HomeServicePool {
diff --git a/app/src/main/java/org/android/go/sopt/remote/Service.kt b/app/src/main/java/org/android/go/sopt/remote/Service.kt
index b777b3d..0f636c5 100644
--- a/app/src/main/java/org/android/go/sopt/remote/Service.kt
+++ b/app/src/main/java/org/android/go/sopt/remote/Service.kt
@@ -7,21 +7,21 @@ import retrofit2.http.*
interface SignService {
@POST("sign-up")
- fun signup(
+ suspend fun signup(
@Body request: RequestSignUpDto
- ): Call
+ ): ResponseSignUpDto
@POST("sign-in")
- fun signin(
+ suspend fun signin(
@Body request: RequestLogin
- ): Call
+ ): ResponseLogin
}
interface HomeService {
@GET("/api/users")
suspend fun listuser(
@Query("page") page: Int = 2
- ): List
+ ): ResponseHome
}
interface ImageService {
diff --git a/app/src/main/java/org/android/go/sopt/sign/LoginActivity.kt b/app/src/main/java/org/android/go/sopt/sign/LoginActivity.kt
index e6045eb..8b1fb52 100644
--- a/app/src/main/java/org/android/go/sopt/sign/LoginActivity.kt
+++ b/app/src/main/java/org/android/go/sopt/sign/LoginActivity.kt
@@ -3,17 +3,16 @@ package org.android.go.sopt.sign
import android.app.Activity
import android.content.Intent
import android.os.Bundle
-import android.util.Log
+import android.widget.Toast
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
-import com.google.android.gms.tasks.OnCompleteListener
import com.google.android.material.snackbar.Snackbar
-import com.google.firebase.messaging.FirebaseMessaging
import org.android.go.sopt.R
import org.android.go.sopt.databinding.ActivityLoginBinding
import org.android.go.sopt.home.HomeActivity
+import timber.log.Timber
class LoginActivity : AppCompatActivity() {
@@ -21,15 +20,14 @@ class LoginActivity : AppCompatActivity() {
private val binding by lazy { ActivityLoginBinding.inflate(layoutInflater) }
// LiveData가 저장되어 있는 ViewModel
- private val viewModel: LoginViewModel by viewModels()
+ private val viewModel: LoginViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
+ Timber.plant(Timber.DebugTree())
super.onCreate(savedInstanceState)
- //binding = ActivityLoginBinding.inflate(layoutInflater)
- setContentView(binding.root)
- getFcmToken()
+ setContentView(binding.root)
resultLauncher =
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
@@ -49,13 +47,18 @@ class LoginActivity : AppCompatActivity() {
}
viewModel.signInResult.observe(this) { signInResult ->
- startActivity(
- Intent(
- this@LoginActivity,
- HomeActivity::class.java
-
+ if (signInResult) {
+ Toast.makeText(this, "로그인 성공", Toast.LENGTH_SHORT).show()
+ startActivity(
+ Intent(
+ this@LoginActivity,
+ HomeActivity::class.java
+ )
)
- )
+ }
+ else{
+ Toast.makeText(this, "로그인 실패", Toast.LENGTH_SHORT).show()
+ }
}
@@ -71,18 +74,6 @@ class LoginActivity : AppCompatActivity() {
}
}
- private fun getFcmToken() {
- FirebaseMessaging.getInstance().token.addOnCompleteListener(OnCompleteListener{ task->
- if (!task.isSuccessful) {
- Log.w("tag", "Fetching FCM registration token failed", task.exception)
- return@OnCompleteListener
- }
- // Get new FCM registration token
- val token = task.result
- // Log
- Log.d("tag", "token is $token")
- })
- }
}
diff --git a/app/src/main/java/org/android/go/sopt/sign/LoginViewModel.kt b/app/src/main/java/org/android/go/sopt/sign/LoginViewModel.kt
index 1d5a23f..becc443 100644
--- a/app/src/main/java/org/android/go/sopt/sign/LoginViewModel.kt
+++ b/app/src/main/java/org/android/go/sopt/sign/LoginViewModel.kt
@@ -1,45 +1,36 @@
package org.android.go.sopt.sign
-import android.util.Log
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
+import androidx.lifecycle.viewModelScope
+import kotlinx.coroutines.launch
import org.android.go.sopt.RequestLogin
-import org.android.go.sopt.ResponseLogin
-import org.android.go.sopt.SignServicePool.signService
-import retrofit2.Call
-import retrofit2.Callback
-import retrofit2.Response
+import org.android.go.sopt.SoptServicePool.signService
class LoginViewModel : ViewModel() {
- private val _signInResult: MutableLiveData = MutableLiveData()
- val signInResult: LiveData = _signInResult
+ private val _signInResult: MutableLiveData = MutableLiveData()
+ val signInResult: LiveData = _signInResult
- fun signIn(id: String, password: String) {
- signService.signin(
- RequestLogin(
- id,
- password
- )
- ).enqueue(object : Callback {
- override fun onResponse(
- call: Call,
- response: Response
- ) {
- if (response.isSuccessful) {
- _signInResult.value = response.body()
- }
- else {
- Log.d("ffffff",response.body().toString())
-
- }
- }
- override fun onFailure(call: Call, t: Throwable) {
-
- }
+ fun signIn(id: String, password: String) {
- })
+ viewModelScope.launch {
+ kotlin.runCatching {
+ signService.signin(
+ RequestLogin(
+ id,
+ password
+ )
+ )
+ }.fold(
+ {
+ _signInResult.value = true
+ },{
+ _signInResult.value = false
+ }
+ )
+ }
}
}
\ No newline at end of file
diff --git a/app/src/main/java/org/android/go/sopt/sign/SignupActivity.kt b/app/src/main/java/org/android/go/sopt/sign/SignupActivity.kt
index d4e3c14..e714a87 100644
--- a/app/src/main/java/org/android/go/sopt/sign/SignupActivity.kt
+++ b/app/src/main/java/org/android/go/sopt/sign/SignupActivity.kt
@@ -3,28 +3,18 @@ package org.android.go.sopt.sign
import android.content.Intent
import android.os.Bundle
-import android.text.Editable
-import android.text.TextWatcher
-import android.util.Log
import android.view.View
-import android.widget.Toast
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
-import androidx.core.view.isInvisible
-import org.android.go.sopt.R
-import org.android.go.sopt.RequestSignUpDto
-import org.android.go.sopt.ResponseSignUpDto
-import org.android.go.sopt.SignServicePool
-import org.android.go.sopt.databinding.ActivityLoginBinding
+import com.google.android.material.snackbar.Snackbar
import org.android.go.sopt.databinding.ActivitySignupBinding
-import retrofit2.Call
-import retrofit2.Response
+import timber.log.Timber
class SignupActivity : AppCompatActivity() {
private val binding by lazy { ActivitySignupBinding.inflate(layoutInflater) }
// LiveData가 저장되어 있는 ViewModel
- private val viewModel: SignupViewModel by viewModels()
+ private val viewModel: SignupViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
@@ -49,7 +39,7 @@ class SignupActivity : AppCompatActivity() {
binding.tvPwWarning.visibility = View.VISIBLE
}
- viewModel.checksignup.observe(this){ isFormValid ->
+ viewModel.checksignup.observe(this) { isFormValid ->
binding.btnSignupEnd.isEnabled = isFormValid
}
@@ -64,17 +54,23 @@ class SignupActivity : AppCompatActivity() {
}
viewModel.signUpResult.observe(this) { signupResult ->
- startActivity(
- Intent(
+
+ if (signupResult){
+ val intent = Intent(
this@SignupActivity,
LoginActivity::class.java
)
- )
+ setResult(RESULT_OK, intent)
+ finish()
+ }
+ else{
+ Snackbar.make(
+ binding.root, "회원가입 실패", Snackbar.LENGTH_SHORT
+ ).show()
+ }
+
}
}
-
-
-
}
diff --git a/app/src/main/java/org/android/go/sopt/sign/SignupViewModel.kt b/app/src/main/java/org/android/go/sopt/sign/SignupViewModel.kt
index 76ade23..ee3f9a0 100644
--- a/app/src/main/java/org/android/go/sopt/sign/SignupViewModel.kt
+++ b/app/src/main/java/org/android/go/sopt/sign/SignupViewModel.kt
@@ -1,29 +1,28 @@
package org.android.go.sopt.sign
-import android.util.Log
import androidx.lifecycle.LiveData
import androidx.lifecycle.MediatorLiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
+import androidx.lifecycle.viewModelScope
+import kotlinx.coroutines.launch
import org.android.go.sopt.RequestSignUpDto
-import org.android.go.sopt.ResponseSignUpDto
-import org.android.go.sopt.SignServicePool.signService
-import retrofit2.Call
-import retrofit2.Callback
-import retrofit2.Response
+import org.android.go.sopt.SoptServicePool.signService
+import timber.log.Timber
+
class SignupViewModel : ViewModel() {
+ private val _signUpResult: MutableLiveData = MutableLiveData()
+ val signUpResult: LiveData = _signUpResult
- private val _signUpResult: MutableLiveData = MutableLiveData()
- val signUpResult: LiveData = _signUpResult
val id = MutableLiveData()
val pw = MutableLiveData()
val name = MutableLiveData()
val hobby = MutableLiveData()
- private val _checksignup : MediatorLiveData = MediatorLiveData()
- val checksignup : LiveData = _checksignup
+ private val _checksignup: MediatorLiveData = MediatorLiveData()
+ val checksignup: LiveData = _checksignup
init {
setupFormValidation()
@@ -40,51 +39,45 @@ class SignupViewModel : ViewModel() {
val isFormValid = canUserSignUp()
_checksignup.value = isFormValid
}
-
+
private fun canUserSignUp(): Boolean {
return ValidId(id.value) && ValidPw(pw.value) && id.value?.isNotBlank() == true &&
pw.value?.isNotBlank() == true && name.value?.isNotBlank() == true && hobby.value?.isNotBlank() == true
}
- fun signUp(id: String, password: String, name : String, skill : String) {
- signService.signup(
- RequestSignUpDto(
- id,
- password,
- name,
- skill
- )
- ).enqueue(object : Callback {
- override fun onResponse(
- call: Call,
- response: Response
- ) {
- if (response.isSuccessful) {
- _signUpResult.value = response.body()
- }
- else {
- Log.d("ffffff",response.body().toString())
-
+ fun signUp(id: String, password: String, name: String, skill: String) {
+
+ viewModelScope.launch {
+ kotlin.runCatching {
+ signService.signup(
+ RequestSignUpDto(
+ id,
+ password,
+ name,
+ skill
+ )
+ )
+ }.fold(
+ {
+ _signUpResult.value = true
+ Timber.d(it.message)
+
+ },
+ {
+ _signUpResult.value = false
}
- }
-
- override fun onFailure(call: Call, t: Throwable) {
-
- }
-
- })
+ )
+ }
}
- fun ValidId(id: String?): Boolean {
+ fun ValidId(id: String?): Boolean {
return id.isNullOrEmpty() || id.matches(Regex("(?=.*[a-zA-Z])(?=.*[0-9])[a-zA-Z0-9]{6,10}"))
}
- fun ValidPw(pw: String?): Boolean {
+ fun ValidPw(pw: String?): Boolean {
return pw.isNullOrEmpty() || pw.matches(Regex("(?=.*[a-zA-Z])(?=.*[0-9])(?=.*[!@#%^&*()])[a-zA-Z0-9!@#%^&*()]{6,12}"))
}
-
-
}
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_login.xml b/app/src/main/res/layout/activity_login.xml
index 19e256f..b892754 100644
--- a/app/src/main/res/layout/activity_login.xml
+++ b/app/src/main/res/layout/activity_login.xml
@@ -66,6 +66,17 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_PW" />
+
+
+ app:layout_constraintTop_toBottomOf="@+id/checkBox" />
ID 조건: 영문, 숫자가 포함되어야 하고 6~10글자 이내
Password 조건: 영문, 숫자, 특수문자가 포함되어야 하고 6~12글자 이내
+ 자동로그인
\ No newline at end of file