Adding a Short cut to note-to-self

Translations, and focuses on edittext upon opening

Signed-off-by: rapterjet2004 <juliuslinus1@gmail.com>
This commit is contained in:
rapterjet2004 2025-06-03 13:45:10 -05:00 committed by Marcel Hibbe
parent 776ba77c3a
commit 5a22f27b64
No known key found for this signature in database
GPG Key ID: C793F8B59F43CE7B
8 changed files with 77 additions and 19 deletions

View File

@ -286,6 +286,7 @@ class WebViewLoginActivity : BaseActivity() {
} }
} }
@SuppressLint("DiscouragedPrivateApi")
@Suppress("Detekt.TooGenericExceptionCaught") @Suppress("Detekt.TooGenericExceptionCaught")
override fun onReceivedSslError(view: WebView, handler: SslErrorHandler, error: SslError) { override fun onReceivedSslError(view: WebView, handler: SslErrorHandler, error: SslError) {
try { try {

View File

@ -6,6 +6,7 @@
*/ */
package com.nextcloud.talk.bottomsheet.items package com.nextcloud.talk.bottomsheet.items
import android.annotation.SuppressLint
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.ImageView import android.widget.ImageView
@ -65,6 +66,7 @@ internal class ListIconDialogAdapter<IT : ListItemWithImage>(
} }
} }
@SuppressLint("RestrictedApi")
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ListItemViewHolder { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ListItemViewHolder {
val listItemView: View = parent.inflate(dialog.windowContext, R.layout.menu_item_sheet) val listItemView: View = parent.inflate(dialog.windowContext, R.layout.menu_item_sheet)
val viewHolder = ListItemViewHolder( val viewHolder = ListItemViewHolder(

View File

@ -16,7 +16,6 @@ package com.nextcloud.talk.chat
import android.Manifest import android.Manifest
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.app.Activity
import android.content.ClipData import android.content.ClipData
import android.content.ClipboardManager import android.content.ClipboardManager
import android.content.Context import android.content.Context
@ -363,6 +362,7 @@ class ChatActivity :
var startCallFromRoomSwitch: Boolean = false var startCallFromRoomSwitch: Boolean = false
var voiceOnly: Boolean = true var voiceOnly: Boolean = true
var focusInput: Boolean = false
private lateinit var path: String private lateinit var path: String
var myFirstMessage: CharSequence? = null var myFirstMessage: CharSequence? = null
@ -546,6 +546,8 @@ class ChatActivity :
startCallFromRoomSwitch = extras?.getBoolean(KEY_START_CALL_AFTER_ROOM_SWITCH, false) == true startCallFromRoomSwitch = extras?.getBoolean(KEY_START_CALL_AFTER_ROOM_SWITCH, false) == true
voiceOnly = extras?.getBoolean(KEY_CALL_VOICE_ONLY, false) == true voiceOnly = extras?.getBoolean(KEY_CALL_VOICE_ONLY, false) == true
focusInput = extras?.getBoolean(BundleKeys.KEY_FOCUS_INPUT) == true
} }
override fun onStart() { override fun onStart() {
@ -637,12 +639,17 @@ class ChatActivity :
supportFragmentManager.commit { supportFragmentManager.commit {
setReorderingAllowed(true) // optimizes out redundant replace operations setReorderingAllowed(true) // optimizes out redundant replace operations
replace(R.id.fragment_container_activity_chat, messageInputFragment) replace(R.id.fragment_container_activity_chat, messageInputFragment)
runOnCommit {
if (focusInput) {
messageInputFragment.binding.fragmentMessageInputView.requestFocus()
}
}
} }
joinRoomWithPassword() joinRoomWithPassword()
if (conversationUser?.userId != "?" && if (conversationUser?.userId != "?" &&
CapabilitiesUtil.hasSpreedFeatureCapability(spreedCapabilities, SpreedFeatures.MENTION_FLAG) hasSpreedFeatureCapability(spreedCapabilities, SpreedFeatures.MENTION_FLAG)
) { ) {
binding.chatToolbar.setOnClickListener { _ -> showConversationInfoScreen() } binding.chatToolbar.setOnClickListener { _ -> showConversationInfoScreen() }
} }
@ -2046,7 +2053,7 @@ class ChatActivity :
private fun shouldShowLobby(): Boolean { private fun shouldShowLobby(): Boolean {
if (currentConversation != null) { if (currentConversation != null) {
return CapabilitiesUtil.hasSpreedFeatureCapability(spreedCapabilities, SpreedFeatures.WEBINARY_LOBBY) && return hasSpreedFeatureCapability(spreedCapabilities, SpreedFeatures.WEBINARY_LOBBY) &&
currentConversation?.lobbyState == ConversationEnums.LobbyState.LOBBY_STATE_MODERATORS_ONLY && currentConversation?.lobbyState == ConversationEnums.LobbyState.LOBBY_STATE_MODERATORS_ONLY &&
!ConversationUtils.canModerate(currentConversation!!, spreedCapabilities) && !ConversationUtils.canModerate(currentConversation!!, spreedCapabilities) &&
!participantPermissions.canIgnoreLobby() !participantPermissions.canIgnoreLobby()
@ -2302,7 +2309,7 @@ class ChatActivity :
} }
private fun executeIfResultOk(result: ActivityResult, onResult: (intent: Intent?) -> Unit) { private fun executeIfResultOk(result: ActivityResult, onResult: (intent: Intent?) -> Unit) {
if (result.resultCode == Activity.RESULT_OK) { if (result.resultCode == RESULT_OK) {
onResult(result.data) onResult(result.data)
} else { } else {
Log.e(TAG, "resultCode for received intent was != ok") Log.e(TAG, "resultCode for received intent was != ok")
@ -2796,7 +2803,7 @@ class ChatActivity :
} }
if (this::spreedCapabilities.isInitialized) { if (this::spreedCapabilities.isInitialized) {
if (CapabilitiesUtil.hasSpreedFeatureCapability(spreedCapabilities, SpreedFeatures.MESSAGE_EXPIRATION)) { if (hasSpreedFeatureCapability(spreedCapabilities, SpreedFeatures.MESSAGE_EXPIRATION)) {
deleteExpiredMessages() deleteExpiredMessages()
} }
} else { } else {
@ -3064,7 +3071,7 @@ class ChatActivity :
super.onPrepareOptionsMenu(menu) super.onPrepareOptionsMenu(menu)
if (this::spreedCapabilities.isInitialized) { if (this::spreedCapabilities.isInitialized) {
if (CapabilitiesUtil.hasSpreedFeatureCapability(spreedCapabilities, SpreedFeatures.READ_ONLY_ROOMS)) { if (hasSpreedFeatureCapability(spreedCapabilities, SpreedFeatures.READ_ONLY_ROOMS)) {
checkShowCallButtons() checkShowCallButtons()
} }
@ -3085,7 +3092,7 @@ class ChatActivity :
}.collect() }.collect()
} }
if (CapabilitiesUtil.hasSpreedFeatureCapability(spreedCapabilities, SpreedFeatures.SILENT_CALL)) { if (hasSpreedFeatureCapability(spreedCapabilities, SpreedFeatures.SILENT_CALL)) {
Handler().post { Handler().post {
findViewById<View?>(R.id.conversation_voice_call)?.setOnLongClickListener { findViewById<View?>(R.id.conversation_voice_call)?.setOnLongClickListener {
showCallButtonMenu(true) showCallButtonMenu(true)
@ -3144,6 +3151,7 @@ class ChatActivity :
else -> super.onOptionsItemSelected(item) else -> super.onOptionsItemSelected(item)
} }
@SuppressLint("InflateParams")
private fun showPopupWindow(anchorView: View) { private fun showPopupWindow(anchorView: View) {
val popupView = layoutInflater.inflate(R.layout.item_event_schedule, null) val popupView = layoutInflater.inflate(R.layout.item_event_schedule, null)
@ -3595,7 +3603,7 @@ class ChatActivity :
fun copyMessage(message: IMessage?) { fun copyMessage(message: IMessage?) {
val clipboardManager = val clipboardManager =
getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager getSystemService(CLIPBOARD_SERVICE) as ClipboardManager
val clipData = ClipData.newPlainText( val clipData = ClipData.newPlainText(
resources?.getString(R.string.nc_app_product_name), resources?.getString(R.string.nc_app_product_name),
message?.text message?.text
@ -3909,7 +3917,7 @@ class ChatActivity :
val isOlderThanSixHours = message val isOlderThanSixHours = message
.createdAt .createdAt
.before(Date(System.currentTimeMillis() - AGE_THRESHOLD_FOR_DELETE_MESSAGE)) .before(Date(System.currentTimeMillis() - AGE_THRESHOLD_FOR_DELETE_MESSAGE))
val hasDeleteMessagesUnlimitedCapability = CapabilitiesUtil.hasSpreedFeatureCapability( val hasDeleteMessagesUnlimitedCapability = hasSpreedFeatureCapability(
spreedCapabilities, spreedCapabilities,
SpreedFeatures.DELETE_MESSAGES_UNLIMITED SpreedFeatures.DELETE_MESSAGES_UNLIMITED
) )
@ -3919,7 +3927,7 @@ class ChatActivity :
!hasDeleteMessagesUnlimitedCapability && isOlderThanSixHours -> false !hasDeleteMessagesUnlimitedCapability && isOlderThanSixHours -> false
message.systemMessageType != ChatMessage.SystemMessageType.DUMMY -> false message.systemMessageType != ChatMessage.SystemMessageType.DUMMY -> false
message.isDeleted -> false message.isDeleted -> false
!CapabilitiesUtil.hasSpreedFeatureCapability(spreedCapabilities, SpreedFeatures.DELETE_MESSAGES) -> false !hasSpreedFeatureCapability(spreedCapabilities, SpreedFeatures.DELETE_MESSAGES) -> false
!participantPermissions.hasChatPermission() -> false !participantPermissions.hasChatPermission() -> false
hasDeleteMessagesUnlimitedCapability -> true hasDeleteMessagesUnlimitedCapability -> true
else -> true else -> true

View File

@ -16,7 +16,6 @@ import android.animation.AnimatorInflater
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.app.SearchManager import android.app.SearchManager
import android.content.ActivityNotFoundException import android.content.ActivityNotFoundException
import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.graphics.drawable.Drawable import android.graphics.drawable.Drawable
@ -41,6 +40,9 @@ import androidx.appcompat.app.AlertDialog
import androidx.appcompat.widget.SearchView import androidx.appcompat.widget.SearchView
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.ui.platform.ViewCompositionStrategy import androidx.compose.ui.platform.ViewCompositionStrategy
import androidx.core.content.pm.ShortcutInfoCompat
import androidx.core.content.pm.ShortcutManagerCompat
import androidx.core.graphics.drawable.IconCompat
import androidx.core.graphics.drawable.toDrawable import androidx.core.graphics.drawable.toDrawable
import androidx.core.net.toUri import androidx.core.net.toUri
import androidx.core.os.bundleOf import androidx.core.os.bundleOf
@ -409,6 +411,10 @@ class ConversationsListActivity :
conversationsListViewModel.getRoomsFlow conversationsListViewModel.getRoomsFlow
.onEach { list -> .onEach { list ->
setConversationList(list) setConversationList(list)
val noteToSelf = list
.firstOrNull { ConversationUtils.isNoteToSelfConversation(it) }
val isNoteToSelfAvailable = noteToSelf != null
handleNoteToSelfShortcut(isNoteToSelfAvailable, noteToSelf?.token ?: "")
}.collect() }.collect()
} }
@ -525,6 +531,30 @@ class ConversationsListActivity :
} }
} }
private fun handleNoteToSelfShortcut(noteToSelfAvailable: Boolean, noteToSelfToken: String) {
// Redundant operations just update the existing id
if (noteToSelfAvailable) {
val bundle = Bundle()
bundle.putString(KEY_ROOM_TOKEN, noteToSelfToken)
bundle.putBoolean(BundleKeys.KEY_FOCUS_INPUT, true)
val intent = Intent(context, ChatActivity::class.java)
intent.putExtras(bundle)
intent.action = Intent.ACTION_VIEW
val openNotesString = resources.getString(R.string.open_notes)
val shortcut = ShortcutInfoCompat.Builder(context, NOTE_TO_SELF_SHORTCUT_ID)
.setShortLabel(openNotesString)
.setLongLabel(openNotesString)
.setIcon(IconCompat.createWithResource(context, R.drawable.ic_pencil_grey600_24dp))
.setIntent(intent)
.build()
ShortcutManagerCompat.pushDynamicShortcut(context, shortcut)
} else {
ShortcutManagerCompat.removeDynamicShortcuts(context, listOf(NOTE_TO_SELF_SHORTCUT_ID))
}
}
private fun setConversationList(list: List<ConversationModel>) { private fun setConversationList(list: List<ConversationModel>) {
// Update Conversations // Update Conversations
conversationItems.clear() conversationItems.clear()
@ -640,7 +670,7 @@ class ConversationsListActivity :
} }
} }
val archiveFilterOn = filterState[ARCHIVE] ?: false val archiveFilterOn = filterState[ARCHIVE] == true
if (archiveFilterOn && newItems.isEmpty()) { if (archiveFilterOn && newItems.isEmpty()) {
binding.noArchivedConversationLayout.visibility = View.VISIBLE binding.noArchivedConversationLayout.visibility = View.VISIBLE
} else { } else {
@ -755,7 +785,7 @@ class ConversationsListActivity :
} }
private fun initSearchView() { private fun initSearchView() {
val searchManager = getSystemService(Context.SEARCH_SERVICE) as SearchManager? val searchManager = getSystemService(SEARCH_SERVICE) as SearchManager?
if (searchItem != null) { if (searchItem != null) {
searchView = MenuItemCompat.getActionView(searchItem) as SearchView searchView = MenuItemCompat.getActionView(searchItem) as SearchView
viewThemeUtils.talk.themeSearchView(searchView!!) viewThemeUtils.talk.themeSearchView(searchView!!)
@ -1217,7 +1247,7 @@ class ConversationsListActivity :
}) })
binding.recyclerView.setOnTouchListener { v: View, _: MotionEvent? -> binding.recyclerView.setOnTouchListener { v: View, _: MotionEvent? ->
if (!isDestroyed) { if (!isDestroyed) {
val imm = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager val imm = getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager
imm.hideSoftInputFromWindow(v.windowToken, 0) imm.hideSoftInputFromWindow(v.windowToken, 0)
} }
false false
@ -1398,7 +1428,7 @@ class ConversationsListActivity :
adapter?.updateDataSet(conversationItems) adapter?.updateDataSet(conversationItems)
adapter?.setFilter("") adapter?.setFilter("")
adapter?.filterItems() adapter?.filterItems()
val archiveFilterOn = filterState[ARCHIVE] ?: false val archiveFilterOn = filterState[ARCHIVE] == true
if (archiveFilterOn && adapter!!.isEmpty) { if (archiveFilterOn && adapter!!.isEmpty) {
binding.noArchivedConversationLayout.visibility = View.VISIBLE binding.noArchivedConversationLayout.visibility = View.VISIBLE
} else { } else {
@ -1809,7 +1839,7 @@ class ConversationsListActivity :
val callsChannelNotEnabled = !NotificationUtils.isCallsNotificationChannelEnabled(this) val callsChannelNotEnabled = !NotificationUtils.isCallsNotificationChannelEnabled(this)
val serverNotificationAppInstalled = val serverNotificationAppInstalled =
currentUser?.capabilities?.notificationsCapability?.features?.isNotEmpty() ?: false currentUser?.capabilities?.notificationsCapability?.features?.isNotEmpty() == true
val settingsOfUserAreWrong = notificationPermissionNotGranted || val settingsOfUserAreWrong = notificationPermissionNotGranted ||
batteryOptimizationNotIgnored || batteryOptimizationNotIgnored ||
@ -2183,5 +2213,6 @@ class ConversationsListActivity :
const val ROOM_TYPE_ONE_ONE = "1" const val ROOM_TYPE_ONE_ONE = "1"
private const val SIXTEEN_HOURS_IN_SECONDS: Long = 57600 private const val SIXTEEN_HOURS_IN_SECONDS: Long = 57600
const val LONG_1000: Long = 1000 const val LONG_1000: Long = 1000
private const val NOTE_TO_SELF_SHORTCUT_ID = "NOTE_TO_SELF_SHORTCUT_ID"
} }
} }

View File

@ -190,6 +190,7 @@ class FullScreenMediaActivity : AppCompatActivity() {
supportActionBar?.show() supportActionBar?.show()
} }
@OptIn(UnstableApi::class)
private fun applyWindowInsets() { private fun applyWindowInsets() {
val playerView = binding.playerView val playerView = binding.playerView
val exoControls = playerView.findViewById<FrameLayout>(R.id.exo_bottom_bar) val exoControls = playerView.findViewById<FrameLayout>(R.id.exo_bottom_bar)

View File

@ -6,14 +6,17 @@
*/ */
package com.nextcloud.talk.receivers package com.nextcloud.talk.receivers
import android.Manifest
import android.app.Notification import android.app.Notification
import android.app.NotificationManager import android.app.NotificationManager
import android.content.BroadcastReceiver import android.content.BroadcastReceiver
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.pm.PackageManager
import android.text.SpannableStringBuilder import android.text.SpannableStringBuilder
import android.text.style.ForegroundColorSpan import android.text.style.ForegroundColorSpan
import android.util.Log import android.util.Log
import androidx.core.app.ActivityCompat
import androidx.core.app.NotificationCompat import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat import androidx.core.app.NotificationManagerCompat
import androidx.core.app.Person import androidx.core.app.Person
@ -162,11 +165,17 @@ class DirectReplyReceiver : BroadcastReceiver() {
// Set the updated style // Set the updated style
previousBuilder.setStyle(previousStyle) previousBuilder.setStyle(previousStyle)
if (ActivityCompat.checkSelfPermission(
context,
Manifest.permission.POST_NOTIFICATIONS
) == PackageManager.PERMISSION_GRANTED
) {
// Check if notification still exists // Check if notification still exists
if (findActiveNotification(systemNotificationId!!) != null) { if (findActiveNotification(systemNotificationId!!) != null) {
NotificationManagerCompat.from(context).notify(systemNotificationId!!, previousBuilder.build()) NotificationManagerCompat.from(context).notify(systemNotificationId!!, previousBuilder.build())
} }
} }
}
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())
.subscribe() .subscribe()
} }

View File

@ -81,4 +81,5 @@ object BundleKeys {
const val KEY_FIELD_MAP: String = "KEY_FIELD_MAP" const val KEY_FIELD_MAP: String = "KEY_FIELD_MAP"
const val KEY_CHAT_URL: String = "KEY_CHAT_URL" const val KEY_CHAT_URL: String = "KEY_CHAT_URL"
const val KEY_SCROLL_TO_NOTIFICATION_CATEGORY: String = "KEY_SCROLL_TO_NOTIFICATION_CATEGORY" const val KEY_SCROLL_TO_NOTIFICATION_CATEGORY: String = "KEY_SCROLL_TO_NOTIFICATION_CATEGORY"
const val KEY_FOCUS_INPUT: String = "KEY_FOCUS_INPUT"
} }

View File

@ -521,6 +521,10 @@ How to translate with transifex:
<string name="nc_reply">Reply</string> <string name="nc_reply">Reply</string>
<string name="nc_reply_privately">Reply privately</string> <string name="nc_reply_privately">Reply privately</string>
<string name="nc_delete_message">Delete</string> <string name="nc_delete_message">Delete</string>
<plurals name="nc_conversation_auto_delete_notice">
<item quantity="one">This conversation will be automatically deleted for everyone in %1$d day of no activity</item>
<item quantity="other">This conversation will be automatically deleted for everyone in %1$d days of no activity</item>
</plurals>
<string name="nc_conversation_auto_delete_notice">This conversation will be automatically deleted for everyone in %1$d days of no activity</string> <string name="nc_conversation_auto_delete_notice">This conversation will be automatically deleted for everyone in %1$d days of no activity</string>
<string name="nc_delete_now">Delete now</string> <string name="nc_delete_now">Delete now</string>
<string name="nc_keep">Keep</string> <string name="nc_keep">Keep</string>
@ -860,4 +864,5 @@ How to translate with transifex:
<string name="unarchived_conversation">Unarchived %1$s</string> <string name="unarchived_conversation">Unarchived %1$s</string>
<string name="conversation_archived">Conversation is archived</string> <string name="conversation_archived">Conversation is archived</string>
<string name="local_time">Local time: %1$s</string> <string name="local_time">Local time: %1$s</string>
<string name="open_notes">Open Notes</string>
</resources> </resources>