-
Notifications
You must be signed in to change notification settings - Fork 0
/
HomeFragment.kt
208 lines (183 loc) · 8.92 KB
/
HomeFragment.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
package com.galaxy.galaxystagram.navigation
import android.content.Context
import android.graphics.Rect
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import android.widget.Toast
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.Glide
import com.galaxy.galaxystagram.MainActivity
import com.galaxy.galaxystagram.R
import com.galaxy.galaxystagram.databinding.FragmentHomeBinding
import com.galaxy.galaxystagram.databinding.PostDetailBinding
import com.galaxy.galaxystagram.model.ContentDTO
import com.galaxy.galaxystagram.model.UserDTO
import com.google.firebase.auth.FirebaseAuth
import com.google.firebase.firestore.FirebaseFirestore
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.tasks.await
import kotlinx.coroutines.withContext
class HomeFragment: Fragment() {
private lateinit var mBinding: FragmentHomeBinding
private var TAG: String = "HomeFragment: "
private var store: FirebaseFirestore = FirebaseFirestore.getInstance()
private var auth: FirebaseAuth = FirebaseAuth.getInstance()
private var adapter: PostAdapter? = null
private var contentsList = arrayListOf<ContentDTO>()
private var usersHashMap = HashMap<String, UserDTO>()
private var contentsId = arrayListOf<String>()
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
mBinding = FragmentHomeBinding.inflate(inflater, container, false)
var followingSet: ArrayList<String>? = null
GlobalScope.launch(Dispatchers.Main) {
withContext(Dispatchers.Default) {
var userDTO = store.collection("users").document(auth.uid!!).get()
.await().toObject(UserDTO::class.java)
followingSet = ArrayList(userDTO!!.followings.keys)
followingSet?.add(auth.currentUser!!.email!!)
store.collection("users")
.whereIn("email", followingSet!!)
.addSnapshotListener { users, error ->
if (error != null)
Log.e(TAG, error.toString())
else {
usersHashMap.clear()
for (user in users!!.documents)
usersHashMap[user.id] = user.toObject(UserDTO::class.java)!!
}
}
}
adapter = PostAdapter(followingSet)
mBinding.postsRecyclerView.adapter = adapter
}
//layoutManager : 아이템의 배치를 담당.
//LinearLayoutManager : 가로/세로
//GirdLayoutManager : 그리드 형식
//StaggeredGirdLayoutManager : 지그재그형의 그리드 형식
mBinding.postsRecyclerView.layoutManager = LinearLayoutManager(activity)
mBinding.postsRecyclerView.addItemDecoration(VerticalItemDecorator(30))
return mBinding.root
}
//Adapter : 데이터와 아이템에 관한 View를 생성.
inner class PostAdapter(followingList: ArrayList<String>?): RecyclerView.Adapter<PostHolder>() {
private lateinit var postDetailBinding: PostDetailBinding
//DB에서 게시글 데이터 가져오기
init {
store.collection("posts")
.whereIn("userEmail", followingList!!)
.addSnapshotListener { posts, e ->
if (e != null) {
Log.e(TAG, e.toString())
Toast.makeText(activity, R.string.upload_fail, Toast.LENGTH_SHORT).show()
} else {
contentsList.clear()
contentsId.clear()
for (post in posts!!.documents) {
var content = post.toObject(ContentDTO::class.java)
contentsList.add(content!!)
contentsId.add(post.id)
}
}
notifyDataSetChanged()
}
}
//post_detail.xml을 아이템뷰 생성
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PostHolder {
var inflater: LayoutInflater = parent.context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
postDetailBinding = PostDetailBinding.inflate(inflater, parent, false)
return PostHolder(postDetailBinding)
}
//아이템뷰 화면에 입력돼야 할 데이터 추가.
override fun onBindViewHolder(holder: PostHolder, position: Int) {
holder.setData(contentsList[position], position)
}
//총 몇 개의 아이템이 추가되어야 하는지 확인.
override fun getItemCount(): Int {
return contentsList.size
}
}
//뷰를 보관하는 Holder 객체.
//item 뷰들을 재활용하기 위해 각 요소를 저장해두고 사용.
//아이템 생성시 뷰 바인딩은 한 번만 하고, 바인딩 된 객체를 가져다 사용해 성능이 효율적.
inner class PostHolder(var postDetailBinding: PostDetailBinding) : RecyclerView.ViewHolder(postDetailBinding.root) {
private var position: Int? = null
init {
postDetailBinding.heartIcon.setOnClickListener {
heartIconClickEvent(position!!)
}
//게시글의 이메일 텍스트뷰를 누르면 계정 정보 화면으로 이동.
postDetailBinding.usernameTextView.setOnClickListener {
(activity as MainActivity).changeFragment(AccountFragment((it as TextView).text.toString()))
}
}
fun setData(content: ContentDTO, position: Int) {
this.position = position
postDetailBinding.usernameTextView.text = content.userEmail
Glide.with(postDetailBinding.root).load(content.imageUrl).into(postDetailBinding.postPhotoIV)
postDetailBinding.favoriteCountTextView.text = "좋아요 ${content.favoriteCount}개"
postDetailBinding.postTextView.text = content.exaplain
try { //프로필 이미지 띄워주기
Glide.with(postDetailBinding.root)
.load(usersHashMap[content.uid]!!.profileImgUrl!!)
.circleCrop()
.into(postDetailBinding.profileImageView)
} catch(e: NullPointerException) { //프로필 이미지가 없는 경우 -> 기본 이미지
postDetailBinding.profileImageView.setImageResource(R.drawable.user)
}
if (content.favorites.containsKey(auth.currentUser!!.uid)) {
//해당 게시글에 좋아요를 누른 사람이면
postDetailBinding.heartIcon.setImageResource(R.drawable.heart_fill)
} else {
//해당 게시글에 좋아요를 누르지 않은 사람이면
postDetailBinding.heartIcon.setImageResource(R.drawable.heart)
}
}
private fun heartIconClickEvent(position: Int) {
var postDoc = store.collection("posts").document(contentsId[position])
store.runTransaction { transaction ->
var content:ContentDTO = transaction.get(postDoc).toObject(ContentDTO::class.java)!!
if (content.favorites.containsKey(auth.currentUser!!.uid)) {
//좋아요를 누른 사람이면 -> 좋아요 취소
content.favoriteCount -= 1
content.favorites.remove(auth.currentUser!!.uid)
} else {
//좋아요를 누르지 않은 사람이면 -> 좋아요!
content.favoriteCount += 1
content.favorites.put(auth.currentUser!!.uid, true)
}
transaction.update(postDoc, "favorites", content.favorites)
transaction.update(postDoc, "favoriteCount", content.favoriteCount)
}.addOnSuccessListener {
adapter?.notifyItemChanged(position)
}.addOnFailureListener {
Log.e(TAG, it.toString())
Toast.makeText(activity, getString(R.string.error_alarm), Toast.LENGTH_SHORT).show()
}
}
}
//아이템 간 수직(위아래) 간격 설정
inner class VerticalItemDecorator(var divHeight: Int):RecyclerView.ItemDecoration() {
override fun getItemOffsets(
outRect: Rect,
view: View,
parent: RecyclerView,
state: RecyclerView.State
) {
super.getItemOffsets(outRect, view, parent, state)
outRect.top = divHeight
outRect.bottom = divHeight
}
}
}