[Android/Flutter 교육] 57일차

MSU·2024년 3월 25일

Android-Flutter

목록 보기
61/85
post-thumbnail

게시판 프로젝트

글 수정

글 번호 확인

// ModifyContentFragment.kt


    // 현재 글 번호를 담을 변수
    var contentIdx = 0
    
    
    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        // Inflate the layout for this fragment

        // fragmentModifyContentBinding = FragmentModifyContentBinding.inflate(inflater)
        fragmentModifyContentBinding = DataBindingUtil.inflate(inflater, R.layout.fragment_modify_content, container, false)
        modifyContentViewModel = ModifyContentViewModel()
        fragmentModifyContentBinding.modifyContentViewModel = modifyContentViewModel
        fragmentModifyContentBinding.lifecycleOwner = this

        contentActivity = activity as ContentActivity

        // 글 번호를 담는다.
        contentIdx = arguments?.getInt("contentIdx")!!
        
        settingToolbarModifyContent()
        settingCameraLauncher()
        settingAlbumLauncher()
        settingInputForm()

        return fragmentModifyContentBinding.root
    }

게시판 종류를 받아 MutableLiveData에 설정하는 메서드 수정

// ModifyContentViewModel.kt


    // 게시판 종류를 받아 MutableLiveData에 설정하는 메서드
    fun settingContentType(contentType: Int){
        toggleModifyContentType.value = when(contentType){
            ContentType.TYPE_ALL.number    -> 0
            ContentType.TYPE_FREE.number   -> R.id.buttonModifyContentType1
            ContentType.TYPE_HUMOR.number  -> R.id.buttonModifyContentType2
            ContentType.TYPE_SOCIETY.number-> R.id.buttonModifyContentType3
            ContentType.TYPE_SPORTS.number -> R.id.buttonModifyContentType4
            else -> 0
        }
    }

글 정보 불러오기

// ModifyContentFragment.kt


    // 입력 요소 초기화
    fun settingInputForm(){
        // 입력 요소에 띄어쓰기를 넣어준다.
        modifyContentViewModel.textFieldModifyContentSubject.value = " "
        modifyContentViewModel.textFieldModifyContentText.value = " "

        CoroutineScope(Dispatchers.Main).launch {

            // 현재 글 번호에 해당하는 글 데이터를 가져온다.
            val contentModel = ContentDao.selectContentData(contentIdx)

            // 가져온 데이터를 보여준다.
            modifyContentViewModel.textFieldModifyContentSubject.value = contentModel?.contentSubject
            modifyContentViewModel.settingContentType(contentModel?.contentType!!)
            modifyContentViewModel.textFieldModifyContentText.value = contentModel?.contentText

            // 이미지 데이터를 불러온다.
            if(contentModel?.contentImage != null) {
                delay(1000L)
                ContentDao.gettingContentImage(contentActivity, contentModel.contentImage!!, fragmentModifyContentBinding.imageViewModifyContent)
            }
        }
    }

글 읽기에서 수정하기로 넘어갈때 글번호 전달

