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

Signed-off-by: Julius Linus <[email protected]>
  • Loading branch information
rapterjet2004 committed Jan 26, 2024
1 parent 091bec7 commit 70b65e6
Show file tree
Hide file tree
Showing 8 changed files with 309 additions and 2 deletions.
75 changes: 73 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,10 @@ class ChatActivity :
}
}

private fun uploadFile(fileUri: String, isVoiceMessage: Boolean, caption: String = "") {
private fun uploadFile(fileUri: String, isVoiceMessage: Boolean, caption: String = "", token: String = "") {
Log.d("Julius", "Upload file called with $token")
var metaData = ""
var room = ""

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

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

Log.d("Julius", "file shared to $room")
try {
require(fileUri.isNotEmpty())
UploadAndShareFilesWorker.upload(
fileUri,
roomToken,
room,
currentConversation?.displayName!!,
metaData
)
Expand Down Expand Up @@ -4171,6 +4176,72 @@ 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
)

Log.d("Julius", "shareUri: $shareUri")
} 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\"}"

}

// TODO check if URI exists, if not, then file isn't downloaded to cache yet
when (type) {
ChatMessage.MessageType.VOICE_MESSAGE ->
uploadFile(shareUri.toString(), true, token = roomToken)
ChatMessage.MessageType.SINGLE_NC_ATTACHMENT_MESSAGE -> {
val caption = if(message.message != "{file}") message.message else ""
uploadFile(shareUri.toString(), false, caption!!, roomToken)
}
ChatMessage.MessageType.SINGLE_NC_GEOLOCATION_MESSAGE -> {
chatViewModel.shareLocationToNotes(
credentials!!,
ApiUtils.getUrlToSendLocation(apiVersion, conversationUser!!.baseUrl, roomToken),
"geo-location",
objectId,
metaData
)
}
ChatMessage.MessageType.REGULAR_TEXT_MESSAGE -> {
chatViewModel.shareToNotes(
credentials!!,
ApiUtils.getUrlForChat(apiVersion, conversationUser!!.baseUrl, roomToken),
message.message!!,
conversationUser!!.displayName!!
)
}
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 @@ -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
21 changes: 21 additions & 0 deletions app/src/main/res/drawable/ic_edit_note_24.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<!--
@author Google LLC
Copyright (C) 2021 Google LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#000000" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">

<path android:fillColor="@android:color/white" android:pathData="M3,10h11v2H3V10zM3,8h11V6H3V8zM3,16h7v-2H3V16zM18.01,12.87l0.71,-0.71c0.39,-0.39 1.02,-0.39 1.41,0l0.71,0.71c0.39,0.39 0.39,1.02 0,1.41l-0.71,0.71L18.01,12.87zM17.3,13.58l-5.3,5.3V21h2.12l5.3,-5.3L17.3,13.58z"/>

</vector>
Loading

0 comments on commit 70b65e6

Please sign in to comment.