[Android 앱 개발 입문] 챌린지 과제 - 자기소개 앱 (1)코드 다듬기-1

0
post-thumbnail
post-custom-banner

🍥구현 기능

  • 전체 코드 다듬기
    • 함수 파라미터 의미있는 이름을 갖도록 변경하기
    • Scope function 적절하게 사용하기
      • this 반환이 필요한 경우 apply 사용
      • this 반환이 필요하지 않은 경우 run/with 사용
    • 사용하지 않는 패키지 import 삭제하기
    • Extra의 키 값 상수로 선언하기
  • TextView 확장함수 삭제하기
    • 이미 존재하는 isVisible 속성 이용해 구현하기
  • EditText 입력 이벤트 처리 코드 변경하기
    • TextWatcher 인터페이스를 구현하는 클래스들 삭제 -> function으로 변경하기
      (NameTextWatcher, EmailTextWatcher, PasswordTextWatcher)
    • companion object로 정의한 입력 값이 유효한지 저장하는 Boolean 변수들 삭제
      (isNameValid, isPasswordValid, isEmailValid)

🍥구현하기

SignInActivity.kt

class SignInActivity : AppCompatActivity() {
    private val TAG = "SignInActivity"

    companion object{
        val EXTRA_SIGN_UP_NAME = "extra_sign_up_name"
        val EXTRA_SIGN_UP_PASSWORD = "extra_sign_up_password"

        fun getResultIntent(signUpName:String, signUpPassword:String) :Intent =
        Intent().apply {
            putExtra(EXTRA_SIGN_UP_NAME, signUpName)
            putExtra(EXTRA_SIGN_UP_PASSWORD, signUpPassword)
        }
    }

    private val nameEditText by lazy { findViewById<EditText>(R.id.et_name) }
    private val passwordEditText by lazy { findViewById<EditText>(R.id.et_password) }

    private val nameWarningTextView by lazy { findViewById<TextView>(R.id.tv_name_warning) }
    private val passwordWarningTextView by lazy { findViewById<TextView>(R.id.tv_password_warning) }

    private val signInWarningTextView by lazy { findViewById<TextView>(R.id.tv_sign_in_warning) }
    private val signInButton by lazy { findViewById<Button>(R.id.btn_sign_in) }
    private val signUpButton by lazy { findViewById<Button>(R.id.btn_sign_up) }

