diff --git a/app/build.gradle b/app/build.gradle index 51dd0fd4..1e4d3dba 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -197,4 +197,6 @@ dependencies { androidTestImplementation 'androidx.test.ext:junit:1.1.2' androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0' + //Facebook shimmer library + implementation "com.facebook.shimmer:shimmer:0.5.0" } \ No newline at end of file diff --git a/app/src/main/java/com/sgs/devcamp2/flametalk_android/data/common/Status.kt b/app/src/main/java/com/sgs/devcamp2/flametalk_android/data/common/Status.kt new file mode 100644 index 00000000..165f215f --- /dev/null +++ b/app/src/main/java/com/sgs/devcamp2/flametalk_android/data/common/Status.kt @@ -0,0 +1,13 @@ +package com.sgs.devcamp2.flametalk_android.data.common + +/** + * @author boris + * @created 2022/03/03 + */ +object Status { + const val OK = 200 + const val BAD_REQUEST = 400 + const val UNAUTHORIZED = 401 + const val FILE_NOT_FOUND = 404 + const val SERVER_ERROR = 500 +} \ No newline at end of file diff --git a/app/src/main/java/com/sgs/devcamp2/flametalk_android/data/repository/AuthRepositoryImpl.kt b/app/src/main/java/com/sgs/devcamp2/flametalk_android/data/repository/AuthRepositoryImpl.kt index c7d6fb7c..b2b3317a 100644 --- a/app/src/main/java/com/sgs/devcamp2/flametalk_android/data/repository/AuthRepositoryImpl.kt +++ b/app/src/main/java/com/sgs/devcamp2/flametalk_android/data/repository/AuthRepositoryImpl.kt @@ -1,5 +1,6 @@ package com.sgs.devcamp2.flametalk_android.data.repository +import com.sgs.devcamp2.flametalk_android.data.common.Status import com.sgs.devcamp2.flametalk_android.data.common.WrappedResponse import com.sgs.devcamp2.flametalk_android.data.model.auth.AuthReq import com.sgs.devcamp2.flametalk_android.data.model.auth.AuthRes @@ -24,15 +25,20 @@ class AuthRepositoryImpl @Inject constructor( return flow { val response = remote.signUp(authReq) if (response.isSuccessful) { - if (response.body()!!.status == 200) { - val data = response.body()!!.data - emit(Results.Success(data!!)) - } else if (response.body()!!.status == 400) { - emit(Results.Error("잘못된 요청입니다")) - } else if (response.body()!!.status == 401) { - emit(Results.Error("권한이 없습니다")) - } else { - emit(Results.Error("서버 에러입니다")) + when (response.body()!!.status) { + Status.OK -> { + val data = response.body()!!.data + emit(Results.Success(data!!)) + } + Status.BAD_REQUEST -> { + emit(Results.Error("잘못된 요청입니다")) + } + Status.UNAUTHORIZED -> { + emit(Results.Error("권한이 없습니다")) + } + else -> { + emit(Results.Error("서버 에러입니다")) + } } } }.flowOn(ioDispatcher) diff --git a/app/src/main/java/com/sgs/devcamp2/flametalk_android/data/repository/ChatRepositoryImp.kt b/app/src/main/java/com/sgs/devcamp2/flametalk_android/data/repository/ChatRepositoryImp.kt index 72e26cb8..9d98132a 100644 --- a/app/src/main/java/com/sgs/devcamp2/flametalk_android/data/repository/ChatRepositoryImp.kt +++ b/app/src/main/java/com/sgs/devcamp2/flametalk_android/data/repository/ChatRepositoryImp.kt @@ -1,6 +1,6 @@ package com.sgs.devcamp2.flametalk_android.data.repository -import android.util.Log +import com.sgs.devcamp2.flametalk_android.data.common.Status import com.sgs.devcamp2.flametalk_android.data.common.WrappedResponse import com.sgs.devcamp2.flametalk_android.data.mapper.mapperToChat import com.sgs.devcamp2.flametalk_android.data.mapper.mapperToChatRoomUpdateModel @@ -10,7 +10,11 @@ import com.sgs.devcamp2.flametalk_android.data.source.remote.api.ChatApi import com.sgs.devcamp2.flametalk_android.domain.entity.LocalResults import com.sgs.devcamp2.flametalk_android.domain.entity.Results import com.sgs.devcamp2.flametalk_android.domain.repository.ChatRepository -import kotlinx.coroutines.* +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Deferred +import kotlinx.coroutines.async +import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.flowOn @@ -20,7 +24,7 @@ import javax.inject.Inject /** * @author 김현국 * @created 2022/01/31 - * Domain layer의 Chatrespository의 구현체 + * Domain layer 의 Chat repository 의 구현체 */ class ChatRepositoryImp @Inject constructor( private val ioDispatcher: CoroutineDispatcher, @@ -28,33 +32,30 @@ class ChatRepositoryImp @Inject constructor( private val remote: ChatApi ) : ChatRepository { /** - * Websocket으로 수신받은 Message를 Local Database에 저장하는 function입니다. + * WebSocket 으로 수신받은 Message 를 Local Database 에 저장하는 function 입니다. * @param chatRes 채팅 수신 response - * @desc 채팅을 수신하면 chat data model로 chatres를 mapping하고 database에 저장합니다. + * @desc 채팅을 수신하면 chat data model 로 ChatRes 를 mapping 하고 database 에 저장합니다. */ override fun saveReceivedMessage(chatRes: ChatRes): Flow { return flow { - val TAG: String = "로그" val chat = mapperToChat(chatRes) - Log.d(TAG, "chat - $chat") - val deferr: Deferred = CoroutineScope(ioDispatcher).async { + val deferred: Deferred = CoroutineScope(ioDispatcher).async { db.chatDao().insert(chat) } - val index = deferr.await() - Log.d(TAG, "index - $index") + val index = deferred.await() val chatRoomUpdateModel = mapperToChatRoomUpdateModel(chatRes) - val deferr2: Deferred = CoroutineScope(ioDispatcher).async { + val deferred2: Deferred = CoroutineScope(ioDispatcher).async { db.chatRoomDao().updateLastReadMessageId(chatRoomUpdateModel) } - deferr2.await() + deferred2.await() emit(index) }.flowOn(ioDispatcher) } /** - * 마지막으로 읽은 메시지 이후에 모든 메시지를 가져오는 function입니다. - * @param roomId 채팅방id + * 마지막으로 읽은 메시지 이후에 모든 메시지를 가져오는 function 입니다. + * @param roomId 채팅방 id * @param lastReadMessage 마지막으로 읽은 메세지 id - * @desc 채팅 텍스트 리스트를 응답받으며, 받은 응답을 room database에 저장합니다. + * @desc 채팅 텍스트 리스트를 응답받으며, 받은 응답을 room database 에 저장합니다. */ override fun getMessageHistory( roomId: String, @@ -62,52 +63,54 @@ class ChatRepositoryImp @Inject constructor( ): Flow, WrappedResponse>>> { return flow { val response = remote.getChatMessageHistory(roomId, lastReadMessage) - val TAG: String = "로그" if (response.isSuccessful) { - if (response.body()!!.status == 200) { - val data = response.body()!!.data - - var deferred = coroutineScope { - async { - try { - for (i in 0 until data!!.size) { - val chat = mapperToChat(data[i]) - db.chatDao().insert(chat) + when (response.body()!!.status) { + Status.OK -> { + val data = response.body()!!.data + val deferred = coroutineScope { + async { + try { + for (i in 0 until data!!.size) { + val chat = mapperToChat(data[i]) + db.chatDao().insert(chat) + } + } catch (e: Exception) { } - Log.d(TAG, "ChatRepositoryImp - getMessageHistory(1) called") - } catch (e: Exception) { } } + deferred.await() + val deferred2: Deferred = CoroutineScope(ioDispatcher).async { + db.chatRoomDao().updateMessageCount(roomId) + } + deferred2.await() + emit(Results.Success(data!!)) + } + Status.BAD_REQUEST -> { + emit(Results.Error("잘못된 요청입니다")) + } + Status.UNAUTHORIZED -> { + emit(Results.Error("권한이 없습니다")) } - deferred.await() - var messageCount = 0 - val deferr2: Deferred = CoroutineScope(ioDispatcher).async { - db.chatRoomDao().updateMessageCount(roomId) + else -> { + emit(Results.Error("서버 에러입니다")) } - messageCount = deferr2.await() - Log.d(TAG, "ChatRepositoryImp - getMessageHistory(2) called") - emit(Results.Success(data!!)) } - } else if (response.body()!!.status == 400) { - emit(Results.Error("잘못된 요청입니다")) - } else if (response.body()!!.status == 401) { - emit(Results.Error("권한이 없습니다")) - } else { - emit(Results.Error("서버 에러입니다")) } }.flowOn(ioDispatcher) } override fun getLastReadMessageId(chatroomId: String): Flow?> { return flow { - val TAG: String = "로그" - var messageId: String = "" - - val deferr: Deferred = CoroutineScope(ioDispatcher).async { + val messageId: String + val deferred: Deferred = CoroutineScope(ioDispatcher).async { db.chatDao().getLastMessageWithRoomId(chatroomId) } - messageId = deferr.await().toString() - emit(LocalResults.Success(messageId)) + messageId = deferred.await().toString() + if (messageId != "") { + emit(LocalResults.Success(messageId)) + } else { + emit(LocalResults.Error("")) + } }.flowOn(ioDispatcher) } } diff --git a/app/src/main/java/com/sgs/devcamp2/flametalk_android/data/repository/ChatRoomRepositoryImpl.kt b/app/src/main/java/com/sgs/devcamp2/flametalk_android/data/repository/ChatRoomRepositoryImpl.kt index 960679f5..4587f123 100644 --- a/app/src/main/java/com/sgs/devcamp2/flametalk_android/data/repository/ChatRoomRepositoryImpl.kt +++ b/app/src/main/java/com/sgs/devcamp2/flametalk_android/data/repository/ChatRoomRepositoryImpl.kt @@ -1,8 +1,11 @@ package com.sgs.devcamp2.flametalk_android.data.repository -import android.util.Log +import com.sgs.devcamp2.flametalk_android.data.common.Status import com.sgs.devcamp2.flametalk_android.data.common.WrappedResponse -import com.sgs.devcamp2.flametalk_android.data.mapper.* +import com.sgs.devcamp2.flametalk_android.data.mapper.mapperToChatRoomEntity +import com.sgs.devcamp2.flametalk_android.data.mapper.mapperToChatRoomModel +import com.sgs.devcamp2.flametalk_android.data.mapper.mapperToGetChatRoomEntity +import com.sgs.devcamp2.flametalk_android.data.mapper.mapperToThumbnail import com.sgs.devcamp2.flametalk_android.data.model.chat.ChatWithRoomId import com.sgs.devcamp2.flametalk_android.data.model.chatroom.ChatRoom import com.sgs.devcamp2.flametalk_android.data.model.chatroom.Thumbnail @@ -28,8 +31,14 @@ import com.sgs.devcamp2.flametalk_android.domain.entity.Results import com.sgs.devcamp2.flametalk_android.domain.entity.chatroom.ChatRoomEntity import com.sgs.devcamp2.flametalk_android.domain.entity.chatroom.GetChatRoomEntity import com.sgs.devcamp2.flametalk_android.domain.repository.ChatRoomRepository -import kotlinx.coroutines.* -import kotlinx.coroutines.flow.* +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Deferred +import kotlinx.coroutines.async +import kotlinx.coroutines.coroutineScope +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flow +import kotlinx.coroutines.flow.flowOn import okhttp3.MultipartBody import okhttp3.RequestBody import javax.inject.Inject @@ -45,28 +54,33 @@ class ChatRoomRepositoryImpl @Inject constructor( private val friendRemote: FriendApi, ) : ChatRoomRepository { /** - * 채팅방 생성 api 호출 및 room database 저장 function입니다. + * 채팅방 생성 api 호출 및 room database 저장 function 입니다. * @param createChatRoomReq 채팅방 생성 request model - * @desc 서버에 채팅방 생성 api를 호출하고, response를 받아 chatroomModel과 chatRoomEntity로 mapping합니다. - * chatRoomModel를 room database에 저장하고, chatRoomEntity는 호출된 viewModel로 이동하게 됩니다. + * @desc 서버에 채팅방 생성 api 를 호출하고, response 를 받아 chatroomModel 과 chatRoomEntity 로 mapping 합니다. + * chatRoomModel 를 room database 에 저장하고, chatRoomEntity 는 호출된 viewModel 로 이동하게 됩니다. */ override fun createChatRoom(createChatRoomReq: CreateChatRoomReq): Flow>> { return flow { val response = remote.createChatRoom(createChatRoomReq) if (response.isSuccessful) { - if (response.body()!!.status == 200) { - val body = response.body()!! - val data = body.data!! - val chatroomModel = mapperToChatRoomModel(data) - local.chatRoomDao().insert(chatroomModel) - val chatRoomEntity = mapperToChatRoomEntity(data) - emit(Results.Success(chatRoomEntity)) - } else if (response.body()!!.status == 400) { - emit(Results.Error("잘못된 요청입니다")) - } else if (response.body()!!.status == 401) { - emit(Results.Error("권한이 없습니다")) - } else { - emit(Results.Error("서버 에러입니다")) + when (response.body()!!.status) { + Status.OK -> { + val body = response.body()!! + val data = body.data!! + val chatroomModel = mapperToChatRoomModel(data) + local.chatRoomDao().insert(chatroomModel) + val chatRoomEntity = mapperToChatRoomEntity(data) + emit(Results.Success(chatRoomEntity)) + } + Status.BAD_REQUEST -> { + emit(Results.Error("잘못된 요청입니다")) + } + Status.UNAUTHORIZED -> { + emit(Results.Error("권한이 없습니다")) + } + else -> { + emit(Results.Error("서버 에러입니다")) + } } } }.flowOn(ioDispatcher) @@ -82,23 +96,23 @@ class ChatRoomRepositoryImpl @Inject constructor( TODO("Not yet implemented") } /** - * 채팅 리스트 불러오기 function입니다. + * 채팅 리스트 불러오기 function 입니다. * @param chatroomId 채팅방 roomId - * @desc room Database에 저장된 채팅 텍스트를 가져옵니다. - * api가 아님 local에서 불러오기 때문에 localResults sealed class를 사용했습니다. + * @desc room Database 에 저장된 채팅 텍스트를 가져옵니다. + * api 가 아님 local 에서 불러오기 때문에 localResults sealed class 를 사용했습니다. */ override fun getChatList(chatroomId: String): Flow> { return flow { - var chatwithRoomId: ChatWithRoomId? = null - var deffer: Deferred = CoroutineScope(ioDispatcher).async { + val chatWithRoomId: ChatWithRoomId? + val deffer: Deferred = CoroutineScope(ioDispatcher).async { local.chatRoomDao().getChatRoomWithId(chatroomId) } - chatwithRoomId = deffer.await() - emit(LocalResults.Success(chatwithRoomId)) + chatWithRoomId = deffer.await() + emit(LocalResults.Success(chatWithRoomId)) }.flowOn(ioDispatcher) } /** - * 채팅의 상세정보 불러오기 function입니다. + * 채팅의 상세정보 불러오기 function 입니다. * @param userChatroomId 유저채팅방Id * @desc api 호출을 통해서 보고자하는 채팅방의 상세 정보 를 볼 수 있습니다. */ @@ -106,76 +120,49 @@ class ChatRoomRepositoryImpl @Inject constructor( return flow { val response = remote.getChatRoom(userChatroomId) if (response.isSuccessful) { - if (response.body()!!.status == 200) { - val body = response.body()!! - val data = body.data!! - val getChatRoomEntity = mapperToGetChatRoomEntity(data) - emit(Results.Success(getChatRoomEntity)) - } else if (response.body()!!.status == 400) { - emit(Results.Error("잘못된 요청입니다")) - } else if (response.body()!!.status == 401) { - emit(Results.Error("권한이 없습니다")) - } else if (response.body()!!.status == 404) { - emit(Results.Error("존재하지 않는 채팅방입니다")) - } else { - emit(Results.Error("서버 에러입니다")) + when (response.body()!!.status) { + Status.OK -> { + val body = response.body()!! + val data = body.data!! + val getChatRoomEntity = mapperToGetChatRoomEntity(data) + emit(Results.Success(getChatRoomEntity)) + } + Status.BAD_REQUEST -> { + emit(Results.Error("잘못된 요청입니다")) + } + Status.UNAUTHORIZED -> { + emit(Results.Error("권한이 없습니다")) + } + Status.FILE_NOT_FOUND -> { + emit(Results.Error("존재하지 않는 채팅방입니다")) + } + else -> { + emit(Results.Error("서버 에러입니다")) + } } } }.flowOn(ioDispatcher) } /** - * 채팅방 리스트 불러오기 function입니다. + * 채팅방 리스트 불러오기 function 입니다. * @param isOpen 오픈채팅방 유무 - * @desc 채팅방 리스트를 불러오고, 내부 database에 저장합니다. - * 또한 변경된 썸네일이 있다면, 기존 내부 database에 저장된 썸네일 리스트를 지우고, + * @desc 채팅방 리스트를 불러오고, 내부 database 에 저장합니다. + * 또한 변경된 썸네일이 있다면, 기존 내부 database 에 저장된 썸네일 리스트를 지우고, * 새로운 썸네일로 변경하고 저장합니다. */ - override fun getChatRoomList(isOpen: Boolean): Flow>> { + override fun getChatRoomList + (isOpen: Boolean): Flow>> { return flow { val response = remote.getChatRoomList(isOpen) if (response.isSuccessful) { - if (response.body()!!.status == 200) { - val body = response.body()!! - val data = body.data!! - for (i in 0 until data.userChatrooms.size) { - // local db에서 데이터가 있는지 찾는다. - val getChatRoomWithThumnail = local.chatRoomDao() - .getChatRoomWithThumbnailAndId(data.userChatrooms[i].chatroomId) - if (getChatRoomWithThumnail == null) { - // 데이터가 없다면 넣는다. - val chatRoom = mapperToChatRoomModel(isOpen, i, data) - var deferred = coroutineScope { - async { - local.chatRoomDao().insert(chatRoom) - } - } - deferred.await() - var deferred2 = coroutineScope { - async { - if (data.userChatrooms[i].thumbnail?.size != 0) { - for (j in 0 until data.userChatrooms[i].thumbnail!!.size) { - lateinit var thumbnail: Thumbnail - if (data.userChatrooms[i].thumbnail?.get(j) - .isNullOrEmpty() - ) { - thumbnail = mapperToThumbnail( - data.userChatrooms[i].chatroomId, - "" - ) - } else { - thumbnail = mapperToThumbnail( - data.userChatrooms[i].chatroomId, - data.userChatrooms[i].thumbnail?.get(j)!! - ) - } - local.chatRoomDao().insertThumbnail(thumbnail) - } - } - } - } - deferred2.await() - } else { - var deffered3 = coroutineScope { + when (response.body()!!.status) { + Status.OK -> { + val body = response.body()!! + val data = body.data!! + for (i in 0 until data.userChatrooms.size) { + // local db 에서 데이터가 있는지 찾는다. + local.chatRoomDao().getChatRoomWithThumbnailAndId(data.userChatrooms[i].chatroomId) + val deferred = coroutineScope { async { local.chatRoomDao().updateChatRoomInfo( data.userChatrooms[i].title, @@ -187,16 +174,15 @@ class ChatRoomRepositoryImpl @Inject constructor( local.chatRoomDao() .deleteThumbnailwithRoomId(data.userChatrooms[i].chatroomId) for (j in 0 until data.userChatrooms[i].thumbnail!!.size) { - lateinit var thumbnail: Thumbnail - if (data.userChatrooms[i].thumbnail?.get(j) + val thumbnail: Thumbnail = if (data.userChatrooms[i].thumbnail?.get(j) .isNullOrEmpty() ) { - thumbnail = mapperToThumbnail( + mapperToThumbnail( data.userChatrooms[i].chatroomId, "" ) } else { - thumbnail = mapperToThumbnail( + mapperToThumbnail( data.userChatrooms[i].chatroomId, data.userChatrooms[i].thumbnail?.get(j)!! ) @@ -206,22 +192,25 @@ class ChatRoomRepositoryImpl @Inject constructor( } } } - deffered3.await() + deferred.await() } + emit(Results.Success(data)) + } + Status.BAD_REQUEST -> { + emit(Results.Error("잘못된 요청입니다")) + } + Status.UNAUTHORIZED -> { + emit(Results.Error("권한이 없습니다")) + } + else -> { + emit(Results.Error("서버 에러입니다")) } - emit(Results.Success(data)) - } else if (response.body()!!.status == 400) { - emit(Results.Error("잘못된 요청입니다")) - } else if (response.body()!!.status == 401) { - emit(Results.Error("권한이 없습니다")) - } else { - emit(Results.Error("서버 에러입니다")) } } }.flowOn(ioDispatcher) } /** - * 내부 local database에 저장된 chatroomList를 가져오는 function입니다. + * 내부 local database 에 저장된 chatroomList 를 가져오는 function 입니다. * @param isOpen 오픈채팅유무 * @desc 채팅방의 썸네일과 함께 채팅룸 리스트를 반환합니다. */ @@ -233,24 +222,35 @@ class ChatRoomRepositoryImpl @Inject constructor( }.flowOn(ioDispatcher) } /** - * 채팅방에 업로드된 파일 리스트를 불러오는 function입니다. - * @param chatroomId 채팅룸id + * 채팅방에 업로드된 파일 리스트를 불러오는 function 입니다. + * @param chatroomId 채팅룸 id */ override fun getChatRoomFileList(chatroomId: String): Flow, WrappedResponse>>> { return flow { val response = remote.getChatRoomFileList(chatroomId) if (response.isSuccessful) { - if (response.body()!!.status == 200) { - val body = response.body()!! - val data = body.data!! - emit(Results.Success(data)) + when (response.body()!!.status) { + Status.OK -> { + val body = response.body()!! + val data = body.data!! + emit(Results.Success(data)) + } + Status.BAD_REQUEST -> { + emit(Results.Error("잘못된 요청입니다")) + } + Status.UNAUTHORIZED -> { + emit(Results.Error("권한이 없습니다")) + } + else -> { + emit(Results.Error("서버 에러입니다")) + } } } }.flowOn(ioDispatcher) } /** - * 채팅방 수정 function입니다. - * @param userChatroomId 유저채팅방id + * 채팅방 수정 function 입니다. + * @param userChatroomId 유저 채팅방 id * @param updateChatRoomReq 업데이트 요청 request model */ override fun updateChatRoom( @@ -261,100 +261,121 @@ class ChatRoomRepositoryImpl @Inject constructor( return flow { val response = remote.updateChatRoom(userChatroomId, updateChatRoomReq) if (response.isSuccessful) { - if (response.body()!!.status == 200) { - val body = response.body()!! - val data = body.data!! - local.chatRoomDao() - .updateChatRoomTitle(data.title, data.inputLock, data.userChatroomId) - if (data.thumbnail[0] != null) { + when (response.body()!!.status) { + 200 -> { + val body = response.body()!! + val data = body.data!! + local.chatRoomDao() + .updateChatRoomTitle(data.title, data.inputLock, data.userChatroomId) local.chatRoomDao().deleteThumbnailwithRoomId(chatroomId) - lateinit var thumbnail: Thumbnail - thumbnail = mapperToThumbnail( + val thumbnail: Thumbnail = mapperToThumbnail( chatroomId, data.thumbnail[0] ) local.chatRoomDao().insertThumbnail(thumbnail) - } - emit(Results.Success(data)) - } else if (response.body()!!.status == 400) { - emit(Results.Error("잘못된 요청입니다")) - } else if (response.body()!!.status == 401) { - emit(Results.Error("권한이 없습니다")) - } else { - emit(Results.Error("서버 에러입니다")) + emit(Results.Success(data)) + } + 400 -> { + emit(Results.Error("잘못된 요청입니다")) + } + 401 -> { + emit(Results.Error("권한이 없습니다")) + } + else -> { + emit(Results.Error("서버 에러입니다")) + } } } }.flowOn(ioDispatcher) } /** - * 채팅방에서 벗어날 때 lastReadMessageId를 갱신하는 function입니다. + * 채팅방에서 벗어날 때 lastReadMessageId를 갱신하는 function 입니다. * @param closeChatRoomReq 채팅방나가기 request model */ override fun closeChatRoom(closeChatRoomReq: CloseChatRoomReq): Flow>> { return flow { - val TAG: String = "로그" val response = remote.closeChatRoom(closeChatRoomReq) if (response.isSuccessful) { - if (response.body()!!.status == 200) { - var response: String = "" - var updateResponse = 0 - var deffer: Deferred = CoroutineScope(ioDispatcher).async { - local.chatDao().getContents(closeChatRoomReq.lastReadMessageId) - } - response = deffer.await() - var deffer2: Deferred = CoroutineScope(ioDispatcher).async { - local.chatRoomDao().updateChatRoomWithMessageText( - closeChatRoomReq.lastReadMessageId, - response, - System.currentTimeMillis(), - closeChatRoomReq.userChatroomId, - ) + when (response.body()!!.status) { + Status.OK -> { + val res: String + val deffer: Deferred = CoroutineScope(ioDispatcher).async { + local.chatDao().getContents(closeChatRoomReq.lastReadMessageId) + } + res = deffer.await() + val deffer2: Deferred = CoroutineScope(ioDispatcher).async { + local.chatRoomDao().updateChatRoomWithMessageText( + closeChatRoomReq.lastReadMessageId, + res, + System.currentTimeMillis(), + closeChatRoomReq.userChatroomId, + ) + } + deffer2.await() + emit(Results.Success(true)) + } + Status.BAD_REQUEST -> { + emit(Results.Error("잘못된 요청입니다")) + } + Status.UNAUTHORIZED -> { + emit(Results.Error("권한이 없습니다")) + } + else -> { + emit(Results.Error("서버 에러입니다")) } - updateResponse = deffer2.await() - emit(Results.Success(true)) - } else if (response.body()!!.status == 400) { - emit(Results.Error("잘못된 요청입니다")) - } else if (response.body()!!.status == 401) { - emit(Results.Error("권한이 없습니다")) - } else { - emit(Results.Error("서버 에러입니다")) } } }.flowOn(ioDispatcher) } /** - * 오픈채팅방 프로필을 업데이트하는 function입니다. + * 오픈채팅방 프로필을 업데이트하는 function 입니다. * @param updateOpenChatRoomProfileReq 오픈채팅방프로필 업데이트 data model */ override fun updateOpenChatRoomProfile(updateOpenChatRoomProfileReq: UpdateOpenChatRoomProfileReq): Flow>> { return flow { val response = remote.updateOpenChatRoomProfile(updateOpenChatRoomProfileReq) if (response.isSuccessful) { - if (response.body()!!.status == 200) { - emit(Results.Success(true)) + when (response.body()!!.status) { + Status.OK -> { + emit(Results.Success(true)) + } + Status.BAD_REQUEST -> { + emit(Results.Error("잘못된 요청입니다")) + } + Status.UNAUTHORIZED -> { + emit(Results.Error("권한이 없습니다")) + } + else -> { + emit(Results.Error("서버 에러입니다")) + } } } }.flowOn(ioDispatcher) } /** - * 채팅방을 나가는(삭제하는) function입니다. - * @param userChatroomId 유저채팅방id + * 채팅방을 나가는(삭제하는) function 입니다. + * @param userChatroomId 유저채팅방 id */ override fun leaveChatRoom(userChatroomId: Long): Flow>> { return flow { val response = remote.leaveChatRoom(userChatroomId) if (response.isSuccessful) { - if (response.body()!!.status == 200) { - local.chatRoomDao().deleteChatRoomWithuserChatroomId(userChatroomId) - emit(Results.Success(true)) - } else if (response.body()!!.status == 400) { - emit(Results.Error("잘못된 요청입니다")) - } else if (response.body()!!.status == 401) { - emit(Results.Error("권한이 없습니다")) - } else { - emit(Results.Error("서버 에러입니다")) + when (response.body()!!.status) { + Status.OK -> { + local.chatRoomDao().deleteChatRoomWithuserChatroomId(userChatroomId) + emit(Results.Success(true)) + } + Status.BAD_REQUEST -> { + emit(Results.Error("잘못된 요청입니다")) + } + Status.UNAUTHORIZED -> { + emit(Results.Error("권한이 없습니다")) + } + else -> { + emit(Results.Error("서버 에러입니다")) + } } } }.flowOn(ioDispatcher) @@ -382,18 +403,22 @@ class ChatRoomRepositoryImpl @Inject constructor( ): Flow>> { return flow { val response = remote.fileCreate(file, chatroomId) - Log.d("로그", "response - $response() called") if (response.isSuccessful) { - if (response.body()!!.status == 200) { - val body = response.body()!! - val data = body.data!! - emit(Results.Success(data)) - } else if (response.body()!!.status == 400) { - emit(Results.Error("잘못된 요청입니다")) - } else if (response.body()!!.status == 401) { - emit(Results.Error("권한이 없습니다")) - } else { - emit(Results.Error("서버 에러입니다")) + when (response.body()!!.status) { + Status.OK -> { + val body = response.body()!! + val data = body.data!! + emit(Results.Success(data)) + } + Status.BAD_REQUEST -> { + emit(Results.Error("잘못된 요청입니다")) + } + Status.UNAUTHORIZED -> { + emit(Results.Error("권한이 없습니다")) + } + else -> { + emit(Results.Error("서버 에러입니다")) + } } } }.flowOn(ioDispatcher) @@ -403,16 +428,21 @@ class ChatRoomRepositoryImpl @Inject constructor( return flow { val response = remote.joinChatRoom(joinChatRoomReq) if (response.isSuccessful) { - if (response.body()!!.status == 200) { - val body = response.body()!! - val data = body.data!! - emit(Results.Success(data)) - } else if (response.body()!!.status == 400) { - emit(Results.Error("잘못된 요청입니다")) - } else if (response.body()!!.status == 401) { - emit(Results.Error("권한이 없습니다")) - } else { - emit(Results.Error("서버 에러입니다")) + when (response.body()!!.status) { + Status.OK -> { + val body = response.body()!! + val data = body.data!! + emit(Results.Success(data)) + } + Status.BAD_REQUEST -> { + emit(Results.Error("잘못된 요청입니다")) + } + Status.UNAUTHORIZED -> { + emit(Results.Error("권한이 없습니다")) + } + else -> { + emit(Results.Error("서버 에러입니다")) + } } } }.flowOn(ioDispatcher) @@ -425,18 +455,22 @@ class ChatRoomRepositoryImpl @Inject constructor( ): Flow, WrappedResponse>>> { return flow { val response = friendRemote.getFriendList(isBirth, isHidden, isBlock) - Log.d("로그", "ChatRoomRepositoryImpl - getFriendUser() called") if (response.isSuccessful) { - if (response.body()!!.status == 200) { - val body = response.body()!! - val data = body.data!! - emit(Results.Success(data)) - } else if (response.body()!!.status == 400) { - emit(Results.Error("잘못된 요청입니다")) - } else if (response.body()!!.status == 401) { - emit(Results.Error("권한이 없습니다")) - } else { - emit(Results.Error("서버 에러입니다")) + when (response.body()!!.status) { + Status.OK -> { + val body = response.body()!! + val data = body.data!! + emit(Results.Success(data)) + } + Status.BAD_REQUEST -> { + emit(Results.Error("잘못된 요청입니다")) + } + Status.UNAUTHORIZED -> { + emit(Results.Error("권한이 없습니다")) + } + else -> { + emit(Results.Error("서버 에러입니다")) + } } } }.flowOn(ioDispatcher) diff --git a/app/src/main/java/com/sgs/devcamp2/flametalk_android/data/repository/DeviceRepositoryImpl.kt b/app/src/main/java/com/sgs/devcamp2/flametalk_android/data/repository/DeviceRepositoryImpl.kt index 7e59f599..54fa3839 100644 --- a/app/src/main/java/com/sgs/devcamp2/flametalk_android/data/repository/DeviceRepositoryImpl.kt +++ b/app/src/main/java/com/sgs/devcamp2/flametalk_android/data/repository/DeviceRepositoryImpl.kt @@ -1,5 +1,6 @@ package com.sgs.devcamp2.flametalk_android.data.repository +import com.sgs.devcamp2.flametalk_android.data.common.Status import com.sgs.devcamp2.flametalk_android.data.common.WrappedResponse import com.sgs.devcamp2.flametalk_android.data.model.device.saveDeviceToken.SaveDeviceTokenReq import com.sgs.devcamp2.flametalk_android.data.model.device.saveDeviceToken.SaveDeviceTokenRes @@ -21,23 +22,27 @@ class DeviceRepositoryImpl @Inject constructor( val remote: DeviceApi ) : DeviceRepository { /** - * 로그인 성공시 fcm의 devicetoken을 업데이트하는 function입니다. + * 로그인 성공시 fcm 의 devicetoken 을 업데이트하는 function 입니다. */ - val TAG: String = "로그" override suspend fun saveDeviceToken(saveDeviceTokenReq: SaveDeviceTokenReq): Flow>> { return flow { val response = remote.saveDeviceToken(saveDeviceTokenReq) if (response.isSuccessful) { - if (response.body()!!.status == 200) { - val body = response.body()!! - val data = body.data!! - emit(Results.Success(data)) - } else if (response.body()!!.status == 400) { - emit(Results.Error("잘못된 요청입니다")) - } else if (response.body()!!.status == 401) { - emit(Results.Error("권한이 없습니다")) - } else { - emit(Results.Error("서버 에러입니다")) + when (response.body()!!.status) { + Status.OK -> { + val body = response.body()!! + val data = body.data!! + emit(Results.Success(data)) + } + Status.BAD_REQUEST -> { + emit(Results.Error("잘못된 요청입니다")) + } + Status.UNAUTHORIZED -> { + emit(Results.Error("권한이 없습니다")) + } + else -> { + emit(Results.Error("서버 에러입니다")) + } } } }.flowOn(ioDispatcher) diff --git a/app/src/main/java/com/sgs/devcamp2/flametalk_android/data/repository/MainActivityRepositoryImpl.kt b/app/src/main/java/com/sgs/devcamp2/flametalk_android/data/repository/MainActivityRepositoryImpl.kt index 24b4425e..1fe766b4 100644 --- a/app/src/main/java/com/sgs/devcamp2/flametalk_android/data/repository/MainActivityRepositoryImpl.kt +++ b/app/src/main/java/com/sgs/devcamp2/flametalk_android/data/repository/MainActivityRepositoryImpl.kt @@ -20,15 +20,12 @@ class MainActivityRepositoryImpl @Inject constructor( private val stompClient: StompClient, ) : MainActivityRepository { /** - * krossbow library를 이용하여 connection을 맺는 function 입니다. + * KrossBow Library 를 이용하여 connection 을 맺는 function 입니다. */ - val TAG: String = "로그" override suspend fun connectWebSocket(): Flow { return flow { - lateinit var connection: StompSession - try { - connection = stompClient.connect(WEB_SOCKET_URL) + val connection = stompClient.connect(WEB_SOCKET_URL) emit(connection) } catch (e: ConnectionTimeout) { emit(null) @@ -41,6 +38,6 @@ class MainActivityRepositoryImpl @Inject constructor( } companion object { - val WEB_SOCKET_URL = "ws://10.0.2.2:8085/stomp/chat/websocket" + const val WEB_SOCKET_URL = "ws://10.0.2.2:8085/stomp/chat/websocket" } } diff --git a/app/src/main/java/com/sgs/devcamp2/flametalk_android/data/repository/OpenProfileRepositoryImpl.kt b/app/src/main/java/com/sgs/devcamp2/flametalk_android/data/repository/OpenProfileRepositoryImpl.kt index aca6dd0e..ecc7cf0a 100644 --- a/app/src/main/java/com/sgs/devcamp2/flametalk_android/data/repository/OpenProfileRepositoryImpl.kt +++ b/app/src/main/java/com/sgs/devcamp2/flametalk_android/data/repository/OpenProfileRepositoryImpl.kt @@ -1,5 +1,6 @@ package com.sgs.devcamp2.flametalk_android.data.repository +import com.sgs.devcamp2.flametalk_android.data.common.Status import com.sgs.devcamp2.flametalk_android.data.common.WrappedResponse import com.sgs.devcamp2.flametalk_android.data.model.openprofile.createopenprofile.CreateOpenProfileReq import com.sgs.devcamp2.flametalk_android.data.model.openprofile.createopenprofile.CreateOpenProfileRes @@ -7,7 +8,6 @@ import com.sgs.devcamp2.flametalk_android.data.model.openprofile.getopenprofile. import com.sgs.devcamp2.flametalk_android.data.model.openprofile.getopenprofilelist.GetOpenProfileListRes import com.sgs.devcamp2.flametalk_android.data.model.openprofile.updateopenprofile.UpdateOpenProfileReq import com.sgs.devcamp2.flametalk_android.data.model.openprofile.updateopenprofile.UpdateOpenProfileRes -import com.sgs.devcamp2.flametalk_android.data.source.local.database.AppDatabase import com.sgs.devcamp2.flametalk_android.data.source.remote.api.OpenProfileApi import com.sgs.devcamp2.flametalk_android.domain.entity.Results import com.sgs.devcamp2.flametalk_android.domain.repository.OpenProfileRepository @@ -23,27 +23,31 @@ import javax.inject.Inject */ class OpenProfileRepositoryImpl @Inject constructor( private val ioDispatcher: CoroutineDispatcher, - private val local: AppDatabase, private val remote: OpenProfileApi ) : OpenProfileRepository { /** - * 오픈프로필을 생성하는 function입니다 + * 오픈프로필을 생성하는 function 입니다 * @param createOpenProfileReq 오픈프로필 생성 request model */ override suspend fun createOpenProfile(createOpenProfileReq: CreateOpenProfileReq): Flow>> { return flow { val response = remote.createOpenProfile(createOpenProfileReq) if (response.isSuccessful) { - if (response.body()!!.status == 200) { - val body = response.body()!! - val data = body.data!! - emit(Results.Success(data)) - } else if (response.body()!!.status == 400) { - emit(Results.Error("잘못된 요청입니다")) - } else if (response.body()!!.status == 401) { - emit(Results.Error("권한이 없습니다")) - } else { - emit(Results.Error("서버 에러입니다")) + when (response.body()!!.status) { + Status.OK -> { + val body = response.body()!! + val data = body.data!! + emit(Results.Success(data)) + } + Status.BAD_REQUEST -> { + emit(Results.Error("잘못된 요청입니다")) + } + Status.UNAUTHORIZED -> { + emit(Results.Error("권한이 없습니다")) + } + else -> { + emit(Results.Error("서버 에러입니다")) + } } } }.flowOn(ioDispatcher) @@ -55,77 +59,97 @@ class OpenProfileRepositoryImpl @Inject constructor( return flow { val response = remote.getOpenProfile(openProfileId) if (response.isSuccessful) { - if (response.body()!!.status == 200) { - val body = response.body()!! - val data = body.data!! - emit(Results.Success(data)) - } else if (response.body()!!.status == 400) { - emit(Results.Error("잘못된 요청입니다")) - } else if (response.body()!!.status == 401) { - emit(Results.Error("권한이 없습니다")) - } else { - emit(Results.Error("서버 에러입니다")) + when (response.body()!!.status) { + Status.OK -> { + val body = response.body()!! + val data = body.data!! + emit(Results.Success(data)) + } + Status.BAD_REQUEST -> { + emit(Results.Error("잘못된 요청입니다")) + } + Status.UNAUTHORIZED -> { + emit(Results.Error("권한이 없습니다")) + } + else -> { + emit(Results.Error("서버 에러입니다")) + } } } }.flowOn(ioDispatcher) } /** - * 오픈 프로필 리스트 조회 function입니다. + * 오픈 프로필 리스트 조회 function 입니다. */ override suspend fun getOpenProfileList(): Flow>> { return flow { val response = remote.getOpenProfileList() if (response.isSuccessful) { - if (response.body()!!.status == 200) { - val body = response.body()!! - val data = body.data!! - emit(Results.Success(data)) - } else if (response.body()!!.status == 400) { - emit(Results.Error("잘못된 요청입니다")) - } else if (response.body()!!.status == 401) { - emit(Results.Error("권한이 없습니다")) - } else { - emit(Results.Error("서버 에러입니다")) + when (response.body()!!.status) { + Status.OK -> { + val body = response.body()!! + val data = body.data!! + emit(Results.Success(data)) + } + Status.BAD_REQUEST -> { + emit(Results.Error("잘못된 요청입니다")) + } + Status.UNAUTHORIZED -> { + emit(Results.Error("권한이 없습니다")) + } + else -> { + emit(Results.Error("서버 에러입니다")) + } } } }.flowOn(ioDispatcher) } /** - * 오픈 프로필 업데이트 function입니다. + * 오픈 프로필 업데이트 function 입니다. */ override suspend fun updateOpenProfile(openProfileId: Long, updateOpenProfileReq: UpdateOpenProfileReq): Flow>> { return flow { val response = remote.updateOpenProfile(openProfileId, updateOpenProfileReq) if (response.isSuccessful) { - if (response.body()!!.status == 200) { - val body = response.body()!! - val data = body.data!! - emit(Results.Success(data)) - } else if (response.body()!!.status == 400) { - emit(Results.Error("잘못된 요청입니다")) - } else if (response.body()!!.status == 401) { - emit(Results.Error("권한이 없습니다")) - } else { - emit(Results.Error("서버 에러입니다")) + when (response.body()!!.status) { + Status.OK -> { + val body = response.body()!! + val data = body.data!! + emit(Results.Success(data)) + } + Status.BAD_REQUEST -> { + emit(Results.Error("잘못된 요청입니다")) + } + Status.UNAUTHORIZED -> { + emit(Results.Error("권한이 없습니다")) + } + else -> { + emit(Results.Error("서버 에러입니다")) + } } } }.flowOn(ioDispatcher) } /** - * 오픈 프로필 삭제 function입니다. + * 오픈 프로필 삭제 function 입니다. */ override suspend fun deleteOpenProfile(openProfileId: Long): Flow>> { return flow { val response = remote.deleteOpenProfile(openProfileId) if (response.isSuccessful) { - if (response.body()!!.status == 200) { - emit(Results.Success(true)) - } else if (response.body()!!.status == 400) { - emit(Results.Error("잘못된 요청입니다")) - } else if (response.body()!!.status == 401) { - emit(Results.Error("권한이 없습니다")) - } else { - emit(Results.Error("서버 에러입니다")) + when (response.body()!!.status) { + Status.OK -> { + emit(Results.Success(true)) + } + Status.BAD_REQUEST -> { + emit(Results.Error("잘못된 요청입니다")) + } + Status.UNAUTHORIZED -> { + emit(Results.Error("권한이 없습니다")) + } + else -> { + emit(Results.Error("서버 에러입니다")) + } } } }.flowOn(ioDispatcher) diff --git a/app/src/main/java/com/sgs/devcamp2/flametalk_android/domain/entity/LocalResults.kt b/app/src/main/java/com/sgs/devcamp2/flametalk_android/domain/entity/LocalResults.kt index c9c16aeb..c1ed884c 100644 --- a/app/src/main/java/com/sgs/devcamp2/flametalk_android/domain/entity/LocalResults.kt +++ b/app/src/main/java/com/sgs/devcamp2/flametalk_android/domain/entity/LocalResults.kt @@ -6,8 +6,6 @@ package com.sgs.devcamp2.flametalk_android.domain.entity * local db의 결과를 wrapping 함 */ sealed class LocalResults { - data class Success(val data: T) : LocalResults() - data class Error(val message: String) : LocalResults() } diff --git a/app/src/main/java/com/sgs/devcamp2/flametalk_android/domain/entity/chatroom/GetChatRoomEntity.kt b/app/src/main/java/com/sgs/devcamp2/flametalk_android/domain/entity/chatroom/GetChatRoomEntity.kt index f1b1205b..f5eb3032 100644 --- a/app/src/main/java/com/sgs/devcamp2/flametalk_android/domain/entity/chatroom/GetChatRoomEntity.kt +++ b/app/src/main/java/com/sgs/devcamp2/flametalk_android/domain/entity/chatroom/GetChatRoomEntity.kt @@ -11,4 +11,4 @@ data class GetChatRoomEntity( val profileImage: String, val profiles: List, val files: List -) \ No newline at end of file +) diff --git a/app/src/main/java/com/sgs/devcamp2/flametalk_android/domain/usecase/chatroom/UpLoadImageUseCase.kt b/app/src/main/java/com/sgs/devcamp2/flametalk_android/domain/usecase/chatroom/UpLoadImageUseCase.kt index 53424d70..5b88a290 100644 --- a/app/src/main/java/com/sgs/devcamp2/flametalk_android/domain/usecase/chatroom/UpLoadImageUseCase.kt +++ b/app/src/main/java/com/sgs/devcamp2/flametalk_android/domain/usecase/chatroom/UpLoadImageUseCase.kt @@ -16,7 +16,7 @@ import javax.inject.Inject class UpLoadImageUseCase @Inject constructor( val repository: ChatRoomRepository ) { - fun invoke(file: MultipartBody.Part, chatroomId: RequestBody?): Flow>> { + fun invoke(file: MultipartBody.Part, chatroomId: RequestBody?): Flow>> { return repository.uploadImage(file, chatroomId) } } diff --git a/app/src/main/java/com/sgs/devcamp2/flametalk_android/ui/chatroom/ChatRoomFragment.kt b/app/src/main/java/com/sgs/devcamp2/flametalk_android/ui/chatroom/ChatRoomFragment.kt index ec9a76b4..731b42c0 100644 --- a/app/src/main/java/com/sgs/devcamp2/flametalk_android/ui/chatroom/ChatRoomFragment.kt +++ b/app/src/main/java/com/sgs/devcamp2/flametalk_android/ui/chatroom/ChatRoomFragment.kt @@ -179,14 +179,26 @@ class ChatRoomFragment : Fragment(), View.OnClickListener { viewLifecycleOwner.lifecycleScope.launch { model.chatList.collectLatest { state -> when (state) { - is UiState.Success -> { - // 채팅 데이터 observe - val list: List = state.data.sortedBy { - it.created_at + is UiState.Init -> + { + } + + is UiState.Success -> + { + // 채팅 데이터 observe + val list: List = state.data.sortedBy { + it.created_at + } + adapter.submitList(list) + binding.rvChatRoom.smoothScrollToPosition(state.data.size) + } + is UiState.Loading -> + { + + } + is UiState.Error -> + { } - adapter.submitList(list) - binding.rvChatRoom.smoothScrollToPosition(state.data.size) - } } } } diff --git a/app/src/main/java/com/sgs/devcamp2/flametalk_android/ui/chatroom/ChatRoomViewModel.kt b/app/src/main/java/com/sgs/devcamp2/flametalk_android/ui/chatroom/ChatRoomViewModel.kt index 7277f7e2..9864b229 100644 --- a/app/src/main/java/com/sgs/devcamp2/flametalk_android/ui/chatroom/ChatRoomViewModel.kt +++ b/app/src/main/java/com/sgs/devcamp2/flametalk_android/ui/chatroom/ChatRoomViewModel.kt @@ -1,6 +1,5 @@ package com.sgs.devcamp2.flametalk_android.ui.chatroom -import android.util.Log import androidx.lifecycle.* import com.google.gson.Gson import com.sgs.devcamp2.flametalk_android.data.model.chat.Chat @@ -52,7 +51,6 @@ class ChatRoomViewModel @Inject constructor( val TAG: String = "로그" private val _chat = MutableStateFlow("") val chat = _chat.asStateFlow() - lateinit var _jsonStompSessions: StompSessionWithKxSerialization private val _drawUserState = MutableStateFlow>(UiState.Loading) @@ -88,11 +86,11 @@ class ChatRoomViewModel @Inject constructor( private val _roomId = MutableStateFlow("") val roomId = _roomId.asStateFlow() - val userChatRoomId = MutableStateFlow(0L) - + private val _userChatRoomId = MutableStateFlow(0L) + val userChatRoomId + get() = _userChatRoomId private val _imageUrl = MutableStateFlow("") val imageUrl = _imageUrl.asStateFlow() - private var webSocket: WebSocket? = null init { @@ -108,19 +106,19 @@ class ChatRoomViewModel @Inject constructor( fun getUserChatRoomId(chatroomId: String) { viewModelScope.launch { - getUserChatRoomIdUseCase.invoke(chatroomId).collect { - result -> + getUserChatRoomIdUseCase.invoke(chatroomId).collect { result -> when (result) { - is LocalResults.Success -> - { - userChatRoomId.value = result.data - } + is LocalResults.Success -> { + _userChatRoomId.value = result.data + } + is LocalResults.Error -> { + _userChatRoomId.value = 0L + } } } } } - -/** + /** * 현재 사용자가 채팅방을 보고 있는지 상태 update하는 function입니다. */ fun connectWebsocket(chatroomId: String, deviceId: String) { @@ -143,14 +141,17 @@ class ChatRoomViewModel @Inject constructor( * 휴대폰 내부 DB에서 채팅 텍스트 리스트를 불러오는 fucntion입니다. */ fun getChatList(chatroomId: String) { - Log.d(TAG, "getChatList - $chatroomId") viewModelScope.launch { getChatListUseCase.invoke(chatroomId).collect { result -> when (result) { is LocalResults.Success -> { _chatList.value = UiState.Success(result.data.chatList) _userChatRoom.value = UiState.Success(result.data.room) - userChatRoomId.value = result.data.room.userChatroomId + _userChatRoomId.value = result.data.room.userChatroomId + } + is LocalResults.Error -> { + _chatList.value = UiState.Loading + _userChatRoom.value = UiState.Loading } } } @@ -163,9 +164,14 @@ class ChatRoomViewModel @Inject constructor( .collectLatest { result -> when (result) { is Results.Success -> { - Log.d(TAG, "getChatList - called") getChatList(chatroomId) } + is Results.Error -> { + getChatList(chatroomId) + } + is Results.Loading -> + { + } } } } @@ -181,6 +187,10 @@ class ChatRoomViewModel @Inject constructor( _drawUserState.value = UiState.Success(result.data) } is Results.Error -> { + _drawUserState.value = UiState.Error(result.message) + } + is Results.Loading -> { + _drawUserState.value = UiState.Loading } } } @@ -200,6 +210,14 @@ class ChatRoomViewModel @Inject constructor( is Results.Success -> { _deleteUiState.value = UiState.Success(true) } + is Results.Loading -> + { + _deleteUiState.value = UiState.Loading + } + is Results.Error -> + { + _deleteUiState.value = UiState.Error(result.message) + } } } } @@ -217,15 +235,11 @@ class ChatRoomViewModel @Inject constructor( _jsonStompSessions = session.withJsonConversions() val subscription: Flow = _jsonStompSessions.subscribe("/sub/chat/room/$roomId", ChatRes.serializer()) - val collectorJob = launch { - subscription.collect { msg -> - _lastReadMessageId.value = msg.message_id // 내가 읽은 메세지 초기화 - Log.d(TAG, "msg - $msg() called") - saveReceivedMessageUseCase.invoke(msg).collect { - if (msg.message_type == "TALK" || msg.message_type == "FILE") { - Log.d(TAG, "message - $msg") - _uiState.value = UiState.Success(it) - } + subscription.collect { msg -> + _lastReadMessageId.value = msg.message_id // 내가 읽은 메세지 초기화 + saveReceivedMessageUseCase.invoke(msg).collect { + if (msg.message_type == "TALK" || msg.message_type == "FILE") { + _uiState.value = UiState.Success(it) } } } @@ -291,9 +305,16 @@ class ChatRoomViewModel @Inject constructor( closeChatRoomUseCase.invoke(closeChatRoomReq).collect { result -> when (result) { is Results.Success -> { - Log.d(TAG, "resultSuccess - closeChatRoom() called") _closeUiState.value = UiState.Success(true) } + is Results.Loading -> + { + _closeUiState.value = UiState.Loading + } + is Results.Error -> + { + _closeUiState.value = UiState.Error(result.message) + } } } } @@ -320,18 +341,17 @@ class ChatRoomViewModel @Inject constructor( fun getLastReadMessageId(chatroomId: String) { viewModelScope.launch { - Log.d(TAG, "ChatRoomViewModel - getLastReadMessageId(1) called") getLastReadMessageUseCase.invoke(chatroomId).collect { result -> when (result) { is LocalResults.Success -> { - Log.d(TAG, "ChatRoomViewModel - getLastReadMessageId(2) called") + if (result.data == "null") { _lastReadMessageId.value = "" + } else { + _lastReadMessageId.value = result.data } - _lastReadMessageId.value = result.data } is LocalResults.Error -> { - Log.d(TAG, "ChatRoomViewModel - getLastReadMessageId(3) called") _lastReadMessageId.value = "" } } @@ -346,9 +366,16 @@ class ChatRoomViewModel @Inject constructor( upLoadImageUseCase.invoke(multipartfile, roomIdBody).collect { result -> when (result) { is Results.Success -> { - Log.d(TAG, "ChatRoomViewModel - uploadImage() called") _uploadUiState.value = UiState.Success(result.data) } + is Results.Error -> + { + _uploadUiState.value = UiState.Error(result.message) + } + is Results.Loading -> + { + _uploadUiState.value = UiState.Loading + } } } } @@ -357,9 +384,6 @@ class ChatRoomViewModel @Inject constructor( fun initUploadImageState() { _uploadUiState.value = UiState.Loading } - fun initLastReadMessage() { - _lastReadMessageId.value = "" - } fun setBackgroundImage(path: String) { if (path != null) { diff --git a/app/src/main/java/com/sgs/devcamp2/flametalk_android/ui/chatroomlist/ChatRoomListFragment.kt b/app/src/main/java/com/sgs/devcamp2/flametalk_android/ui/chatroomlist/ChatRoomListFragment.kt index 5b2c048b..17e3a342 100644 --- a/app/src/main/java/com/sgs/devcamp2/flametalk_android/ui/chatroomlist/ChatRoomListFragment.kt +++ b/app/src/main/java/com/sgs/devcamp2/flametalk_android/ui/chatroomlist/ChatRoomListFragment.kt @@ -3,7 +3,6 @@ package com.sgs.devcamp2.flametalk_android.ui.chatroomlist import android.app.AlertDialog import android.content.* import android.os.Bundle -import android.util.Log import android.view.LayoutInflater import android.view.View import android.view.ViewGroup @@ -20,6 +19,7 @@ import com.sgs.devcamp2.flametalk_android.data.model.chatroom.ThumbnailWithRoomI import com.sgs.devcamp2.flametalk_android.databinding.FragmentChatRoomListBinding import com.sgs.devcamp2.flametalk_android.domain.entity.UiState import com.sgs.devcamp2.flametalk_android.ui.chattingviewpager.ChattingViewPagerFragmentDirections +import com.sgs.devcamp2.flametalk_android.util.showToast import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.launch @@ -37,7 +37,7 @@ class ChatRoomListFragment : Fragment(), ChatRoomListAdapter.ClickCallBack { inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? - ): View? { + ): View { binding = FragmentChatRoomListBinding.inflate(inflater, container, false) initUI(this.requireContext()) initObserve() @@ -64,6 +64,16 @@ class ChatRoomListFragment : Fragment(), ChatRoomListAdapter.ClickCallBack { is UiState.Success -> { model.getLocalChatRoomList(false) } + is UiState.Error -> + { + model.getLocalChatRoomList(false) + } + is UiState.Loading -> + { + } + is UiState.Init -> + { + } } } } @@ -82,6 +92,15 @@ class ChatRoomListFragment : Fragment(), ChatRoomListAdapter.ClickCallBack { adapterRoom.submitList(list) } } + is UiState.Error -> + { + } + is UiState.Loading -> + { + } + is UiState.Init -> + { + } } } } @@ -91,15 +110,15 @@ class ChatRoomListFragment : Fragment(), ChatRoomListAdapter.ClickCallBack { successSavedToken() } - override fun onItemLongClicked(position: Int, chatroom: ThumbnailWithRoomId) { + override fun onItemLongClicked(position: Int, chatRoom: ThumbnailWithRoomId) { /** * itemClickCallback * item long Click 시 dialog 생성 * items 로 메뉴 생성 후 인덱스로 접근 */ - var items = arrayOf("채팅방 이름 설정", "즐겨찾기에 추가", "채팅방 상단 고정", "채팅방 알람 켜기", "나가기") - var dialog = AlertDialog.Builder(this.requireContext()) - var dialogListener = DialogInterface.OnClickListener { _, which -> + val items = arrayOf("채팅방 이름 설정", "즐겨찾기에 추가", "채팅방 상단 고정", "채팅방 알람 켜기", "나가기") + val dialog = AlertDialog.Builder(this.requireContext()) + val dialogListener = DialogInterface.OnClickListener { _, which -> run { when (which) { 4 -> { @@ -109,20 +128,18 @@ class ChatRoomListFragment : Fragment(), ChatRoomListAdapter.ClickCallBack { } } - dialog.setTitle(chatroom.room.title) + dialog.setTitle(chatRoom.room.title) dialog.setItems( items, dialogListener ) dialog.show() - true } - override fun onItemShortClicked(position: Int, chatroomid: ThumbnailWithRoomId) { - var action = + override fun onItemShortClicked(position: Int, chatRoom: ThumbnailWithRoomId) { + val action = ChattingViewPagerFragmentDirections.actionNavigationChattingViewPagerFragmentToNavigationChatRoom( - chatroomid.room.id, + chatRoom.room.id, ) - Log.d(TAG, "chatRoomId - ${chatroomid.room.id}() called") findNavController().navigate(action) } @@ -133,6 +150,15 @@ class ChatRoomListFragment : Fragment(), ChatRoomListAdapter.ClickCallBack { is UiState.Success -> { model.saveDeviceToken(state.data) } + is UiState.Error -> + { + } + is UiState.Init -> + { + } + is UiState.Loading -> + { + } } } } @@ -143,7 +169,11 @@ class ChatRoomListFragment : Fragment(), ChatRoomListAdapter.ClickCallBack { model.deviceTokenUiState.collect { state -> when (state) { is UiState.Success -> { - Log.d(TAG, "successSavedToken - ${state.data} called") + context?.showToast("토큰 저장 성공") + } + else -> { + // Log.d(TAG, "successSavedToken - error() called") + context?.showToast("토큰 저장 실패") } } } diff --git a/app/src/main/java/com/sgs/devcamp2/flametalk_android/ui/chatroomlist/ChatRoomListViewModel.kt b/app/src/main/java/com/sgs/devcamp2/flametalk_android/ui/chatroomlist/ChatRoomListViewModel.kt index d26fe24d..4634d182 100644 --- a/app/src/main/java/com/sgs/devcamp2/flametalk_android/ui/chatroomlist/ChatRoomListViewModel.kt +++ b/app/src/main/java/com/sgs/devcamp2/flametalk_android/ui/chatroomlist/ChatRoomListViewModel.kt @@ -1,7 +1,6 @@ package com.sgs.devcamp2.flametalk_android.ui.chatroomlist import android.content.Context -import android.util.Log import androidx.lifecycle.* import com.sgs.devcamp2.flametalk_android.data.model.chatroom.ThumbnailWithRoomId import com.sgs.devcamp2.flametalk_android.data.model.chatroom.getchatroomlist.GetChatRoomListRes @@ -18,6 +17,7 @@ import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.* import kotlinx.coroutines.launch import javax.inject.Inject + /** * @author 김현국 * @created 2022/01/26 @@ -32,16 +32,13 @@ class ChatRoomListViewModel @Inject constructor( val TAG: String = "로그" private val _uiState = MutableStateFlow>(UiState.Loading) val uiState = _uiState.asStateFlow() - - private val _localUiState = MutableStateFlow>>(UiState.Loading) + private val _localUiState = + MutableStateFlow>>(UiState.Loading) val localUiState = _localUiState.asStateFlow() - private val _deviceToken = MutableStateFlow>(UiState.Loading) val deviceToken = _deviceToken.asStateFlow() - private val _deviceTokenUiState = MutableStateFlow>(UiState.Loading) val deviceTokenUiState = _deviceTokenUiState.asStateFlow() - /** * 채팅방 리스트를 서버에서 가져오는 function입니다. * @param isOpen 오픈 채팅 유무 @@ -54,6 +51,12 @@ class ChatRoomListViewModel @Inject constructor( is Results.Success -> { _uiState.value = UiState.Success(result.data) } + is Results.Error -> { + _uiState.value = UiState.Error(result.message) + } + is Results.Loading -> { + _uiState.value = UiState.Loading + } } } } @@ -65,13 +68,14 @@ class ChatRoomListViewModel @Inject constructor( fun getLocalChatRoomList(isOpen: Boolean) { viewModelScope.launch { getLocalChatRoomListUseCase.invoke(isOpen) - .collect { - result -> + .collect { result -> when (result) { - is LocalResults.Success -> - { - _localUiState.value = UiState.Success(result.data) - } + is LocalResults.Success -> { + _localUiState.value = UiState.Success(result.data) + } + is LocalResults.Error -> { + _localUiState.value = UiState.Error(result.message) + } } } } @@ -80,16 +84,17 @@ class ChatRoomListViewModel @Inject constructor( * 채팅방 삭제 fucntion입니다. * @param userChatroomId 유저의 채팅방 id */ - fun deleteChatRoom(userChatroomId: Long) { viewModelScope.launch { - deleteChatRoomUseCase.invoke(userChatroomId).collect { - result -> + deleteChatRoomUseCase.invoke(userChatroomId).collect { result -> when (result) { - is Results.Success -> - { - // _deleteUiState.value = UiState.Success(true) - } + is Results.Success -> { + // _deleteUiState.value = UiState.Success(true) + } + is Results.Error -> { + } + is Results.Loading -> { + } } } } @@ -100,21 +105,25 @@ class ChatRoomListViewModel @Inject constructor( fun saveDeviceToken(deviceToken: String) { viewModelScope.launch { val saveDeviceTokenReq = SaveDeviceTokenReq(deviceToken) - Log.d(TAG, "saveDeviceTokenReq - $saveDeviceTokenReq") - saveDeviceTokenUseCase.invoke(saveDeviceTokenReq).collect { - result -> + saveDeviceTokenUseCase.invoke(saveDeviceTokenReq).collect { result -> when (result) { - is Results.Success -> - { - _deviceTokenUiState.value = UiState.Success(result.data) - } + is Results.Success -> { + _deviceTokenUiState.value = UiState.Success(result.data) + } + is Results.Error -> { + _deviceTokenUiState.value = UiState.Error(result.message) + } + is Results.Loading -> { + _deviceTokenUiState.value = UiState.Loading + } } } } } + fun getDeviceToken(context: Context) { val pref = context.getSharedPreferences("deviceToken", Context.MODE_PRIVATE) - var token = pref.getString("deviceToken", "") + val token = pref.getString("deviceToken", "") _deviceToken.value = UiState.Success(token.toString()) } } diff --git a/app/src/main/java/com/sgs/devcamp2/flametalk_android/ui/createchatroom/CreateChatRoomViewModel.kt b/app/src/main/java/com/sgs/devcamp2/flametalk_android/ui/createchatroom/CreateChatRoomViewModel.kt index 8adfebc8..f87717ff 100644 --- a/app/src/main/java/com/sgs/devcamp2/flametalk_android/ui/createchatroom/CreateChatRoomViewModel.kt +++ b/app/src/main/java/com/sgs/devcamp2/flametalk_android/ui/createchatroom/CreateChatRoomViewModel.kt @@ -1,6 +1,5 @@ package com.sgs.devcamp2.flametalk_android.ui.createchatroom -import android.util.Log import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.sgs.devcamp2.flametalk_android.data.mapper.mapperToUserChatRoomModel @@ -63,7 +62,6 @@ class CreateChatRoomViewModel @Inject constructor( */ fun createChatRoom(users: List) { val userList = users.toMutableList() - Log.d("로그", "userList - $userList") userList.add(_userId.value) val createChatRoomReq = CreateChatRoomReq( hostId = _userId.value, @@ -83,7 +81,7 @@ class CreateChatRoomViewModel @Inject constructor( } is Results.Error -> { - Log.d("로그", "CreateChatRoomViewModel - createChatRoom() called") + _createUiState.value = UiState.Error(result.message) } } } diff --git a/detekt.yml b/detekt.yml new file mode 100644 index 00000000..8de2c5db --- /dev/null +++ b/detekt.yml @@ -0,0 +1,676 @@ +build: + maxIssues: 0 + excludeCorrectable: false + weights: + # complexity: 2 + # LongParameterList: 1 + # style: 1 + # comments: 1 + +config: + validation: true + warningsAsErrors: false + # when writing own rules with new properties, exclude the property path e.g.: 'my_rule_set,.*>.*>[my_property]' + excludes: '' + +processors: + active: true + exclude: + - 'DetektProgressListener' + # - 'KtFileCountProcessor' + # - 'PackageCountProcessor' + # - 'ClassCountProcessor' + # - 'FunctionCountProcessor' + # - 'PropertyCountProcessor' + # - 'ProjectComplexityProcessor' + # - 'ProjectCognitiveComplexityProcessor' + # - 'ProjectLLOCProcessor' + # - 'ProjectCLOCProcessor' + # - 'ProjectLOCProcessor' + # - 'ProjectSLOCProcessor' + # - 'LicenseHeaderLoaderExtension' + +console-reports: + active: true + exclude: + - 'ProjectStatisticsReport' + - 'ComplexityReport' + - 'NotificationReport' + - 'FindingsReport' + - 'FileBasedFindingsReport' + # - 'LiteFindingsReport' + +output-reports: + active: true + exclude: + # - 'TxtOutputReport' + # - 'XmlOutputReport' + # - 'HtmlOutputReport' + +comments: + active: true + AbsentOrWrongFileLicense: + active: false + licenseTemplateFile: 'license.template' + licenseTemplateIsRegex: false + CommentOverPrivateFunction: + active: false + CommentOverPrivateProperty: + active: false + DeprecatedBlockTag: + active: false + EndOfSentenceFormat: + active: false + endOfSentenceFormat: '([.?!][ \t\n\r\f<])|([.?!:]$)' + OutdatedDocumentation: + active: false + matchTypeParameters: true + matchDeclarationsOrder: true + allowParamOnConstructorProperties: false + UndocumentedPublicClass: + active: false + excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] + searchInNestedClass: true + searchInInnerClass: true + searchInInnerObject: true + searchInInnerInterface: true + UndocumentedPublicFunction: + active: false + excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] + UndocumentedPublicProperty: + active: false + excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] + +complexity: + active: true + ComplexCondition: + active: true + threshold: 4 + ComplexInterface: + active: false + threshold: 10 + includeStaticDeclarations: false + includePrivateDeclarations: false + ComplexMethod: + active: true + threshold: 15 + ignoreSingleWhenExpression: false + ignoreSimpleWhenEntries: false + ignoreNestingFunctions: false + nestingFunctions: + - 'also' + - 'apply' + - 'forEach' + - 'isNotNull' + - 'ifNull' + - 'let' + - 'run' + - 'use' + - 'with' + LabeledExpression: + active: false + ignoredLabels: [] + LargeClass: + active: true + threshold: 600 + LongMethod: + active: true + threshold: 60 + LongParameterList: + active: true + functionThreshold: 6 + constructorThreshold: 7 + ignoreDefaultParameters: false + ignoreDataClasses: true + ignoreAnnotatedParameter: [] + MethodOverloading: + active: false + threshold: 6 + NamedArguments: + active: false + threshold: 3 + NestedBlockDepth: + active: true + threshold: 4 + ReplaceSafeCallChainWithRun: + active: false + StringLiteralDuplication: + active: false + excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] + threshold: 3 + ignoreAnnotation: true + excludeStringsWithLessThan5Characters: true + ignoreStringsRegex: '$^' + TooManyFunctions: + active: true + excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] + thresholdInFiles: 11 + thresholdInClasses: 11 + thresholdInInterfaces: 11 + thresholdInObjects: 11 + thresholdInEnums: 11 + ignoreDeprecated: false + ignorePrivate: false + ignoreOverridden: false + +coroutines: + active: true + GlobalCoroutineUsage: + active: false + InjectDispatcher: + active: false + dispatcherNames: + - 'IO' + - 'Default' + - 'Unconfined' + RedundantSuspendModifier: + active: false + SleepInsteadOfDelay: + active: false + SuspendFunWithFlowReturnType: + active: false + +empty-blocks: + active: true + EmptyCatchBlock: + active: true + allowedExceptionNameRegex: '_|(ignore|expected).*' + EmptyClassBlock: + active: true + EmptyDefaultConstructor: + active: true + EmptyDoWhileBlock: + active: true + EmptyElseBlock: + active: true + EmptyFinallyBlock: + active: true + EmptyForBlock: + active: true + EmptyFunctionBlock: + active: true + ignoreOverridden: false + EmptyIfBlock: + active: true + EmptyInitBlock: + active: true + EmptyKtFile: + active: true + EmptySecondaryConstructor: + active: true + EmptyTryBlock: + active: true + EmptyWhenBlock: + active: true + EmptyWhileBlock: + active: true + +exceptions: + active: true + ExceptionRaisedInUnexpectedLocation: + active: true + methodNames: + - 'equals' + - 'finalize' + - 'hashCode' + - 'toString' + InstanceOfCheckForException: + active: false + excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] + NotImplementedDeclaration: + active: false + ObjectExtendsThrowable: + active: false + PrintStackTrace: + active: true + RethrowCaughtException: + active: true + ReturnFromFinally: + active: true + ignoreLabeled: false + SwallowedException: + active: true + ignoredExceptionTypes: + - 'InterruptedException' + - 'MalformedURLException' + - 'NumberFormatException' + - 'ParseException' + allowedExceptionNameRegex: '_|(ignore|expected).*' + ThrowingExceptionFromFinally: + active: true + ThrowingExceptionInMain: + active: false + ThrowingExceptionsWithoutMessageOrCause: + active: true + excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] + exceptions: + - 'ArrayIndexOutOfBoundsException' + - 'Exception' + - 'IllegalArgumentException' + - 'IllegalMonitorStateException' + - 'IllegalStateException' + - 'IndexOutOfBoundsException' + - 'NullPointerException' + - 'RuntimeException' + - 'Throwable' + ThrowingNewInstanceOfSameException: + active: true + TooGenericExceptionCaught: + active: true + excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] + exceptionNames: + - 'ArrayIndexOutOfBoundsException' + - 'Error' + - 'Exception' + - 'IllegalMonitorStateException' + - 'IndexOutOfBoundsException' + - 'NullPointerException' + - 'RuntimeException' + - 'Throwable' + allowedExceptionNameRegex: '_|(ignore|expected).*' + TooGenericExceptionThrown: + active: true + exceptionNames: + - 'Error' + - 'Exception' + - 'RuntimeException' + - 'Throwable' + +naming: + active: true + BooleanPropertyNaming: + active: false + allowedPattern: '^(is|has|are)' + ClassNaming: + active: true + classPattern: '[A-Z][a-zA-Z0-9]*' + ConstructorParameterNaming: + active: true + parameterPattern: '[a-z][A-Za-z0-9]*' + privateParameterPattern: '[a-z][A-Za-z0-9]*' + excludeClassPattern: '$^' + ignoreOverridden: true + EnumNaming: + active: true + enumEntryPattern: '[A-Z][_a-zA-Z0-9]*' + ForbiddenClassName: + active: false + forbiddenName: [] + FunctionMaxLength: + active: false + maximumFunctionNameLength: 30 + FunctionMinLength: + active: false + minimumFunctionNameLength: 3 + FunctionNaming: + active: true + excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] + functionPattern: '[a-z][a-zA-Z0-9]*' + excludeClassPattern: '$^' + ignoreOverridden: true + FunctionParameterNaming: + active: true + parameterPattern: '[a-z][A-Za-z0-9]*' + excludeClassPattern: '$^' + ignoreOverridden: true + InvalidPackageDeclaration: + active: false + rootPackage: '' + requireRootInDeclaration: false + LambdaParameterNaming: + active: false + parameterPattern: '[a-z][A-Za-z0-9]*|_' + MatchingDeclarationName: + active: true + mustBeFirst: true + MemberNameEqualsClassName: + active: true + ignoreOverridden: true + NoNameShadowing: + active: false + NonBooleanPropertyPrefixedWithIs: + active: false + ObjectPropertyNaming: + active: true + constantPattern: '[A-Za-z][_A-Za-z0-9]*' + propertyPattern: '[A-Za-z][_A-Za-z0-9]*' + privatePropertyPattern: '(_)?[A-Za-z][_A-Za-z0-9]*' + PackageNaming: + active: true + packagePattern: '[a-z]+(\.[a-z][A-Za-z0-9]*)*' + TopLevelPropertyNaming: + active: true + constantPattern: '[A-Z][_A-Z0-9]*' + propertyPattern: '[A-Za-z][_A-Za-z0-9]*' + privatePropertyPattern: '_?[A-Za-z][_A-Za-z0-9]*' + VariableMaxLength: + active: false + maximumVariableNameLength: 64 + VariableMinLength: + active: false + minimumVariableNameLength: 1 + VariableNaming: + active: true + variablePattern: '[a-z][A-Za-z0-9]*' + privateVariablePattern: '(_)?[a-z][A-Za-z0-9]*' + excludeClassPattern: '$^' + ignoreOverridden: true + +performance: + active: true + ArrayPrimitive: + active: true + ForEachOnRange: + active: true + excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] + SpreadOperator: + active: true + excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] + UnnecessaryTemporaryInstantiation: + active: true + +potential-bugs: + active: true + AvoidReferentialEquality: + active: false + forbiddenTypePatterns: + - 'kotlin.String' + CastToNullableType: + active: false + Deprecation: + active: false + DontDowncastCollectionTypes: + active: false + DoubleMutabilityForCollection: + active: false + mutableTypes: + - 'kotlin.collections.MutableList' + - 'kotlin.collections.MutableMap' + - 'kotlin.collections.MutableSet' + - 'java.util.ArrayList' + - 'java.util.LinkedHashSet' + - 'java.util.HashSet' + - 'java.util.LinkedHashMap' + - 'java.util.HashMap' + DuplicateCaseInWhenExpression: + active: true + EqualsAlwaysReturnsTrueOrFalse: + active: true + EqualsWithHashCodeExist: + active: true + ExitOutsideMain: + active: false + ExplicitGarbageCollectionCall: + active: true + HasPlatformType: + active: false + IgnoredReturnValue: + active: false + restrictToAnnotatedMethods: true + returnValueAnnotations: + - '*.CheckResult' + - '*.CheckReturnValue' + ignoreReturnValueAnnotations: + - '*.CanIgnoreReturnValue' + ignoreFunctionCall: [] + ImplicitDefaultLocale: + active: true + ImplicitUnitReturnType: + active: false + allowExplicitReturnType: true + InvalidRange: + active: true + IteratorHasNextCallsNextMethod: + active: true + IteratorNotThrowingNoSuchElementException: + active: true + LateinitUsage: + active: false + excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] + ignoreOnClassesPattern: '' + MapGetWithNotNullAssertionOperator: + active: false + MissingPackageDeclaration: + active: false + excludes: ['**/*.kts'] + MissingWhenCase: + active: true + allowElseExpression: true + NullCheckOnMutableProperty: + active: false + NullableToStringCall: + active: false + RedundantElseInWhen: + active: true + UnconditionalJumpStatementInLoop: + active: false + UnnecessaryNotNullOperator: + active: true + UnnecessarySafeCall: + active: true + UnreachableCatchBlock: + active: false + UnreachableCode: + active: true + UnsafeCallOnNullableType: + active: true + excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] + UnsafeCast: + active: true + UnusedUnaryOperator: + active: false + UselessPostfixExpression: + active: false + WrongEqualsTypeParameter: + active: true + +style: + active: true + CanBeNonNullable: + active: false + ClassOrdering: + active: false + CollapsibleIfStatements: + active: false + DataClassContainsFunctions: + active: false + conversionFunctionPrefix: 'to' + DataClassShouldBeImmutable: + active: false + DestructuringDeclarationWithTooManyEntries: + active: false + maxDestructuringEntries: 3 + EqualsNullCall: + active: true + EqualsOnSignatureLine: + active: false + ExplicitCollectionElementAccessMethod: + active: false + ExplicitItLambdaParameter: + active: false + ExpressionBodySyntax: + active: false + includeLineWrapping: false + ForbiddenComment: + active: true + values: + - 'FIXME:' + - 'STOPSHIP:' + - 'TODO:' + allowedPatterns: '' + customMessage: '' + ForbiddenImport: + active: false + imports: [] + forbiddenPatterns: '' + ForbiddenMethodCall: + active: false + methods: + - 'kotlin.io.print' + - 'kotlin.io.println' + ForbiddenPublicDataClass: + active: true + excludes: ['**'] + ignorePackages: + - '*.internal' + - '*.internal.*' + ForbiddenVoid: + active: false + ignoreOverridden: false + ignoreUsageInGenerics: false + FunctionOnlyReturningConstant: + active: true + ignoreOverridableFunction: true + ignoreActualFunction: true + excludedFunctions: '' + LibraryCodeMustSpecifyReturnType: + active: true + excludes: ['**'] + LibraryEntitiesShouldNotBePublic: + active: true + excludes: ['**'] + LoopWithTooManyJumpStatements: + active: true + maxJumpCount: 1 + MagicNumber: + active: true + excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] + ignoreNumbers: + - '-1' + - '0' + - '1' + - '2' + ignoreHashCodeFunction: true + ignorePropertyDeclaration: false + ignoreLocalVariableDeclaration: false + ignoreConstantDeclaration: true + ignoreCompanionObjectPropertyDeclaration: true + ignoreAnnotation: false + ignoreNamedArgument: true + ignoreEnums: false + ignoreRanges: false + ignoreExtensionFunctions: true + MandatoryBracesIfStatements: + active: false + MandatoryBracesLoops: + active: false + MaxLineLength: + active: true + maxLineLength: 120 + excludePackageStatements: true + excludeImportStatements: true + excludeCommentStatements: false + MayBeConst: + active: true + ModifierOrder: + active: true + MultilineLambdaItParameter: + active: false + NestedClassesVisibility: + active: true + NewLineAtEndOfFile: + active: true + NoTabs: + active: false + ObjectLiteralToLambda: + active: false + OptionalAbstractKeyword: + active: true + OptionalUnit: + active: false + OptionalWhenBraces: + active: false + PreferToOverPairSyntax: + active: false + ProtectedMemberInFinalClass: + active: true + RedundantExplicitType: + active: false + RedundantHigherOrderMapUsage: + active: false + RedundantVisibilityModifierRule: + active: false + ReturnCount: + active: true + max: 2 + excludedFunctions: 'equals' + excludeLabeled: false + excludeReturnFromLambda: true + excludeGuardClauses: false + SafeCast: + active: true + SerialVersionUIDInSerializableClass: + active: true + SpacingBetweenPackageAndImports: + active: false + ThrowsCount: + active: true + max: 2 + excludeGuardClauses: false + TrailingWhitespace: + active: false + UnderscoresInNumericLiterals: + active: false + acceptableLength: 4 + allowNonStandardGrouping: false + UnnecessaryAbstractClass: + active: true + UnnecessaryAnnotationUseSiteTarget: + active: false + UnnecessaryApply: + active: true + UnnecessaryFilter: + active: false + UnnecessaryInheritance: + active: true + UnnecessaryInnerClass: + active: false + UnnecessaryLet: + active: false + UnnecessaryParentheses: + active: false + UntilInsteadOfRangeTo: + active: false + UnusedImports: + active: false + UnusedPrivateClass: + active: true + UnusedPrivateMember: + active: true + allowedNames: '(_|ignored|expected|serialVersionUID)' + UseAnyOrNoneInsteadOfFind: + active: false + UseArrayLiteralsInAnnotations: + active: false + UseCheckNotNull: + active: false + UseCheckOrError: + active: false + UseDataClass: + active: false + allowVars: false + UseEmptyCounterpart: + active: false + UseIfEmptyOrIfBlank: + active: false + UseIfInsteadOfWhen: + active: false + UseIsNullOrEmpty: + active: false + UseOrEmpty: + active: false + UseRequire: + active: false + UseRequireNotNull: + active: false + UselessCallOnNotNull: + active: true + UtilityClassWithPublicConstructor: + active: true + VarCouldBeVal: + active: true + WildcardImport: + active: true + excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] + excludeImports: + - 'java.util.*' \ No newline at end of file