[Adroid]と同期したSNSアプリの作成


🚩 同世代のSNS


大学に入って、活動を続けるサークルがあります!
かつてコンピュータ工学部の学術サークルで、管理職から副会長まで、私個人はとても彼が好きで、ほほほ
特に同期たち!!休学期間中の5年間は本当にたくさんのことをしました
これからは自分たちのSNSアプリ&webを作りましょう!ある人は、
もうすぐ運行する「ENFP」だったので、早速やってみました.
(ここまでは私のTMI大盛宴、、、)

1.テクニックとツールの使用

  • 言語:Kotlin(100%)
  • 環境:Android Studio
  • Database : Firebase
  • その他:Glide、Facebook API、Google API、View Binding、okhttp、multidex
  • 2.作品説明

  • 写真付き投稿を作成
  • メッセージ、いいね
  • 会員加入/登録/登録抹消(電子メールとFacebook)
  • プロファイルの編集
  • 注目/非注目
  • アラーム機能(注目、コメント、賛)
  • 写真をダウンロード 
  • 3.機能の理解


    登録と会員登録


    以上の機能は以前の他の項目でも何度も使用されているので、難しくはありません.
    方法には別の位置づけがある.👉 Facebookにログイン & GoogleとEメールログイン

    投稿をアップロード(+写真)


    // 갤러리로 이동하기
    private fun goGallery() {
            val galleryIntent = Intent(Intent.ACTION_PICK) 
            galleryIntent.type = "image/*" //선택한 파일의 종류를 지정해준다 (이미지만 지정하겠다는 뜻)
            intent.putExtra("crop", true)
            startActivityForResult(galleryIntent, PICK_IMAGE_FROM_ALBUM)
    }
    
    // 이미지 크롭하기
    private fun cropImage(uri: Uri?) {
            CropImage.activity(uri).setGuidelines(CropImageView.Guidelines.ON)
                .setCropShape(CropImageView.CropShape.RECTANGLE)
                .start(this)
    }
    
    // 사진을 Storage에 업로드
    private fun contentUpload() {
            //현재 시간을 String으로 만들기
            //20210306_141238
            val timestamp = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(Date())
            //만약 나라를 지정하지않고 단말기의 설정된 시간으로 하고 싶다면 Locale.getDefault(), 한국으로 하고 싶으면 Locale.KOREA
            val fileName = "IMAGE_$timestamp.png"
    
            //서버 스토리지에 접근하기!
            val storageRef = storage?.reference?.child("images")?.child(fileName)
    
            // 서버 스토리지에 파일 업로드하기!
            storageRef?.putFile(photoUri!!)?.continueWithTask() {
                return@continueWithTask storageRef.downloadUrl
                //나중에 이미지를 다른 곳에서 불러오고 할떄 url을 가져올수있게해놓음
            }?.addOnSuccessListener {
                upload(it, fileName)
                Toast.makeText(this, getString(R.string.upload_success), Toast.LENGTH_SHORT).show()
            }?.addOnCanceledListener {
                //업로드 취소 시
            }?.addOnFailureListener {
                //업로드 실패 시
    	}
    }
    
    // Storage 업로드 된 사진의 uri를 가지고
    // Firestore에 게시물 업로드
    private fun upload(uri: Uri, fileName: String) {
    	//contentDto 객체를 생성한다.
    	val contentDto = ContentDto(
                  imageUrl = uri.toString(),
                  uid = auth?.currentUser?.uid,
                  userId = auth?.currentUser?.email,
                  explain = contentEditText.text.toString(),
                  timestamp = System.currentTimeMillis().toLong(),
                  imageStorage = fileName
            )
    
            //Dto를 Firestore에 추가
            firestore?.collection("images")?.document()?.set(contentDto)
    
            //액티비티 종료
            setResult(Activity.RESULT_OK)
            finish()
    }

    に注目


    対象者については、Firebase DBを使用して管理します.「Follow」Documentには、ユーザーのuidローカルセットが含まれています.
    次のフィールドには、次の内容が含まれており、対応するユーザーのuidが格納されています.
    Follow Dtoデータクラスを生成し、リストを交換します.
    data class FollowDto(
        // 이 사람을 팔로잉하는 사람들
        var followers : MutableMap<String, Boolean> = HashMap(),
    
        // 이 사람이 팔로잉 중인 사람들
        var followings : MutableMap<String, Boolean> = HashMap()
    )
    実際に関心を持つ/関心を持たない状況は以下の通りである.
    リストにユーザーのuidがあるかどうかを確認した後、状況に応じて注目/キャンセルします.
    val firestore = FirebaseFirestore.getInstance()
    val currentUid = FirebaseAuth.getInstance().currentUser!!.uid
    val txDocTargetUser = firestore?.collection("follow")?.document(this.targetUserId!!)
    	//Firestore에 데이터 저장 : runTransaction{...}
        	firestore.runTransaction {
                // it : Transaction
                // it.get(Document) : 해당 Document 받아오기
                // it.set(Document, Dto 객체) : 해당 Document에 Dto 객체 저장하기
                var followDto = it.get(txDocTargetUser).toObject(FollowDto::class.java)
    
                if (followDto == null) {
                    followDto = FollowDto().apply {
                        followers[currentUid!!] = true
                        notifyFollow()
                    }
                } else {
                    with(followDto) {
                        if (followers.containsKey(currentUid!!)) {
                        	// 언팔로우
                            followers.remove(currentUid!!)
                        } else {
                        	// 팔로우
                            followers[currentUid!!] = true
                            notifyFollow()
                        }
                    }
                }
    	it.set(txDocTargetUser, followDto)
    	return@runTransaction
    }

    機能


    讃機能の場合も、上記の注目/非注目機能と非常に似ています.
    良いユーザーのuidを保存します.
    プレイヤーがリストにいない場合は「はい」、ある場合は「キャンセル」します.

    メッセージ


    // Dto
    data class ContentDto(
    	// 게시글
        var uid: String? = "",
        ...
    ) {
        // 댓글
        // ContentDto.Comment 로 접근한다.
        data class Comment(
            //얘도 primary키 필요함!
            var uid: String? = "",
            var userId: String? = "",  // 업로드한 유저의 이메일
            var content: String? = "", //댓글 내용
            var timeStamp: Long? = null //댓글 작성 시간
        )
    }
    
    // 댓글 업로드 함수
    private fun commentUpload() {
            val commentDto = ContentDto.Comment(
                uid = auth?.currentUser?.uid,
                userId = auth?.currentUser?.email,
                content = etCommentContent.text.toString(),
                timeStamp = System.currentTimeMillis()
            )
            // 알림 함수 실행
            notifyComment(commentDto.uid, commentDto.userId, commentDto.timeStamp)
            
            //Dto를 firebase에 추가!
            val doc = firestore?.collection("images")?.document(content_uid!!)
    
            firestore?.runTransaction {
                val contentDto = it.get(doc!!).toObject(ContentDto::class.java)
                doc.collection("comments").document().set(commentDto)
                if (contentDto != null) {
                    contentDto.commentCount += 1
                    it.set(doc, contentDto)
                }
            }
            etCommentContent.setText("")
            hideKeyboard()
    
    }

    写真をダウンロード


    ダウンロードマネージャを介してデバイスに写真をダウンロードします.
    ダウンロード通知が来ると止まり、一気にクラッシュしました.
    元々はsetNotificationVisibilityが設定されていないため続行し、プロンプトウィンドウから消えてしまいます.
    また、ディレクトリパスをEnvironmentに設定します.DIRECTORY DOWNLOADS.
    ギャラリーには確認できないでたらめな状況が現れた.
    もしかしてPICTURESかな?やってみて、簡単に解決しました.
    private fun downloadImage(url: String) {
                val downloadManager: DownloadManager =
                    context?.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
    
                val request = DownloadManager.Request(Uri.parse(url))
                request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
                request.setDestinationInExternalPublicDir(
                    Environment.DIRECTORY_PICTURES,
                    "Aunae" + ".jpg"
                )
                downloadManager.enqueue(request)
    }

    ◾通知機能


    通知には3つのタイプがあります.
    // Content.kt
    const val NOTIFICATION_FAVORITE = 0
    const val NOTIFICATION_FOLLOW = 1
    const val NOTIFICATION_COMMENT = 2
    通知情報を含むDtoを生成します.
    data class NotificationDto(
          var destinationUid:String? = "",
          var sender : String? = "",
          var senderUid : String? = "",
          var type : Int? = null,
          var timestamp: Long? = null,
          var timeInfo : String? = "",
          var contentUid : String? = ""
    )
    これで、Firebaseに情報をアップロードします.
    たとえば、コメント通知をアップロードする関数です.
     private fun notifyComment(uid: String?, email: String?, timeStamp: Long?) {
            if (uid == destination_uid)
                return
            val date = Date(timeStamp!!)
    
            // 날짜, 시간을 가져오고 싶은 형태 선언
            val dateFormat = SimpleDateFormat("yyyy/MM/dd HH:mm:ss", Locale("ko", "KR"))
    
            // 현재 시간을 dateFormat 에 선언한 형태의 String 으로 변환
            val timeData = dateFormat.format(date)
    
            val notificationDto = NotificationDto().apply {
                destinationUid = destination_uid
                sender = email
                senderUid = uid
                type = NOTIFICATION_COMMENT
                timestamp = timeStamp
                timeInfo = timeData.toString()
                this.contentUid = content_uid
            }
            FirebaseFirestore.getInstance().collection("notifications").document().set(notificationDto)
    }
    AlarmFragmentでは、ユーザーは自分の通知を表示できます.
    FirebaseFirestore.getInstance().collection("notifications")
                    .whereEqualTo("destinationUid", currentId)
                    .addSnapshotListener { value, error ->
                        notifyDtoList.clear()
                        notifyId.clear()
                        if (value == null) return@addSnapshotListener
                        value.forEach {
                            notifyDtoList.add(it.toObject(NotificationDto::class.java))
                            notifyId.add(it.id)
                        }
    notifyDataSetChanged()
    最大の機能を実現したコードを書いてみましたが、長すぎます.
    RecyclerViewやBottomNavigationなど他の位置決めでも触れた機能に加えて!
    終わったら、学生たちが使ってくれるたびに、私は喜んでいます.
    ネット版も同期が早く連動してくれるのを楽しみにしています!
    Gitの表示