Skip to content

Commit

Permalink
Impl "Add to Notes Action"
Browse files Browse the repository at this point in the history
- Note to self option should only appear if conversation is available
- Added ic_edit_note_24_xml
- Implemented MVVM functions for cleaner data flow
- Added the option to the XML
- Works for Voice Messages
- Works for Files(and Gifs) + captions
- Works for GeoLocation Messages
- Added SnackBar

Signed-off-by: Julius Linus <[email protected]>
  • Loading branch information
rapterjet2004 authored and mahibi committed Feb 1, 2024
1 parent 5b85731 commit d45277b
Show file tree
Hide file tree
Showing 9 changed files with 318 additions and 3 deletions.
83 changes: 81 additions & 2 deletions app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2682,8 +2682,9 @@ class ChatActivity :
}
}

private fun uploadFile(fileUri: String, isVoiceMessage: Boolean, caption: String = "") {
private fun uploadFile(fileUri: String, isVoiceMessage: Boolean, caption: String = "", token: String = "") {
var metaData = ""
var room = ""

if (!participantPermissions.hasChatPermission()) {
Log.w(TAG, "uploading file(s) is forbidden because of missing attendee permissions")
Expand All @@ -2698,11 +2699,13 @@ class ChatActivity :
metaData = "{\"caption\":\"$caption\"}"
}

if (token == "") room = roomToken else room = token

try {
require(fileUri.isNotEmpty())
UploadAndShareFilesWorker.upload(
fileUri,
roomToken,
room,
currentConversation?.displayName!!,
metaData
)
Expand Down Expand Up @@ -4171,6 +4174,82 @@ class ChatActivity :
}
}

fun shareToNotes(message: ChatMessage, roomToken: String) {
val apiVersion = ApiUtils.getChatApiVersion(conversationUser, intArrayOf(1))
val type = message.getCalculateMessageType()
var shareUri: Uri? = null
var data: HashMap<String?, String?>?
var metaData: String = ""
var objectId: String = ""
if (message.hasFileAttachment()) {
val filename = message.selectedIndividualHashMap!!["name"]
path = applicationContext.cacheDir.absolutePath + "/" + filename
shareUri = FileProvider.getUriForFile(
this,
BuildConfig.APPLICATION_ID,
File(path)
)

this.grantUriPermission(
applicationContext.packageName,
shareUri,
Intent.FLAG_GRANT_WRITE_URI_PERMISSION or Intent.FLAG_GRANT_READ_URI_PERMISSION
)
} else if (message.hasGeoLocation()) {
data = message.messageParameters?.get("object")
objectId = data?.get("id")!!
val name = data.get("name")!!
val lat = data.get("latitude")!!
val lon = data.get("longitude")!!
metaData =
"{\"type\":\"geo-location\",\"id\":\"geo:$lat,$lon\",\"latitude\":\"$lat\"," +
"\"longitude\":\"$lon\",\"name\":\"$name\"}"
}

when (type) {
ChatMessage.MessageType.VOICE_MESSAGE -> {
uploadFile(shareUri.toString(), true, token = roomToken)
Snackbar.make(binding.root, R.string.nc_message_sent, Snackbar.LENGTH_SHORT).show()
}
ChatMessage.MessageType.SINGLE_NC_ATTACHMENT_MESSAGE -> {
val caption = if (message.message != "{file}") message.message else ""
if (null != shareUri) {
try {
context.contentResolver.openInputStream(shareUri)?.close()
uploadFile(shareUri.toString(), false, caption!!, roomToken)
Snackbar.make(binding.root, R.string.nc_message_sent, Snackbar.LENGTH_SHORT).show()
} catch (e: java.lang.Exception) {
Log.w(TAG, "File corresponding to the uri does not exist " + shareUri.toString())
downloadFileToCache(message, false) {
uploadFile(shareUri.toString(), false, caption!!, roomToken)
Snackbar.make(binding.root, R.string.nc_message_sent, Snackbar.LENGTH_SHORT).show()
}
}
}
}
ChatMessage.MessageType.SINGLE_NC_GEOLOCATION_MESSAGE -> {
chatViewModel.shareLocationToNotes(
credentials!!,
ApiUtils.getUrlToSendLocation(apiVersion, conversationUser!!.baseUrl, roomToken),
"geo-location",
objectId,
metaData
)
Snackbar.make(binding.root, R.string.nc_message_sent, Snackbar.LENGTH_SHORT).show()
}
ChatMessage.MessageType.REGULAR_TEXT_MESSAGE -> {
chatViewModel.shareToNotes(
credentials!!,
ApiUtils.getUrlForChat(apiVersion, conversationUser!!.baseUrl, roomToken),
message.message!!,
conversationUser!!.displayName!!
)
Snackbar.make(binding.root, R.string.nc_message_sent, Snackbar.LENGTH_SHORT).show()
}
else -> {}
}
}

fun openInFilesApp(message: ChatMessage) {
val keyID = message.selectedIndividualHashMap!![PreviewMessageViewHolder.KEY_ID]
val link = message.selectedIndividualHashMap!!["link"]
Expand Down
15 changes: 15 additions & 0 deletions app/src/main/java/com/nextcloud/talk/chat/data/ChatRepository.kt
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ package com.nextcloud.talk.chat.data

import com.nextcloud.talk.data.user.model.User
import com.nextcloud.talk.models.domain.ConversationModel
import com.nextcloud.talk.models.json.conversations.RoomsOverall
import com.nextcloud.talk.models.json.generic.GenericOverall
import com.nextcloud.talk.models.json.reminder.Reminder
import io.reactivex.Observable
Expand All @@ -32,4 +33,18 @@ interface ChatRepository {
fun setReminder(user: User, roomToken: String, messageId: String, timeStamp: Int): Observable<Reminder>
fun getReminder(user: User, roomToken: String, messageId: String): Observable<Reminder>
fun deleteReminder(user: User, roomToken: String, messageId: String): Observable<GenericOverall>
fun shareToNotes(
credentials: String,
url: String,
message: String,
displayName: String
): Observable<GenericOverall> // last two fields are false
fun checkForNoteToSelf(credentials: String, url: String, includeStatus: Boolean): Observable<RoomsOverall>
fun shareLocationToNotes(
credentials: String,
url: String,
objectType: String,
objectId: String,
metadata: String
): Observable<GenericOverall>
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ package com.nextcloud.talk.chat.data
import com.nextcloud.talk.api.NcApi
import com.nextcloud.talk.data.user.model.User
import com.nextcloud.talk.models.domain.ConversationModel
import com.nextcloud.talk.models.json.conversations.RoomsOverall
import com.nextcloud.talk.models.json.generic.GenericOverall
import com.nextcloud.talk.models.json.reminder.Reminder
import com.nextcloud.talk.utils.ApiUtils
Expand Down Expand Up @@ -83,4 +84,40 @@ class ChatRepositoryImpl(private val ncApi: NcApi) : ChatRepository {
it
}
}

override fun shareToNotes(
credentials: String,
url: String,
message: String,
displayName: String
): Observable<GenericOverall> {
return ncApi.sendChatMessage(
credentials,
url,
message,
displayName,
null,
false
).map {
it
}
}

override fun checkForNoteToSelf(
credentials: String,
url: String,
includeStatus: Boolean
): Observable<RoomsOverall> {
return ncApi.getRooms(credentials, url, includeStatus).map { it }
}

override fun shareLocationToNotes(
credentials: String,
url: String,
objectType: String,
objectId: String,
metadata: String
): Observable<GenericOverall> {
return ncApi.sendLocation(credentials, url, objectType, objectId, metadata).map { it }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,10 @@ import androidx.lifecycle.ViewModel
import com.nextcloud.talk.chat.data.ChatRepository
import com.nextcloud.talk.data.user.model.User
import com.nextcloud.talk.models.domain.ConversationModel
import com.nextcloud.talk.models.json.conversations.RoomsOverall
import com.nextcloud.talk.models.json.generic.GenericOverall
import com.nextcloud.talk.models.json.reminder.Reminder
import com.nextcloud.talk.utils.ConversationUtils
import io.reactivex.Observer
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.Disposable
Expand All @@ -49,6 +51,13 @@ class ChatViewModel @Inject constructor(private val repository: ChatRepository)
val getReminderExistState: LiveData<ViewState>
get() = _getReminderExistState

object NoteToSelfNotAvaliableState : ViewState
open class NoteToSelfAvaliableState(val roomToken: String) : ViewState

private val _getNoteToSelfAvaliability: MutableLiveData<ViewState> = MutableLiveData(NoteToSelfNotAvaliableState)
val getNoteToSelfAvaliability: LiveData<ViewState>
get() = _getNoteToSelfAvaliability

open class GetRoomSuccessState(val conversationModel: ConversationModel) : ViewState

private val _getRoomViewState: MutableLiveData<ViewState> = MutableLiveData(GetRoomStartState)
Expand Down Expand Up @@ -117,6 +126,58 @@ class ChatViewModel @Inject constructor(private val repository: ChatRepository)
})
}

