From fd6f505864d55177ad290b62ba263a5c0bff5e52 Mon Sep 17 00:00:00 2001 From: cherrylime69 Date: Wed, 29 Jun 2022 19:42:13 +0900 Subject: [PATCH 01/13] =?UTF-8?q?feat=20:=20=EB=92=A4=EB=A1=9C=20=EA=B0=80?= =?UTF-8?q?=EA=B8=B0=EB=A5=BC=20=EB=88=8C=EB=9F=AC=EB=8F=84=20=EC=9D=B4?= =?UTF-8?q?=EC=8A=88=20=EB=AA=A9=EB=A1=9D=EC=9D=B4=20=EB=B3=B4=EC=97=AC?= =?UTF-8?q?=EC=A7=80=EB=8F=84=EB=A1=9D=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 필터된 이슈 목록 리스트가 빈값이 아닐 때만 이슈 목록이 갱신되도록 수정 --- .../example/issu_tracker/ui/issue/IssueFragment.kt | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/com/example/issu_tracker/ui/issue/IssueFragment.kt b/app/src/main/java/com/example/issu_tracker/ui/issue/IssueFragment.kt index ca754f3cf1..80d244a186 100644 --- a/app/src/main/java/com/example/issu_tracker/ui/issue/IssueFragment.kt +++ b/app/src/main/java/com/example/issu_tracker/ui/issue/IssueFragment.kt @@ -119,11 +119,13 @@ class IssueFragment : Fragment() { issueAdapter.submitList(it.filter { it.state }) } } -// launch { -// homeViewModel.filteredIssueList.collect { -// issueAdapter.submitList(it) -// } -// } + launch { + homeViewModel.filteredIssueList.collect { + if (it.isNotEmpty()) { + issueAdapter.submitList(it) + } + } + } } } } @@ -151,7 +153,7 @@ class IssueFragment : Fragment() { issueAdapter.isEditMode = false binding.clIssueOriginalModeTop.visibility = View.VISIBLE binding.clIssueEditModeTop.visibility = View.GONE - Log.d("sdsd" , "sdsd") + Log.d("sdsd", "sdsd") itemTouchHelper.attachToRecyclerView(binding.rvIssue) } From 56123e7db1706c8a2b68d35ec9dab8d7819e044c Mon Sep 17 00:00:00 2001 From: shim506 Date: Thu, 30 Jun 2022 14:39:25 +0900 Subject: [PATCH 02/13] =?UTF-8?q?feat=20:=20=EB=A7=88=EC=A7=80=EB=A7=89=20?= =?UTF-8?q?pr=20=EB=B0=98=EC=98=81=20:=20joinToString=20=EC=9C=BC=EB=A1=9C?= =?UTF-8?q?=20=EB=A6=AC=ED=8E=99=ED=84=B0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../example/issu_tracker/ui/detail/DetailEditDialogFragment.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/example/issu_tracker/ui/detail/DetailEditDialogFragment.kt b/app/src/main/java/com/example/issu_tracker/ui/detail/DetailEditDialogFragment.kt index af7621b3d7..399ce5a52b 100644 --- a/app/src/main/java/com/example/issu_tracker/ui/detail/DetailEditDialogFragment.kt +++ b/app/src/main/java/com/example/issu_tracker/ui/detail/DetailEditDialogFragment.kt @@ -28,7 +28,7 @@ class DetailEditDialogFragment(val labelNameList: List, mileStoneName: S ): View? { binding = DetailEditDialogFragmentBinding.inflate(inflater, container, false) - binding.tvLabelContent.text = labelNameList.stringListToText() + binding.tvLabelContent.text = labelNameList.joinToString(", ") return binding.root } From ba55b74113037408f514106a24853451f38206c3 Mon Sep 17 00:00:00 2001 From: shim506 Date: Thu, 30 Jun 2022 23:42:24 +0900 Subject: [PATCH 03/13] =?UTF-8?q?feat=20:=20=EB=84=A4=ED=8A=B8=EC=9B=8C?= =?UTF-8?q?=ED=81=AC=20=EC=83=81=ED=83=9C=20=EA=B4=80=EB=A6=AC=20=ED=81=B4?= =?UTF-8?q?=EB=9E=98=EC=8A=A4=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../issu_tracker/data/network/NetworkResult.kt | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 app/src/main/java/com/example/issu_tracker/data/network/NetworkResult.kt diff --git a/app/src/main/java/com/example/issu_tracker/data/network/NetworkResult.kt b/app/src/main/java/com/example/issu_tracker/data/network/NetworkResult.kt new file mode 100644 index 0000000000..aac01e88d1 --- /dev/null +++ b/app/src/main/java/com/example/issu_tracker/data/network/NetworkResult.kt @@ -0,0 +1,12 @@ +package com.example.issu_tracker.data.network + +sealed class NetworkResult { + class Success(val data: T) : NetworkResult() + class Cached(val data: T) : NetworkResult() + class Loading : NetworkResult() + class Error(val code: Int = EMPTY) : NetworkResult() + class Exception(val e: Throwable) : NetworkResult() + companion object { + const val EMPTY = 0 + } +} From 8140a53b6aa3b4acea9d75aaf826d82c62c14319 Mon Sep 17 00:00:00 2001 From: shim506 Date: Thu, 30 Jun 2022 23:43:20 +0900 Subject: [PATCH 04/13] =?UTF-8?q?feat=20:=20=EC=B9=9C=EA=B5=AC=20=EB=AA=A9?= =?UTF-8?q?=EB=A1=9D=20=EB=B6=80=EB=B6=84=20=EB=84=A4=ED=8A=B8=EC=9B=8C?= =?UTF-8?q?=ED=81=AC=20=EC=83=81=ED=83=9C=EC=97=90=20=EB=94=B0=EB=A5=B8=20?= =?UTF-8?q?=EB=B6=84=EA=B8=B0=EC=B2=98=EB=A6=AC=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 네트워크 O -> 리모트에서 로컬에 캐시해줌, 로컬에서 내려주기 2. 네트워크 X -> 로컬에서 내려주기 --- .../data/repository/FriendRemoteRepository.kt | 3 +- .../repository/FriendRemoteRepositoryIml.kt | 46 ++++++++++++------- .../data/repository/Repository.kt | 30 ++++++------ .../issu_tracker/di/RepositoryModule.kt | 6 ++- .../ui/account/AccountViewModel.kt | 21 +++++---- .../ui/account/MyAccountFragment.kt | 18 ++++++-- .../ui/detail/DetailEditDialogFragment.kt | 2 +- 7 files changed, 79 insertions(+), 47 deletions(-) diff --git a/app/src/main/java/com/example/issu_tracker/data/repository/FriendRemoteRepository.kt b/app/src/main/java/com/example/issu_tracker/data/repository/FriendRemoteRepository.kt index aa564ddeab..b79dfcdecf 100644 --- a/app/src/main/java/com/example/issu_tracker/data/repository/FriendRemoteRepository.kt +++ b/app/src/main/java/com/example/issu_tracker/data/repository/FriendRemoteRepository.kt @@ -2,11 +2,12 @@ package com.example.issu_tracker.data.repository import android.util.Log import com.example.issu_tracker.data.User +import com.example.issu_tracker.data.network.NetworkResult import kotlinx.coroutines.tasks.await interface FriendRemoteRepository { - suspend fun loadFriendList(): List + suspend fun loadFriendList(): NetworkResult> suspend fun updateFriend(users: List) } \ No newline at end of file diff --git a/app/src/main/java/com/example/issu_tracker/data/repository/FriendRemoteRepositoryIml.kt b/app/src/main/java/com/example/issu_tracker/data/repository/FriendRemoteRepositoryIml.kt index afdaa9a836..e194c98eb1 100644 --- a/app/src/main/java/com/example/issu_tracker/data/repository/FriendRemoteRepositoryIml.kt +++ b/app/src/main/java/com/example/issu_tracker/data/repository/FriendRemoteRepositoryIml.kt @@ -2,9 +2,13 @@ package com.example.issu_tracker.data.repository import android.util.Log import com.example.issu_tracker.data.User +import com.example.issu_tracker.data.network.NetworkResult +import com.example.issu_tracker.data.network.NetworkResult.Companion.EMPTY import com.example.issu_tracker.ui.home.userUid import com.google.firebase.firestore.FirebaseFirestore +import com.google.protobuf.Empty import kotlinx.coroutines.tasks.await +import java.lang.Exception import java.lang.StringBuilder import javax.inject.Inject @@ -12,24 +16,32 @@ import javax.inject.Inject class FriendRemoteRepositoryIml @Inject constructor(private val fireStore: FirebaseFirestore) : FriendRemoteRepository { - override suspend fun loadFriendList(): List { - val userData = - fireStore.collection(HomeRepositoryImpl.FIREBASE_COLLECTION_FRIEND_PATH) - .document(userUid).get().await() - val friendData = userData["friend"] as List> - Log.d("friend", friendData.toString()) - - val friendList = mutableListOf() - - friendData.forEach { - val user = - User( - it["UID"] ?: "", it["name"] ?: "", - it["userPhoto"] ?: "" - ) - friendList.add(user) + override suspend fun loadFriendList(): NetworkResult> { + try { + val userData = + fireStore.collection(HomeRepositoryImpl.FIREBASE_COLLECTION_FRIEND_PATH) + .document(userUid).get().await() + val friendData = userData["friend"] as List> + Log.d("friend", friendData.toString()) + + val friendList = mutableListOf() + + friendData.forEach { + val user = + User( + it["UID"] ?: "", it["name"] ?: "", + it["userPhoto"] ?: "" + ) + friendList.add(user) + } + return if (friendList.isNotEmpty()) { + NetworkResult.Success(friendList) + } else { + NetworkResult.Error(EMPTY) + } + } catch (e: Exception) { + return NetworkResult.Exception(e) } - return friendList } override suspend fun updateFriend(users: List) { diff --git a/app/src/main/java/com/example/issu_tracker/data/repository/Repository.kt b/app/src/main/java/com/example/issu_tracker/data/repository/Repository.kt index 01fac9c3aa..d8b568a4e5 100644 --- a/app/src/main/java/com/example/issu_tracker/data/repository/Repository.kt +++ b/app/src/main/java/com/example/issu_tracker/data/repository/Repository.kt @@ -3,31 +3,33 @@ package com.example.issu_tracker.data.repository import android.util.Log import com.example.issu_tracker.data.User import com.example.issu_tracker.data.local.FriendDatabase +import com.example.issu_tracker.data.network.NetworkResult import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch +import java.lang.Exception import javax.inject.Inject class Repository @Inject constructor( private val friendLocalDatabase: FriendDatabase, private val friendRemoteDatabase: FriendRemoteRepository ) { - suspend fun loadFriendList(): List { - // TODO 네트워크 상태에 따른 분기 처리 필요 - Log.d("sdd","0") - // 1. 리모트에서 로컬에 캐시해줌 - updateRemoteDatabase() + suspend fun loadFriendList(): NetworkResult> { + // 1. 네트워크 O -> 리모트에서 로컬에 캐시해줌, 로컬에서 내려주기 + // 2. 네트워크 X -> 로컬에서 내려주기 + val loadResult = friendRemoteDatabase.loadFriendList() - // 2. 업데이트된 로컬을 통해서 반환해줌 - val result = friendLocalDatabase.userDao().getAll() - return result + return if (loadResult is NetworkResult.Success) { + updateRemoteDatabase(loadResult.data) + NetworkResult.Success(friendLocalDatabase.userDao().getAll()) + } else { + NetworkResult.Cached(friendLocalDatabase.userDao().getAll()) + } } - suspend fun updateRemoteDatabase() { + suspend fun updateRemoteDatabase(userList: List = listOf()) { // 1. 리모트에서 로컬에 캐시해줌 - val userList = friendRemoteDatabase.loadFriendList() - Log.d("sdd","1") CoroutineScope(Dispatchers.IO).launch { friendLocalDatabase.userDao().deleteAllUsers() userList.forEach { @@ -36,14 +38,10 @@ class Repository @Inject constructor( } } }.join() - Log.d("sdd","2") - } - - suspend fun loadFriendListFromRemote(): List { - return friendRemoteDatabase.loadFriendList() } suspend fun updateFriend(userList: List) { friendRemoteDatabase.updateFriend(userList) } + } \ No newline at end of file diff --git a/app/src/main/java/com/example/issu_tracker/di/RepositoryModule.kt b/app/src/main/java/com/example/issu_tracker/di/RepositoryModule.kt index fee08fae67..67fe52350c 100644 --- a/app/src/main/java/com/example/issu_tracker/di/RepositoryModule.kt +++ b/app/src/main/java/com/example/issu_tracker/di/RepositoryModule.kt @@ -7,6 +7,7 @@ import com.example.issu_tracker.data.local.FriendDatabase import com.example.issu_tracker.data.local.UserDao import com.example.issu_tracker.data.repository.* import com.google.firebase.firestore.FirebaseFirestore +import com.google.firebase.firestore.ktx.firestoreSettings import dagger.Module import dagger.Provides import dagger.hilt.InstallIn @@ -36,7 +37,10 @@ object RepositoryModule { @Provides fun provideFireStoreDB(): FirebaseFirestore { - return FirebaseFirestore.getInstance() + val setting = firestoreSettings { isPersistenceEnabled = false } + val db = FirebaseFirestore.getInstance() + db.firestoreSettings = setting + return db } @Provides diff --git a/app/src/main/java/com/example/issu_tracker/ui/account/AccountViewModel.kt b/app/src/main/java/com/example/issu_tracker/ui/account/AccountViewModel.kt index d14bfd95bc..9ac2b16f2a 100644 --- a/app/src/main/java/com/example/issu_tracker/ui/account/AccountViewModel.kt +++ b/app/src/main/java/com/example/issu_tracker/ui/account/AccountViewModel.kt @@ -4,6 +4,7 @@ import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.example.issu_tracker.data.repository.Repository import com.example.issu_tracker.data.User +import com.example.issu_tracker.data.network.NetworkResult import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow @@ -12,22 +13,26 @@ import javax.inject.Inject @HiltViewModel class AccountViewModel @Inject constructor(private val repository: Repository) : ViewModel() { - private val _friendList = MutableStateFlow>(listOf()) - val friendList: StateFlow> = _friendList + private val _friendList = MutableStateFlow>>(NetworkResult.Loading()) + val friendList: StateFlow>> = _friendList + fun loadFriendList() { viewModelScope.launch { - _friendList.value = repository.loadFriendList() + val result = repository.loadFriendList() + _friendList.value = result } } fun dltFriend(user: User) { viewModelScope.launch { - val updateList = friendList.value.toMutableList() - updateList.remove(user) - repository.updateFriend(updateList) - _friendList.value = repository.loadFriendListFromRemote() - repository.updateRemoteDatabase() + if (friendList.value is NetworkResult.Success) { + val updateList = (friendList.value as NetworkResult.Success).data.toMutableList() + updateList.remove(user) + repository.updateFriend(updateList) + loadFriendList() + repository.updateRemoteDatabase() + } } } diff --git a/app/src/main/java/com/example/issu_tracker/ui/account/MyAccountFragment.kt b/app/src/main/java/com/example/issu_tracker/ui/account/MyAccountFragment.kt index a0992ee3c3..557dcbb50b 100644 --- a/app/src/main/java/com/example/issu_tracker/ui/account/MyAccountFragment.kt +++ b/app/src/main/java/com/example/issu_tracker/ui/account/MyAccountFragment.kt @@ -1,9 +1,12 @@ package com.example.issu_tracker.ui.account +import android.net.Network +import android.net.NetworkRequest import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import android.widget.Toast import androidx.databinding.BindingAdapter import androidx.databinding.DataBindingUtil import androidx.fragment.app.Fragment @@ -13,6 +16,7 @@ import androidx.lifecycle.lifecycleScope import androidx.lifecycle.repeatOnLifecycle import androidx.recyclerview.widget.LinearLayoutManager import com.example.issu_tracker.R +import com.example.issu_tracker.data.network.NetworkResult import com.example.issu_tracker.databinding.FragmentIssueBinding import com.example.issu_tracker.databinding.FragmentMyAccountBinding import com.google.firebase.firestore.auth.User @@ -33,7 +37,6 @@ class MyAccountFragment : Fragment() { setRecyclerView() listenFriendListUpdate() - return binding.root } @@ -41,7 +44,16 @@ class MyAccountFragment : Fragment() { viewLifecycleOwner.lifecycleScope.launch { viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) { accountViewModel.friendList.collect { - adapter.submitList(it) + if (it is NetworkResult.Success) { + adapter.submitList(it.data) + } else if (it is NetworkResult.Cached) { + adapter.submitList(it.data) + Toast.makeText( + this@MyAccountFragment.requireContext(), + "최신 데이터가 아닐 수 있습니다", + Toast.LENGTH_LONG + ).show() + } } } } @@ -51,7 +63,7 @@ class MyAccountFragment : Fragment() { private fun setRecyclerView() { accountViewModel.loadFriendList() - adapter = FriendAdapter(object :UserAdapterEventListener{ + adapter = FriendAdapter(object : UserAdapterEventListener { override fun dltUser(user: com.example.issu_tracker.data.User) { accountViewModel.dltFriend(user) } diff --git a/app/src/main/java/com/example/issu_tracker/ui/detail/DetailEditDialogFragment.kt b/app/src/main/java/com/example/issu_tracker/ui/detail/DetailEditDialogFragment.kt index 399ce5a52b..fdd57887cd 100644 --- a/app/src/main/java/com/example/issu_tracker/ui/detail/DetailEditDialogFragment.kt +++ b/app/src/main/java/com/example/issu_tracker/ui/detail/DetailEditDialogFragment.kt @@ -11,7 +11,7 @@ import com.example.issu_tracker.databinding.DetailEditDialogFragmentBinding import java.lang.StringBuilder -class DetailEditDialogFragment(val labelNameList: List, mileStoneName: String? = null) : +class DetailEditDialogFragment(private val labelNameList: List, mileStoneName: String? = null) : DialogFragment() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) From bd279568bf7450ea47ff50a98eb0823f1ba97916 Mon Sep 17 00:00:00 2001 From: shim506 Date: Fri, 1 Jul 2022 01:27:50 +0900 Subject: [PATCH 05/13] =?UTF-8?q?feat=20:=20Issue=EC=9D=98=20Entitiy=20?= =?UTF-8?q?=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle | 3 ++ .../com/example/issu_tracker/data/Comment.kt | 2 + .../com/example/issu_tracker/data/Issue.kt | 42 ++++++++++++++++++- .../com/example/issu_tracker/data/Label.kt | 3 +- .../issu_tracker/data/local/FriendDatabase.kt | 10 ----- .../issu_tracker/data/local/IssueDao.kt | 24 +++++++++++ .../data/local/IssueTrackerDatabase.kt | 16 +++++++ 7 files changed, 88 insertions(+), 12 deletions(-) delete mode 100644 app/src/main/java/com/example/issu_tracker/data/local/FriendDatabase.kt create mode 100644 app/src/main/java/com/example/issu_tracker/data/local/IssueDao.kt create mode 100644 app/src/main/java/com/example/issu_tracker/data/local/IssueTrackerDatabase.kt diff --git a/app/build.gradle b/app/build.gradle index a777ba42b9..c00c0dfaae 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -38,6 +38,9 @@ android { } dependencies { + + implementation 'com.google.code.gson:gson:2.9.0' + //Room implementation "androidx.room:room-ktx:2.4.2" kapt "androidx.room:room-compiler:2.4.2" diff --git a/app/src/main/java/com/example/issu_tracker/data/Comment.kt b/app/src/main/java/com/example/issu_tracker/data/Comment.kt index f0ce20d15d..4940a67308 100644 --- a/app/src/main/java/com/example/issu_tracker/data/Comment.kt +++ b/app/src/main/java/com/example/issu_tracker/data/Comment.kt @@ -1,7 +1,9 @@ package com.example.issu_tracker.data +import androidx.room.Entity import java.io.Serializable +@Entity data class Comment( val user: User? = null, val content: String = "", diff --git a/app/src/main/java/com/example/issu_tracker/data/Issue.kt b/app/src/main/java/com/example/issu_tracker/data/Issue.kt index 1f7eff9924..4ce14940e6 100644 --- a/app/src/main/java/com/example/issu_tracker/data/Issue.kt +++ b/app/src/main/java/com/example/issu_tracker/data/Issue.kt @@ -1,5 +1,8 @@ package com.example.issu_tracker.data +import androidx.room.* +import com.google.gson.Gson +import com.google.gson.reflect.TypeToken import java.io.Serializable import java.lang.Exception @@ -14,7 +17,9 @@ data class IssueDto( val user: User? = null ) +@Entity data class Issue( + @ColumnInfo(name = "issue_id") var id: String, val comments: List, val description: String, @@ -22,8 +27,43 @@ data class Issue( val mileStone: String, val state: Boolean, val title: String, + @Embedded val user: User -) : Serializable +) : Serializable{ + @PrimaryKey(autoGenerate = true) + var idx: Int = 0 +} + +class Converters { + @TypeConverter + fun fromCommentList(comments: List): String? { + val gson = Gson() + val type = object : TypeToken>() {}.type + return gson.toJson(comments, type) + } + + @TypeConverter + fun toCommentList(value: String?): List { + val gson = Gson() + val type = object : TypeToken>() {}.type + return gson.fromJson(value, type) + } + + @TypeConverter + fun fromLabelList(comments: List