diff --git a/.editorconfig b/.editorconfig
index 1606d61f..697c8a67 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -1,9 +1,3 @@
-# Copying and distribution of this file, with or without modification,
-# are permitted in any medium without royalty provided this notice is
-# preserved. This file is offered as-is, without any warranty.
-# Names of contributors must not be used to endorse or promote products
-# derived from this file without specific prior written permission.
-
# EditorConfig
# http://EditorConfig.org
@@ -17,7 +11,12 @@ insert_final_newline = true
charset = utf-8
indent_style = space
indent_size = 4
-continuation_indent_size = 8
+continuation_indent_size = 4
+max_line_length = 160
[*.xml]
continuation_indent_size = 4
+
+[*.kt]
+ij_kotlin_name_count_to_use_star_import = 5
+ij_kotlin_name_count_to_use_star_import_for_members = 5
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 6830fd49..0f7b11cc 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,56 @@
Changelog
==========
+Version 5.9.4 *(2021-05-23)*
+----------------------------
+
+ * Adding some UX, stability and translation improvements
+
+Version 5.9.3 *(2021-04-15)*
+----------------------------
+
+ * Fixed a glitch with current conversation not being updated correctly at incoming messages
+ * Couple other stability, translation and bugfixes
+
+Version 5.9.2 *(2021-03-22)*
+----------------------------
+
+ * Fixed an error message wrongly popping up in some cases
+ * Some stabiliy and translation improvements
+
+Version 5.9.1 *(2021-03-15)*
+----------------------------
+
+ * Improved search
+ * Properly handle sending messages from notification Reply action
+ * Some design, stability and translation improvements
+
+Version 5.9.0 *(2021-02-16)*
+----------------------------
+
+ * Added Search
+ * Added a White theme with special handling
+ * Some stability and translation improvements
+
+Version 5.8.3 *(2021-01-27)*
+----------------------------
+
+ * Adding some stability and translation improvements
+
+Version 5.8.2 *(2021-01-18)*
+----------------------------
+
+ * Fixed a glitch with inability to send messages in empty conversations
+ * Adding a settings item for quickly getting into notification settings
+ * Some stability and translation improvements
+
+Version 5.8.1 *(2021-01-11)*
+----------------------------
+
+ * Fixed a glitch with "Sending..." stuck at messages
+ * Allow selecting a phone numbers at contacts with multiple ones
+ * Some translation and stability improvements
+
Version 5.8.0 *(2021-01-02)*
----------------------------
diff --git a/README.md b/README.md
index 6ab5c2c8..34019b8a 100644
--- a/README.md
+++ b/README.md
@@ -11,20 +11,21 @@ It comes with material design and dark theme by default, provides great user exp
Contains no ads or unnecessary permissions. It is fully opensource, provides customizable colors.
-Check out the full suite of Simple Tools here:
+Check out the full suite of Simple Tools here:
https://www.simplemobiletools.com
-Facebook:
+Facebook:
https://www.facebook.com/simplemobiletools
-Reddit:
+Reddit:
https://www.reddit.com/r/SimpleMobileTools
diff --git a/app/build.gradle b/app/build.gradle
index 91ee3631..d6947337 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -16,8 +16,8 @@ android {
applicationId "com.simplemobiletools.smsmessenger"
minSdkVersion 22
targetSdkVersion 30
- versionCode 25
- versionName "5.8.0"
+ versionCode 34
+ versionName "5.9.4"
setProperty("archivesBaseName", "sms-messenger")
}
@@ -56,14 +56,14 @@ android {
}
dependencies {
- implementation 'com.simplemobiletools:commons:5.32.20'
+ implementation 'com.github.SimpleMobileTools:Simple-Commons:203ed6018e'
implementation 'org.greenrobot:eventbus:3.2.0'
implementation 'com.klinkerapps:android-smsmms:5.2.6'
- implementation 'com.github.tibbi:IndicatorFastScroll:08f512858a'
+ implementation 'com.github.tibbi:IndicatorFastScroll:c3de1d040a'
implementation "me.leolin:ShortcutBadger:1.1.22"
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0'
- kapt "androidx.room:room-compiler:2.2.6"
- implementation "androidx.room:room-runtime:2.2.6"
- annotationProcessor "androidx.room:room-compiler:2.2.6"
+ kapt "androidx.room:room-compiler:2.3.0"
+ implementation "androidx.room:room-runtime:2.3.0"
+ annotationProcessor "androidx.room:room-compiler:2.3.0"
}
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 2e542b99..a40d3d85 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -13,11 +13,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/activities/MainActivity.kt b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/activities/MainActivity.kt
index 58550850..513e50ac 100644
--- a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/activities/MainActivity.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/activities/MainActivity.kt
@@ -100,11 +100,13 @@ class MainActivity : SimpleActivity() {
override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.menu_main, menu)
+ updateMenuItemColors(menu)
return true
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
+ R.id.search -> launchSearch()
R.id.settings -> launchSettings()
R.id.about -> launchAbout()
else -> return super.onOptionsItemSelected(item)
@@ -182,7 +184,7 @@ class MainActivity : SimpleActivity() {
}
private fun getNewConversations(cachedConversations: ArrayList) {
- val privateCursor = getMyContactsCursor()?.loadInBackground()
+ val privateCursor = getMyContactsCursor(false, true)?.loadInBackground()
ensureBackgroundThread {
val privateContacts = MyContactsContentProvider.getSimpleContacts(this, privateCursor)
val conversations = getConversations(privateContacts = privateContacts)
@@ -245,6 +247,7 @@ class MainActivity : SimpleActivity() {
conversations_list.adapter = this
}
+ conversations_list.scheduleLayoutAnimation()
conversations_fastscroller.setViews(conversations_list) {
val listItem = (conversations_list.adapter as? ConversationsAdapter)?.conversations?.getOrNull(it)
conversations_fastscroller.updateBubbleText(listItem?.title ?: "")
@@ -295,6 +298,10 @@ class MainActivity : SimpleActivity() {
.build()
}
+ private fun launchSearch() {
+ startActivity(Intent(applicationContext, SearchActivity::class.java))
+ }
+
private fun launchSettings() {
startActivity(Intent(applicationContext, SettingsActivity::class.java))
}
diff --git a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/activities/NewConversationActivity.kt b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/activities/NewConversationActivity.kt
index ae831c2e..4b226365 100644
--- a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/activities/NewConversationActivity.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/activities/NewConversationActivity.kt
@@ -7,8 +7,10 @@ import android.view.Menu
import android.view.WindowManager
import com.google.gson.Gson
import com.reddit.indicatorfastscroll.FastScrollItemIndicator
+import com.simplemobiletools.commons.dialogs.RadioGroupDialog
import com.simplemobiletools.commons.extensions.*
import com.simplemobiletools.commons.helpers.*
+import com.simplemobiletools.commons.models.RadioItem
import com.simplemobiletools.commons.models.SimpleContact
import com.simplemobiletools.smsmessenger.R
import com.simplemobiletools.smsmessenger.adapters.ContactsAdapter
@@ -62,7 +64,10 @@ class NewConversationActivity : SimpleActivity() {
val searchString = it
val filteredContacts = ArrayList()
allContacts.forEach {
- if (it.phoneNumbers.any { it.contains(searchString, true) } || it.name.contains(searchString, true)) {
+ if (it.phoneNumbers.any { it.contains(searchString, true) } ||
+ it.name.contains(searchString, true) ||
+ it.name.contains(searchString.normalizeString(), true) ||
+ it.name.normalizeString().contains(searchString, true)) {
filteredContacts.add(it)
}
}
@@ -87,9 +92,12 @@ class NewConversationActivity : SimpleActivity() {
}
}
+ val adjustedPrimaryColor = getAdjustedPrimaryColor()
contacts_letter_fastscroller.textColor = config.textColor.getColorStateList()
+ contacts_letter_fastscroller.pressedTextColor = adjustedPrimaryColor
contacts_letter_fastscroller_thumb.setupWithFastScroller(contacts_letter_fastscroller)
- contacts_letter_fastscroller_thumb.textColor = config.primaryColor.getContrastColor()
+ contacts_letter_fastscroller_thumb?.textColor = adjustedPrimaryColor.getContrastColor()
+ contacts_letter_fastscroller_thumb?.thumbColor = adjustedPrimaryColor.getColorStateList()
}
private fun isThirdPartyIntent(): Boolean {
@@ -130,18 +138,38 @@ class NewConversationActivity : SimpleActivity() {
no_contacts_placeholder.text = getString(placeholderText)
}
- ContactsAdapter(this, contacts, contacts_list, null) {
- hideKeyboard()
- launchThreadActivity((it as SimpleContact).phoneNumbers.first(), it.name)
- }.apply {
- contacts_list.adapter = this
+ val currAdapter = contacts_list.adapter
+ if (currAdapter == null) {
+ ContactsAdapter(this, contacts, contacts_list, null) {
+ hideKeyboard()
+ val contact = it as SimpleContact
+ val phoneNumbers = contact.phoneNumbers
+ if (phoneNumbers.size > 1) {
+ val items = ArrayList()
+ phoneNumbers.forEachIndexed { index, phoneNumber ->
+ items.add(RadioItem(index, phoneNumber, phoneNumber))
+ }
+
+ RadioGroupDialog(this, items) {
+ launchThreadActivity(it as String, contact.name)
+ }
+ } else {
+ launchThreadActivity(phoneNumbers.first(), contact.name)
+ }
+ }.apply {
+ contacts_list.adapter = this
+ }
+
+ contacts_list.scheduleLayoutAnimation()
+ } else {
+ (currAdapter as ContactsAdapter).updateContacts(contacts)
}
setupLetterFastscroller(contacts)
}
private fun fillSuggestedContacts(callback: () -> Unit) {
- val privateCursor = getMyContactsCursor()?.loadInBackground()
+ val privateCursor = getMyContactsCursor(false, true)?.loadInBackground()
ensureBackgroundThread {
privateContacts = MyContactsContentProvider.getSimpleContacts(this, privateCursor)
val suggestions = getSuggestedContacts(privateContacts)
@@ -179,7 +207,7 @@ class NewConversationActivity : SimpleActivity() {
try {
val name = contacts[position].name
val character = if (name.isNotEmpty()) name.substring(0, 1) else ""
- FastScrollItemIndicator.Text(character.toUpperCase(Locale.getDefault()))
+ FastScrollItemIndicator.Text(character.toUpperCase(Locale.getDefault()).normalizeString())
} catch (e: Exception) {
FastScrollItemIndicator.Text("")
}
diff --git a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/activities/SearchActivity.kt b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/activities/SearchActivity.kt
new file mode 100644
index 00000000..a3ea9ad5
--- /dev/null
+++ b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/activities/SearchActivity.kt
@@ -0,0 +1,146 @@
+package com.simplemobiletools.smsmessenger.activities
+
+import android.annotation.SuppressLint
+import android.app.SearchManager
+import android.content.Context
+import android.content.Intent
+import android.os.Bundle
+import android.text.TextUtils
+import android.util.TypedValue
+import android.view.Menu
+import android.view.MenuItem
+import androidx.appcompat.widget.SearchView
+import androidx.core.view.MenuItemCompat
+import com.simplemobiletools.commons.extensions.*
+import com.simplemobiletools.commons.helpers.ensureBackgroundThread
+import com.simplemobiletools.smsmessenger.R
+import com.simplemobiletools.smsmessenger.adapters.SearchResultsAdapter
+import com.simplemobiletools.smsmessenger.extensions.conversationsDB
+import com.simplemobiletools.smsmessenger.extensions.messagesDB
+import com.simplemobiletools.smsmessenger.helpers.SEARCHED_MESSAGE_ID
+import com.simplemobiletools.smsmessenger.helpers.THREAD_ID
+import com.simplemobiletools.smsmessenger.helpers.THREAD_TITLE
+import com.simplemobiletools.smsmessenger.models.Conversation
+import com.simplemobiletools.smsmessenger.models.Message
+import com.simplemobiletools.smsmessenger.models.SearchResult
+import kotlinx.android.synthetic.main.activity_search.*
+
+class SearchActivity : SimpleActivity() {
+ private var mIsSearchOpen = false
+ private var mLastSearchedText = ""
+ private var mSearchMenuItem: MenuItem? = null
+
+ @SuppressLint("InlinedApi")
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_search)
+ updateTextColors(search_holder)
+ search_placeholder.setTextSize(TypedValue.COMPLEX_UNIT_PX, getTextSize())
+ search_placeholder_2.setTextSize(TypedValue.COMPLEX_UNIT_PX, getTextSize())
+ }
+
+ override fun onCreateOptionsMenu(menu: Menu): Boolean {
+ menuInflater.inflate(R.menu.menu_search, menu)
+ setupSearch(menu)
+ return true
+ }
+
+ private fun setupSearch(menu: Menu) {
+ val searchManager = getSystemService(Context.SEARCH_SERVICE) as SearchManager
+ mSearchMenuItem = menu.findItem(R.id.search)
+
+ MenuItemCompat.setOnActionExpandListener(mSearchMenuItem, object : MenuItemCompat.OnActionExpandListener {
+ override fun onMenuItemActionExpand(item: MenuItem?): Boolean {
+ mIsSearchOpen = true
+ return true
+ }
+
+ // this triggers on device rotation too, avoid doing anything
+ override fun onMenuItemActionCollapse(item: MenuItem?): Boolean {
+ if (mIsSearchOpen) {
+ mIsSearchOpen = false
+ mLastSearchedText = ""
+ finish()
+ }
+ return true
+ }
+ })
+
+ mSearchMenuItem?.expandActionView()
+ (mSearchMenuItem?.actionView as? SearchView)?.apply {
+ setSearchableInfo(searchManager.getSearchableInfo(componentName))
+ isSubmitButtonEnabled = false
+ setOnQueryTextListener(object : SearchView.OnQueryTextListener {
+ override fun onQueryTextSubmit(query: String) = false
+
+ override fun onQueryTextChange(newText: String): Boolean {
+ if (mIsSearchOpen) {
+ mLastSearchedText = newText
+ textChanged(newText)
+ }
+ return true
+ }
+ })
+ }
+ }
+
+ private fun textChanged(text: String) {
+ search_placeholder_2.beGoneIf(text.length >= 2)
+ if (text.length >= 2) {
+ ensureBackgroundThread {
+ val searchQuery = "%$text%"
+ val messages = messagesDB.getMessagesWithText(searchQuery)
+ val conversations = conversationsDB.getConversationsWithText(searchQuery)
+ if (text == mLastSearchedText) {
+ showSearchResults(messages, conversations, text)
+
+ }
+ }
+ } else {
+ search_placeholder.beVisible()
+ search_results_list.beGone()
+ }
+ }
+
+ private fun showSearchResults(messages: List, conversations: List, searchedText: String) {
+ val searchResults = ArrayList()
+ conversations.forEach { conversation ->
+ val date = conversation.date.formatDateOrTime(this, true, true)
+ val searchResult = SearchResult(-1, conversation.title, conversation.phoneNumber, date, conversation.threadId, conversation.photoUri)
+ searchResults.add(searchResult)
+ }
+
+ messages.forEach { message ->
+ var recipient = message.senderName
+ if (recipient.isEmpty() && message.participants.isNotEmpty()) {
+ val participantNames = message.participants.map { it.name }
+ recipient = TextUtils.join(", ", participantNames)
+ }
+
+ val date = message.date.formatDateOrTime(this, true, true)
+ val searchResult = SearchResult(message.id, recipient, message.body, date, message.threadId, message.senderPhotoUri)
+ searchResults.add(searchResult)
+ }
+
+ runOnUiThread {
+ search_results_list.beVisibleIf(searchResults.isNotEmpty())
+ search_placeholder.beVisibleIf(searchResults.isEmpty())
+
+ val currAdapter = search_results_list.adapter
+ if (currAdapter == null) {
+ SearchResultsAdapter(this, searchResults, search_results_list, searchedText) {
+ Intent(this, ThreadActivity::class.java).apply {
+ putExtra(THREAD_ID, (it as SearchResult).threadId)
+ putExtra(THREAD_TITLE, it.title)
+ putExtra(SEARCHED_MESSAGE_ID, it.messageId)
+ startActivity(this)
+ }
+ }.apply {
+ search_results_list.adapter = this
+ }
+ } else {
+ (currAdapter as SearchResultsAdapter).updateItems(searchResults, searchedText)
+ }
+ }
+ }
+}
diff --git a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/activities/SettingsActivity.kt b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/activities/SettingsActivity.kt
index b421f16d..9617b5a1 100644
--- a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/activities/SettingsActivity.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/activities/SettingsActivity.kt
@@ -34,6 +34,7 @@ class SettingsActivity : SimpleActivity() {
setupPurchaseThankYou()
setupCustomizeColors()
+ setupCustomizeNotifications()
setupUseEnglish()
setupManageBlockedNumbers()
setupChangeDateTimeFormat()
@@ -71,6 +72,13 @@ class SettingsActivity : SimpleActivity() {
}
}
+ private fun setupCustomizeNotifications() {
+ settings_customize_notifications_holder.beVisibleIf(isOreoPlus())
+ settings_customize_notifications_holder.setOnClickListener {
+ launchCustomizeNotificationsIntent()
+ }
+ }
+
private fun setupUseEnglish() {
settings_use_english_holder.beVisibleIf(config.wasUseEnglishToggled || Locale.getDefault().language != "en")
settings_use_english.isChecked = config.useEnglish
diff --git a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/activities/ThreadActivity.kt b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/activities/ThreadActivity.kt
index 881af882..5e601968 100644
--- a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/activities/ThreadActivity.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/activities/ThreadActivity.kt
@@ -5,6 +5,7 @@ import android.app.Activity
import android.content.Intent
import android.graphics.BitmapFactory
import android.graphics.drawable.Drawable
+import android.graphics.drawable.LayerDrawable
import android.media.MediaMetadataRetriever
import android.net.Uri
import android.os.Bundle
@@ -88,6 +89,15 @@ class ThreadActivity : SimpleActivity() {
if (it) {
setupButtons()
setupCachedMessages {
+ val searchedMessageId = intent.getLongExtra(SEARCHED_MESSAGE_ID, -1L)
+ intent.removeExtra(SEARCHED_MESSAGE_ID)
+ if (searchedMessageId != -1L) {
+ val index = threadItems.indexOfFirst { (it as? Message)?.id == searchedMessageId }
+ if (index != -1) {
+ thread_messages_list.smoothScrollToPosition(index)
+ }
+ }
+
setupThread()
}
} else {
@@ -106,13 +116,83 @@ class ThreadActivity : SimpleActivity() {
isActivityVisible = false
}
- private fun setupThread() {
- val privateCursor = getMyContactsCursor()?.loadInBackground()
+ override fun onDestroy() {
+ super.onDestroy()
+ bus?.unregister(this)
+ }
+
+ override fun onCreateOptionsMenu(menu: Menu): Boolean {
+ menuInflater.inflate(R.menu.menu_thread, menu)
+ menu.apply {
+ findItem(R.id.delete).isVisible = threadItems.isNotEmpty()
+ findItem(R.id.block_number).isVisible = isNougatPlus()
+ }
+
+ updateMenuItemColors(menu)
+ return true
+ }
+
+ override fun onOptionsItemSelected(item: MenuItem): Boolean {
+ if (participants.isEmpty()) {
+ return true
+ }
+
+ when (item.itemId) {
+ R.id.block_number -> blockNumber()
+ R.id.delete -> askConfirmDelete()
+ R.id.manage_people -> managePeople()
+ R.id.mark_as_unread -> markAsUnread()
+ else -> return super.onOptionsItemSelected(item)
+ }
+ return true
+ }
+
+ override fun onActivityResult(requestCode: Int, resultCode: Int, resultData: Intent?) {
+ super.onActivityResult(requestCode, resultCode, resultData)
+ if (requestCode == PICK_ATTACHMENT_INTENT && resultCode == Activity.RESULT_OK && resultData != null && resultData.data != null) {
+ addAttachment(resultData.data!!)
+ }
+ }
+
+ private fun setupCachedMessages(callback: () -> Unit) {
ensureBackgroundThread {
- val cachedMessagesCode = messages.hashCode()
+ messages = try {
+ messagesDB.getThreadMessages(threadId).toMutableList() as ArrayList
+ } catch (e: Exception) {
+ ArrayList()
+ }
+
+ setupParticipants()
+ setupAdapter()
+
+ runOnUiThread {
+ if (messages.isEmpty()) {
+ window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE)
+ thread_type_message.requestFocus()
+ }
+
+ setupThreadTitle()
+ setupSIMSelector()
+ callback()
+ }
+ }
+ }
+
+ private fun setupThread() {
+ val privateCursor = getMyContactsCursor(false, true)?.loadInBackground()
+ ensureBackgroundThread {
+ val cachedMessagesCode = messages.clone().hashCode()
messages = getMessages(threadId)
- if (messages.hashCode() == cachedMessagesCode) {
- return@ensureBackgroundThread
+
+ val hasParticipantWithoutName = participants.any {
+ it.phoneNumbers.contains(it.name)
+ }
+
+ try {
+ if (participants.isNotEmpty() && messages.hashCode() == cachedMessagesCode && !hasParticipantWithoutName) {
+ return@ensureBackgroundThread
+ }
+ } catch (ignored: Exception) {
}
setupParticipants()
@@ -162,63 +242,6 @@ class ThreadActivity : SimpleActivity() {
}
}
- override fun onDestroy() {
- super.onDestroy()
- bus?.unregister(this)
- }
-
- override fun onCreateOptionsMenu(menu: Menu): Boolean {
- menuInflater.inflate(R.menu.menu_thread, menu)
- menu.apply {
- findItem(R.id.delete).isVisible = threadItems.isNotEmpty()
- findItem(R.id.block_number).isVisible = isNougatPlus()
- }
-
- updateMenuItemColors(menu)
- return true
- }
-
- override fun onOptionsItemSelected(item: MenuItem): Boolean {
- if (participants.isEmpty()) {
- return true
- }
-
- when (item.itemId) {
- R.id.block_number -> blockNumber()
- R.id.delete -> askConfirmDelete()
- R.id.manage_people -> managePeople()
- R.id.mark_as_unread -> markAsUnread()
- else -> return super.onOptionsItemSelected(item)
- }
- return true
- }
-
- override fun onActivityResult(requestCode: Int, resultCode: Int, resultData: Intent?) {
- super.onActivityResult(requestCode, resultCode, resultData)
- if (requestCode == PICK_ATTACHMENT_INTENT && resultCode == Activity.RESULT_OK && resultData != null && resultData.data != null) {
- addAttachment(resultData.data!!)
- }
- }
-
- private fun setupCachedMessages(callback: () -> Unit) {
- ensureBackgroundThread {
- messages = messagesDB.getThreadMessages(threadId).toMutableList() as ArrayList
- setupParticipants()
- setupAdapter()
-
- runOnUiThread {
- if (messages.isEmpty()) {
- window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE)
- thread_type_message.requestFocus()
- }
-
- setupThreadTitle()
- setupSIMSelector()
- callback()
- }
- }
- }
-
private fun setupAdapter() {
threadItems = getThreadItems()
invalidateOptionsMenu()
@@ -458,11 +481,20 @@ class ThreadActivity : SimpleActivity() {
}
private fun showSelectedContacts() {
+ val adjustedColor = getAdjustedPrimaryColor()
+
val views = ArrayList()
participants.forEach {
val contact = it
layoutInflater.inflate(R.layout.item_selected_contact, null).apply {
+ val selectedContactBg = resources.getDrawable(R.drawable.item_selected_contact_background)
+ (selectedContactBg as LayerDrawable).findDrawableByLayerId(R.id.selected_contact_bg).applyColorFilter(adjustedColor)
+ selected_contact_holder.background = selectedContactBg
+
selected_contact_name.text = contact.name
+ selected_contact_name.setTextColor(adjustedColor.getContrastColor())
+ selected_contact_remove.applyColorFilter(adjustedColor.getContrastColor())
+
selected_contact_remove.setOnClickListener {
if (contact.rawId != participants.first().rawId) {
removeSelectedContact(contact.rawId)
@@ -514,7 +546,7 @@ class ThreadActivity : SimpleActivity() {
var hadUnreadItems = false
val cnt = messages.size
for (i in 0 until cnt) {
- val message = messages[i]
+ val message = messages.getOrNull(i) ?: continue
// do not show the date/time above every message, only if the difference between the 2 messages is at least MIN_DATE_TIME_DIFF_SECS
if (message.date - prevDateTime > MIN_DATE_TIME_DIFF_SECS) {
val simCardID = subscriptionIdToSimId[message.subscriptionId] ?: "?"
diff --git a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/adapters/AutoCompleteTextViewAdapter.kt b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/adapters/AutoCompleteTextViewAdapter.kt
index 445c8294..13199da6 100644
--- a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/adapters/AutoCompleteTextViewAdapter.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/adapters/AutoCompleteTextViewAdapter.kt
@@ -5,35 +5,46 @@ import android.view.View
import android.view.ViewGroup
import android.widget.ArrayAdapter
import android.widget.Filter
+import android.widget.RelativeLayout
import android.widget.TextView
+import com.simplemobiletools.commons.extensions.darkenColor
+import com.simplemobiletools.commons.extensions.getContrastColor
import com.simplemobiletools.commons.extensions.normalizeString
import com.simplemobiletools.commons.helpers.SimpleContactsHelper
import com.simplemobiletools.commons.models.SimpleContact
import com.simplemobiletools.smsmessenger.R
import com.simplemobiletools.smsmessenger.activities.SimpleActivity
+import com.simplemobiletools.smsmessenger.extensions.config
class AutoCompleteTextViewAdapter(val activity: SimpleActivity, val contacts: ArrayList) : ArrayAdapter(activity, 0, contacts) {
var resultList = ArrayList()
override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
- val contact = resultList[position]
+ val contact = resultList.getOrNull(position)
var listItem = convertView
- if (listItem == null || listItem.tag != contact.name.isNotEmpty()) {
+ if (listItem == null || listItem.tag != contact?.name?.isNotEmpty()) {
listItem = LayoutInflater.from(activity).inflate(R.layout.item_contact_with_number, parent, false)
}
listItem!!.apply {
- tag = contact.name.isNotEmpty()
+ tag = contact?.name?.isNotEmpty()
// clickable and focusable properties seem to break Autocomplete clicking, so remove them
findViewById(R.id.item_contact_frame).apply {
isClickable = false
isFocusable = false
}
- findViewById(R.id.item_contact_name).text = contact.name
- findViewById(R.id.item_contact_number).text = contact.phoneNumbers.first()
+ val backgroundColor = activity.config.backgroundColor
+ findViewById(R.id.item_contact_holder).setBackgroundColor(backgroundColor.darkenColor())
- SimpleContactsHelper(context).loadContactImage(contact.photoUri, findViewById(R.id.item_contact_image), contact.name)
+ findViewById(R.id.item_contact_name).setTextColor(backgroundColor.getContrastColor())
+ findViewById(R.id.item_contact_number).setTextColor(backgroundColor.getContrastColor())
+
+ if (contact != null) {
+ findViewById(R.id.item_contact_name).text = contact.name
+ findViewById(R.id.item_contact_number).text = contact.phoneNumbers.first()
+ SimpleContactsHelper(context).loadContactImage(contact.photoUri, findViewById(R.id.item_contact_image), contact.name)
+ }
}
return listItem
diff --git a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/adapters/ContactsAdapter.kt b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/adapters/ContactsAdapter.kt
index b6d41b29..1f48eb53 100644
--- a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/adapters/ContactsAdapter.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/adapters/ContactsAdapter.kt
@@ -17,8 +17,10 @@ import com.simplemobiletools.smsmessenger.R
import com.simplemobiletools.smsmessenger.activities.SimpleActivity
import java.util.*
-class ContactsAdapter(activity: SimpleActivity, var contacts: ArrayList, recyclerView: MyRecyclerView, fastScroller: FastScroller?,
- itemClick: (Any) -> Unit) : MyRecyclerViewAdapter(activity, recyclerView, fastScroller, itemClick) {
+class ContactsAdapter(
+ activity: SimpleActivity, var contacts: ArrayList, recyclerView: MyRecyclerView, fastScroller: FastScroller?,
+ itemClick: (Any) -> Unit
+) : MyRecyclerViewAdapter(activity, recyclerView, fastScroller, itemClick) {
private var fontSize = activity.getTextSize()
override fun getActionMenuId() = 0
@@ -51,10 +53,12 @@ class ContactsAdapter(activity: SimpleActivity, var contacts: ArrayList(R.id.item_contact_image))
+ fun updateContacts(newContacts: ArrayList) {
+ val oldHashCode = contacts.hashCode()
+ val newHashCode = newContacts.hashCode()
+ if (newHashCode != oldHashCode) {
+ contacts = newContacts
+ notifyDataSetChanged()
}
}
@@ -75,4 +79,11 @@ class ContactsAdapter(activity: SimpleActivity, var contacts: ArrayList(R.id.item_contact_image))
+ }
+ }
}
diff --git a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/adapters/ConversationsAdapter.kt b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/adapters/ConversationsAdapter.kt
index 8b1de0ca..c895ea85 100644
--- a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/adapters/ConversationsAdapter.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/adapters/ConversationsAdapter.kt
@@ -1,5 +1,6 @@
package com.simplemobiletools.smsmessenger.adapters
+import android.content.ActivityNotFoundException
import android.content.Intent
import android.graphics.Typeface
import android.net.Uri
@@ -26,8 +27,10 @@ import com.simplemobiletools.smsmessenger.helpers.refreshMessages
import com.simplemobiletools.smsmessenger.models.Conversation
import kotlinx.android.synthetic.main.item_conversation.view.*
-class ConversationsAdapter(activity: SimpleActivity, var conversations: ArrayList, recyclerView: MyRecyclerView, fastScroller: FastScroller,
- itemClick: (Any) -> Unit) : MyRecyclerViewAdapter(activity, recyclerView, fastScroller, itemClick) {
+class ConversationsAdapter(
+ activity: SimpleActivity, var conversations: ArrayList, recyclerView: MyRecyclerView, fastScroller: FastScroller,
+ itemClick: (Any) -> Unit
+) : MyRecyclerViewAdapter(activity, recyclerView, fastScroller, itemClick) {
private var fontSize = activity.getTextSize()
init {
@@ -120,11 +123,13 @@ class ConversationsAdapter(activity: SimpleActivity, var conversations: ArrayLis
Intent(Intent.ACTION_DIAL).apply {
data = Uri.fromParts("tel", conversation.phoneNumber, null)
- if (resolveActivity(activity.packageManager) != null) {
+ try {
activity.startActivity(this)
finishActMode()
- } else {
+ } catch (e: ActivityNotFoundException) {
activity.toast(R.string.no_app_found)
+ } catch (e: Exception) {
+ activity.showErrorToast(e)
}
}
}
@@ -185,12 +190,7 @@ class ConversationsAdapter(activity: SimpleActivity, var conversations: ArrayLis
action = Intent.ACTION_INSERT_OR_EDIT
type = "vnd.android.cursor.item/contact"
putExtra(KEY_PHONE, conversation.phoneNumber)
-
- if (resolveActivity(activity.packageManager) != null) {
- activity.startActivity(this)
- } else {
- activity.toast(R.string.no_app_found)
- }
+ activity.launchActivityIntent(this)
}
}
@@ -209,10 +209,11 @@ class ConversationsAdapter(activity: SimpleActivity, var conversations: ArrayLis
}
fun updateConversations(newConversations: ArrayList) {
+ val latestConversations = newConversations.clone() as ArrayList
val oldHashCode = conversations.hashCode()
- val newHashCode = newConversations.hashCode()
+ val newHashCode = latestConversations.hashCode()
if (newHashCode != oldHashCode) {
- conversations = newConversations
+ conversations = latestConversations
notifyDataSetChanged()
}
}
@@ -232,7 +233,7 @@ class ConversationsAdapter(activity: SimpleActivity, var conversations: ArrayLis
}
conversation_date.apply {
- text = conversation.date.formatDateOrTime(context, true)
+ text = conversation.date.formatDateOrTime(context, true, false)
setTextSize(TypedValue.COMPLEX_UNIT_PX, fontSize * 0.8f)
}
diff --git a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/adapters/SearchResultsAdapter.kt b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/adapters/SearchResultsAdapter.kt
new file mode 100644
index 00000000..01df81e2
--- /dev/null
+++ b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/adapters/SearchResultsAdapter.kt
@@ -0,0 +1,96 @@
+package com.simplemobiletools.smsmessenger.adapters
+
+import android.util.TypedValue
+import android.view.Menu
+import android.view.View
+import android.view.ViewGroup
+import com.bumptech.glide.Glide
+import com.simplemobiletools.commons.adapters.MyRecyclerViewAdapter
+import com.simplemobiletools.commons.extensions.getTextSize
+import com.simplemobiletools.commons.extensions.highlightTextPart
+import com.simplemobiletools.commons.helpers.SimpleContactsHelper
+import com.simplemobiletools.commons.views.MyRecyclerView
+import com.simplemobiletools.smsmessenger.R
+import com.simplemobiletools.smsmessenger.activities.SimpleActivity
+import com.simplemobiletools.smsmessenger.models.SearchResult
+import kotlinx.android.synthetic.main.item_search_result.view.*
+import java.util.*
+
+class SearchResultsAdapter(
+ activity: SimpleActivity, var searchResults: ArrayList, recyclerView: MyRecyclerView, highlightText: String, itemClick: (Any) -> Unit
+) : MyRecyclerViewAdapter(activity, recyclerView, null, itemClick) {
+
+ private var fontSize = activity.getTextSize()
+ private var textToHighlight = highlightText
+
+ override fun getActionMenuId() = 0
+
+ override fun prepareActionMode(menu: Menu) {}
+
+ override fun actionItemPressed(id: Int) {}
+
+ override fun getSelectableItemCount() = searchResults.size
+
+ override fun getIsItemSelectable(position: Int) = false
+
+ override fun getItemSelectionKey(position: Int) = searchResults.getOrNull(position)?.hashCode()
+
+ override fun getItemKeyPosition(key: Int) = searchResults.indexOfFirst { it.hashCode() == key }
+
+ override fun onActionModeCreated() {}
+
+ override fun onActionModeDestroyed() {}
+
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = createViewHolder(R.layout.item_search_result, parent)
+
+ override fun onBindViewHolder(holder: ViewHolder, position: Int) {
+ val searchResult = searchResults[position]
+ holder.bindView(searchResult, true, false) { itemView, layoutPosition ->
+ setupView(itemView, searchResult)
+ }
+ bindViewHolder(holder)
+ }
+
+ override fun getItemCount() = searchResults.size
+
+ fun updateItems(newItems: ArrayList, highlightText: String = "") {
+ if (newItems.hashCode() != searchResults.hashCode()) {
+ searchResults = newItems.clone() as ArrayList
+ textToHighlight = highlightText
+ notifyDataSetChanged()
+ } else if (textToHighlight != highlightText) {
+ textToHighlight = highlightText
+ notifyDataSetChanged()
+ }
+ }
+
+ private fun setupView(view: View, searchResult: SearchResult) {
+ view.apply {
+ search_result_title.apply {
+ text = searchResult.title.highlightTextPart(textToHighlight, adjustedPrimaryColor)
+ setTextColor(textColor)
+ setTextSize(TypedValue.COMPLEX_UNIT_PX, fontSize * 1.2f)
+ }
+
+ search_result_snippet.apply {
+ text = searchResult.snippet.highlightTextPart(textToHighlight, adjustedPrimaryColor)
+ setTextColor(textColor)
+ setTextSize(TypedValue.COMPLEX_UNIT_PX, fontSize * 0.9f)
+ }
+
+ search_result_date.apply {
+ text = searchResult.date
+ setTextSize(TypedValue.COMPLEX_UNIT_PX, fontSize * 0.8f)
+ }
+
+ SimpleContactsHelper(context).loadContactImage(searchResult.photoUri, search_result_image, searchResult.title)
+ }
+ }
+
+ override fun onViewRecycled(holder: ViewHolder) {
+ super.onViewRecycled(holder)
+ if (!activity.isDestroyed && !activity.isFinishing && holder.itemView.search_result_image != null) {
+ Glide.with(activity).clear(holder.itemView.search_result_image)
+ }
+ }
+}
diff --git a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/adapters/ThreadAdapter.kt b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/adapters/ThreadAdapter.kt
index 8c6ae60b..63b0abac 100644
--- a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/adapters/ThreadAdapter.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/adapters/ThreadAdapter.kt
@@ -1,6 +1,7 @@
package com.simplemobiletools.smsmessenger.adapters
import android.annotation.SuppressLint
+import android.content.ActivityNotFoundException
import android.content.Intent
import android.graphics.drawable.Drawable
import android.net.Uri
@@ -42,8 +43,10 @@ import kotlinx.android.synthetic.main.item_thread_error.view.*
import kotlinx.android.synthetic.main.item_thread_sending.view.*
import kotlinx.android.synthetic.main.item_thread_success.view.*
-class ThreadAdapter(activity: SimpleActivity, var messages: ArrayList, recyclerView: MyRecyclerView, fastScroller: FastScroller,
- itemClick: (Any) -> Unit) : MyRecyclerViewAdapter(activity, recyclerView, fastScroller, itemClick) {
+class ThreadAdapter(
+ activity: SimpleActivity, var messages: ArrayList, recyclerView: MyRecyclerView, fastScroller: FastScroller,
+ itemClick: (Any) -> Unit
+) : MyRecyclerViewAdapter(activity, recyclerView, fastScroller, itemClick) {
private val roundedCornersRadius = resources.getDimension(R.dimen.normal_margin).toInt()
private var fontSize = activity.getTextSize()
@@ -134,17 +137,17 @@ class ThreadAdapter(activity: SimpleActivity, var messages: ArrayList) {
+ val latestMessages = newMessages.clone() as ArrayList
val oldHashCode = messages.hashCode()
- val newHashCode = newMessages.hashCode()
+ val newHashCode = latestMessages.hashCode()
if (newHashCode != oldHashCode) {
- messages = newMessages
+ messages = latestMessages
notifyDataSetChanged()
recyclerView.scrollToPosition(messages.size - 1)
}
@@ -224,7 +228,7 @@ class ThreadAdapter(activity: SimpleActivity, var messages: ArrayList): Long {
}
fun Context.showReceivedMessageNotification(address: String, body: String, threadId: Long, bitmap: Bitmap?) {
- val privateCursor = getMyContactsCursor()?.loadInBackground()
+ val privateCursor = getMyContactsCursor(false, true)?.loadInBackground()
ensureBackgroundThread {
val senderName = getNameFromAddress(address, privateCursor)
@@ -709,37 +712,41 @@ fun Context.showMessageNotification(address: String, body: String, threadId: Lon
val builder = NotificationCompat.Builder(this, NOTIFICATION_CHANNEL).apply {
when (config.notificationSetting) {
CONFIGURE_NAME_AND_MESSAGE -> {
- this.setContentTitle(sender)
- this.setLargeIcon(largeIcon)
- this.setContentText(body)
+ setContentTitle(sender)
+ setLargeIcon(largeIcon)
+ setContentText(body)
}
CONFIGURE_NAME -> {
- this.setContentTitle(sender)
- this.setLargeIcon(largeIcon)
+ setContentTitle(sender)
+ setLargeIcon(largeIcon)
}
}
- this.color = config.primaryColor
- this.setSmallIcon(R.drawable.ic_messenger)
- this.setStyle(NotificationCompat.BigTextStyle().setSummaryText(summaryText).bigText(body))
- this.setContentIntent(pendingIntent)
- this.priority = NotificationCompat.PRIORITY_MAX
- this.setDefaults(Notification.DEFAULT_LIGHTS)
- this.setCategory(Notification.CATEGORY_MESSAGE)
- this.setAutoCancel(true)
- this.setSound(soundUri, AudioManager.STREAM_NOTIFICATION)
+
+ color = getAdjustedPrimaryColor()
+ setSmallIcon(R.drawable.ic_messenger)
+ setStyle(NotificationCompat.BigTextStyle().setSummaryText(summaryText).bigText(body))
+ setContentIntent(pendingIntent)
+ priority = NotificationCompat.PRIORITY_MAX
+ setDefaults(Notification.DEFAULT_LIGHTS)
+ setCategory(Notification.CATEGORY_MESSAGE)
+ setAutoCancel(true)
+ setSound(soundUri, AudioManager.STREAM_NOTIFICATION)
}
if (replyAction != null && config.notificationSetting == CONFIGURE_NAME_AND_MESSAGE) {
builder.addAction(replyAction)
}
+
builder.addAction(R.drawable.ic_check_vector, getString(R.string.mark_as_read), markAsReadPendingIntent)
.setChannelId(NOTIFICATION_CHANNEL)
notificationManager.notify(threadId.hashCode(), builder.build())
}
-fun Context.getConfigurationText(type: Int) = getString(when (type) {
- CONFIGURE_NAME_AND_MESSAGE -> R.string.configure_name_and_message
- CONFIGURE_NAME -> R.string.configure_name
- else -> R.string.configure_no_details
-})
+fun Context.getConfigurationText(type: Int) = getString(
+ when (type) {
+ CONFIGURE_NAME_AND_MESSAGE -> R.string.sender_and_message
+ CONFIGURE_NAME -> R.string.sender_only
+ else -> R.string.nothing
+ }
+)
diff --git a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/helpers/Constants.kt b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/helpers/Constants.kt
index 11425c0a..ca72c64a 100644
--- a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/helpers/Constants.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/helpers/Constants.kt
@@ -9,6 +9,7 @@ const val THREAD_TEXT = "thread_text"
const val THREAD_NUMBER = "thread_number"
const val THREAD_ATTACHMENT_URI = "thread_attachment_uri"
const val THREAD_ATTACHMENT_URIS = "thread_attachment_uris"
+const val SEARCHED_MESSAGE_ID = "searched_message_id"
const val USE_SIM_ID_PREFIX = "use_sim_id_"
const val NOTIFICATION_CHANNEL = "simple_sms_messenger"
const val SHOW_CHARACTER_COUNTER = "show_character_counter"
diff --git a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/interfaces/ConversationsDao.kt b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/interfaces/ConversationsDao.kt
index 8980593d..534cdc1f 100644
--- a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/interfaces/ConversationsDao.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/interfaces/ConversationsDao.kt
@@ -17,6 +17,9 @@ interface ConversationsDao {
@Query("SELECT * FROM conversations WHERE read = 0")
fun getUnreadConversations(): List
+ @Query("SELECT * FROM conversations WHERE title LIKE :text")
+ fun getConversationsWithText(text: String): List
+
@Query("UPDATE conversations SET read = 1 WHERE thread_id = :threadId")
fun markRead(threadId: Long)
diff --git a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/interfaces/MessagesDao.kt b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/interfaces/MessagesDao.kt
index c3dc8d71..c4689b4d 100644
--- a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/interfaces/MessagesDao.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/interfaces/MessagesDao.kt
@@ -23,6 +23,9 @@ interface MessagesDao {
@Query("SELECT * FROM messages WHERE thread_id = :threadId")
fun getThreadMessages(threadId: Long): List
+ @Query("SELECT * FROM messages WHERE body LIKE :text")
+ fun getMessagesWithText(text: String): List
+
@Query("UPDATE messages SET read = 1 WHERE id = :id")
fun markRead(id: Long)
diff --git a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/models/SearchResult.kt b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/models/SearchResult.kt
new file mode 100644
index 00000000..e6fd47ed
--- /dev/null
+++ b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/models/SearchResult.kt
@@ -0,0 +1,3 @@
+package com.simplemobiletools.smsmessenger.models
+
+data class SearchResult(val messageId: Long, val title: String, val snippet: String, val date: String, val threadId: Long, var photoUri: String)
diff --git a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/receivers/DirectReplyReceiver.kt b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/receivers/DirectReplyReceiver.kt
index d4148c86..8a4ee30c 100644
--- a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/receivers/DirectReplyReceiver.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/receivers/DirectReplyReceiver.kt
@@ -3,17 +3,14 @@ package com.simplemobiletools.smsmessenger.receivers
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
-import androidx.core.app.NotificationCompat
import androidx.core.app.RemoteInput
import com.klinker.android.send_message.Settings
import com.klinker.android.send_message.Transaction
import com.simplemobiletools.commons.extensions.notificationManager
import com.simplemobiletools.commons.extensions.showErrorToast
import com.simplemobiletools.commons.helpers.ensureBackgroundThread
-import com.simplemobiletools.smsmessenger.R
import com.simplemobiletools.smsmessenger.extensions.conversationsDB
import com.simplemobiletools.smsmessenger.extensions.markThreadMessagesRead
-import com.simplemobiletools.smsmessenger.helpers.NOTIFICATION_CHANNEL
import com.simplemobiletools.smsmessenger.helpers.REPLY
import com.simplemobiletools.smsmessenger.helpers.THREAD_ID
import com.simplemobiletools.smsmessenger.helpers.THREAD_NUMBER
@@ -22,26 +19,28 @@ class DirectReplyReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
val address = intent.getStringExtra(THREAD_NUMBER)
val threadId = intent.getLongExtra(THREAD_ID, 0L)
- val msg = RemoteInput.getResultsFromIntent(intent).getCharSequence(REPLY).toString()
+ val msg = RemoteInput.getResultsFromIntent(intent).getCharSequence(REPLY)?.toString() ?: return
val settings = Settings()
settings.useSystemSending = true
+ settings.deliveryReports = true
val transaction = Transaction(context, settings)
val message = com.klinker.android.send_message.Message(msg, address)
try {
+ val smsSentIntent = Intent(context, SmsStatusSentReceiver::class.java)
+ val deliveredIntent = Intent(context, SmsStatusDeliveredReceiver::class.java)
+
+ transaction.setExplicitBroadcastForSentSms(smsSentIntent)
+ transaction.setExplicitBroadcastForDeliveredSms(deliveredIntent)
+
transaction.sendNewMessage(message, threadId)
} catch (e: Exception) {
context.showErrorToast(e)
}
- val repliedNotification = NotificationCompat.Builder(context, NOTIFICATION_CHANNEL)
- .setSmallIcon(R.drawable.ic_messenger)
- .setContentText(msg)
- .build()
-
- context.notificationManager.notify(threadId.hashCode(), repliedNotification)
+ context.notificationManager.cancel(threadId.hashCode())
ensureBackgroundThread {
context.markThreadMessagesRead(threadId)
diff --git a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/receivers/SmsReceiver.kt b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/receivers/SmsReceiver.kt
index cc2efb88..f431cac9 100644
--- a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/receivers/SmsReceiver.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/receivers/SmsReceiver.kt
@@ -40,17 +40,21 @@ class SmsReceiver : BroadcastReceiver() {
val newMessageId = context.insertNewSMS(address, subject, body, date, read, threadId, type, subscriptionId)
val conversation = context.getConversations(threadId).firstOrNull() ?: return@ensureBackgroundThread
- context.conversationsDB.insertOrUpdate(conversation)
- context.updateUnreadCountBadge(context.conversationsDB.getUnreadConversations())
+ try {
+ context.conversationsDB.insertOrUpdate(conversation)
+ } catch (ignored: Exception) {
+ }
+ context.updateUnreadCountBadge(context.conversationsDB.getUnreadConversations())
val participant = SimpleContact(0, 0, address, "", arrayListOf(address), ArrayList(), ArrayList())
- val message = Message(newMessageId, body, type, arrayListOf(participant), (date / 1000).toInt(), false, threadId,
- false, null, address, "", subscriptionId)
+ val participants = arrayListOf(participant)
+ val messageDate = (date / 1000).toInt()
+ val message = Message(newMessageId, body, type, participants, messageDate, false, threadId, false, null, address, "", subscriptionId)
context.messagesDB.insertOrUpdate(message)
+ refreshMessages()
}
context.showReceivedMessageNotification(address, body, threadId, null)
- refreshMessages()
}
}
}
diff --git a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/receivers/SmsStatusDeliveredReceiver.kt b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/receivers/SmsStatusDeliveredReceiver.kt
index b7aa5593..b4c805e5 100644
--- a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/receivers/SmsStatusDeliveredReceiver.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/receivers/SmsStatusDeliveredReceiver.kt
@@ -1,20 +1,20 @@
package com.simplemobiletools.smsmessenger.receivers
-import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Handler
import android.os.Looper
import android.provider.Telephony
+import com.klinker.android.send_message.DeliveredReceiver
import com.simplemobiletools.commons.helpers.ensureBackgroundThread
import com.simplemobiletools.smsmessenger.extensions.messagesDB
import com.simplemobiletools.smsmessenger.extensions.updateMessageType
import com.simplemobiletools.smsmessenger.helpers.refreshMessages
-class SmsStatusDeliveredReceiver : BroadcastReceiver() {
+class SmsStatusDeliveredReceiver : DeliveredReceiver() {
- override fun onReceive(context: Context, intent: Intent) {
+ override fun onMessageStatusUpdated(context: Context, intent: Intent, receiverResultCode: Int) {
if (intent.extras?.containsKey("message_uri") == true) {
val uri = Uri.parse(intent.getStringExtra("message_uri"))
val messageId = uri?.lastPathSegment?.toLong() ?: 0L
diff --git a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/receivers/SmsStatusSentReceiver.kt b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/receivers/SmsStatusSentReceiver.kt
index 6f7451f6..f128ac9e 100644
--- a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/receivers/SmsStatusSentReceiver.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/receivers/SmsStatusSentReceiver.kt
@@ -5,7 +5,6 @@ import android.app.Notification
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
-import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.media.AudioAttributes
@@ -16,6 +15,8 @@ import android.os.Handler
import android.os.Looper
import android.provider.Telephony
import androidx.core.app.NotificationCompat
+import com.klinker.android.send_message.SentReceiver
+import com.simplemobiletools.commons.extensions.getAdjustedPrimaryColor
import com.simplemobiletools.commons.extensions.getMyContactsCursor
import com.simplemobiletools.commons.helpers.SimpleContactsHelper
import com.simplemobiletools.commons.helpers.ensureBackgroundThread
@@ -27,9 +28,9 @@ import com.simplemobiletools.smsmessenger.helpers.NOTIFICATION_CHANNEL
import com.simplemobiletools.smsmessenger.helpers.THREAD_ID
import com.simplemobiletools.smsmessenger.helpers.refreshMessages
-class SmsStatusSentReceiver : BroadcastReceiver() {
+class SmsStatusSentReceiver : SentReceiver() {
- override fun onReceive(context: Context, intent: Intent) {
+ override fun onMessageStatusUpdated(context: Context, intent: Intent, receiverResultCode: Int) {
if (intent.extras?.containsKey("message_uri") == true) {
val uri = Uri.parse(intent.getStringExtra("message_uri"))
val messageId = uri?.lastPathSegment?.toLong() ?: 0L
@@ -40,6 +41,7 @@ class SmsStatusSentReceiver : BroadcastReceiver() {
} else {
Telephony.Sms.MESSAGE_TYPE_OUTBOX
}
+
context.updateMessageType(messageId, type)
context.messagesDB.updateType(messageId, type)
refreshMessages()
@@ -49,7 +51,7 @@ class SmsStatusSentReceiver : BroadcastReceiver() {
private fun showSendingFailedNotification(context: Context, messageId: Long) {
Handler(Looper.getMainLooper()).post {
- val privateCursor = context.getMyContactsCursor()?.loadInBackground()
+ val privateCursor = context.getMyContactsCursor(false, true)?.loadInBackground()
ensureBackgroundThread {
val address = context.getMessageRecipientAddress(messageId)
val threadId = context.getThreadId(address)
@@ -92,7 +94,7 @@ class SmsStatusSentReceiver : BroadcastReceiver() {
val builder = NotificationCompat.Builder(context, NOTIFICATION_CHANNEL)
.setContentTitle(context.getString(R.string.message_not_sent_short))
.setContentText(summaryText)
- .setColor(context.config.primaryColor)
+ .setColor(context.getAdjustedPrimaryColor())
.setSmallIcon(R.drawable.ic_messenger)
.setLargeIcon(largeIcon)
.setStyle(NotificationCompat.BigTextStyle().bigText(summaryText))
diff --git a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/services/HeadlessSmsSendService.kt b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/services/HeadlessSmsSendService.kt
index eaeba8fb..de6df798 100644
--- a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/services/HeadlessSmsSendService.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/services/HeadlessSmsSendService.kt
@@ -6,6 +6,8 @@ import android.net.Uri
import com.klinker.android.send_message.Settings
import com.klinker.android.send_message.Transaction
import com.simplemobiletools.smsmessenger.extensions.getThreadId
+import com.simplemobiletools.smsmessenger.receivers.SmsStatusDeliveredReceiver
+import com.simplemobiletools.smsmessenger.receivers.SmsStatusSentReceiver
class HeadlessSmsSendService : Service() {
override fun onBind(intent: Intent?) = null
@@ -20,8 +22,17 @@ class HeadlessSmsSendService : Service() {
val text = intent.getStringExtra(Intent.EXTRA_TEXT)
val settings = Settings()
settings.useSystemSending = true
+ settings.deliveryReports = true
+
val transaction = Transaction(this, settings)
val message = com.klinker.android.send_message.Message(text, number)
+
+ val smsSentIntent = Intent(this, SmsStatusSentReceiver::class.java)
+ val deliveredIntent = Intent(this, SmsStatusDeliveredReceiver::class.java)
+
+ transaction.setExplicitBroadcastForSentSms(smsSentIntent)
+ transaction.setExplicitBroadcastForDeliveredSms(deliveredIntent)
+
transaction.sendNewMessage(message, getThreadId(number))
} catch (ignored: Exception) {
}
diff --git a/app/src/main/res/drawable/item_selected_contact_background.xml b/app/src/main/res/drawable/item_selected_contact_background.xml
index f55fbc8f..f0d2b728 100644
--- a/app/src/main/res/drawable/item_selected_contact_background.xml
+++ b/app/src/main/res/drawable/item_selected_contact_background.xml
@@ -1,9 +1,12 @@
-
+
+ -
+
-
+
-
+
-
+
+
+
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
index aaa99efc..911f9b31 100644
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main.xml
@@ -43,6 +43,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
+ android:layoutAnimation="@anim/layout_animation"
android:overScrollMode="ifContentScrolls"
android:scrollbars="none"
app:layoutManager="com.simplemobiletools.commons.views.MyLinearLayoutManager" />
diff --git a/app/src/main/res/layout/activity_new_conversation.xml b/app/src/main/res/layout/activity_new_conversation.xml
index aaf95c05..7279f684 100644
--- a/app/src/main/res/layout/activity_new_conversation.xml
+++ b/app/src/main/res/layout/activity_new_conversation.xml
@@ -101,6 +101,7 @@
android:layout_height="match_parent"
android:layout_below="@+id/suggestions_scrollview"
android:clipToPadding="false"
+ android:layoutAnimation="@anim/layout_animation"
android:overScrollMode="ifContentScrolls"
android:scrollbars="none"
app:layoutManager="com.simplemobiletools.commons.views.MyLinearLayoutManager" />
diff --git a/app/src/main/res/layout/activity_search.xml b/app/src/main/res/layout/activity_search.xml
new file mode 100644
index 00000000..a8e2fe2d
--- /dev/null
+++ b/app/src/main/res/layout/activity_search.xml
@@ -0,0 +1,46 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/activity_settings.xml b/app/src/main/res/layout/activity_settings.xml
index 73b74258..a54f0241 100644
--- a/app/src/main/res/layout/activity_settings.xml
+++ b/app/src/main/res/layout/activity_settings.xml
@@ -53,6 +53,27 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/item_suggested_contact.xml b/app/src/main/res/layout/item_suggested_contact.xml
index 7535748b..6851fb13 100644
--- a/app/src/main/res/layout/item_suggested_contact.xml
+++ b/app/src/main/res/layout/item_suggested_contact.xml
@@ -3,8 +3,8 @@
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/suggested_contact_holder"
android:layout_width="wrap_content"
- android:background="?selectableItemBackground"
- android:layout_height="wrap_content">
+ android:layout_height="wrap_content"
+ android:background="?selectableItemBackground">
+ app:showAsAction="always" />
-
+ app:showAsAction="always" />
+
+ app:showAsAction="always" />
+ app:showAsAction="always" />
+
-
-