Skip to content

Commit

Permalink
Notify me Later
Browse files Browse the repository at this point in the history
- Added new Dialog Fragment
- Added API functions for handling reminders
- Added JSON Models for those reminders
- Implemented the reminder functions using MVVM

Signed-off-by: Julius Linus <julius.linus@nextcloud.com>
  • Loading branch information
rapterjet2004 committed Aug 30, 2023
1 parent bf0a958 commit 37df402
Show file tree
Hide file tree
Showing 17 changed files with 896 additions and 6 deletions.
15 changes: 15 additions & 0 deletions app/src/main/java/com/nextcloud/talk/api/NcApi.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
import com.nextcloud.talk.models.json.participants.ParticipantsOverall;
import com.nextcloud.talk.models.json.push.PushRegistrationOverall;
import com.nextcloud.talk.models.json.reactions.ReactionsOverall;
import com.nextcloud.talk.models.json.reminder.ReminderOverall;
import com.nextcloud.talk.models.json.search.ContactsByNumberOverall;
import com.nextcloud.talk.models.json.signaling.SignalingOverall;
import com.nextcloud.talk.models.json.signaling.settings.SignalingSettingsOverall;
Expand Down Expand Up @@ -671,4 +672,18 @@ Observable<TranslationsOverall> translateMessage(@Header("Authorization") String
@Query("text") String text,
@Query("toLanguage") String toLanguage,
@Nullable @Query("fromLanguage") String fromLanguage);

@GET
Observable<ReminderOverall> getReminder(@Header("Authorization") String authorization,
@Url String url);

@DELETE
Observable<GenericOverall> deleteReminder(@Header("Authorization") String authorization,
@Url String url);

@FormUrlEncoded
@POST
Observable<ReminderOverall> setReminder(@Header("Authorization") String authorization,
@Url String url,
@Field("timestamp") int timestamp);
}
12 changes: 12 additions & 0 deletions app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ import androidx.core.text.bold
import androidx.core.widget.doAfterTextChanged
import androidx.emoji2.text.EmojiCompat
import androidx.emoji2.widget.EmojiTextView
import androidx.fragment.app.DialogFragment
import androidx.lifecycle.ViewModelProvider
import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.LinearLayoutManager
Expand Down Expand Up @@ -183,6 +184,7 @@ import com.nextcloud.talk.ui.MicInputCloud
import com.nextcloud.talk.ui.StatusDrawable
import com.nextcloud.talk.ui.bottom.sheet.ProfileBottomSheet
import com.nextcloud.talk.ui.dialog.AttachmentDialog
import com.nextcloud.talk.ui.dialog.DateTimePickerFragment
import com.nextcloud.talk.ui.dialog.MessageActionsDialog
import com.nextcloud.talk.ui.dialog.ShowReactionsDialog
import com.nextcloud.talk.ui.recyclerview.MessageSwipeActions
Expand Down Expand Up @@ -3860,6 +3862,16 @@ class ChatActivity :
startActivity(intent)
}

fun remindMeLater(message: ChatMessage?) {
Log.d(TAG, "remindMeLater called")
val newFragment: DialogFragment = DateTimePickerFragment.newInstance(
roomToken,
message!!.id,
chatViewModel
)
newFragment.show(supportFragmentManager, DateTimePickerFragment.TAG)
}