fun shareToNotes(credentials: String, url: String, message: String, displayName: String) {
repository.shareToNotes(credentials, url, message, displayName)
.subscribeOn(Schedulers.io())
?.observeOn(AndroidSchedulers.mainThread())
?.subscribe(object : Observer<GenericOverall> {
override fun onSubscribe(d: Disposable) {
// unused atm
}

override fun onNext(genericOverall: GenericOverall) {
// unused atm
}

override fun onError(e: Throwable) {
Log.d(TAG, "Error when sharing to notes $e")
}

override fun onComplete() {
// unused atm
}
})
}

fun checkForNoteToSelf(credentials: String, baseUrl: String, includeStatus: Boolean) {
repository.checkForNoteToSelf(credentials, baseUrl, includeStatus).subscribeOn(Schedulers.io())
?.observeOn(AndroidSchedulers.mainThread())
?.subscribe(CheckForNoteToSelfObserver())
}

fun shareLocationToNotes(credentials: String, url: String, objectType: String, objectId: String, metadata: String) {
repository.shareLocationToNotes(credentials, url, objectType, objectId, metadata)
.subscribeOn(Schedulers.io())
?.observeOn(AndroidSchedulers.mainThread())
?.subscribe(object : Observer<GenericOverall> {
override fun onSubscribe(d: Disposable) {
// unused atm
}

override fun onNext(genericOverall: GenericOverall) {
// unused atm
}

override fun onError(e: Throwable) {
Log.e(TAG, "Error when sharing location to notes $e")
}

override fun onComplete() {
// unused atm
}
})
}