    private val userInfoManager = UserInfoManager.getInstance()
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_sign_in)

        initNameEditText()
        initPasswordEditText()

        initSignInButton()

        val startForResultLauncher = registerForActivityResult(
            ActivityResultContracts.StartActivityForResult()
        ) { result ->

            if (result.resultCode == Activity.RESULT_OK) {
                Log.d(TAG, "startForResultLauncher) RESULT_OK")
                val intent = result.data

                intent?.let {
                    val signUpName = it.getStringExtra(EXTRA_SIGN_UP_NAME) ?: " "
                    val signUpPassword = it.getStringExtra(EXTRA_SIGN_UP_PASSWORD) ?: " "
                    Log.d(TAG, "startForResultLauncher) $signUpName $signUpPassword")

                    nameEditText.setText(signUpName)
                    passwordEditText.setText(signUpPassword)
                }
            }
        }

        initSignUpButton(startForResultLauncher)
    }

    private fun initNameEditText() {
        nameEditText.addTextChangedListener { text ->
            //로그인하는 경우, 이름이 비어있는지만 확인
            nameWarningTextView.run {
                if (text.isNullOrBlank()) {
                    setText(R.string.empty_name_warning)
                    isVisible = true
                } else {
                    isVisible = false
                }
            }
        }
    }

    private fun initPasswordEditText() {
        passwordEditText.addTextChangedListener { text ->
            //로그인하는 경우, 비밀번호 비어있는 지만 확인
            passwordWarningTextView.run {
                if (text.isNullOrBlank()) {
                    setText(R.string.empty_password_warning)
                    setTextColor(resources.getColor(R.color.warning_color))
                    isVisible = true
                } else {
                    isVisible = false
                }
            }
        }
    }

    private fun isNameValid(): Boolean {
        return !nameEditText.text.isNullOrBlank()
    }

    private fun isPasswordValid(): Boolean {
        return !passwordEditText.text.isNullOrBlank()
    }

    private fun initSignInButton() {
        signInButton.setOnClickListener {
            //로그인 하기 위해 모든 입력 유효한지 확인
            signInWarningTextView.run {
                if (!isNameValid()) {
                    Log.d(TAG, "sign in button) name is empty")
                    text = resources.getText(R.string.empty_name_warning)
                    isVisible = true
                    return@setOnClickListener
                }
                if (!isPasswordValid()) {
                    Log.d(TAG, "sign in button) password is empty")
                    text = resources.getText(R.string.empty_password_warning)
                    isVisible = true
                    return@setOnClickListener
                }
            }

            //로그인 시도하기
            val name = nameEditText.text.toString()
            val password = passwordEditText.text.toString()

            if (userInfoManager.signIn(name, password)) {
                //로그인 성공
                Log.d(TAG, "sign in button) sign in success")
                signInWarningTextView.isVisible = false

                startActivity(HomeActivity.newIntent(this, name, password))
            } else {
                //로그인 실패
                Log.d(TAG, "sign in button) sign in fail")
                signInWarningTextView.text = resources.getText(R.string.sign_in_fail_warning)
                signInWarningTextView.isVisible = true

            }
        }
    }

    private fun initSignUpButton(startForResultLauncher:ActivityResultLauncher<Intent>){
        signUpButton.setOnClickListener {
            val intent = Intent(applicationContext, SignUpActivity::class.java)
            startForResultLauncher.launch(intent)
        }
    }

}

SignUpActivity.kt

class SignUpActivity : AppCompatActivity() {
    private val TAG = "SignUpActivity"

    private val nameEditText by lazy { findViewById<EditText>(R.id.et_name) }
    private val nameWarningTextView by lazy { findViewById<TextView>(R.id.tv_name_warning) }

    private val emailEditText by lazy { findViewById<EditText>(R.id.et_email) }
    private val emailProviderEditText by lazy { findViewById<EditText>(R.id.et_email_provider) }
    private val emailProviderSpinner by lazy { findViewById<Spinner>(R.id.spinner_email_provider) }
    private val emailWarningTextView by lazy { findViewById<TextView>(R.id.tv_email_warning) }

    private val passwordEditText by lazy { findViewById<EditText>(R.id.et_password) }
    private val passwordWarningTextView by lazy { findViewById<TextView>(R.id.tv_password_warning) }

    private val passwordCheckEditText by lazy { findViewById<EditText>(R.id.et_password_check) }
    private val passwordCheckWarningTextView by lazy { findViewById<TextView>(R.id.tv_password_check_warning) }

    private val signUpWarningTextView by lazy { findViewById<TextView>(R.id.tv_sign_up_warning) }
    private val signUpButton by lazy { findViewById<Button>(R.id.btn_sign_up) }

    private val userInfoManager = UserInfoManager.getInstance()

