[Android/Flutter 교육] 52일차

MSU·2024년 3월 14일

Android-Flutter

목록 보기
55/85
post-thumbnail

게시판 프로젝트

회원가입 기능

파이어베이스 스토리지

build.gradle.ktsimplementation("com.google.firebase:firebase-storage:20.3.0") 추가

dependencies {

    implementation("androidx.core:core-ktx:1.12.0")
    implementation("androidx.appcompat:appcompat:1.6.1")
    implementation("com.google.android.material:material:1.11.0")
    implementation("androidx.constraintlayout:constraintlayout:2.1.4")
    testImplementation("junit:junit:4.13.2")
    androidTestImplementation("androidx.test.ext:junit:1.1.5")
    androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
    implementation("androidx.core:core-splashscreen:1.0.1")

    implementation(platform("com.google.firebase:firebase-bom:32.7.4"))
    implementation("com.google.firebase:firebase-analytics")

    implementation("com.google.firebase:firebase-firestore:24.10.3")
    implementation("com.google.firebase:firebase-storage:20.3.0")
}

저장할 데이터

회원번호
아이디
비밀번호
닉네임
나이
성별
취미 6가지
회원 상태

데이터를 저장할 때,
객체로 데이터를 넣으면 프로퍼티가 필드이름이 되고,
맵으로 데이터를 넣으면 키값이 필드이름이 된다.

주로 데이터를 수정할때 맵을, 데이터를 저장할 때 객체를 사용한다.

Sequence 컬렉션 생성

파이어스토어는 auto increment가 없으므로 시퀀스 컬렉션을 따로 만들어서 회원번호와 글번호를 필드로 둔다.

JoinFragment 번들

사용자가 입력한 데이터를 번들에 담아 다음 프래그먼트로 이동할때 전달한다.


    // 다음 버튼
    fun settingButtonJoinNext(){
        fragmentJoinBinding.apply {
            buttonJoinNext.apply {
                // 버튼을 눌렀을 때
                setOnClickListener {
                    // 입력을 검사한다.
                    val chk = checkTextInput()
                    // 입력이 모두 잘 되어 있다면...
                    if(chk == true){
                        joinNext()
                    }
                }
            }
        }
    }
    

    // 다음 과정으로 이동한다.
    fun joinNext(){
        // 사용자가 입력한 데이터를 담는다.
        val joinBundle = Bundle()
        joinBundle.putString("joinUserId",joinViewModel.textFieldJoinUserId.value!!)
        joinBundle.putString("joinUserPw",joinViewModel.textFieldJoinUserPw.value!!)

        // 키보드를 내려준다.
        Tools.hideSoftInput(mainActivity)
        // AddUserInfoFragment를 보여준다.
        mainActivity.replaceFragment(MainFragmentName.ADD_USER_INFO_FRAGMENT, true, true, joinBundle)
    }

AddUserInfoFragment

JoinFragment에서 전달받은 데이터와 AddUserInfoFragment에서 입력한 정보를 합쳐서 데이터를 저장한다.

UserModel

model 패키지 생성 후 그 안에 UserModel 데이터 클래스 생성

// UserModel.kt


// 회원번호, 아이디, 비밀번호, 닉네임, 나이, 성별 , 취미6가지, 회원상태
data class UserModel(
    var userIdx:Int,
    var userId:String,
    var userPw:String,
    var userNickName:String,
    var userAge:Int,
    var userGender:Int,
    var userHobby1:Boolean, var userHobby2:Boolean, var userHobby3:Boolean,
    var userHobby4:Boolean, var userHobby5:Boolean, var userHobby6:Boolean,
    var userState:Int
)

성별과 회원상태를 정의할 enum class

// Tools.kt



// 남자 또는 여자를 나타내는 값을 정의한다.
enum class Gender(var str:String, var num:Int){
    MALE("male", 1),
    FEMALE("female", 2)
}

// 회원 상태를 나타내는 값을 정의한다
enum class UserState(var str:String, var num:Int){
    USER_STATE_NORMAL("정상", 1),
    USER_STATE_SIGNOUT("탈퇴", 2),
}

UserDao 클래스 생성

dao 패키지 생성 후 UserDao 클래스 생성

사용자 번호 시퀀스값을 가져오는 메서드 작성

// UserDao.kt


class UserDao {

    companion object {

        // 사용자 번호 시퀀스값을 가져온다.
        suspend fun getUserSequence():Int{

            var userSequence = 0

            val job1 = CoroutineScope(Dispatchers.IO).launch {
                // 컬렉션에 접근할 수 있는 객체를 가져온다.
                val collectionReference = Firebase.firestore.collection("Sequence")
                // 사용자 번호 시퀀스값을 가지고 있는 문서에 접근할 수 있는 객체를 가져온다.
                val documentReference = collectionReference.document("UserSequence")
                // 문서내에 있는 데이터를 가져올 수 있는 객체를 가져온다.
                val documentSnapShot = documentReference.get().await()

                userSequence = documentSnapShot.getLong("value")?.toInt()!!
            }
            job1.join()

            return userSequence
        }
    }

}

