data class UserInfo(val name:String, val email:String, val password:String)
class UserInfoManager private constructor() {
private var userInfoArray = arrayOf<UserInfo>()
companion object{
private var instance: UserInfoManager? = null
fun getInstance(): UserInfoManager {
if(instance == null) instance = UserInfoManager()
return instance!!
}
}
fun signIn(name: String, password: String):Boolean{
for(user in userInfoArray) {
if((user.name == name) && (user.password == password)) return true
}
return false
}
fun findUserEmail(name: String, password: String): String {
for(user in userInfoArray) {
if((user.name == name) && (user.password == password)) return user.email
}
return ""
}
fun findSameName(name:String):Boolean{
for(user in userInfoArray){
if(user.name == name) return true
}
return false
}
fun signUp(name:String, email:String, password: String){
userInfoArray += UserInfo(name, email, password)
}
}
fun TextView.setVisible() {
visibility = View.VISIBLE
}
fun TextView.setInvisible() {
visibility = View.INVISIBLE
}
로그인 화면과 회원가입 화면에서 EditText를 실시간으로 관찰하며,
입력 칸이 비어있는지, 입력된 값이 유효한 값인지 확인해야 한다
이를 위해 add TextChangedListner와 TextWatcher 인터페이스를 사용한다!
nameEditText.addTextChangedListener { //onTextChanged에서 수행하고자 하는 코드 작성하기... }
editText.addTextChangedListner(object: TextWatcher{ override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) { TODO("Not yet implemented") } override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) { TODO("Not yet implemented") } override fun afterTextChanged(p0: Editable?) { TODO("Not yet implemented") } })
자기소개 앱에는 방법 3와 4을 사용하여 구현했다
enum class ActivityCode (val code:Int) {
SIGN_IN(1),
SIGN_UP(2)
}
class NameTextWatcher(warningTextView: TextView, activityCode: ActivityCode): TextWatcher{
private var warningTextView:TextView
private var activityCode:ActivityCode
init{
this.warningTextView = warningTextView
this.activityCode = activityCode
}
override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) = Unit
override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {
when(activityCode) {
ActivityCode.SIGN_IN -> {
//로그인하는 경우, 이름이 비어있는지만 확인
if (p0.isNullOrBlank()){
warningTextView.apply{
text = resources.getText(R.string.empty_name_warning)
setVisible()
}
SignInActivity.isNameValid = false
}
else{
warningTextView.setInvisible()
SignInActivity.isNameValid = true
}
}
ActivityCode.SIGN_UP -> {
val userInfoManager = UserInfoManager.getInstance()
//회원가입하는 경우,
//(1) 이름이 비어있는지 확인
if(p0.isNullOrBlank()){
warningTextView.apply{
text = resources.getText(R.string.empty_name_warning)
setVisible()
}
SignUpActivity.isNameValid = false
}
//(2) 이미 존재하는 이름인지 확인
else if(userInfoManager.findSameName(p0.toString())){
warningTextView.apply{
text = resources.getText(R.string.same_name_warning)
setVisible()
}
SignUpActivity.isNameValid = false
}
else{
warningTextView.setInvisible()
SignUpActivity.isNameValid = true
}
}
}
}
override fun afterTextChanged(p0: Editable?) = Unit
}
class EmailTextWatcher(warningTextView: TextView): TextWatcher {
private var warningTextView: TextView
init{
this.warningTextView = warningTextView
}
override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) = Unit
override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {
if (p0.isNullOrBlank()){
warningTextView.setVisible()
SignUpActivity.isEmailValid = false
}
else{
warningTextView.setInvisible()
SignUpActivity.isEmailValid = true
}
}
override fun afterTextChanged(p0: Editable?) = Unit
}
class PasswordTextWatcher(warningTextView: TextView, activityCode: ActivityCode) : TextWatcher {
private var warningTextView: TextView
private var activityCode: ActivityCode
init {
this.warningTextView = warningTextView
this.activityCode = activityCode
}
override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) = Unit
override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {
when (activityCode) {
ActivityCode.SIGN_IN -> {
//로그인하는 경우, 비밀번호 비어있는 지만 확인
if (p0.isNullOrBlank()) {
warningTextView.apply {
text = resources.getString(R.string.empty_password_warning)
setTextColor(resources.getColor(R.color.warning_color))
setVisible()
}
SignInActivity.isPasswordValid = false
} else {
warningTextView.setInvisible()
SignInActivity.isPasswordValid = true
}
}
ActivityCode.SIGN_UP -> {
//회원가입하는 경우,
//(1) 비어있는지 확인
if (p0.isNullOrBlank()) {
warningTextView.apply {
text = resources.getString(R.string.empty_password_warning)
setTextColor(resources.getColor(R.color.warning_color))
setVisible()
SignUpActivity.isPasswordValid = false
}
}
//(2) 10자리 이상인지 확인
else if (!isLongEnough(p0.toString())) {
warningTextView.apply {
text = resources.getString(R.string.password_length_information)
setTextColor(resources.getColor(R.color.information_color))
setVisible()
SignUpActivity.isPasswordValid = false
}
}
//(3) 대문자 포함하는지 확인
else if (!containsUppercase(p0.toString())) {
warningTextView.apply {
text = resources.getString(R.string.password_uppercase_information)
setTextColor(resources.getColor(R.color.information_color))
setVisible()
SignUpActivity.isPasswordValid = false
}
}
//(4) 특수문자 포함하는지 확인
else if (!containsSpecialChar(p0.toString())) {
warningTextView.apply {
text = resources.getString(R.string.password_special_char_information)
setTextColor(resources.getColor(R.color.information_color))
setVisible()
SignUpActivity.isPasswordValid = false
}
}
else warningTextView.setInvisible()
SignUpActivity.isPasswordValid = true
}
}
}
override fun afterTextChanged(p0: Editable?) = Unit
private fun isLongEnough(password: String): Boolean = (password.length >= 10)
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
}
}
class SignInActivity : AppCompatActivity() {
//로그 출력할 때 사용할 tag 값
private val TAG = "SignInActivity"
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) }
companion object{
var isNameValid = false
var isPasswordValid = false
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_sign_in)
nameEditText.addTextChangedListener(
NameTextWatcher(nameWarningTextView, ActivityCode.SIGN_IN))
passwordEditText.addTextChangedListener(
PasswordTextWatcher(passwordWarningTextView, ActivityCode.SIGN_IN))
signInButton.setOnClickListener(signInOnClickListener)
signUpButton.setOnClickListener {
val intent = Intent(this, SignUpActivity::class.java)
startActivity(intent)
}
}
private val signInOnClickListener = object: OnClickListener{
override fun onClick(p0: View?) {
//로그인 하기 위해 모든 입력 유효한지 확인
if (!isNameValid) {
Log.d(TAG, "sign in button) name is empty")
signInWarningTextView.apply{
text = resources.getText(R.string.empty_name_warning)
setVisible()
}
return
}
if (!isPasswordValid) {
Log.d(TAG, "sign in button) password is empty")
signInWarningTextView.apply{
text = resources.getText(R.string.empty_password_warning)
setVisible()
}
return
}
//로그인
val name = nameEditText.text.toString()
val password = passwordEditText.text.toString()
if (UserInfoManager.getInstance().signIn(name, password)) {
Log.d(TAG, "sign in button) sign in success")
signInWarningTextView.setInvisible()
val intent = Intent(applicationContext, HomeActivity::class.java)
intent.putExtra("name", name)
intent.putExtra("password", password)
startActivity(intent)
} else {
Log.d(TAG, "sign in button) sign in fail")
signInWarningTextView.apply{
text = resources.getText(R.string.sign_in_fail_warning)
setVisible()
}
}
}
}
}
class HomeActivity : AppCompatActivity() {
//로그 출력할 때 사용할 tag 값
private val TAG = "HomeActivity"
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)}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_home)
val name = intent.getStringExtra("name")!!
val password = intent.getStringExtra("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()
}
}
}
1. 레이아웃에 스피너 추가하기
<Spinner android:id="@+id/planets_spinner" android:layout_width="match_parent" android:layout_height="wrap_content" />
2. 스피너 항목으로 사용할 문자열 배열 strings.xml에 추가하기
<?xml version="1.0" encoding="utf-8"?> <resources> <string-array name="planets_array"> <item>Mercury</item> <item>Venus</item> <item>Earth</item> <item>Mars</item> <item>Jupiter</item> <item>Saturn</item> <item>Uranus</item> <item>Neptune</item> </string-array> </resources>
3. ArrayAdapter 인스턴스를 통해 스피너에 문자열 배열 제공하기
val spinner: Spinner = findViewById(R.id.spinner) // Create an ArrayAdapter using the string array and a default spinner layout ArrayAdapter.createFromResource( this, R.array.planets_array, //선택된 항목이 스피너 컨트롤에 나타나는 방식 정의하는 레이아웃 android.R.layout.simple_spinner_item ).also { adapter -> // Specify the layout to use when the list of choices appears //스피너 선택 항목의 목록을 표시하는 데 사용하는 레이아웃 adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item) // Apply the adapter to the spinner spinner.adapter = adapter }
4. 사용자의 항목 선택 이벤트 수신하기
class SpinnerActivity : Activity(), AdapterView.OnItemSelectedListener { override fun onItemSelected(parent: AdapterView<*>, view: View?, pos: Int, id: Long) { // An item was selected. You can retrieve the selected item using // parent.getItemAtPosition(pos) } override fun onNothingSelected(parent: AdapterView<*>) { // Another interface callback } }
class SignUpActivity : AppCompatActivity() {
//로그 출력할 때 사용할 tag 값
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)}
companion object{
var isNameValid = false
var isEmailValid = false
var isPasswordValid = false
}
private var isPasswordCheckValid = false
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_sign_up)
nameEditText.addTextChangedListener(
NameTextWatcher(nameWarningTextView, ActivityCode.SIGN_UP))
emailEditText.addTextChangedListener(
EmailTextWatcher(emailWarningTextView))
passwordEditText.addTextChangedListener(
PasswordTextWatcher(passwordWarningTextView, ActivityCode.SIGN_UP))
passwordCheckEditText.addTextChangedListener(passwordCheckTextWatcher)
//Spinner
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
}
val emailProvider:String? = null
emailProviderSpinner.onItemSelectedListener = spinnerOnItemSelectListener
signUpButton.setOnClickListener(signUpOnClickListner)
}
private val passwordCheckTextWatcher = object : TextWatcher {
override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) = Unit
override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {
//비어있는지 확인
if (p0.isNullOrBlank()) {
passwordCheckWarningTextView.apply {
text = resources.getString(R.string.empty_password_warning)
setVisible()
}
isPasswordCheckValid = false
}
//비밀번호와 일치하는지 확인
else if (p0.toString() != passwordEditText.text.toString()) {
passwordCheckWarningTextView.apply {
text = resources.getString(R.string.password_different_warning)
setVisible()
}
isPasswordCheckValid = false
} else {
passwordCheckWarningTextView.setInvisible()
isPasswordCheckValid = true
}
}
override fun afterTextChanged(p0: Editable?) = Unit
}
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 val signUpOnClickListner = object : OnClickListener {
override fun onClick(p0: View?) {
//회원가입하기 위해 모든 입력 유효한지 확인
if (isNameValid && isEmailValid && isPasswordValid && isPasswordCheckValid) {
Log.d(TAG, "sign up button) sign up success")
signUpWarningTextView.setInvisible()
//회원가입
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)
finish()
} else {
Log.d(TAG, "sign up button) sign up fail")
signUpWarningTextView.setVisible()
}
}
}
}