    private var isNameValid = false
    private var isEmailValid = false
    private var isPasswordValid = false
    private var isPasswordCheckValid = false

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_sign_up)

        initNameEditText()
        initEmailEditText()
        initPasswordEditText()
        initPasswordCheckEditText()

        initEmailProviderSpinner()

        initSignUpButton()
    }

    private fun initNameEditText() {
        nameEditText.addTextChangedListener { text ->
            nameWarningTextView.run {
                //(1) 이름이 비어있는지 확인
                if (text.isNullOrBlank()) {
                    setText(R.string.empty_name_warning)
                    isVisible = true
                    isNameValid = false
                }
                //(2) 이미 존재하는 이름인지 확인
                else if (userInfoManager.findSameName(text.toString())) {
                    setText(R.string.same_name_warning)
                    isVisible = true
                    isNameValid = false
                } else {
                    isVisible = false
                    isNameValid = true
                }
            }
        }
    }

    private fun initEmailEditText() {
        emailEditText.addTextChangedListener { text ->
            emailWarningTextView.isVisible = text.isNullOrBlank()
            isEmailValid = !text.isNullOrBlank()
        }
    }

    private fun initPasswordEditText() {
        passwordEditText.addTextChangedListener { text ->
            //(1) 비어있는지 확인
            passwordWarningTextView.apply {
                if (text.isNullOrBlank()) {
                    setText(R.string.empty_password_warning)
                    setTextColor(resources.getColor(R.color.warning_color))
                    isVisible = true
                    isPasswordValid = false
                }
                //(2) 10자리 이상인지 확인
                else if (text.length < 10) {
                    setText(R.string.password_length_information)
                    setTextColor(resources.getColor(R.color.information_color))
                    isVisible = true
                    isPasswordValid = false

                }
                //(3) 대문자 포함하는지 확인
                else if (!containsUppercase(text.toString())) {
                    setText(R.string.password_uppercase_information)
                    setTextColor(resources.getColor(R.color.information_color))
                    isVisible = true
                    isPasswordValid = false
                }
                //(4) 특수문자 포함하는지 확인
                else if (!containsSpecialChar(text.toString())) {
                    setText(R.string.password_special_char_information)
                    setTextColor(resources.getColor(R.color.information_color))
                    isVisible = true
                    isPasswordValid = false
                } else {
                    isVisible = false
                    isPasswordValid = true
                }
            }
        }
    }

    private fun containsUppercase(password: String): Boolean {
        for (ch in password) {
            if (('A'.code <= ch.code) && (ch.code <= 'Z'.code)) return true
        }
        return false
    }

    private fun containsSpecialChar(password: String): Boolean {
        val possibleSpecialChars =
            listOf('!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '-', '+', '=')
        for (ch in password) {
            if (possibleSpecialChars.contains(ch)) return true
        }
        return false
    }

    private fun initPasswordCheckEditText() {
        passwordCheckEditText.addTextChangedListener { text ->
            passwordCheckWarningTextView.apply {
                //비어있는지 확인
                if (text.isNullOrBlank()) {
                    setText(R.string.empty_password_warning)
                    isVisible = true
                    isPasswordCheckValid = false
                }
                //비밀번호와 일치하는지 확인
                else if (text.toString() != passwordEditText.text.toString()) {
                    setText(R.string.password_different_warning)
                    isVisible = true
                    isPasswordCheckValid = false
                } else {
                    isVisible = false
                    isPasswordCheckValid = true
                }
            }
        }
    }

    private fun initEmailProviderSpinner(){
        ArrayAdapter.createFromResource(
            this,
            R.array.email_providers_array,
            android.R.layout.simple_spinner_item
        ).also { adapter ->
            adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
            emailProviderSpinner.adapter = adapter
        }
        emailProviderSpinner.onItemSelectedListener = spinnerOnItemSelectListener
    }

    private val spinnerOnItemSelectListener = object : AdapterView.OnItemSelectedListener {
        override fun onItemSelected(p0: AdapterView<*>?, view: View?, position: Int, id: Long) {
            Log.d(TAG, "email provider spinner) onItemSelected")
            if (position == emailProviderSpinner.adapter.count - 1) {
                emailProviderSpinner.visibility = View.GONE
                emailProviderEditText.visibility = View.VISIBLE
            }
        }
        override fun onNothingSelected(p0: AdapterView<*>?) {
            Log.d(TAG, "email provider spinner) onNothingSelected")
        }
    }

    private fun initSignUpButton(){
     signUpButton.setOnClickListener {
         //회원가입하기 위해 모든 입력 유효한지 확인
         if (isNameValid && isEmailValid && isPasswordValid && isPasswordCheckValid) {
             Log.d(TAG, "sign up button) sign up success")
             signUpWarningTextView.isVisible = false

             //회원가입
             val name = nameEditText.text.toString()
             val password = passwordEditText.text.toString()
             var email = emailEditText.text.toString()
             //email 서비스 제공자 붙이기
             email += if (emailProviderSpinner.visibility == View.VISIBLE) {
                 emailProviderSpinner.selectedItem.toString()
             } else {
                 emailProviderEditText.text?.toString() ?: ""
             }

             val userInfoManager = UserInfoManager.getInstance()
             userInfoManager.signUp(name, email, password)

             finishSignUpActivity(name, password)
         } else {
             Log.d(TAG, "sign up button) sign up fail")
             signUpWarningTextView.isVisible = true
         } }
    }

    private fun finishSignUpActivity(name: String, password: String) {
        setResult(Activity.RESULT_OK, SignInActivity.getResultIntent(name,password))
        finish()
    }
}

