diff --git a/app/build.gradle b/app/build.gradle index 2a5b0d9..8ca63a7 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,8 +1,12 @@ plugins { id 'com.android.application' id 'org.jetbrains.kotlin.android' + id 'org.jetbrains.kotlin.plugin.serialization' version '1.9.0' } +Properties properties = new Properties() +properties.load(project.rootProject.file('local.properties').newDataInputStream()) + android { namespace 'com.sopt.now' compileSdk 34 @@ -15,6 +19,7 @@ android { versionName "1.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + buildConfigField "String", "AUTH_BASE_URL", properties["base.url"] } buildTypes { @@ -32,6 +37,7 @@ android { } buildFeatures { viewBinding = true + buildConfig = true } } @@ -42,6 +48,7 @@ dependencies { implementation 'com.google.android.material:material:1.11.0' implementation 'androidx.constraintlayout:constraintlayout:2.1.4' implementation 'androidx.activity:activity:1.8.0' + implementation 'androidx.test:core-ktx:1.5.0' testImplementation 'junit:junit:4.13.2' androidTestImplementation 'androidx.test.ext:junit:1.1.5' androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' @@ -50,4 +57,14 @@ dependencies { implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.2" implementation "androidx.fragment:fragment-ktx:1.6.1" implementation "androidx.activity:activity-ktx:1.8.0" + + //api + implementation 'com.squareup.retrofit2:retrofit:2.9.0' + implementation 'org.jetbrains.kotlinx:kotlinx-serialization-json:1.4.1' + implementation 'com.jakewharton.retrofit:retrofit2-kotlinx-serialization-converter:1.0.0' + // define a BOM and its version + implementation(platform("com.squareup.okhttp3:okhttp-bom:4.10.0")) + // define any required OkHttp artifacts without version + implementation("com.squareup.okhttp3:okhttp") + implementation("com.squareup.okhttp3:logging-interceptor") } \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 1466163..71b8e05 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -2,6 +2,8 @@ + + + diff --git a/app/src/main/java/com/sopt/now/ApiFactory.kt b/app/src/main/java/com/sopt/now/ApiFactory.kt new file mode 100644 index 0000000..3a1764e --- /dev/null +++ b/app/src/main/java/com/sopt/now/ApiFactory.kt @@ -0,0 +1,60 @@ +package com.sopt.now + +import android.util.Log +import com.jakewharton.retrofit2.converter.kotlinx.serialization.asConverterFactory +import com.sopt.now.presentation.auth.login.LoginActivity +import com.sopt.now.data.remote.service.AuthService +import com.sopt.now.data.remote.service.FollwerService +import com.sopt.now.data.remote.service.UserService +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 + const val USER_ID:String = "userId" + + val retrofit: Retrofit by lazy { + Retrofit.Builder() + .baseUrl(BASE_URL) + .addConverterFactory(Json.asConverterFactory("application/json".toMediaType())) + .build() + } + + val userRetrofit: Retrofit by lazy { + Retrofit.Builder() + .baseUrl(BASE_URL) + .client(provideOkHttpClient(HeaderInterceptor())) + .addConverterFactory(Json.asConverterFactory("application/json".toMediaType())) + .build() + } + private fun provideOkHttpClient(interceptor: HeaderInterceptor): OkHttpClient + = OkHttpClient.Builder().run { + addInterceptor(interceptor) + build() + } + class HeaderInterceptor : Interceptor { + @Throws(IOException::class) + override fun intercept(chain: Interceptor.Chain): Response = with(chain) { + val accessToken = LoginActivity.prefs.getString(USER_ID, "") + val newRequest = request().newBuilder() + .addHeader("memberId", accessToken) + .build() + proceed(newRequest) + } + } + inline fun create(): T = retrofit.create(T::class.java) + inline fun createUser(): T = userRetrofit.create(T::class.java) +} + +object ServicePool { + val authService = ApiFactory.create() + val userService = ApiFactory.createUser() + val followerService = ApiFactory.create() +} + + diff --git a/app/src/main/java/com/sopt/now/BindingFragment.kt b/app/src/main/java/com/sopt/now/BindingFragment.kt new file mode 100644 index 0000000..dd242af --- /dev/null +++ b/app/src/main/java/com/sopt/now/BindingFragment.kt @@ -0,0 +1,30 @@ +package com.sopt.now + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import androidx.viewbinding.ViewBinding + +abstract class BindingFragment : Fragment() { + private var _binding: T? = null + val binding: T + get() = requireNotNull(_binding) { "_binding이 null이 아닌 경우만 _binding 반환" } + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + _binding = fragmentBinding(inflater, container) + return binding.root + } + + abstract fun fragmentBinding(inflater: LayoutInflater, container: ViewGroup?): T + + override fun onDestroyView() { + _binding = null + super.onDestroyView() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/sopt/now/LoginActivity.kt b/app/src/main/java/com/sopt/now/LoginActivity.kt deleted file mode 100644 index 769464b..0000000 --- a/app/src/main/java/com/sopt/now/LoginActivity.kt +++ /dev/null @@ -1,80 +0,0 @@ -package com.sopt.now - -import android.content.Intent -import android.os.Bundle -import android.widget.Toast -import androidx.activity.result.ActivityResultLauncher -import androidx.activity.result.contract.ActivityResultContracts -import androidx.appcompat.app.AppCompatActivity -import com.sopt.now.databinding.ActivityLoginBinding - -class LoginActivity : AppCompatActivity() { - private lateinit var binding: ActivityLoginBinding - private lateinit var resultLauncher: ActivityResultLauncher - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - binding = ActivityLoginBinding.inflate(layoutInflater) - setContentView(binding.root) - - getUserInfo() - - moveToSignUp() - } - private fun getUserInfo() { - var id = "" - var pw = "" - var nick = "" - resultLauncher = registerForActivityResult( - ActivityResultContracts.StartActivityForResult() - ) { result -> - if (result.resultCode == RESULT_OK) { - result.data?.let { data -> - id = data.getStringExtra("id") ?: "" - pw = data.getStringExtra("pw") ?: "" - nick = data.getStringExtra("nick") ?: "" - } - } - } - binding.btnLogin.setOnClickListener { - moveToMain(id,pw,nick) - } - } - private fun moveToSignUp(){ - binding.btnLoginSignIn.setOnClickListener { - val intent = Intent(this, SignUpActivity::class.java) - resultLauncher.launch(intent) - } - } - private fun moveToMain(id:String,pw:String,nick:String){ - if (isLoginAvailable(id, pw)) { - val intent = Intent(this, MainActivity::class.java).apply { - saveUserInfo(id, pw, nick) - } - startActivity(intent) - } - } - private fun saveUserInfo(id:String,pw:String,nick:String) { - val sharedPreferences = getSharedPreferences("userInfo", MODE_PRIVATE) - val editor = sharedPreferences.edit() - editor - .putString("userId", id) - .putString("userPw", pw) - .putString("userNick", nick) - .apply() - } - private fun isLoginAvailable(id: String, pw: String) :Boolean { - var loginBool = false - val userId = binding.etvLoginId.text.toString() - val userPw = binding.etvLoginPw.text.toString() - val message = when{ - userId.isBlank() || userPw.isBlank() -> getString(R.string.login_error_blank) - userId != id || userPw != pw -> getString(R.string.login_error_different) - else -> { - loginBool = true - getString(R.string.login_success) - } - } - Toast.makeText(this,message,Toast.LENGTH_SHORT).show() - return loginBool - } -} diff --git a/app/src/main/java/com/sopt/now/MyPageFragment.kt b/app/src/main/java/com/sopt/now/MyPageFragment.kt deleted file mode 100644 index 3db5ae2..0000000 --- a/app/src/main/java/com/sopt/now/MyPageFragment.kt +++ /dev/null @@ -1,38 +0,0 @@ -package com.sopt.now - -import android.content.Context -import android.os.Bundle -import android.util.Log -import androidx.fragment.app.Fragment -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import com.sopt.now.databinding.FragmentHomeBinding -import com.sopt.now.databinding.FragmentMyPageBinding - -class MyPageFragment : Fragment() { - private val binding: FragmentMyPageBinding - get()= requireNotNull(_binding){"_binding이 null이 아닌 경우만 _binding 반환"} - private var _binding: FragmentMyPageBinding?= null - - override fun onCreateView( - inflater: LayoutInflater, container: ViewGroup?, - savedInstanceState: Bundle? - ): View? { - _binding = FragmentMyPageBinding.inflate(inflater,container,false) - getUserInfo() - return binding.root - } - - private fun getUserInfo() { - val userInfo = activity?.getSharedPreferences("userInfo", Context.MODE_PRIVATE) - binding.tvMainNick.text = userInfo?.getString("userNick", "") - binding.tvMainId.text = userInfo?.getString("userId", "") - binding.tvMainPw.text = userInfo?.getString("userPw", "") - } - - override fun onDestroyView() { - super.onDestroyView() - _binding = null - } -} \ No newline at end of file diff --git a/app/src/main/java/com/sopt/now/PreferenceUtil.kt b/app/src/main/java/com/sopt/now/PreferenceUtil.kt new file mode 100644 index 0000000..4638997 --- /dev/null +++ b/app/src/main/java/com/sopt/now/PreferenceUtil.kt @@ -0,0 +1,21 @@ +package com.sopt.now + +import android.content.Context +import android.content.SharedPreferences + +class PreferenceUtil(context: Context) { + private val prefs: SharedPreferences = + context.getSharedPreferences(USER_ID, Context.MODE_PRIVATE) + + fun getString(key: String, defValue: String): String { + return prefs.getString(key, defValue).toString() + } + + fun setString(key: String, str: String) { + prefs.edit().putString(key, str).apply() + } + + companion object { + const val USER_ID = "userId" + } +} \ No newline at end of file diff --git a/app/src/main/java/com/sopt/now/SearchFragment.kt b/app/src/main/java/com/sopt/now/SearchFragment.kt deleted file mode 100644 index 5c3307e..0000000 --- a/app/src/main/java/com/sopt/now/SearchFragment.kt +++ /dev/null @@ -1,27 +0,0 @@ -package com.sopt.now - -import android.os.Bundle -import androidx.fragment.app.Fragment -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import com.sopt.now.databinding.FragmentMyPageBinding -import com.sopt.now.databinding.FragmentSearchBinding - -class SearchFragment : Fragment() { - private val binding: FragmentSearchBinding - get()= requireNotNull(_binding){"_binding이 null이 아닌 경우만 _binding 반환"} - private var _binding: FragmentSearchBinding?= null - - override fun onCreateView( - inflater: LayoutInflater, container: ViewGroup?, - savedInstanceState: Bundle? - ): View? { - return inflater.inflate(R.layout.fragment_search, container, false) - } - - override fun onDestroyView() { - super.onDestroyView() - _binding = null - } -} \ No newline at end of file diff --git a/app/src/main/java/com/sopt/now/SignUpActivity.kt b/app/src/main/java/com/sopt/now/SignUpActivity.kt deleted file mode 100644 index 48b0d23..0000000 --- a/app/src/main/java/com/sopt/now/SignUpActivity.kt +++ /dev/null @@ -1,63 +0,0 @@ -package com.sopt.now - -import android.content.Intent -import android.os.Bundle -import android.widget.Toast -import androidx.appcompat.app.AppCompatActivity -import com.sopt.now.databinding.ActivitySignUpBinding - -class SignUpActivity : AppCompatActivity() { - private lateinit var binding: ActivitySignUpBinding - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - binding = ActivitySignUpBinding.inflate(layoutInflater) - setContentView(binding.root) - - getUserInfo() - } - - private fun getUserInfo() { - binding.btnSignIn.setOnClickListener { - val id = binding.etvSignInId.text.toString() - val pw = binding.etvSignInPw.text.toString() - val nick = binding.etvSignInNick.text.toString() - val etc = binding.etvSignInEtc.text.toString() - - sendUserInfo(id, pw, nick, etc) - } - } - - private fun sendUserInfo(id: String, pw: String, nick: String, etc: String) { - if (isSignUpAvailable(id, pw, nick, etc)) { - val intent = Intent(this, LoginActivity::class.java) - intent.putExtra("id", id).putExtra("pw", pw).putExtra("nick", nick) - setResult(RESULT_OK, intent) - finish() - } - } - - private fun isSignUpAvailable(id: String, pw: String, nick: String, etc: String): Boolean { - var signUpBool = false - val message = when { - id.isEmpty() || pw.isEmpty() || nick.isEmpty() || etc.isEmpty() -> getString(R.string.sign_up_error_blank) - id.length !in MIN_ID_LENGTH..MAX_ID_LENGTH -> getString(R.string.sign_up_error_id) - pw.length !in MIN_PW_LENGTH..MAX_PW_LENGTH -> getString(R.string.sign_up_error_pw) - nick.isBlank() || nick.length != nick.trim().length -> getString(R.string.sign_up_error_nick) - etc.length !in 1..Int.MAX_VALUE -> getString(R.string.sign_up_error_etc) - else -> { - signUpBool = true - getString(R.string.sign_up_success) - } - } - Toast.makeText(this, message, Toast.LENGTH_SHORT).show() - return signUpBool - } - - companion object { - const val MIN_ID_LENGTH = 6 - const val MAX_ID_LENGTH = 10 - const val MIN_PW_LENGTH = 8 - const val MAX_PW_LENGTH = 12 - } -} \ No newline at end of file diff --git a/app/src/main/java/com/sopt/now/data/remote/dto/request/RequestChagePwDto.kt b/app/src/main/java/com/sopt/now/data/remote/dto/request/RequestChagePwDto.kt new file mode 100644 index 0000000..b68bdeb --- /dev/null +++ b/app/src/main/java/com/sopt/now/data/remote/dto/request/RequestChagePwDto.kt @@ -0,0 +1,15 @@ +package com.sopt.now.data.remote.dto.request + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable + +data class RequestChagePasswordDto ( + @SerialName("previousPassword") + val previousPassword: String, + @SerialName("newPassword") + val newPassword: String, + @SerialName("newPasswordVerification") + val newPasswordVerification: String +) \ No newline at end of file diff --git a/app/src/main/java/com/sopt/now/data/remote/dto/request/RequestLoginDto.kt b/app/src/main/java/com/sopt/now/data/remote/dto/request/RequestLoginDto.kt new file mode 100644 index 0000000..80dc1e5 --- /dev/null +++ b/app/src/main/java/com/sopt/now/data/remote/dto/request/RequestLoginDto.kt @@ -0,0 +1,12 @@ +package com.sopt.now.data.remote.dto.request + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class RequestLoginDto( + @SerialName("authenticationId") + val authenticationId: String, + @SerialName("password") + val password: String +) \ No newline at end of file diff --git a/app/src/main/java/com/sopt/now/data/remote/dto/request/RequestSignUpDto.kt b/app/src/main/java/com/sopt/now/data/remote/dto/request/RequestSignUpDto.kt new file mode 100644 index 0000000..abb97ab --- /dev/null +++ b/app/src/main/java/com/sopt/now/data/remote/dto/request/RequestSignUpDto.kt @@ -0,0 +1,16 @@ +package com.sopt.now.data.remote.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, +) diff --git a/app/src/main/java/com/sopt/now/data/remote/dto/response/ResponseChangePwDto.kt b/app/src/main/java/com/sopt/now/data/remote/dto/response/ResponseChangePwDto.kt new file mode 100644 index 0000000..ae1e2c7 --- /dev/null +++ b/app/src/main/java/com/sopt/now/data/remote/dto/response/ResponseChangePwDto.kt @@ -0,0 +1,13 @@ +package com.sopt.now.data.remote.dto.response + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable + +data class ResponseChangePasswordDto ( + @SerialName("code") + val code: Int, + @SerialName("message") + val message: String +) \ No newline at end of file diff --git a/app/src/main/java/com/sopt/now/data/remote/dto/response/ResponseFollowerDto.kt b/app/src/main/java/com/sopt/now/data/remote/dto/response/ResponseFollowerDto.kt new file mode 100644 index 0000000..84221d7 --- /dev/null +++ b/app/src/main/java/com/sopt/now/data/remote/dto/response/ResponseFollowerDto.kt @@ -0,0 +1,40 @@ +package com.sopt.now.data.remote.dto.response + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class ResponseFollowerDto( + @SerialName("data") + val data: List, + @SerialName("page") + val page: Int, + @SerialName("per_page") + val perPage: Int, + @SerialName("support") + val support: Support, + @SerialName("total") + val total: Int, + @SerialName("total_pages") + val totalPages: Int +) +@Serializable +data class Data( + @SerialName("avatar") + val avatar: String, + @SerialName("email") + val email: String, + @SerialName("first_name") + val firstName: String, + @SerialName("id") + val id: Int, + @SerialName("last_name") + val lastName: String +) +@Serializable +data class Support( + @SerialName("text") + val text: String, + @SerialName("url") + val url: String +) \ No newline at end of file diff --git a/app/src/main/java/com/sopt/now/data/remote/dto/response/ResponseLoginDto.kt b/app/src/main/java/com/sopt/now/data/remote/dto/response/ResponseLoginDto.kt new file mode 100644 index 0000000..63e0146 --- /dev/null +++ b/app/src/main/java/com/sopt/now/data/remote/dto/response/ResponseLoginDto.kt @@ -0,0 +1,12 @@ +package com.sopt.now.data.remote.dto.response + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class ResponseLoginDto ( + @SerialName("code") + val code: Int, + @SerialName("message") + val message: String +) \ No newline at end of file diff --git a/app/src/main/java/com/sopt/now/data/remote/dto/response/ResponseSignUpDto.kt b/app/src/main/java/com/sopt/now/data/remote/dto/response/ResponseSignUpDto.kt new file mode 100644 index 0000000..708abaf --- /dev/null +++ b/app/src/main/java/com/sopt/now/data/remote/dto/response/ResponseSignUpDto.kt @@ -0,0 +1,12 @@ +package com.sopt.now.data.remote.dto.response + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class ResponseSignUpDto( + @SerialName("code") + val code: Int, + @SerialName("message") + val message: String +) diff --git a/app/src/main/java/com/sopt/now/data/remote/dto/response/ResponseUserInfoDto.kt b/app/src/main/java/com/sopt/now/data/remote/dto/response/ResponseUserInfoDto.kt new file mode 100644 index 0000000..6d46336 --- /dev/null +++ b/app/src/main/java/com/sopt/now/data/remote/dto/response/ResponseUserInfoDto.kt @@ -0,0 +1,23 @@ +package com.sopt.now.data.remote.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("nicknamename") + val nicknamename: String, + @SerialName("phone") + val phone: String +) \ No newline at end of file diff --git a/app/src/main/java/com/sopt/now/data/remote/service/AuthService.kt b/app/src/main/java/com/sopt/now/data/remote/service/AuthService.kt new file mode 100644 index 0000000..b903ba7 --- /dev/null +++ b/app/src/main/java/com/sopt/now/data/remote/service/AuthService.kt @@ -0,0 +1,24 @@ +package com.sopt.now.data.remote.service + +import com.sopt.now.data.remote.dto.request.RequestChagePasswordDto +import com.sopt.now.data.remote.dto.request.RequestLoginDto +import com.sopt.now.data.remote.dto.request.RequestSignUpDto +import com.sopt.now.data.remote.dto.response.ResponseChangePasswordDto +import com.sopt.now.data.remote.dto.response.ResponseLoginDto +import com.sopt.now.data.remote.dto.response.ResponseSignUpDto +import retrofit2.Call +import retrofit2.http.Body +import retrofit2.http.PATCH +import retrofit2.http.POST + +interface AuthService { + @POST("member/join") //http 메소드 + fun postSignUp( + @Body request: RequestSignUpDto + ): Call //비동기->callback + @POST("member/login") + fun postLogin( + @Body request : RequestLoginDto + ) : Call + +} \ No newline at end of file diff --git a/app/src/main/java/com/sopt/now/data/remote/service/FollwerService.kt b/app/src/main/java/com/sopt/now/data/remote/service/FollwerService.kt new file mode 100644 index 0000000..23937f4 --- /dev/null +++ b/app/src/main/java/com/sopt/now/data/remote/service/FollwerService.kt @@ -0,0 +1,13 @@ +package com.sopt.now.data.remote.service + +import com.sopt.now.data.remote.dto.response.ResponseFollowerDto +import retrofit2.Call +import retrofit2.http.GET +import retrofit2.http.Query + +interface FollwerService { + @GET("/api/users") + fun getFollowerInfo( + @Query ("page") page : Int + ) : Call +} \ No newline at end of file diff --git a/app/src/main/java/com/sopt/now/data/remote/service/UserService.kt b/app/src/main/java/com/sopt/now/data/remote/service/UserService.kt new file mode 100644 index 0000000..1b86854 --- /dev/null +++ b/app/src/main/java/com/sopt/now/data/remote/service/UserService.kt @@ -0,0 +1,19 @@ +package com.sopt.now.data.remote.service + +import com.sopt.now.data.remote.dto.request.RequestChagePasswordDto +import com.sopt.now.data.remote.dto.response.ResponseChangePasswordDto +import com.sopt.now.data.remote.dto.response.ResponseUserInfoDto +import retrofit2.Call +import retrofit2.http.Body +import retrofit2.http.GET +import retrofit2.http.PATCH + +interface UserService { + @GET("/member/info") + fun getUserInfo() : Call + + @PATCH("member/password") + fun patchChangePassword( + @Body request : RequestChagePasswordDto + ) : Call +} \ No newline at end of file diff --git a/app/src/main/java/com/sopt/now/presentation/auth/changepassword/ChangePasswordActivity.kt b/app/src/main/java/com/sopt/now/presentation/auth/changepassword/ChangePasswordActivity.kt new file mode 100644 index 0000000..26b7ffa --- /dev/null +++ b/app/src/main/java/com/sopt/now/presentation/auth/changepassword/ChangePasswordActivity.kt @@ -0,0 +1,60 @@ +package com.sopt.now.presentation.auth.changepassword + +import android.content.Intent +import android.os.Bundle +import android.widget.Toast +import androidx.activity.viewModels +import androidx.appcompat.app.AppCompatActivity +import com.sopt.now.PreferenceUtil +import com.sopt.now.data.remote.dto.request.RequestChagePasswordDto +import com.sopt.now.databinding.ActivityChangePasswordBinding +import com.sopt.now.presentation.auth.login.LoginActivity + +class ChangePasswordActivity : AppCompatActivity() { + private val binding by lazy { ActivityChangePasswordBinding.inflate(layoutInflater) } + private val viewModel by viewModels() + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(binding.root) + prefs = PreferenceUtil(applicationContext) + initViews() + initObserver() + } + + private fun initViews() { + binding.tvChangePassword.setOnClickListener { + viewModel.changePassword(getChangePasswordRequestDto()) + } + } + + private fun initObserver() { + viewModel.liveData.observe(this) { loginState -> + Toast.makeText( + this@ChangePasswordActivity, + loginState.message, + Toast.LENGTH_SHORT, + ).show() + if (loginState.isSuccess) { + Intent(this, LoginActivity::class.java).apply { + startActivity(this) + } + finish() + } + } + } + + private fun getChangePasswordRequestDto(): RequestChagePasswordDto { + val oldPassword = binding.etvOldPassword.text.toString() + val newPassword = binding.etvNewPassword.text.toString() + val checkPassword = binding.etvNewPasswordCheck.text.toString() + return RequestChagePasswordDto( + previousPassword = oldPassword, + newPassword = newPassword, + newPasswordVerification = checkPassword + ) + } + + companion object { + lateinit var prefs: PreferenceUtil + } +} \ No newline at end of file diff --git a/app/src/main/java/com/sopt/now/presentation/auth/changepassword/ChangePasswordState.kt b/app/src/main/java/com/sopt/now/presentation/auth/changepassword/ChangePasswordState.kt new file mode 100644 index 0000000..6d8efa6 --- /dev/null +++ b/app/src/main/java/com/sopt/now/presentation/auth/changepassword/ChangePasswordState.kt @@ -0,0 +1,6 @@ +package com.sopt.now.presentation.auth.changepassword + +data class ChangePasswordState( + val isSuccess: Boolean, + val message: String +) \ No newline at end of file diff --git a/app/src/main/java/com/sopt/now/presentation/auth/changepassword/ChangePasswordViewModel.kt b/app/src/main/java/com/sopt/now/presentation/auth/changepassword/ChangePasswordViewModel.kt new file mode 100644 index 0000000..4b9fb45 --- /dev/null +++ b/app/src/main/java/com/sopt/now/presentation/auth/changepassword/ChangePasswordViewModel.kt @@ -0,0 +1,46 @@ +package com.sopt.now.presentation.auth.changepassword + +import android.util.Log +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel +import com.sopt.now.ServicePool +import com.sopt.now.data.remote.dto.request.RequestChagePasswordDto +import com.sopt.now.data.remote.dto.response.ResponseChangePasswordDto +import retrofit2.Call +import retrofit2.Callback +import retrofit2.Response + +class ChangePasswordViewModel : ViewModel() { + private val userService by lazy { ServicePool.userService } + val liveData = MutableLiveData() + + fun changePassword(request : RequestChagePasswordDto) { + userService.patchChangePassword(request).enqueue(object : Callback { + override fun onResponse( + call: Call, + response: Response, + ) { + if (response.isSuccessful) { + val data: ResponseChangePasswordDto? = response.body() + liveData.value = ChangePasswordState( + isSuccess = true, + message = "비밀번호가 성공적으로 변경되었습니다. 재로그인이 필요합니다." + ) + } else { + val error = response.message() + liveData.value = ChangePasswordState( + isSuccess = false, + message = "비밀번호 변경에 실패했습니다. $error" + ) + } + } + + override fun onFailure(call: Call, t: Throwable) { + liveData.value = ChangePasswordState( + isSuccess = false, + message = "서버에러" + ) + } + }) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/sopt/now/presentation/auth/login/LoginActivity.kt b/app/src/main/java/com/sopt/now/presentation/auth/login/LoginActivity.kt new file mode 100644 index 0000000..692cdb4 --- /dev/null +++ b/app/src/main/java/com/sopt/now/presentation/auth/login/LoginActivity.kt @@ -0,0 +1,64 @@ +package com.sopt.now.presentation.auth.login + +import android.content.Intent +import android.os.Bundle +import android.widget.Toast +import androidx.activity.viewModels +import androidx.appcompat.app.AppCompatActivity +import com.sopt.now.presentation.main.MainActivity +import com.sopt.now.PreferenceUtil +import com.sopt.now.presentation.auth.signup.SignUpActivity +import com.sopt.now.databinding.ActivityLoginBinding +import com.sopt.now.data.remote.dto.request.RequestLoginDto + +class LoginActivity : AppCompatActivity() { + + private val binding by lazy { ActivityLoginBinding.inflate(layoutInflater) } + private val viewModel by viewModels() + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(binding.root) + prefs = PreferenceUtil(applicationContext) + initViews() + initObserver() + moveToSignUp() + } + + private fun initViews() { + binding.btnLogin.setOnClickListener { + viewModel.login( + RequestLoginDto( + authenticationId = binding.etvLoginId.text.toString(), + password = binding.etvLoginPassword.text.toString() + ) + ) + } + } + + private fun initObserver() { + viewModel.liveData.observe(this) { loginState -> + Toast.makeText( + this@LoginActivity, + loginState.message, + Toast.LENGTH_SHORT, + ).show() + if (loginState.isSuccess) { + Intent(this, MainActivity::class.java).apply { + startActivity(this) + } + } + } + } + + private fun moveToSignUp() { + binding.btnLoginSignIn.setOnClickListener { + Intent(this, SignUpActivity::class.java).apply { + startActivity(this) + } + } + } + + companion object { + lateinit var prefs: PreferenceUtil + } +} \ No newline at end of file diff --git a/app/src/main/java/com/sopt/now/presentation/auth/login/LoginState.kt b/app/src/main/java/com/sopt/now/presentation/auth/login/LoginState.kt new file mode 100644 index 0000000..45b8fdd --- /dev/null +++ b/app/src/main/java/com/sopt/now/presentation/auth/login/LoginState.kt @@ -0,0 +1,6 @@ +package com.sopt.now.presentation.auth.login + +data class LoginState( + val isSuccess: Boolean, + val message: String +) \ No newline at end of file diff --git a/app/src/main/java/com/sopt/now/presentation/auth/login/LoginViewModel.kt b/app/src/main/java/com/sopt/now/presentation/auth/login/LoginViewModel.kt new file mode 100644 index 0000000..53e0a92 --- /dev/null +++ b/app/src/main/java/com/sopt/now/presentation/auth/login/LoginViewModel.kt @@ -0,0 +1,57 @@ +package com.sopt.now.presentation.auth.login + +import android.util.Log +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel +import com.sopt.now.ServicePool +import com.sopt.now.data.remote.dto.request.RequestLoginDto +import com.sopt.now.data.remote.dto.response.ResponseLoginDto +import retrofit2.Call +import retrofit2.Callback +import retrofit2.Response + + +class LoginViewModel : ViewModel() { + private val authService by lazy { ServicePool.authService } + private val _liveData = MutableLiveData() + val liveData : LiveData + get() = _liveData + var userId: String? = "" + + fun login(request: RequestLoginDto) { + authService.postLogin(request).enqueue(object : Callback { + override fun onResponse( + call: Call, + response: Response, + ) { + if (response.isSuccessful) { + val data: ResponseLoginDto? = response.body() + userId = response.headers()[LOCATION] + userId?.let { LoginActivity.prefs.setString(USER_ID, it) } + _liveData.value = LoginState( + isSuccess = true, + message = "로그인 성공 유저의 ID는 $userId 입니다" + ) + } else { + val error = response.message() + _liveData.value = LoginState( + isSuccess = false, + message = "로그인이 실패했습니다 $error" + ) + } + } + + override fun onFailure(call: Call, t: Throwable) { + _liveData.value = LoginState( + isSuccess = false, + message = "서버에러" + ) + } + }) + } + companion object { + const val USER_ID = "userId" + const val LOCATION = "location" + } +} \ No newline at end of file diff --git a/app/src/main/java/com/sopt/now/presentation/auth/signup/SignUpActivity.kt b/app/src/main/java/com/sopt/now/presentation/auth/signup/SignUpActivity.kt new file mode 100644 index 0000000..4c9e865 --- /dev/null +++ b/app/src/main/java/com/sopt/now/presentation/auth/signup/SignUpActivity.kt @@ -0,0 +1,60 @@ +package com.sopt.now.presentation.auth.signup + +import android.os.Bundle +import android.widget.Toast +import androidx.activity.viewModels +import androidx.appcompat.app.AppCompatActivity +import com.sopt.now.R +import com.sopt.now.databinding.ActivitySignUpBinding +import com.sopt.now.data.remote.dto.request.RequestSignUpDto + +class SignUpActivity : AppCompatActivity() { + + private val binding by lazy { ActivitySignUpBinding.inflate(layoutInflater) } + private val viewModel by viewModels() + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(binding.root) + initViews() + initObserver() + } + + private fun initViews() { + binding.btnSignUp.setOnClickListener { + viewModel.signUp(getSignUpRequestDto()) + } + } + + private fun initObserver() { + viewModel.liveData.observe(this) { signUpState -> + if (signUpState.isSuccess) { + Toast.makeText( + this@SignUpActivity, + getString(R.string.sign_up_success, signUpState.message), + Toast.LENGTH_SHORT + ).show() + finish() + } + else { + Toast.makeText( + this@SignUpActivity, + getString(R.string.sign_up_failed, signUpState.message), + Toast.LENGTH_SHORT + ).show() + } + } + } + + private fun getSignUpRequestDto(): RequestSignUpDto { + val id = binding.etvSignUpId.text.toString() + val password = binding.etvSignUpPassword.text.toString() + val nickname = binding.etvSignUpNickname.text.toString() + val phoneNumber = binding.etvSignUpPhone.text.toString() + return RequestSignUpDto( + authenticationId = id, + password = password, + nickname = nickname, + phone = phoneNumber + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/sopt/now/presentation/auth/signup/SignUpState.kt b/app/src/main/java/com/sopt/now/presentation/auth/signup/SignUpState.kt new file mode 100644 index 0000000..b74986e --- /dev/null +++ b/app/src/main/java/com/sopt/now/presentation/auth/signup/SignUpState.kt @@ -0,0 +1,6 @@ +package com.sopt.now.presentation.auth.signup + +data class SignUpState( + val isSuccess: Boolean, + val message: String +) diff --git a/app/src/main/java/com/sopt/now/presentation/auth/signup/SignUpViewModel.kt b/app/src/main/java/com/sopt/now/presentation/auth/signup/SignUpViewModel.kt new file mode 100644 index 0000000..4b15e95 --- /dev/null +++ b/app/src/main/java/com/sopt/now/presentation/auth/signup/SignUpViewModel.kt @@ -0,0 +1,54 @@ +package com.sopt.now.presentation.auth.signup + +import android.util.Log +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel +import com.sopt.now.ServicePool +import com.sopt.now.data.remote.dto.request.RequestSignUpDto +import com.sopt.now.data.remote.dto.response.ResponseSignUpDto +import retrofit2.Call +import retrofit2.Callback +import retrofit2.Response + + +class SignUpViewModel : ViewModel() { + private val authService by lazy { ServicePool.authService } + val _liveData = MutableLiveData() + val liveData : LiveData + get()= _liveData + + fun signUp(request: RequestSignUpDto) { + authService.postSignUp(request).enqueue(object : Callback { + override fun onResponse( + call: Call, + response: Response, + ) { + if (response.isSuccessful) { + val data: ResponseSignUpDto? = response.body() + val userId = response.headers()[LOCATION] + _liveData.value = SignUpState( + isSuccess = true, + message = "회원가입 성공 유저의 ID는 $userId 입니다" + ) + } else { + val error = response.message() + _liveData.value = SignUpState( + isSuccess = false, + message = "회원가입이 실패했습니다 $error" + ) + } + } + + override fun onFailure(call: Call, t: Throwable) { + _liveData.value = SignUpState( + isSuccess = false, + message = "서버에러" + ) + } + }) + } + companion object { + const val LOCATION = "location" + } +} \ No newline at end of file diff --git a/app/src/main/java/com/sopt/now/MainActivity.kt b/app/src/main/java/com/sopt/now/presentation/main/MainActivity.kt similarity index 86% rename from app/src/main/java/com/sopt/now/MainActivity.kt rename to app/src/main/java/com/sopt/now/presentation/main/MainActivity.kt index 258b069..f152575 100644 --- a/app/src/main/java/com/sopt/now/MainActivity.kt +++ b/app/src/main/java/com/sopt/now/presentation/main/MainActivity.kt @@ -1,9 +1,13 @@ -package com.sopt.now +package com.sopt.now.presentation.main import android.os.Bundle import androidx.appcompat.app.AppCompatActivity import androidx.fragment.app.Fragment +import com.sopt.now.R import com.sopt.now.databinding.ActivityMainBinding +import com.sopt.now.presentation.main.home.HomeFragment +import com.sopt.now.presentation.main.mypage.MyPageFragment +import com.sopt.now.presentation.main.search.SearchFragment class MainActivity : AppCompatActivity() { private lateinit var binding: ActivityMainBinding diff --git a/app/src/main/java/com/sopt/now/presentation/main/home/FollowerState.kt b/app/src/main/java/com/sopt/now/presentation/main/home/FollowerState.kt new file mode 100644 index 0000000..2f78a0a --- /dev/null +++ b/app/src/main/java/com/sopt/now/presentation/main/home/FollowerState.kt @@ -0,0 +1,6 @@ +package com.sopt.now.presentation.main.home + +data class FollowerState( + val isSuccess: Boolean, + val message: String +) diff --git a/app/src/main/java/com/sopt/now/presentation/main/home/FollowerViewModel.kt b/app/src/main/java/com/sopt/now/presentation/main/home/FollowerViewModel.kt new file mode 100644 index 0000000..830ef0f --- /dev/null +++ b/app/src/main/java/com/sopt/now/presentation/main/home/FollowerViewModel.kt @@ -0,0 +1,47 @@ +package com.sopt.now.presentation.main.home + +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel +import com.sopt.now.ServicePool +import com.sopt.now.data.remote.dto.response.ResponseFollowerDto +import retrofit2.Call +import retrofit2.Callback +import retrofit2.Response + +class FollowerViewModel : ViewModel() { + private val followerService by lazy { ServicePool.followerService } + private val _liveData = MutableLiveData() + val liveData : LiveData + get()=_liveData + + fun followerInfo(page:Int) { + followerService.getFollowerInfo(page).enqueue(object : Callback { + override fun onResponse( + call: Call, + response: Response, + ) { + if (response.isSuccessful) { + val data: ResponseFollowerDto? = response.body() + _liveData.value = FollowerState( + isSuccess = true, + message = "팔로워 정보 불러오기에 성공했습니다.", + ) + } else { + val error = response.message() + _liveData.value = FollowerState( + isSuccess = false, + message = "팔로워 정보 불러오기에 실패했습니다. $error" + ) + } + } + + override fun onFailure(call: Call, t: Throwable) { + _liveData.value = FollowerState( + isSuccess = false, + message = "서버에러" + ) + } + }) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/sopt/now/HomeFragment.kt b/app/src/main/java/com/sopt/now/presentation/main/home/HomeFragment.kt similarity index 53% rename from app/src/main/java/com/sopt/now/HomeFragment.kt rename to app/src/main/java/com/sopt/now/presentation/main/home/HomeFragment.kt index aa2b6ef..21f23af 100644 --- a/app/src/main/java/com/sopt/now/HomeFragment.kt +++ b/app/src/main/java/com/sopt/now/presentation/main/home/HomeFragment.kt @@ -1,27 +1,20 @@ -package com.sopt.now +package com.sopt.now.presentation.main.home import android.os.Bundle -import androidx.fragment.app.Fragment import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.fragment.app.viewModels import androidx.recyclerview.widget.LinearLayoutManager +import com.sopt.now.BindingFragment import com.sopt.now.databinding.FragmentHomeBinding -class HomeFragment : Fragment() { - private val binding:FragmentHomeBinding - get()= requireNotNull(_binding){"_binding이 null이 아닌 경우만 _binding 반환"} - private var _binding: FragmentHomeBinding ?= null +class HomeFragment : BindingFragment() { private val viewModel by viewModels() - - override fun onCreateView( - inflater: LayoutInflater, container: ViewGroup?, - savedInstanceState: Bundle? - ): View { - _binding = FragmentHomeBinding.inflate(inflater,container,false) - return binding.root - } + override fun fragmentBinding( + inflater: LayoutInflater, + container: ViewGroup? + ): FragmentHomeBinding = FragmentHomeBinding.inflate(inflater, container, false) override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) @@ -32,10 +25,4 @@ class HomeFragment : Fragment() { } homeListAdapter.setHomeList(viewModel.homeListData) } - - override fun onDestroyView() { - super.onDestroyView() - _binding = null - } - } \ No newline at end of file diff --git a/app/src/main/java/com/sopt/now/HomeList.kt b/app/src/main/java/com/sopt/now/presentation/main/home/HomeList.kt similarity index 86% rename from app/src/main/java/com/sopt/now/HomeList.kt rename to app/src/main/java/com/sopt/now/presentation/main/home/HomeList.kt index f3552df..a9c37e8 100644 --- a/app/src/main/java/com/sopt/now/HomeList.kt +++ b/app/src/main/java/com/sopt/now/presentation/main/home/HomeList.kt @@ -1,4 +1,4 @@ -package com.sopt.now +package com.sopt.now.presentation.main.home import androidx.annotation.DrawableRes diff --git a/app/src/main/java/com/sopt/now/HomeListAdapter.kt b/app/src/main/java/com/sopt/now/presentation/main/home/HomeListAdapter.kt similarity index 97% rename from app/src/main/java/com/sopt/now/HomeListAdapter.kt rename to app/src/main/java/com/sopt/now/presentation/main/home/HomeListAdapter.kt index 3463924..41de13b 100644 --- a/app/src/main/java/com/sopt/now/HomeListAdapter.kt +++ b/app/src/main/java/com/sopt/now/presentation/main/home/HomeListAdapter.kt @@ -1,4 +1,4 @@ -package com.sopt.now +package com.sopt.now.presentation.main.home import android.view.LayoutInflater import android.view.ViewGroup diff --git a/app/src/main/java/com/sopt/now/HomeListViewHolder.kt b/app/src/main/java/com/sopt/now/presentation/main/home/HomeListViewHolder.kt similarity index 95% rename from app/src/main/java/com/sopt/now/HomeListViewHolder.kt rename to app/src/main/java/com/sopt/now/presentation/main/home/HomeListViewHolder.kt index 2e77535..17490b0 100644 --- a/app/src/main/java/com/sopt/now/HomeListViewHolder.kt +++ b/app/src/main/java/com/sopt/now/presentation/main/home/HomeListViewHolder.kt @@ -1,4 +1,4 @@ -package com.sopt.now +package com.sopt.now.presentation.main.home import androidx.recyclerview.widget.RecyclerView import com.sopt.now.databinding.ItemFriendBinding diff --git a/app/src/main/java/com/sopt/now/HomeViewModel.kt b/app/src/main/java/com/sopt/now/presentation/main/home/HomeViewModel.kt similarity index 97% rename from app/src/main/java/com/sopt/now/HomeViewModel.kt rename to app/src/main/java/com/sopt/now/presentation/main/home/HomeViewModel.kt index b488844..08069f3 100644 --- a/app/src/main/java/com/sopt/now/HomeViewModel.kt +++ b/app/src/main/java/com/sopt/now/presentation/main/home/HomeViewModel.kt @@ -1,6 +1,7 @@ -package com.sopt.now +package com.sopt.now.presentation.main.home import androidx.lifecycle.ViewModel +import com.sopt.now.R class HomeViewModel : ViewModel() { val homeListData = listOf( diff --git a/app/src/main/java/com/sopt/now/presentation/main/mypage/MyPageFragment.kt b/app/src/main/java/com/sopt/now/presentation/main/mypage/MyPageFragment.kt new file mode 100644 index 0000000..74295c0 --- /dev/null +++ b/app/src/main/java/com/sopt/now/presentation/main/mypage/MyPageFragment.kt @@ -0,0 +1,52 @@ +package com.sopt.now.presentation.main.mypage + +import android.content.Intent +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.Toast +import androidx.fragment.app.viewModels +import com.sopt.now.BindingFragment +import com.sopt.now.databinding.FragmentMyPageBinding +import com.sopt.now.presentation.auth.changepassword.ChangePasswordActivity + +class MyPageFragment : BindingFragment() { + private val viewModel by viewModels() + override fun fragmentBinding( + inflater: LayoutInflater, + container: ViewGroup? + ): FragmentMyPageBinding = FragmentMyPageBinding.inflate(inflater, container, false) + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + initObserver() + moveToChangePassword() + } + + private fun initObserver() { + viewModel.liveData.observe(viewLifecycleOwner) { userInfoState -> + Toast.makeText( + activity, + userInfoState.message, + Toast.LENGTH_SHORT, + ).show() + if (userInfoState.isSuccess) { + with(binding) { + tvMainNickname.text = userInfoState.userNickname + tvMainId.text = userInfoState.userId + tvMainPhone.text = userInfoState.userPhone + } + } + } + } + + private fun moveToChangePassword() { + binding.tvChangePassword.setOnClickListener { + Intent(activity, ChangePasswordActivity::class.java).apply { + startActivity(this) + activity?.finish() + } + } + } +} diff --git a/app/src/main/java/com/sopt/now/presentation/main/mypage/UserInfoState.kt b/app/src/main/java/com/sopt/now/presentation/main/mypage/UserInfoState.kt new file mode 100644 index 0000000..f696e16 --- /dev/null +++ b/app/src/main/java/com/sopt/now/presentation/main/mypage/UserInfoState.kt @@ -0,0 +1,9 @@ +package com.sopt.now.presentation.main.mypage + +data class UserInfoState( + val isSuccess: Boolean, + val message: String, + val userId : String? = "", + val userNickname : String? = "", + val userPhone : String? = "" +) \ No newline at end of file diff --git a/app/src/main/java/com/sopt/now/presentation/main/mypage/UserInfoViewModel.kt b/app/src/main/java/com/sopt/now/presentation/main/mypage/UserInfoViewModel.kt new file mode 100644 index 0000000..a854d49 --- /dev/null +++ b/app/src/main/java/com/sopt/now/presentation/main/mypage/UserInfoViewModel.kt @@ -0,0 +1,56 @@ +package com.sopt.now.presentation.main.mypage + +import android.util.Log +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel +import com.sopt.now.ServicePool +import com.sopt.now.data.remote.dto.response.ResponseUserInfoDto +import com.sopt.now.data.remote.dto.response.UserInfo +import retrofit2.Call +import retrofit2.Callback +import retrofit2.Response + +class UserInfoViewModel : ViewModel() { + private val userService by lazy { ServicePool.userService } + private val _liveData = MutableLiveData() + val liveData : LiveData + get()=_liveData + + init{ + userInfo() + } + + fun userInfo() { + userService.getUserInfo().enqueue(object : Callback { + override fun onResponse( + call: Call, + response: Response, + ) { + if (response.isSuccessful) { + val data: ResponseUserInfoDto? = response.body() + _liveData.value = UserInfoState( + isSuccess = true, + message = "회원 정보 불러오기에 성공했습니다.", + userId = data?.data?.authenticationId, + userNickname = data?.data?.nicknamename, + userPhone = data?.data?.phone + ) + } else { + val error = response.message() + _liveData.value = UserInfoState( + isSuccess = false, + message = "회원 정보 불러오기에 실패했습니다. $error" + ) + } + } + + override fun onFailure(call: Call, t: Throwable) { + _liveData.value = UserInfoState( + isSuccess = false, + message = "서버에러" + ) + } + }) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/sopt/now/presentation/main/search/SearchFragment.kt b/app/src/main/java/com/sopt/now/presentation/main/search/SearchFragment.kt new file mode 100644 index 0000000..a9df7e6 --- /dev/null +++ b/app/src/main/java/com/sopt/now/presentation/main/search/SearchFragment.kt @@ -0,0 +1,14 @@ +package com.sopt.now.presentation.main.search + +import android.view.LayoutInflater +import android.view.ViewGroup +import com.sopt.now.BindingFragment +import com.sopt.now.databinding.FragmentSearchBinding + +class SearchFragment : BindingFragment() { + override fun fragmentBinding( + inflater: LayoutInflater, + container: ViewGroup? + ): FragmentSearchBinding = FragmentSearchBinding.inflate(inflater, container, false) + +} \ No newline at end of file diff --git a/app/src/main/res/layout/activity_change_password.xml b/app/src/main/res/layout/activity_change_password.xml new file mode 100644 index 0000000..3dd5616 --- /dev/null +++ b/app/src/main/res/layout/activity_change_password.xml @@ -0,0 +1,84 @@ + + + + + + + + + + + + + \ 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 4e11b9e..a09684b 100644 --- a/app/src/main/res/layout/activity_login.xml +++ b/app/src/main/res/layout/activity_login.xml @@ -5,7 +5,7 @@ android:id="@+id/main" android:layout_width="match_parent" android:layout_height="match_parent" - tools:context=".LoginActivity"> + tools:context=".presentation.auth.login.LoginActivity">