// ReadContentFragment.kt



                setOnMenuItemClickListener {
                    // 메뉴의 id로 분기한다.
                    when(it.itemId){
                        // 댓글
                        R.id.menuItemReadContentReply -> {
                            // 댓글을 보여줄 BottomSheet를 띄운다.
                            showReplyBottomSheet()
                        }
                        // 수정하기
                        R.id.menuItemReadContentModify -> {
                            // 수정 화면이 보이게 한다.
                            val modifyBundle = Bundle()
                            modifyBundle.putInt("contentIdx",contentIdx)
                            contentActivity.replaceFragment(ContentFragmentName.MODIFY_CONTENT_FRAGMENT, true, true, modifyBundle)
                        }

초기화 메뉴를 위한 셋팅

// ModifyContentFragment.kt


    // 초기화 메뉴를 누르면 입력요소에 설정할 값을 가지고 있는 데이터
    var resetSubject=""
    var resetContentType = 0
    var resetContentText = ""
    var resetImage:Bitmap? = null
    
    
    // 입력 요소 초기화
    fun settingInputForm(){
        // 입력 요소에 띄어쓰기를 넣어준다.
        modifyContentViewModel.textFieldModifyContentSubject.value = " "
        modifyContentViewModel.textFieldModifyContentText.value = " "

        CoroutineScope(Dispatchers.Main).launch {

            // 현재 글 번호에 해당하는 글 데이터를 가져온다.
            val contentModel = ContentDao.selectContentData(contentIdx)

            // 가져온 글 정보 중 초기화를 위한 데이터를 프로퍼티에 담아준다.
            resetSubject = contentModel?.contentSubject!!
            resetContentType = contentModel?.contentType!!
            resetContentText = contentModel?.contentText!!

            // 가져온 데이터를 보여준다.
            modifyContentViewModel.textFieldModifyContentSubject.value = contentModel?.contentSubject
            modifyContentViewModel.settingContentType(contentModel?.contentType!!)
            modifyContentViewModel.textFieldModifyContentText.value = contentModel?.contentText

            // 이미지 데이터를 불러온다.
            if(contentModel?.contentImage != null) {
                delay(1000L)
                ContentDao.gettingContentImage(contentActivity, contentModel.contentImage!!, fragmentModifyContentBinding.imageViewModifyContent)

                // 이미지뷰로부터 이미지를 가져와 초기화를 위한 프로퍼티에 담아준다.
                val bitmapDrawable = fragmentModifyContentBinding.imageViewModifyContent.drawable as BitmapDrawable
                resetImage = bitmapDrawable.bitmap
            }
        }
    }

입력 요소를 초기화하는 메서드

// ModifyContentFragment.kt


                // 메뉴
                inflateMenu(R.menu.menu_modify_content)
                setOnMenuItemClickListener {
                    when (it.itemId) {
                        // 카메라
                        R.id.menuItemModifyContentCamera -> {
                            startCameraLauncher()
                        }
                        // 앨범
                        R.id.menuItemModifyContentAlbum -> {
                            startAlbumLauncher()
                        }
                        // 초기화
                        R.id.menuItemModifyContentReset -> {
                            resetInputForm()
                        }
                        
                        


    // 입력 요소를 초기화 한다.
    fun resetInputForm(){
        // 가져온 데이터를 보여준다.
        modifyContentViewModel.textFieldModifyContentSubject.value = resetSubject
        modifyContentViewModel.settingContentType(resetContentType)
        modifyContentViewModel.textFieldModifyContentText.value = resetContentText

        // 이미지 데이터를 불러온다.
        if(resetImage != null) {
            fragmentModifyContentBinding.imageViewModifyContent.setImageBitmap(resetImage)
        }
    }

이미지 삭제 버튼

실제 삭제가 아니라 기본 이미지로 이미지뷰를 변경해준다.

// ModifyContentFragment.kt



    // 이미지 삭제 버튼
    fun settingButtonModifyContentImageDelete(){
        fragmentModifyContentBinding.buttonModifyContentImageDelete.setOnClickListener {
            // 이미지 뷰의 이미지를 변경한다.
            fragmentModifyContentBinding.imageViewModifyContent.setImageResource(R.drawable.panorama_24px)
        }
    }

글 데이터를 수정하는 메서드 작성

// ContentDao.kt



        // 글 데이터를 수정하는 메서드
        suspend fun updateContentData(contentModel: ContentModel, isRemoveImage:Boolean){
            val job1 = CoroutineScope(Dispatchers.IO).launch {
                // 컬렉션에 접근할 수 있는 객체를 가져온다.
                val collectionReference = Firebase.firestore.collection("ContentData")
                // 컬렉션이 가지고 있는 문서들 중에 수정한 글 정보를 가져온다.
                val query = collectionReference.whereEqualTo("contentIdx", contentModel.contentIdx).get().await()

                // 저장할 데이터를 담을 HashMap을 만들어준다.
                val map = mutableMapOf<String, Any?>()
                map["contentSubject"] = contentModel.contentSubject
                map["contentText"] = contentModel.contentText
                map["contentType"] = contentModel.contentType

                if(contentModel.contentImage != null){
                    map["contentImage"] = contentModel.contentImage!!
                }
                // 사용자가 이미지를 삭제했다면
                if(isRemoveImage == true){
                    map["contentImage"] = null
                }
                // 저장한다.
                // 가져온 문서 중 첫 번째 문서에 접근하여 데이터를 수정한다.
                query.documents[0].reference.update(map)
            }
            job1.join()
        }

사용자에 의한 이미지 변경 여부를 체크하는 변수

// ModifyContentFragment.kt


    // 사용자에 의해서 이미지가 변경되었는지..
    var isChangeImage = false
    // 사용자가 이미지를 삭제했는지
    var isRemoveImage = false
    
    
    
    
	// 입력 요소를 초기화 한다.
    fun resetInputForm(){
        // 가져온 데이터를 보여준다.
        modifyContentViewModel.textFieldModifyContentSubject.value = resetSubject
        modifyContentViewModel.settingContentType(resetContentType)
        modifyContentViewModel.textFieldModifyContentText.value = resetContentText

        // 이미지 데이터를 불러온다.
        if(resetImage != null) {
            fragmentModifyContentBinding.imageViewModifyContent.setImageBitmap(resetImage)
        }
        
        // 사용자가 이미지를 변경했는지의 값을 초기화한다.
        isChangeImage = false
        isRemoveImage = false
    }
    
    
    // 카메라 런처 설정
    fun settingCameraLauncher(){
        val contract1 = ActivityResultContracts.StartActivityForResult()
        cameraLauncher = registerForActivityResult(contract1){
            // 사진을 사용하겠다고 한 다음에 돌아왔을 경우
            if(it.resultCode == AppCompatActivity.RESULT_OK){
                // 사진 객체를 생성한다.
                val bitmap = BitmapFactory.decodeFile(contentUri.path)

                // 회전 각도값을 구한다.
                val degree = Tools.getDegree(contentActivity, contentUri)
                // 회전된 이미지를 구한다.
                val bitmap2 = Tools.rotateBitmap(bitmap, degree.toFloat())
                // 크기를 조정한 이미지를 구한다.
                val bitmap3 = Tools.resizeBitmap(bitmap2, 1024)

                fragmentModifyContentBinding.imageViewModifyContent.setImageBitmap(bitmap3)
                isChangeImage = true
                
                // 사진 파일을 삭제한다.
                val file = File(contentUri.path)
                file.delete()
            }
        }
    }
    
    
    // 앨범 런처 설정
    fun settingAlbumLauncher() {
        // 앨범 실행을 위한 런처
        val contract2 = ActivityResultContracts.StartActivityForResult()
        albumLauncher = registerForActivityResult(contract2){
            // 사진 선택을 완료한 후 돌아왔다면
            if(it.resultCode == AppCompatActivity.RESULT_OK){
                // 선택한 이미지의 경로 데이터를 관리하는 Uri 객체를 추출한다.
                val uri = it.data?.data
                if(uri != null){
                    // 안드로이드 Q(10) 이상이라면
                    val bitmap = if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q){
                        // 이미지를 생성할 수 있는 객체를 생성한다.
                        val source = ImageDecoder.createSource(contentActivity.contentResolver, uri)
                        // Bitmap을 생성한다.
                        ImageDecoder.decodeBitmap(source)
                    } else {
                        // 컨텐츠 프로바이더를 통해 이미지 데이터에 접근한다.
                        val cursor = contentActivity.contentResolver.query(uri, null, null, null, null)
                        if(cursor != null){
                            cursor.moveToNext()

                            // 이미지의 경로를 가져온다.
                            val idx = cursor.getColumnIndex(MediaStore.Images.Media.DATA)
                            val source = cursor.getString(idx)

                            // 이미지를 생성한다
                            BitmapFactory.decodeFile(source)
                        }  else {
                            null
                        }
                    }

                    // 회전 각도값을 가져온다.
                    val degree = Tools.getDegree(contentActivity, uri)
                    // 회전 이미지를 가져온다
                    val bitmap2 = Tools.rotateBitmap(bitmap!!, degree.toFloat())
                    // 크기를 줄인 이미지를 가져온다.
                    val bitmap3 = Tools.resizeBitmap(bitmap2, 1024)

                    fragmentModifyContentBinding.imageViewModifyContent.setImageBitmap(bitmap3)
                    isChangeImage = true
                }
            }
        }
    }
    
    
    // 이미지 삭제 버튼
    fun settingButtonModifyContentImageDelete(){
        fragmentModifyContentBinding.buttonModifyContentImageDelete.setOnClickListener {
            // 이미지 뷰의 이미지를 변경한다.
            fragmentModifyContentBinding.imageViewModifyContent.setImageResource(R.drawable.panorama_24px)
            isChangeImage = true
            isRemoveImage = true
        }
    }

게시판 타입 반환하는 메서드

// ModifyContentViewModel.kt


    // 게시판의 타입을 반환하는 메서드를 만들어준다.
    fun gettingContentType() = when(toggleModifyContentType.value){
        R.id.buttonModifyContentType1 -> ContentType.TYPE_FREE.number
        R.id.buttonModifyContentType2 -> ContentType.TYPE_HUMOR.number
        R.id.buttonModifyContentType3 -> ContentType.TYPE_SOCIETY.number
        R.id.buttonModifyContentType4 -> ContentType.TYPE_SPORTS.number
        else -> 0
    }

글 정보 업로드 메서드

// ModifyContentFragment.kt


                // 메뉴
                inflateMenu(R.menu.menu_modify_content)
                setOnMenuItemClickListener {
                    when (it.itemId) {
                        // 카메라
                        R.id.menuItemModifyContentCamera -> {
                            startCameraLauncher()
                        }
                        // 앨범
                        R.id.menuItemModifyContentAlbum -> {
                            startAlbumLauncher()
                        }
                        // 초기화
                        R.id.menuItemModifyContentReset -> {
                            resetInputForm()
                        }
                        // 완료
                        R.id.menuItemModifyContentDone -> {
                            // 입력 요소 검사
                            val chk = checkInputForm()
                            if(chk == true){
                                updateContentData()
                            }
                        }
                    }
                    



    // 글 정보를 업로드하는 메서드
    fun updateContentData(){
        CoroutineScope(Dispatchers.Main).launch {
            // 서버에서의 첨부 이미지 파일 이름
            var serverFileName:String? = null

            // 사용자가 이미지를 변경하였다면(삭제 X)
            if(isChangeImage == true && isRemoveImage == false) {
                // 이미지의 뷰의 이미지 데이터를 파일로 저장한다.
                Tools.saveImageViewData(contentActivity, fragmentModifyContentBinding.imageViewModifyContent, "uploadTemp.jpg")
                // 서버에서의 파일 이름
                serverFileName = "image_${System.currentTimeMillis()}.jpg"
                // 서버로 업로드한다.
                ContentDao.uploadImage(contentActivity, "uploadTemp.jpg", serverFileName)
            }

            // 업로드할 정보를 담아준다.
            val contentSubject = modifyContentViewModel.textFieldModifyContentSubject.value!!
            val contentType = modifyContentViewModel.gettingContentType()
            val contentText = modifyContentViewModel.textFieldModifyContentText.value!!

            // 객체에 담아준다.
            val contentModel = ContentModel(contentIdx, contentSubject, contentType, contentText, null, 0, "", 0)

            // 업로드된 이미지가 있다면
            if(serverFileName != null){
                contentModel.contentImage = serverFileName
            }

            // 업로드한다.
            ContentDao.updateContentData(contentModel, isRemoveImage)

            // 이전으로 돌아간다.
            contentActivity.removeFragment(ContentFragmentName.MODIFY_CONTENT_FRAGMENT)
        }
    }
profile
안드로이드공부

0개의 댓글