inner class GetRoomObserver : Observer<ConversationModel> {
override fun onSubscribe(d: Disposable) {
// unused atm
Expand Down Expand Up @@ -192,6 +253,36 @@ class ChatViewModel @Inject constructor(private val repository: ChatRepository)
}
}

inner class CheckForNoteToSelfObserver : Observer<RoomsOverall> {
override fun onSubscribe(d: Disposable) {
// unused atm
}

override fun onNext(roomsOverall: RoomsOverall) {
val rooms = roomsOverall.ocs?.data
rooms?.let {
try {
val noteToSelf = rooms.first {
val model = ConversationModel.mapToConversationModel(it)
ConversationUtils.isNoteToSelfConversation(model)
}
_getNoteToSelfAvaliability.value = NoteToSelfAvaliableState(noteToSelf.token!!)
} catch (e: NoSuchElementException) {
_getNoteToSelfAvaliability.value = NoteToSelfNotAvaliableState
Log.e(TAG, "Note to self not found $e")
}
}
}

override fun onError(e: Throwable) {
Log.d(TAG, "Error when getting rooms for Note to Self Observer $e")
}

override fun onComplete() {
// unused atm
}
}

companion object {
private val TAG = ChatViewModel::class.simpleName
const val JOIN_ROOM_RETRY_COUNT: Long = 3
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ class UploadAndShareFilesWorker(val context: Context, workerParameters: WorkerPa
remotePath
)
} else {
Log.d(TAG, "starting normal upload (not chunked)")
Log.d(TAG, "starting normal upload (not chunked) of $fileName")

uploadSuccess = FileUploader(
context,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import com.google.android.material.bottomsheet.BottomSheetDialog
import com.nextcloud.talk.R
import com.nextcloud.talk.application.NextcloudTalkApplication
import com.nextcloud.talk.chat.ChatActivity
import com.nextcloud.talk.chat.viewmodels.ChatViewModel
import com.nextcloud.talk.data.user.model.User
import com.nextcloud.talk.databinding.DialogMessageActionsBinding
import com.nextcloud.talk.models.domain.ConversationModel
Expand All @@ -48,6 +49,8 @@ import com.nextcloud.talk.models.domain.ReactionDeletedModel
import com.nextcloud.talk.models.json.chat.ChatMessage
import com.nextcloud.talk.repositories.reactions.ReactionsRepository
import com.nextcloud.talk.ui.theme.ViewThemeUtils
import com.nextcloud.talk.utils.ApiUtils
import com.nextcloud.talk.utils.ConversationUtils
import com.nextcloud.talk.utils.database.user.CapabilitiesUtilNew
import com.vanniktech.emoji.EmojiPopup
import com.vanniktech.emoji.EmojiTextView
Expand Down Expand Up @@ -96,6 +99,31 @@ class MessageActionsDialog(
viewThemeUtils.platform.themeDialog(dialogMessageActionsBinding.root)
initEmojiBar(hasChatPermission)
initMenuItemCopy(!message.isDeleted)
val apiVersion = ApiUtils.getConversationApiVersion(user, intArrayOf(ApiUtils.APIv4, ApiUtils.APIv3, 1))
chatActivity.chatViewModel.checkForNoteToSelf(
ApiUtils.getCredentials(user!!.username, user.token),
ApiUtils.getUrlForRooms(
apiVersion,
user.baseUrl
),
false
)
chatActivity.chatViewModel.getNoteToSelfAvaliability.observe(this) { state ->
when (state) {
is ChatViewModel.NoteToSelfAvaliableState -> {
initMenuAddToNote(
!message.isDeleted && !ConversationUtils.isNoteToSelfConversation(currentConversation),
state.roomToken
)
}
else -> {
initMenuAddToNote(
false
)
}
}
}

initMenuItemTranslate(
!message.isDeleted &&
ChatMessage.MessageType.REGULAR_TEXT_MESSAGE == message.getCalculateMessageType() &&
Expand Down Expand Up @@ -374,6 +402,16 @@ class MessageActionsDialog(
dialogMessageActionsBinding.menuSaveMessage.visibility = getVisibility(visible)
}

private fun initMenuAddToNote(visible: Boolean, roomToken: String = "") {
if (visible) {
dialogMessageActionsBinding.menuShareToNote.setOnClickListener {
chatActivity.shareToNotes(message, roomToken)
dismiss()
}
}
dialogMessageActionsBinding.menuShareToNote.visibility = getVisibility(visible)
}

private fun getVisibility(visible: Boolean): Int {
return if (visible) {
View.VISIBLE
Expand Down
Loading

0 comments on commit d45277b

Please sign in to comment.