회원가입 정보 저장 메서드

AddUserInfoFragment에서 getUserSequence 메서드 호출

// AddUserInfoFragment.kt


    // 데이터를 저장하고 이동한다.
    fun saveUserData(){
        CoroutineScope(Dispatchers.Main).launch{
            // 사용자 번호 시퀀스 값을 가져온다.
            val userSequence = UserDao.getUserSequence()
            Log.d("test1234","userSequence : $userSequence")
        }
    }
    

사용자 시퀀스 값을 업데이트하는 메서드 작성

// UserDao.kt


        // 사용자 시퀀스 값을 업데이트 한다.
        suspend fun updateUserSequence(userSequence: Int){
            val job1 = CoroutineScope(Dispatchers.IO).launch {
                // 컬렉션에 접근할 수 있는 객체를 가져온다.
                val collectionReference = Firebase.firestore.collection("Sequence")
                // 사용자 번호 시퀀스값을 가지고 있는 문서에 접근할 수 있는 객체를 가져온다.
                val documentReference = collectionReference.document("UserSequence")
                // 저장할 데이터를 담을 HashMap을 만들어준다.
                val map = mutableMapOf<String, Long>()
                // "value"라는 이름의 필드가 있다면 값이 덮어씌워지고 필드가 없다면 필드가 새로 생성된다.
                map["value"] = userSequence.toLong()
                // 저장한다.
                documentReference.set(map)
            }
            job1.join()
        }

사용자 시퀀스 값을 업데이트 하는 메서드 호출

// AddUserInfoFragment.kt

    // 데이터를 저장하고 이동한다.
    fun saveUserData(){
        CoroutineScope(Dispatchers.Main).launch{
            // 사용자 번호 시퀀스 값을 가져온다.
            val userSequence = UserDao.getUserSequence()
            // Log.d("test1234","userSequence : $userSequence")
            // 시퀀스 값을 1 증가시켜 덮어씌워준다.
            UserDao.updateUserSequence(userSequence + 1)
        }
    }

테스트해보면 실제로 값이 증가하는 것을 확인할 수 있다.

회원정보를 받아 데이터 저장하기 전에 성별값을 반환하는 메서드 작성

// AddUserInfoViewModel.kt

    // 성별값을 반환하는 메서드
    fun gettingGender():Gender = when(toggleAddUserInfoGender.value){
        R.id.buttonAddUserInfoMale -> Gender.MALE
        else -> Gender.FEMALE
    }

사용자 정보를 저장하는 dao메서드 작성

// UserDao.kt


    // 사용자 정보를 저장한다.
    suspend fun insertUserData(userModel: UserModel){
        val job1 = CoroutineScope(Dispatchers.IO).launch {
            // 컬렉션에 접근할 수 있는 객체를 가져온다.
            val collectionReference = Firebase.firestore.collection("UserData")
            // 컬렉션에 문서를 추가한다.
            // 문서를 추가할 때 객체나 맵을 지정한다.
            // 추가된 문서 내부의 필드는 객체가 가진 프로퍼티의 이름이나 맵에 있는 데이터의 이름으로 동일하게 결정된다.
            collectionReference.add(userModel)
        }
        job1.join()
    }

회원정보를 받아 객체에 담아서 전달하여 데이터베이스에 저장하는 메서드 작성