HomeActivity.kt

class HomeActivity : AppCompatActivity() {
    private val TAG = "HomeActivity"

    companion object{
        val EXTRA_NAME = "extra_name"
        val EXTRA_PASSWORD = "extra_password"

        fun newIntent(context: Context, name:String, password:String): Intent =
            Intent(context, HomeActivity::class.java).apply {
                putExtra(EXTRA_NAME, name)
                putExtra(EXTRA_PASSWORD, password)
            }
    }


    private val homeImageView:ImageView by lazy{findViewById(R.id.iv_home)}
    private val imageButton:Button by lazy{findViewById(R.id.btn_image)}

    private val nameTextView:TextView by lazy{findViewById(R.id.tv_home_name)}
    private val emailTextView:TextView by lazy {findViewById(R.id.tv_home_email)}

    private val exitButton: Button by lazy{findViewById(R.id.btn_exit)}


    private var isImageUploaded = false

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_home)

        setHomeImageViewRandom()
        val pickMedia = registerForActivityResult(ActivityResultContracts.PickVisualMedia()) { uri ->
            if (uri != null) {
                Log.d(TAG, "Photo Picker) Selected URI: $uri")
                setHomeImageView(uri)
                //버튼 상태 바꾸기
                setImageButtonUpload(false)
            } else {
                Log.d(TAG, "Photo Picker) No media selected")
            }
        }
        imageButton.setOnClickListener {
            if(!isImageUploaded){
                //사진 선택하기
                pickMedia.launch(PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.ImageOnly))
            }
            else{
                //사진 삭제하기
                setHomeImageViewRandom()
                //버튼 상태 바꾸기
                setImageButtonUpload(true)
            }
        }

        val name = intent.getStringExtra(EXTRA_NAME)!!
        val password = intent.getStringExtra(EXTRA_PASSWORD)!!
        val email = UserInfoManager.getInstance().findUserEmail(name, password)

        nameTextView.text = resources.getString(R.string.home_name, name)
        emailTextView.text = resources.getString(R.string.home_email, email)

        exitButton.setOnClickListener {
            finish()
        }
    }

    private fun setHomeImageViewRandom(){
        val imageNumber:Int = Random.nextInt(5)+1
        val imageId = resources.getIdentifier("ham${imageNumber}", "drawable", packageName)
        homeImageView.setImageResource(imageId)
    }
    private fun setHomeImageView(uri:Uri){
        homeImageView.setImageURI(uri)
    }

    private fun setImageButtonUpload(flag:Boolean){
        if(flag) {
            isImageUploaded = false
            imageButton.text = getString(R.string.upload_image)
        }
        else{
            isImageUploaded = true
            imageButton.text = getString(R.string.delete_image)
        }
    }
}
profile
Be able to be vulnerable, in search of truth
post-custom-banner

0개의 댓글