fun markAsUnread(message: IMessage?) {
val chatMessage = message as ChatMessage?
if (chatMessage!!.previousMessageId > NO_PREVIOUS_MESSAGE_ID) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,14 @@ 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.generic.GenericOverall
import com.nextcloud.talk.models.json.reminder.Reminder
import io.reactivex.Observable

interface ChatRepository {
fun getRoom(user: User, roomToken: String): Observable<ConversationModel>
fun joinRoom(user: User, roomToken: String, roomPassword: String): Observable<ConversationModel>
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>
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ 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.generic.GenericOverall
import com.nextcloud.talk.models.json.reminder.Reminder
import com.nextcloud.talk.utils.ApiUtils
import io.reactivex.Observable

Expand Down Expand Up @@ -54,4 +56,38 @@ class ChatRepositoryImpl(private val ncApi: NcApi) : ChatRepository {
roomPassword
).map { ConversationModel.mapToConversationModel(it.ocs?.data!!) }
}

override fun setReminder(user: User, roomToken: String, messageId: String, timeStamp: Int): Observable<Reminder> {
val credentials: String = ApiUtils.getCredentials(user.username, user.token)
val apiVersion = ApiUtils.getChatApiVersion(user, intArrayOf(ApiUtils.APIv1, 1))
return ncApi.setReminder(
credentials,
ApiUtils.getUrlForReminder(user, roomToken, messageId, apiVersion),
timeStamp
).map {
it.ocs!!.data
}
}

override fun getReminder(user: User, roomToken: String, messageId: String): Observable<Reminder> {
val credentials: String = ApiUtils.getCredentials(user.username, user.token)
val apiVersion = ApiUtils.getChatApiVersion(user, intArrayOf(ApiUtils.APIv1, 1))
return ncApi.getReminder(
credentials,
ApiUtils.getUrlForReminder(user, roomToken, messageId, apiVersion)
).map {
it.ocs!!.data
}
}

override fun deleteReminder(user: User, roomToken: String, messageId: String): Observable<GenericOverall> {
val credentials: String = ApiUtils.getCredentials(user.username, user.token)
val apiVersion = ApiUtils.getChatApiVersion(user, intArrayOf(ApiUtils.APIv1, 1))
return ncApi.deleteReminder(
credentials,
ApiUtils.getUrlForReminder(user, roomToken, messageId, apiVersion)
).map {
it
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ 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.generic.GenericOverall
import com.nextcloud.talk.models.json.reminder.Reminder
import io.reactivex.Observer
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.Disposable
Expand All @@ -40,6 +42,13 @@ class ChatViewModel @Inject constructor(private val repository: ChatRepository)

object GetRoomStartState : ViewState
object GetRoomErrorState : ViewState
object GetReminderStartState : ViewState
open class GetReminderExistState(val reminder: Reminder) : ViewState

private val _getReminderExistState: MutableLiveData<ViewState> = MutableLiveData(GetReminderStartState)
val getReminderExistState: LiveData<ViewState>
get() = _getReminderExistState

open class GetRoomSuccessState(val conversationModel: ConversationModel) : ViewState

private val _getRoomViewState: MutableLiveData<ViewState> = MutableLiveData(GetRoomStartState)
Expand Down Expand Up @@ -71,6 +80,43 @@ class ChatViewModel @Inject constructor(private val repository: ChatRepository)
?.subscribe(JoinRoomObserver())
}

fun setReminder(user: User, roomToken: String, messageId: String, timestamp: Int) {
repository.setReminder(user, roomToken, messageId, timestamp)
.subscribeOn(Schedulers.io())
?.observeOn(AndroidSchedulers.mainThread())
?.subscribe(SetReminderObserver())
}

fun getReminder(user: User, roomToken: String, messageId: String) {
repository.getReminder(user, roomToken, messageId)
.subscribeOn(Schedulers.io())
?.observeOn(AndroidSchedulers.mainThread())
?.subscribe(GetReminderObserver())
}

fun deleteReminder(user: User, roomToken: String, messageId: String) {
repository.deleteReminder(user, roomToken, messageId)
.subscribeOn(Schedulers.io())
?.observeOn(AndroidSchedulers.mainThread())
?.subscribe(object : Observer<GenericOverall> {
override fun onSubscribe(d: Disposable) {
// unused atm
}

override fun onNext(genericOverall: GenericOverall) {
_getReminderExistState.value = GetReminderStartState
}

override fun onError(e: Throwable) {
Log.d(TAG, "Error when deleting reminder $e")
}

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

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

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

override fun onNext(reminder: Reminder) {
Log.d(TAG, "reminder set successfully")
}

override fun onError(e: Throwable) {
Log.e(TAG, "Error when sending reminder, $e")
}

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

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

override fun onNext(reminder: Reminder) {
_getReminderExistState.value = GetReminderExistState(reminder)
}

override fun onError(e: Throwable) {
Log.d(TAG, "Error when getting reminder $e")
_getReminderExistState.value = GetReminderStartState
}

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

companion object {
private val TAG = ChatViewModel::class.simpleName
const val JOIN_ROOM_RETRY_COUNT: Long = 3
Expand Down
13 changes: 9 additions & 4 deletions app/src/main/java/com/nextcloud/talk/jobs/NotificationWorker.kt
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ class NotificationWorker(context: Context, workerParams: WorkerParameters) : Wor
} else if (isSpreedNotification()) {
Log.d(TAG, "pushMessage.type: " + pushMessage.type)
when (pushMessage.type) {
TYPE_CHAT, TYPE_ROOM, TYPE_RECORDING -> handleNonCallPushMessage()
TYPE_CHAT, TYPE_ROOM, TYPE_RECORDING, TYPE_REMINDER -> handleNonCallPushMessage()
TYPE_CALL -> handleCallPushMessage()
else -> Log.e(TAG, "unknown pushMessage.type")
}
Expand Down Expand Up @@ -407,7 +407,7 @@ class NotificationWorker(context: Context, workerParams: WorkerParameters) : Wor
) {
var category = ""
when (pushMessage.type) {
TYPE_CHAT, TYPE_ROOM, TYPE_RECORDING -> category = Notification.CATEGORY_MESSAGE
TYPE_CHAT, TYPE_ROOM, TYPE_RECORDING, TYPE_REMINDER -> category = Notification.CATEGORY_MESSAGE
TYPE_CALL -> category = Notification.CATEGORY_CALL
else -> Log.e(TAG, "unknown pushMessage.type")
}
Expand Down Expand Up @@ -464,7 +464,7 @@ class NotificationWorker(context: Context, workerParams: WorkerParameters) : Wor

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
when (pushMessage.type) {
TYPE_CHAT, TYPE_ROOM, TYPE_RECORDING -> {
TYPE_CHAT, TYPE_ROOM, TYPE_RECORDING, TYPE_REMINDER -> {
notificationBuilder.setChannelId(
NotificationUtils.NotificationChannels.NOTIFICATION_CHANNEL_MESSAGES_V4.name
)
Expand All @@ -489,7 +489,9 @@ class NotificationWorker(context: Context, workerParams: WorkerParameters) : Wor
val systemNotificationId: Int =
activeStatusBarNotification?.id ?: calculateCRC32(System.currentTimeMillis().toString()).toInt()

if (TYPE_CHAT == pushMessage.type && pushMessage.notificationUser != null) {
if ((TYPE_CHAT == pushMessage.type || TYPE_REMINDER == pushMessage.type) &&
pushMessage.notificationUser != null
) {
prepareChatNotification(notificationBuilder, activeStatusBarNotification, systemNotificationId)
addReplyAction(notificationBuilder, systemNotificationId)
addMarkAsReadAction(notificationBuilder, systemNotificationId)
Expand Down Expand Up @@ -522,6 +524,8 @@ class NotificationWorker(context: Context, workerParams: WorkerParameters) : Wor
else -> // assuming one2one
largeIcon = if (TYPE_CHAT == pushMessage.type || TYPE_ROOM == pushMessage.type) {
ContextCompat.getDrawable(context!!, R.drawable.ic_comment)?.toBitmap()!!
} else if (TYPE_REMINDER == pushMessage.type) {
ContextCompat.getDrawable(context!!, R.drawable.ic_timer_black_24dp)?.toBitmap()!!
} else {
ContextCompat.getDrawable(context!!, R.drawable.ic_call_black_24dp)?.toBitmap()!!
}
Expand Down Expand Up @@ -984,6 +988,7 @@ class NotificationWorker(context: Context, workerParams: WorkerParameters) : Wor
private const val TYPE_ROOM = "room"
private const val TYPE_CALL = "call"
private const val TYPE_RECORDING = "recording"
private const val TYPE_REMINDER = "reminder"
private const val SPREED_APP = "spreed"
private const val TIMER_START = 1
private const val TIMER_COUNT = 12
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* Nextcloud Talk application
*
* @author Julius Linus
* Copyright (C) 2023 Julius Linus <julius.linus@nextcloud.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.nextcloud.talk.models.json.reminder

import android.os.Parcelable
import com.bluelinelabs.logansquare.annotation.JsonField
import com.bluelinelabs.logansquare.annotation.JsonObject
import kotlinx.parcelize.Parcelize

@Parcelize
@JsonObject
data class Reminder(
@JsonField(name = ["userid"])
var userid: String? = null,
@JsonField(name = ["token"])
var token: String? = null,
@JsonField(name = ["messageId"])
var messageId: Int? = null,
@JsonField(name = ["timestamp"])
var timestamp: Int? = null
) : Parcelable {
// This constructor is added to work with the 'com.bluelinelabs.logansquare.annotation.JsonObject'
constructor() : this(null, null, null, null)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* Nextcloud Talk application
*
* @author Julius Linus
* Copyright (C) 2023 Julius Linus <julius.linus@nextcloud.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.nextcloud.talk.models.json.reminder

import android.os.Parcelable
import com.bluelinelabs.logansquare.annotation.JsonField
import com.bluelinelabs.logansquare.annotation.JsonObject
import com.nextcloud.talk.models.json.generic.GenericMeta
import kotlinx.parcelize.Parcelize

@Parcelize
@JsonObject
data class ReminderOCS(
@JsonField(name = ["meta"])
var meta: GenericMeta? = null,
@JsonField(name = ["data"])
var data: Reminder? = null
) : Parcelable {
// This constructor is added to work with the 'com.bluelinelabs.logansquare.annotation.JsonObject'
constructor() : this(null, null)
}
Loading

0 comments on commit 37df402

Please sign in to comment.