// AddUserInfoViewModel.kt


    // 데이터를 저장하고 이동한다.
    fun saveUserData(){
        CoroutineScope(Dispatchers.Main).launch{
            // 사용자 번호 시퀀스 값을 가져온다.
            val userSequence = UserDao.getUserSequence()
            // Log.d("test1234","userSequence : $userSequence")
            // 시퀀스 값을 1 증가시켜 덮어씌워준다.
            UserDao.updateUserSequence(userSequence + 1)

            // 저장할 데이터를 가져온다.
            val userIdx = userSequence + 1
            val userId = arguments?.getString("joinUserId")!!
            val userPw = arguments?.getString("joinUserPw")!!
            val userNickName = addUserInfoViewModel.textFieldAddUserInfoNickName.value!!
            val userAge = addUserInfoViewModel.textFieldAddUserInfoAge.value!!.toInt()
            val userGender = addUserInfoViewModel.gettingGender().num
            val userHobby1 = addUserInfoViewModel.checkBoxAddUserInfoHobby1.value!!
            val userHobby2 = addUserInfoViewModel.checkBoxAddUserInfoHobby2.value!!
            val userHobby3 = addUserInfoViewModel.checkBoxAddUserInfoHobby3.value!!
            val userHobby4 = addUserInfoViewModel.checkBoxAddUserInfoHobby4.value!!
            val userHobby5 = addUserInfoViewModel.checkBoxAddUserInfoHobby5.value!!
            val userHobby6 = addUserInfoViewModel.checkBoxAddUserInfoHobby6.value!!
            val userState = UserState.USER_STATE_NORMAL.num

            // 저장할 데이터를 객체에 담는다.
            val userModel = UserModel(
                userIdx, userId, userPw, userNickName, userAge, userGender,
                userHobby1, userHobby2, userHobby3, userHobby4, userHobby5, userHobby6, userState
            )

            // 사용자 정보를 저장한다.
            UserDao.insertUserData(userModel)

            val materialAlertDialogBuilder = MaterialAlertDialogBuilder(mainActivity)
            materialAlertDialogBuilder.apply {
                setTitle("가입완료")
                setMessage("가입이 완료되었습니다\n로그인해주세요")
                setPositiveButton("확인"){ dialogInterface: DialogInterface, i: Int ->
                    mainActivity.removeFragment(MainFragmentName.ADD_USER_INFO_FRAGMENT)
                    mainActivity.removeFragment(MainFragmentName.JOIN_FRAGMENT)
                }
            }
            materialAlertDialogBuilder.show()
        }
    }

작성한 saveUserData 메서드를 호출한다.

// AddUserInfoViewModel.kt




    // 가입 버튼
    fun settingButtonAddUserInfoSubmit(){
        fragmentAddUserInfoBinding.buttonAddUserInfoSubmit.apply {
            // 눌렀을 때
            setOnClickListener {
                // 유효성 검사를 수행한다.
                val chk = checkInputForm()
                // 모든 유효성 검사에 통과를 했다면
                if(chk == true){
                    saveUserData()
                }
            }
        }
    }

아이디 중복확인

입력한 아이디가 저장되어 있는 문서가 있는지 확인하는 메서드 작성

// UserDao.kt



        // 입력한 아이디가 저장되어 있는 문서가 있는지 확인한다(중복처리)
        // 사용할 수 있는 아이디라면 true, 이미 존재하는 아이디라면 false를 반환한다.
        suspend fun checkUserIdExist(joinUserId:String):Boolean{

            var chk = false

            val job1 = CoroutineScope(Dispatchers.IO).launch {
                // 컬렉션에 접근할 수 있는 객체를 가져온다.
                val collectionReference = Firebase.firestore.collection("UserData")
                // UserId 필드가 사용자가 입력한 아이디와 같은 문서들을 가져온다.
                // whereArrayContains, whereIn : 지정한 배열에 있는 값이 포함되어 있는 것들
                // whereEqualTo : 같은 것
                // whereGreaterThan : 큰 것
                // whereGreaterThanOrEqualTo : 크거나 같은 것
                // whereLessThan : 작은 것
                // whereLessThanOrEqualTo : 작거나 같은 것
                // whereNotEqualTo : 다른 것
                // 필드의 이름, 값 형태로 넣어준다
                val querySnapshot = collectionReference.whereEqualTo("userId", joinUserId).get().await()
                // 반환되는 리스트에 담긴 문서 객체가 없다면 존재하는 아이디로 취급한다.
                chk = querySnapshot.isEmpty
            }
            job1.join()

            return chk
        }

작성한 메서드를 중복확인 버튼에 호출

// JoinFragment.kt


    // 중복확인 버튼
    fun settingButtonJoinCheckId(){
        fragmentJoinBinding.apply {
            buttonJoinCheckId.apply {
                setOnClickListener {
                    if(joinViewModel?.textFieldJoinUserId?.value!!.isEmpty()){
                        Tools.showErrorDialog(mainActivity, fragmentJoinBinding.textFieldJoinUserId, "아이디 입력 오류", "아이디를 입력해주세요")
                        return@setOnClickListener
                    }

                    CoroutineScope(Dispatchers.Main).launch {
                        checkUserIdExist = UserDao.checkUserIdExist(joinViewModel?.textFieldJoinUserId?.value!!)

                        if(checkUserIdExist == false){
                            joinViewModel?.textFieldJoinUserId?.value = ""
                            Tools.showErrorDialog(mainActivity, fragmentJoinBinding.textFieldJoinUserId, "아이디 입력 오류", "존재하는 아이디입니다\n다른 아이디를 입력해주세요")
                        } else {
                            Tools.showErrorDialog(mainActivity, fragmentJoinBinding.textFieldJoinUserId, "아이디 중복 확인", "사용 가능한 아이디 입니다")
                        }
                    }

                    // checkUserIdExist = true
                }
            }
        }
    }

profile
안드로이드공부

0개의 댓글