mirror of
https://github.com/nextcloud/talk-android.git
synced 2024-11-23 05:25:31 +03:00
Merge pull request #3256 from nextcloud/issue-3221-notify-me-later
Notify Me Later About a Message
This commit is contained in:
commit
1672caff55
17 changed files with 896 additions and 6 deletions
|
@ -40,6 +40,7 @@ import com.nextcloud.talk.models.json.participants.AddParticipantOverall;
|
|||
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;
|
||||
|
@ -671,4 +672,18 @@ public interface NcApi {
|
|||
@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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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) {
|
||||
|
|
|
@ -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>
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
|
@ -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")
|
||||
}
|
||||
|
@ -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
|
||||
)
|
||||
|
@ -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)
|
||||
|
@ -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()!!
|
||||
}
|
||||
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* 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 ReminderOverall(
|
||||
@JsonField(name = ["ocs"])
|
||||
var ocs: ReminderOCS? = null
|
||||
) : Parcelable {
|
||||
// This constructor is added to work with the 'com.bluelinelabs.logansquare.annotation.JsonObject'
|
||||
constructor() : this(null)
|
||||
}
|
|
@ -0,0 +1,309 @@
|
|||
/*
|
||||
* Nextcloud Talk application
|
||||
*
|
||||
* @author Julius Linus
|
||||
* Copyright (C) 2023 Julius Linus <julius.linu@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.ui.dialog
|
||||
|
||||
import android.app.Dialog
|
||||
import android.os.Bundle
|
||||
import android.text.format.DateUtils
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import autodagger.AutoInjector
|
||||
import com.google.android.material.datepicker.CalendarConstraints
|
||||
import com.google.android.material.datepicker.DateValidatorPointForward
|
||||
import com.google.android.material.datepicker.MaterialDatePicker
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import com.google.android.material.timepicker.MaterialTimePicker
|
||||
import com.nextcloud.android.common.ui.theme.utils.ColorRole
|
||||
import com.nextcloud.talk.R
|
||||
import com.nextcloud.talk.application.NextcloudTalkApplication
|
||||
import com.nextcloud.talk.chat.viewmodels.ChatViewModel
|
||||
import com.nextcloud.talk.databinding.DialogDateTimePickerBinding
|
||||
import com.nextcloud.talk.ui.theme.ViewThemeUtils
|
||||
import com.nextcloud.talk.users.UserManager
|
||||
import java.util.Calendar
|
||||
import java.util.TimeZone
|
||||
import javax.inject.Inject
|
||||
|
||||
@Suppress("TooManyFunctions")
|
||||
@AutoInjector(NextcloudTalkApplication::class)
|
||||
class DateTimePickerFragment(
|
||||
token: String,
|
||||
id: String,
|
||||
chatViewModel: ChatViewModel
|
||||
) : DialogFragment() {
|
||||
lateinit var binding: DialogDateTimePickerBinding
|
||||
private var dialogView: View? = null
|
||||
private var viewModel = chatViewModel
|
||||
private var currentTimeStamp: Long? = null
|
||||
private var roomToken = token
|
||||
private var messageId = id
|
||||
private var laterTodayTimeStamp = 0L
|
||||
private var tomorrowTimeStamp = 0L
|
||||
private var weekendTimeStamp = 0L
|
||||
private var nextWeekTimeStamp = 0L
|
||||
|
||||
@Inject
|
||||
lateinit var userManager: UserManager
|
||||
|
||||
@Inject
|
||||
lateinit var viewThemeUtils: ViewThemeUtils
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
binding = DialogDateTimePickerBinding.inflate(LayoutInflater.from(context))
|
||||
dialogView = binding.root
|
||||
return MaterialAlertDialogBuilder(requireContext()).setView(dialogView).create()
|
||||
}
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
NextcloudTalkApplication.sharedApplication!!.componentApplication.inject(this)
|
||||
setUpDefaults()
|
||||
setUpColors()
|
||||
setListeners()
|
||||
getReminder()
|
||||
viewModel.getReminderExistState.observe(this) { state ->
|
||||
when (state) {
|
||||
is ChatViewModel.GetReminderExistState -> {
|
||||
val timeStamp = state.reminder.timestamp?.toLong()?.times(ONE_SEC)
|
||||
showDelete(true)
|
||||
setTimeStamp(getTimeFromTimeStamp(timeStamp!!))
|
||||
}
|
||||
|
||||
else -> {
|
||||
showDelete(false)
|
||||
binding.dateTimePickerTimestamp.text = ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return inflater.inflate(R.layout.dialog_date_time_picker, container, false)
|
||||
}
|
||||
|
||||
private fun setUpDefaults() {
|
||||
val currTime = getTimeFromCalendar()
|
||||
val currentWeekInYear = Calendar.getInstance().get(Calendar.WEEK_OF_YEAR)
|
||||
|
||||
laterTodayTimeStamp = getTimeFromCalendar(hour = HOUR_SIX_PM, minute = 0)
|
||||
binding.dateTimePickerLaterTodayTextview.text = getTimeFromTimeStamp(laterTodayTimeStamp)
|
||||
|
||||
if (Calendar.getInstance().get(Calendar.DAY_OF_WEEK) == Calendar.SATURDAY) {
|
||||
tomorrowTimeStamp = getTimeFromCalendar(
|
||||
hour = HOUR_EIGHT_AM,
|
||||
minute = 0,
|
||||
daysToAdd = 1,
|
||||
weekInYear =
|
||||
currentWeekInYear + 1
|
||||
)
|
||||
|
||||
binding.dateTimePickerWeekend.visibility = View.GONE // because today is the weekend
|
||||
} else {
|
||||
tomorrowTimeStamp = getTimeFromCalendar(hour = HOUR_EIGHT_AM, minute = 0, daysToAdd = 1)
|
||||
weekendTimeStamp = getTimeFromCalendar(hour = HOUR_EIGHT_AM, day = Calendar.SATURDAY, minute = 0)
|
||||
}
|
||||
binding.dateTimePickerTomorrowTextview.text = getTimeFromTimeStamp(tomorrowTimeStamp)
|
||||
binding.dateTimePickerWeekendTextview.text = getTimeFromTimeStamp(weekendTimeStamp)
|
||||
|
||||
nextWeekTimeStamp = getTimeFromCalendar(
|
||||
hour = HOUR_EIGHT_AM,
|
||||
day = Calendar.MONDAY,
|
||||
minute = 0,
|
||||
weekInYear =
|
||||
currentWeekInYear + 1
|
||||
) // this should only pick mondays from next week only
|
||||
binding.dateTimePickerNextWeekTextview.text = getTimeFromTimeStamp(nextWeekTimeStamp)
|
||||
|
||||
// This is to hide the later today option, if it's past 6pm
|
||||
if (currTime > laterTodayTimeStamp) {
|
||||
binding.dateTimePickerLaterToday.visibility = View.GONE
|
||||
}
|
||||
|
||||
// This is to hide the tomorrow option, if that's also the weekend
|
||||
if (binding.dateTimePickerTomorrowTextview.text == binding.dateTimePickerWeekendTextview.text) {
|
||||
binding.dateTimePickerTomorrow.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
|
||||
private fun getReminder() {
|
||||
viewModel.getReminder(userManager.currentUser.blockingGet(), roomToken, messageId)
|
||||
}
|
||||
|
||||
private fun showDelete(value: Boolean) {
|
||||
if (value) {
|
||||
binding.buttonDelete.visibility = View.VISIBLE
|
||||
} else {
|
||||
binding.buttonDelete.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
|
||||
private fun setUpColors() {
|
||||
binding.root.let {
|
||||
viewThemeUtils.platform.colorViewBackground(it)
|
||||
}
|
||||
|
||||
binding.dateTimePickerCustomIcon.let {
|
||||
viewThemeUtils.platform.colorImageView(it, ColorRole.PRIMARY)
|
||||
}
|
||||
|
||||
binding.dateTimePickerTimestamp.let {
|
||||
viewThemeUtils.material.themeSearchBarText(it)
|
||||
}
|
||||
|
||||
binding.run {
|
||||
listOf(
|
||||
binding.buttonClose,
|
||||
binding.buttonSet
|
||||
)
|
||||
}.forEach(viewThemeUtils.material::colorMaterialButtonPrimaryBorderless)
|
||||
}
|
||||
|
||||
private fun setListeners() {
|
||||
binding.dateTimePickerLaterToday.setOnClickListener {
|
||||
currentTimeStamp = laterTodayTimeStamp / ONE_SEC
|
||||
setTimeStamp(getTimeFromTimeStamp(laterTodayTimeStamp))
|
||||
}
|
||||
binding.dateTimePickerTomorrow.setOnClickListener {
|
||||
currentTimeStamp = tomorrowTimeStamp / ONE_SEC
|
||||
setTimeStamp(getTimeFromTimeStamp(tomorrowTimeStamp))
|
||||
}
|
||||
binding.dateTimePickerWeekend.setOnClickListener {
|
||||
currentTimeStamp = weekendTimeStamp / ONE_SEC
|
||||
setTimeStamp(getTimeFromTimeStamp(weekendTimeStamp))
|
||||
}
|
||||
binding.dateTimePickerNextWeek.setOnClickListener {
|
||||
currentTimeStamp = nextWeekTimeStamp / ONE_SEC
|
||||
setTimeStamp(getTimeFromTimeStamp(nextWeekTimeStamp))
|
||||
}
|
||||
binding.dateTimePickerCustom.setOnClickListener {
|
||||
val constraintsBuilder = CalendarConstraints.Builder()
|
||||
.setValidator(DateValidatorPointForward.now())
|
||||
.build()
|
||||
val time = System.currentTimeMillis()
|
||||
val datePicker = MaterialDatePicker.Builder.datePicker()
|
||||
.setTitleText(R.string.nc_remind)
|
||||
.setSelection(time + TimeZone.getDefault().getOffset(time))
|
||||
.setCalendarConstraints(constraintsBuilder).build()
|
||||
|
||||
datePicker.addOnPositiveButtonClickListener { selection ->
|
||||
val localTimeInMillis = selection - TimeZone.getDefault().getOffset(selection)
|
||||
val calendar = Calendar.getInstance()
|
||||
calendar.timeInMillis = localTimeInMillis
|
||||
|
||||
val year = calendar.get(Calendar.YEAR)
|
||||
val month = calendar.get(Calendar.MONTH)
|
||||
val day = calendar.get(Calendar.DAY_OF_WEEK)
|
||||
val weekInYear = calendar.get(Calendar.WEEK_OF_YEAR)
|
||||
|
||||
setUpTimePicker(year, month, day, weekInYear)
|
||||
}
|
||||
datePicker.show(this.parentFragmentManager, TAG)
|
||||
}
|
||||
|
||||
binding.buttonClose.setOnClickListener { dismiss() }
|
||||
binding.buttonSet.setOnClickListener {
|
||||
currentTimeStamp?.let { time ->
|
||||
viewModel.setReminder(userManager.currentUser.blockingGet(), roomToken, messageId, time.toInt())
|
||||
}
|
||||
dismiss()
|
||||
}
|
||||
binding.buttonDelete.setOnClickListener {
|
||||
viewModel.deleteReminder(userManager.currentUser.blockingGet(), roomToken, messageId)
|
||||
}
|
||||
}
|
||||
|
||||
private fun setUpTimePicker(year: Int, month: Int, day: Int, weekInYear: Int) {
|
||||
val timePicker = MaterialTimePicker
|
||||
.Builder()
|
||||
.setTitleText(R.string.nc_remind)
|
||||
.build()
|
||||
|
||||
timePicker.addOnPositiveButtonClickListener {
|
||||
val timestamp = getTimeFromCalendar(
|
||||
year,
|
||||
month,
|
||||
day,
|
||||
timePicker.hour,
|
||||
timePicker.minute,
|
||||
weekInYear = weekInYear
|
||||
)
|
||||
setTimeStamp(getTimeFromTimeStamp(timestamp))
|
||||
currentTimeStamp = timestamp / ONE_SEC
|
||||
}
|
||||
|
||||
timePicker.show(this.parentFragmentManager, TAG)
|
||||
}
|
||||
|
||||
@Suppress("LongParameterList")
|
||||
private fun getTimeFromCalendar(
|
||||
year: Int = Calendar.getInstance().get(Calendar.YEAR),
|
||||
month: Int = Calendar.getInstance().get(Calendar.MONTH),
|
||||
day: Int = Calendar.getInstance().get(Calendar.DAY_OF_WEEK),
|
||||
hour: Int = Calendar.getInstance().get(Calendar.HOUR_OF_DAY),
|
||||
minute: Int = Calendar.getInstance().get(Calendar.MINUTE),
|
||||
daysToAdd: Int = 0,
|
||||
weekInYear: Int = Calendar.getInstance().get(Calendar.WEEK_OF_YEAR)
|
||||
): Long {
|
||||
val calendar: Calendar = Calendar.getInstance().apply {
|
||||
set(Calendar.YEAR, year)
|
||||
set(Calendar.MONTH, month)
|
||||
set(Calendar.DAY_OF_WEEK, day)
|
||||
add(Calendar.DAY_OF_WEEK, daysToAdd)
|
||||
set(Calendar.WEEK_OF_YEAR, weekInYear)
|
||||
set(Calendar.HOUR_OF_DAY, hour)
|
||||
set(Calendar.MINUTE, minute)
|
||||
set(Calendar.SECOND, 0)
|
||||
}
|
||||
return calendar.timeInMillis
|
||||
}
|
||||
|
||||
private fun setTimeStamp(date: String) {
|
||||
binding.dateTimePickerTimestamp.text = date
|
||||
}
|
||||
|
||||
private fun getTimeFromTimeStamp(time: Long): String {
|
||||
return DateUtils.formatDateTime(
|
||||
requireContext(),
|
||||
time,
|
||||
DateUtils.FORMAT_SHOW_DATE
|
||||
) + ", " + DateUtils.formatDateTime(
|
||||
requireContext(),
|
||||
time,
|
||||
DateUtils.FORMAT_SHOW_TIME
|
||||
)
|
||||
}
|
||||
|
||||
companion object {
|
||||
val TAG = DateTimePickerFragment::class.simpleName
|
||||
private const val ONE_SEC = 1000
|
||||
private const val HOUR_EIGHT_AM = 8
|
||||
private const val HOUR_SIX_PM = 18
|
||||
|
||||
@JvmStatic
|
||||
fun newInstance(
|
||||
token: String,
|
||||
id: String,
|
||||
chatViewModel: ChatViewModel
|
||||
) = DateTimePickerFragment(
|
||||
token,
|
||||
id,
|
||||
chatViewModel
|
||||
)
|
||||
}
|
||||
}
|
|
@ -109,6 +109,7 @@ class MessageActionsDialog(
|
|||
ChatMessage.MessageType.REGULAR_TEXT_MESSAGE == message.getCalculateMessageType() &&
|
||||
!(message.isDeletedCommentMessage || message.isDeleted)
|
||||
)
|
||||
initMenuRemindMessage(!message.isDeleted && CapabilitiesUtilNew.isRemindSupported(user))
|
||||
initMenuMarkAsUnread(
|
||||
message.previousMessageId > NO_PREVIOUS_MESSAGE_ID &&
|
||||
ChatMessage.MessageType.SYSTEM_MESSAGE != message.getCalculateMessageType()
|
||||
|
@ -264,6 +265,17 @@ class MessageActionsDialog(
|
|||
dialogMessageActionsBinding.menuForwardMessage.visibility = getVisibility(visible)
|
||||
}
|
||||
|
||||
private fun initMenuRemindMessage(visible: Boolean) {
|
||||
if (visible) {
|
||||
dialogMessageActionsBinding.menuNotifyMessage.setOnClickListener {
|
||||
chatActivity.remindMeLater(message)
|
||||
dismiss()
|
||||
}
|
||||
}
|
||||
|
||||
dialogMessageActionsBinding.menuNotifyMessage.visibility = getVisibility(visible)
|
||||
}
|
||||
|
||||
private fun initMenuDeleteMessage(visible: Boolean) {
|
||||
if (visible) {
|
||||
dialogMessageActionsBinding.menuDeleteMessage.setOnClickListener {
|
||||
|
|
|
@ -530,4 +530,9 @@ public class ApiUtils {
|
|||
public static String getUrlForTranslation(String baseUrl) {
|
||||
return baseUrl + ocsApiVersion + "/translation/translate";
|
||||
}
|
||||
|
||||
public static String getUrlForReminder(User user, String roomToken, String messageId, int version) {
|
||||
String url = ApiUtils.getUrlForChatMessage(version, user.getBaseUrl(), roomToken, messageId);
|
||||
return url + "/reminder";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -145,7 +145,7 @@ object CapabilitiesUtilNew {
|
|||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getAttachmentFolder(user: User): String? {
|
||||
fun getAttachmentFolder(user: User): String {
|
||||
if (user.capabilities?.spreedCapability?.config?.containsKey("attachments") == true) {
|
||||
val map = user.capabilities!!.spreedCapability!!.config!!["attachments"]
|
||||
if (map?.containsKey("folder") == true) {
|
||||
|
@ -241,5 +241,14 @@ object CapabilitiesUtilNew {
|
|||
}
|
||||
}
|
||||
|
||||
fun isRemindSupported(user: User?): Boolean {
|
||||
if (user?.capabilities != null) {
|
||||
val capabilities = user.capabilities
|
||||
return capabilities?.spreedCapability?.features?.contains("remind-me-later") == true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
const val DEFAULT_CHAT_SIZE = 1000
|
||||
}
|
||||
|
|
27
app/src/main/res/drawable/baseline_calendar_month_24.xml
Normal file
27
app/src/main/res/drawable/baseline_calendar_month_24.xml
Normal file
|
@ -0,0 +1,27 @@
|
|||
<!--
|
||||
@author Google LLC
|
||||
Copyright (C) 2018 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 android:height="24dp"
|
||||
android:tint="#000000"
|
||||
android:viewportHeight="24"
|
||||
android:viewportWidth="24"
|
||||
android:width="24dp"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M19,4h-1V2h-2v2H8V2H6v2H5C3.89,4 3.01,4.9 3.01,6L3,20c0,1.1 0.89,2 2,2h14c1.1,0 2,-0.9 2,-2V6C21,4.9 20.1,4 19,4zM19,20H5V10h14V20zM9,14H7v-2h2V14zM13,14h-2v-2h2V14zM17,14h-2v-2h2V14zM9,18H7v-2h2V18zM13,18h-2v-2h2V18zM17,18h-2v-2h2V18z" />
|
||||
</vector>
|
218
app/src/main/res/layout/dialog_date_time_picker.xml
Normal file
218
app/src/main/res/layout/dialog_date_time_picker.xml
Normal file
|
@ -0,0 +1,218 @@
|
|||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
~ 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/>.
|
||||
-->
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:background="@color/white">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="@dimen/standard_margin"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/nc_remind"
|
||||
android:layout_weight="1"
|
||||
android:textSize="@dimen/md_title_textsize" />
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/date_time_picker_timestamp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
tools:text="Apr 15th, 8:00 AM"
|
||||
android:textSize="@dimen/supporting_text_text_size"
|
||||
android:textStyle="bold" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
<com.google.android.material.divider.MaterialDivider
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/date_time_picker_later_today"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:orientation="horizontal"
|
||||
android:padding="@dimen/standard_padding">
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="@string/later_today"
|
||||
android:textSize="@dimen/headline_text_size" />
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/date_time_picker_later_today_textview"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="@dimen/headline_text_size"
|
||||
android:text="" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/date_time_picker_tomorrow"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:orientation="horizontal"
|
||||
android:padding="@dimen/standard_padding">
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="@string/tomorrow"
|
||||
android:textSize="@dimen/headline_text_size" />
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/date_time_picker_tomorrow_textview"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="@dimen/headline_text_size"
|
||||
android:text="" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/date_time_picker_weekend"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:orientation="horizontal"
|
||||
android:padding="@dimen/standard_padding">
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="@string/this_weekend"
|
||||
android:textSize="@dimen/headline_text_size" />
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/date_time_picker_weekend_textview"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="@dimen/headline_text_size"
|
||||
android:text="" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/date_time_picker_next_week"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:orientation="horizontal"
|
||||
android:padding="@dimen/standard_padding">
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="@string/next_week"
|
||||
android:textSize="@dimen/headline_text_size" />
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/date_time_picker_next_week_textview"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="@dimen/headline_text_size"
|
||||
android:text="" />
|
||||
</LinearLayout>
|
||||
|
||||
<com.google.android.material.divider.MaterialDivider
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/date_time_picker_custom"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:padding="@dimen/standard_padding"
|
||||
android:background="?android:attr/selectableItemBackground">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/date_time_picker_custom_icon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:src="@drawable/baseline_calendar_month_24"
|
||||
android:paddingEnd="@dimen/standard_double_padding"
|
||||
tools:ignore="RtlSymmetry"
|
||||
android:contentDescription="@string/calendar" />
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/custom"
|
||||
android:layout_weight="1"
|
||||
android:textSize="@dimen/headline_text_size" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:layout_weight="1">
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/button_delete"
|
||||
style="@style/Button.Borderless"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="@dimen/min_size_clickable_area"
|
||||
android:text="@string/nc_delete"
|
||||
android:textColor="@color/design_default_color_error" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/button_set"
|
||||
style="@style/Button.Borderless"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="@dimen/min_size_clickable_area"
|
||||
android:text="@string/set" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/button_close"
|
||||
style="@style/Button.Borderless"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="end"
|
||||
android:minHeight="@dimen/min_size_clickable_area"
|
||||
android:text="@string/close" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
</LinearLayout>
|
|
@ -221,6 +221,39 @@
|
|||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/menu_notify_message"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/bottom_sheet_item_height"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal"
|
||||
tools:ignore="UseCompoundDrawables">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/menu_icon_notify_message"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:contentDescription="@null"
|
||||
android:paddingStart="@dimen/standard_padding"
|
||||
android:paddingEnd="@dimen/zero"
|
||||
android:src="@drawable/ic_timer_black_24dp"
|
||||
app:tint="@color/high_emphasis_menu_icon" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
android:id="@+id/menu_text_notify_message"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="start|center_vertical"
|
||||
android:paddingStart="@dimen/standard_double_padding"
|
||||
android:paddingEnd="@dimen/standard_padding"
|
||||
android:text="@string/nc_remind"
|
||||
android:textAlignment="viewStart"
|
||||
android:textColor="@color/high_emphasis_text"
|
||||
android:textSize="@dimen/bottom_sheet_text_size" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/menu_mark_as_unread"
|
||||
android:layout_width="match_parent"
|
||||
|
|
|
@ -697,5 +697,13 @@ How to translate with transifex:
|
|||
<string name="nc_settings_socks_value" translatable="false">1080</string>
|
||||
<string name="this_is_a_test_message">This is a test message</string>
|
||||
<string name="continuous_voice_message_recording">Lock recording for continuously recording of the voice message</string>
|
||||
<string name="nc_remind">Remind me later</string>
|
||||
<string name="next_week">Next week</string>
|
||||
<string name="this_weekend">This weekend</string>
|
||||
<string name="tomorrow">Tomorrow</string>
|
||||
<string name="later_today">Later today</string>
|
||||
<string name="custom">Custom</string>
|
||||
<string name="set">Set</string>
|
||||
<string name="calendar">Calendar</string>
|
||||
|
||||
</resources>
|
||||
|
|
Loading…
Reference in a new issue