diff --git a/CHANGELOG.md b/CHANGELOG.md index 279108c6..cda2ade2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,47 @@ Changelog ========== +Version 5.5.0 *(2020-11-04)* +---------------------------- + + * Allow dialing or copying selected conversation phone numbers + * Allow copying specific parts of messages into clipboard + * Adding an option to show character counter at outgoing messages + * Couple other UI, translation and stability improvements + +Version 5.4.5 *(2020-10-27)* +---------------------------- + + * Fixed some smaller glitches + translation improvements + +Version 5.4.4 *(2020-09-23)* +---------------------------- + + * Fixing a crash at receiving MMS + +Version 5.4.3 *(2020-09-23)* +---------------------------- + + * Fixing a crash at receiving MMS + +Version 5.4.2 *(2020-09-22)* +---------------------------- + + * Fix incoming message notifications sometimes not being shown + +Version 5.4.1 *(2020-08-23)* +---------------------------- + + * Show a tick at successfully sent messages + * Properly show the sender name at incoming messages, if sent by a private contact + +Version 5.4.0 *(2020-07-27)* +---------------------------- + + * Show unread message badges on some devices that support it + * Added some improvements related to handling private contacts + * Other stability, UI and translation improvements + Version 5.3.0 *(2020-06-18)* ---------------------------- diff --git a/app/build.gradle b/app/build.gradle index 5cbaaebf..420817fd 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -10,15 +10,14 @@ if (keystorePropertiesFile.exists()) { } android { - compileSdkVersion 29 - buildToolsVersion "29.0.3" + compileSdkVersion 30 defaultConfig { applicationId "com.simplemobiletools.smsmessenger" minSdkVersion 22 - targetSdkVersion 29 - versionCode 10 - versionName "5.3.0" + targetSdkVersion 30 + versionCode 18 + versionName "5.5.0" setProperty("archivesBaseName", "sms-messenger") } @@ -57,10 +56,11 @@ android { } dependencies { - implementation 'com.simplemobiletools:commons:5.29.7' + implementation 'com.simplemobiletools:commons:5.31.23' implementation 'org.greenrobot:eventbus:3.2.0' implementation 'com.klinkerapps:android-smsmms:5.2.6' implementation 'com.github.tibbi:IndicatorFastScroll:08f512858a' + implementation "me.leolin:ShortcutBadger:1.1.22" kapt "androidx.room:room-compiler:2.2.5" implementation "androidx.room:room-runtime:2.2.5" 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 091eb54f..3e57dd0e 100644 --- a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/activities/MainActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/activities/MainActivity.kt @@ -21,6 +21,7 @@ import com.simplemobiletools.smsmessenger.adapters.ConversationsAdapter import com.simplemobiletools.smsmessenger.extensions.config import com.simplemobiletools.smsmessenger.extensions.conversationsDB import com.simplemobiletools.smsmessenger.extensions.getConversations +import com.simplemobiletools.smsmessenger.extensions.updateUnreadCountBadge import com.simplemobiletools.smsmessenger.helpers.THREAD_ID import com.simplemobiletools.smsmessenger.helpers.THREAD_TITLE import com.simplemobiletools.smsmessenger.models.Conversation @@ -137,7 +138,10 @@ class MainActivity : SimpleActivity() { handlePermission(PERMISSION_READ_CONTACTS) { initMessenger() bus = EventBus.getDefault() - bus!!.register(this) + try { + bus!!.register(this) + } catch (e: Exception) { + } } } else { finish() @@ -164,7 +168,13 @@ class MainActivity : SimpleActivity() { private fun getCachedConversations() { ensureBackgroundThread { - val conversations = conversationsDB.getAll().sortedByDescending { it.date }.toMutableList() as ArrayList + val conversations = try { + conversationsDB.getAll().sortedByDescending { it.date }.toMutableList() as ArrayList + } catch (e: Exception) { + ArrayList() + } + + updateUnreadCountBadge(conversations) runOnUiThread { setupConversations(conversations) getNewConversations(conversations) @@ -173,7 +183,7 @@ class MainActivity : SimpleActivity() { } private fun getNewConversations(cachedConversations: ArrayList) { - val privateCursor = getMyContactsContentProviderCursorLoader().loadInBackground() + val privateCursor = getMyContactsCursor().loadInBackground() ensureBackgroundThread { val conversations = getConversations() @@ -181,9 +191,11 @@ class MainActivity : SimpleActivity() { val privateContacts = MyContactsContentProvider.getSimpleContacts(this, privateCursor) if (privateContacts.isNotEmpty()) { conversations.filter { it.title == it.phoneNumber }.forEach { conversation -> - privateContacts.firstOrNull { it.phoneNumber == conversation.phoneNumber }?.apply { - conversation.title = name - conversation.photoUri = photoUri + privateContacts.forEach { contact -> + if (contact.doesContainPhoneNumber(conversation.phoneNumber)) { + conversation.title = contact.name + conversation.photoUri = contact.photoUri + } } } } @@ -232,7 +244,10 @@ class MainActivity : SimpleActivity() { conversations_list.adapter = this } } else { - (currAdapter as ConversationsAdapter).updateConversations(conversations) + try { + (currAdapter as ConversationsAdapter).updateConversations(conversations) + } catch (ignored: Exception) { + } } } @@ -283,7 +298,8 @@ class MainActivity : SimpleActivity() { val faqItems = arrayListOf( FAQItem(R.string.faq_2_title_commons, R.string.faq_2_text_commons), - FAQItem(R.string.faq_6_title_commons, R.string.faq_6_text_commons) + FAQItem(R.string.faq_6_title_commons, R.string.faq_6_text_commons), + FAQItem(R.string.faq_9_title_commons, R.string.faq_9_text_commons) ) startAboutActivity(R.string.app_name, licenses, BuildConfig.VERSION_NAME, faqItems, true) 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 4baea150..68b9c411 100644 --- a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/activities/NewConversationActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/activities/NewConversationActivity.kt @@ -5,6 +5,7 @@ import android.net.Uri import android.os.Bundle import android.view.Menu import android.view.WindowManager +import com.google.gson.Gson import com.reddit.indicatorfastscroll.FastScrollItemIndicator import com.simplemobiletools.commons.extensions.* import com.simplemobiletools.commons.helpers.MyContactsContentProvider @@ -64,7 +65,7 @@ class NewConversationActivity : SimpleActivity() { val searchString = it val filteredContacts = ArrayList() allContacts.forEach { - if (it.phoneNumber.contains(searchString, true) || it.name.contains(searchString, true)) { + if (it.phoneNumbers.any { it.contains(searchString, true) } || it.name.contains(searchString, true)) { filteredContacts.add(it) } } @@ -134,7 +135,7 @@ class NewConversationActivity : SimpleActivity() { ContactsAdapter(this, contacts, contacts_list, null) { hideKeyboard() - launchThreadActivity((it as SimpleContact).phoneNumber, it.name) + launchThreadActivity((it as SimpleContact).phoneNumbers.first(), it.name) }.apply { contacts_list.adapter = this } @@ -143,7 +144,7 @@ class NewConversationActivity : SimpleActivity() { } private fun fillSuggestedContacts(callback: () -> Unit) { - val privateCursor = getMyContactsContentProviderCursorLoader().loadInBackground() + val privateCursor = getMyContactsCursor().loadInBackground() ensureBackgroundThread { privateContacts = MyContactsContentProvider.getSimpleContacts(this, privateCursor) val suggestions = getSuggestedContacts(privateContacts) @@ -159,10 +160,14 @@ class NewConversationActivity : SimpleActivity() { val contact = it layoutInflater.inflate(R.layout.item_suggested_contact, null).apply { suggested_contact_name.text = contact.name - SimpleContactsHelper(this@NewConversationActivity).loadContactImage(contact.photoUri, suggested_contact_image, contact.name) - suggestions_holder.addView(this) - setOnClickListener { - launchThreadActivity(contact.phoneNumber, contact.name) + suggested_contact_name.setTextColor(baseConfig.textColor) + + if (!isDestroyed) { + SimpleContactsHelper(this@NewConversationActivity).loadContactImage(contact.photoUri, suggested_contact_image, contact.name) + suggestions_holder.addView(this) + setOnClickListener { + launchThreadActivity(contact.phoneNumbers.first(), contact.name) + } } } } @@ -186,11 +191,13 @@ class NewConversationActivity : SimpleActivity() { private fun launchThreadActivity(phoneNumber: String, name: String) { val text = intent.getStringExtra(Intent.EXTRA_TEXT) ?: "" + val numbers = phoneNumber.split(";").toSet() + val number = if (numbers.size == 1) phoneNumber else Gson().toJson(numbers) Intent(this, ThreadActivity::class.java).apply { - putExtra(THREAD_ID, getThreadId(phoneNumber).toInt()) + putExtra(THREAD_ID, getThreadId(numbers).toInt()) putExtra(THREAD_TITLE, name) putExtra(THREAD_TEXT, text) - putExtra(THREAD_NUMBER, phoneNumber) + putExtra(THREAD_NUMBER, number) if (intent.action == Intent.ACTION_SEND && intent.extras?.containsKey(Intent.EXTRA_STREAM) == true) { val uri = intent.getParcelableExtra(Intent.EXTRA_STREAM) 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 c9a3d38d..680c3422 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() { setupManageBlockedNumbers() setupChangeDateTimeFormat() setupFontSize() + setupShowCharacterCounter() updateTextColors(settings_scrollview) if (blockedNumbersAtPause != -1 && blockedNumbersAtPause != getBlockedNumbers().hashCode()) { @@ -106,4 +107,12 @@ class SettingsActivity : SimpleActivity() { } } } + + private fun setupShowCharacterCounter() { + settings_show_character_counter.isChecked = config.showCharacterCounter + settings_show_character_counter_holder.setOnClickListener { + settings_show_character_counter.toggle() + config.showCharacterCounter = settings_show_character_counter.isChecked + } + } } 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 01179818..220694fc 100644 --- a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/activities/ThreadActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/activities/ThreadActivity.kt @@ -11,6 +11,7 @@ import android.os.Bundle import android.provider.Telephony import android.telephony.SubscriptionManager import android.text.TextUtils +import android.util.TypedValue import android.view.* import android.view.inputmethod.EditorInfo import android.widget.LinearLayout @@ -51,6 +52,7 @@ class ThreadActivity : SimpleActivity() { private var threadId = 0 private var currentSIMCardIndex = 0 + private var isActivityVisible = false private var threadItems = ArrayList() private var bus: EventBus? = null private var participants = ArrayList() @@ -86,8 +88,18 @@ class ThreadActivity : SimpleActivity() { } } + override fun onResume() { + super.onResume() + isActivityVisible = true + } + + override fun onPause() { + super.onPause() + isActivityVisible = false + } + private fun setupThread() { - val privateCursor = getMyContactsContentProviderCursorLoader().loadInBackground() + val privateCursor = getMyContactsCursor().loadInBackground() ensureBackgroundThread { messages = getMessages(threadId) participants = if (messages.isEmpty()) { @@ -100,9 +112,9 @@ class ThreadActivity : SimpleActivity() { privateContacts = MyContactsContentProvider.getSimpleContacts(this, privateCursor) if (privateContacts.isNotEmpty()) { val senderNumbersToReplace = HashMap() - participants.filter { it.name == it.phoneNumber }.forEach { participant -> - privateContacts.firstOrNull { it.phoneNumber == participant.phoneNumber }?.apply { - senderNumbersToReplace[participant.phoneNumber] = name + participants.filter { it.doesContainPhoneNumber(it.name) }.forEach { participant -> + privateContacts.firstOrNull { it.doesContainPhoneNumber(participant.phoneNumbers.first()) }?.apply { + senderNumbersToReplace[participant.phoneNumbers.first()] = name participant.name = name participant.photoUri = photoUri } @@ -124,7 +136,7 @@ class ThreadActivity : SimpleActivity() { return@ensureBackgroundThread } - val contact = SimpleContact(0, 0, name, "", number) + val contact = SimpleContact(0, 0, name, "", arrayListOf(number), ArrayList(), ArrayList()) participants.add(contact) } @@ -140,8 +152,8 @@ class ThreadActivity : SimpleActivity() { } else if (it.mimetype.startsWith("video/")) { val metaRetriever = MediaMetadataRetriever() metaRetriever.setDataSource(this, it.uri) - it.width = metaRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH).toInt() - it.height = metaRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT).toInt() + it.width = metaRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH)!!.toInt() + it.height = metaRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT)!!.toInt() } if (it.width < 0) { @@ -241,7 +253,7 @@ class ThreadActivity : SimpleActivity() { confirm_inserted_number?.setOnClickListener { val number = add_contact_or_number.value - val contact = SimpleContact(number.hashCode(), number.hashCode(), number, "", number) + val contact = SimpleContact(number.hashCode(), number.hashCode(), number, "", arrayListOf(number), ArrayList(), ArrayList()) addSelectedContact(contact) } } @@ -253,6 +265,10 @@ class ThreadActivity : SimpleActivity() { confirm_manage_contacts.applyColorFilter(textColor) thread_add_attachment.applyColorFilter(textColor) + thread_character_counter.beVisibleIf(config.showCharacterCounter) + thread_character_counter.setTextSize(TypedValue.COMPLEX_UNIT_PX, getTextSize()) + + thread_type_message.setTextSize(TypedValue.COMPLEX_UNIT_PX, getTextSize()) thread_send_message.setOnClickListener { sendMessage() } @@ -260,13 +276,20 @@ class ThreadActivity : SimpleActivity() { thread_send_message.isClickable = false thread_type_message.onTextChangeListener { checkSendMessageAvailability() + thread_character_counter.text = it.length.toString() } confirm_manage_contacts.setOnClickListener { hideKeyboard() thread_add_contacts.beGone() - val numbers = participants.map { it.phoneNumber }.toSet() + val numbers = HashSet() + participants.forEach { + it.phoneNumbers.forEach { + numbers.add(it) + } + } + val newThreadId = getThreadId(numbers).toInt() if (threadId != newThreadId) { Intent(this, ThreadActivity::class.java).apply { @@ -297,7 +320,7 @@ class ThreadActivity : SimpleActivity() { val availableSIMs = SubscriptionManager.from(this).activeSubscriptionInfoList ?: return if (availableSIMs.size > 1) { availableSIMs.forEachIndexed { index, subscriptionInfo -> - var label = subscriptionInfo.displayName.toString() + var label = subscriptionInfo.displayName?.toString() ?: "" if (subscriptionInfo.number?.isNotEmpty() == true) { label += " (${subscriptionInfo.number})" } @@ -305,7 +328,13 @@ class ThreadActivity : SimpleActivity() { availableSIMCards.add(SIMCard) } - val numbers = participants.map { it.phoneNumber }.toTypedArray() + val numbers = ArrayList() + participants.forEach { + it.phoneNumbers.forEach { + numbers.add(it) + } + } + currentSIMCardIndex = availableSIMs.indexOfFirstOrNull { it.subscriptionId == config.getUseSIMIdAtNumber(numbers.first()) } ?: 0 thread_select_sim_icon.applyColorFilter(config.textColor) @@ -327,7 +356,13 @@ class ThreadActivity : SimpleActivity() { } private fun blockNumber() { - val numbers = participants.map { it.phoneNumber } + val numbers = ArrayList() + participants.forEach { + it.phoneNumbers.forEach { + numbers.add(it) + } + } + val numbersString = TextUtils.join(", ", numbers) val question = String.format(resources.getString(R.string.block_confirmation), numbersString) @@ -421,24 +456,30 @@ class ThreadActivity : SimpleActivity() { var prevDateTime = 0 var hadUnreadItems = false - messages.forEach { + val cnt = messages.size + for (i in 0 until cnt) { + val message = messages[i] // 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 (it.date - prevDateTime > MIN_DATE_TIME_DIFF_SECS) { - val simCardID = subscriptionIdToSimId[it.subscriptionId] ?: "?" - items.add(ThreadDateTime(it.date, simCardID)) - prevDateTime = it.date + if (message.date - prevDateTime > MIN_DATE_TIME_DIFF_SECS) { + val simCardID = subscriptionIdToSimId[message.subscriptionId] ?: "?" + items.add(ThreadDateTime(message.date, simCardID)) + prevDateTime = message.date } - items.add(it) + items.add(message) - if (it.type == Telephony.Sms.MESSAGE_TYPE_FAILED) { - items.add(ThreadError(it.id)) + if (message.type == Telephony.Sms.MESSAGE_TYPE_FAILED) { + items.add(ThreadError(message.id)) } - if (!it.read) { + if (!message.read) { hadUnreadItems = true - markMessageRead(it.id, it.isMMS) + markMessageRead(message.id, message.isMMS) conversationsDB.markRead(threadId.toLong()) } + + if (i == cnt - 1 && message.type == Telephony.Sms.MESSAGE_TYPE_SENT) { + items.add(ThreadSuccess(message.id)) + } } if (hadUnreadItems) { @@ -518,7 +559,13 @@ class ThreadActivity : SimpleActivity() { return } - val numbers = participants.map { it.phoneNumber }.toTypedArray() + val numbers = ArrayList() + participants.forEach { + it.phoneNumbers.forEach { + numbers.add(it) + } + } + val settings = Settings() settings.useSystemSending = true @@ -531,7 +578,7 @@ class ThreadActivity : SimpleActivity() { } val transaction = Transaction(this, settings) - val message = com.klinker.android.send_message.Message(msg, numbers) + val message = com.klinker.android.send_message.Message(msg, numbers.toTypedArray()) if (attachmentUris.isNotEmpty()) { for (uri in attachmentUris) { @@ -613,7 +660,10 @@ class ThreadActivity : SimpleActivity() { @Subscribe(threadMode = ThreadMode.ASYNC) fun refreshMessages(event: Events.RefreshMessages) { - notificationManager.cancel(threadId) + if (isActivityVisible) { + notificationManager.cancel(threadId) + } + messages = getMessages(threadId) setupAdapter() } 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 68c38b7f..445c8294 100644 --- a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/adapters/AutoCompleteTextViewAdapter.kt +++ b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/adapters/AutoCompleteTextViewAdapter.kt @@ -31,7 +31,7 @@ class AutoCompleteTextViewAdapter(val activity: SimpleActivity, val contacts: Ar } findViewById(R.id.item_contact_name).text = contact.name - findViewById(R.id.item_contact_number).text = contact.phoneNumber + findViewById(R.id.item_contact_number).text = contact.phoneNumbers.first() SimpleContactsHelper(context).loadContactImage(contact.photoUri, findViewById(R.id.item_contact_image), contact.name) } @@ -46,7 +46,7 @@ class AutoCompleteTextViewAdapter(val activity: SimpleActivity, val contacts: Ar resultList.clear() val searchString = constraint.toString().normalizeString() contacts.forEach { - if (it.phoneNumber.contains(searchString, true) || it.name.contains(searchString, true)) { + if (it.doesContainPhoneNumber(searchString) || it.name.contains(searchString, true)) { resultList.add(it) } } 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 a7ed2248..b6d41b29 100644 --- a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/adapters/ContactsAdapter.kt +++ b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/adapters/ContactsAdapter.kt @@ -67,7 +67,7 @@ class ContactsAdapter(activity: SimpleActivity, var contacts: ArrayList(R.id.item_contact_number).apply { - text = contact.phoneNumber + text = contact.phoneNumbers.first() setTextColor(textColor) setTextSize(TypedValue.COMPLEX_UNIT_PX, fontSize) } 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 a1d0a118..9bf1df22 100644 --- a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/adapters/ConversationsAdapter.kt +++ b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/adapters/ConversationsAdapter.kt @@ -2,6 +2,7 @@ package com.simplemobiletools.smsmessenger.adapters import android.content.Intent import android.graphics.Typeface +import android.net.Uri import android.text.TextUtils import android.util.TypedValue import android.view.Menu @@ -37,8 +38,10 @@ class ConversationsAdapter(activity: SimpleActivity, var conversations: ArrayLis override fun prepareActionMode(menu: Menu) { menu.apply { - findItem(R.id.cab_add_number_to_contact).isVisible = isOneItemSelected() && getSelectedItems().firstOrNull()?.isGroupConversation == false findItem(R.id.cab_block_number).isVisible = isNougatPlus() + findItem(R.id.cab_add_number_to_contact).isVisible = isOneItemSelected() && getSelectedItems().firstOrNull()?.isGroupConversation == false + findItem(R.id.cab_dial_number).isVisible = isOneItemSelected() && getSelectedItems().firstOrNull()?.isGroupConversation == false + findItem(R.id.cab_copy_number).isVisible = isOneItemSelected() && getSelectedItems().firstOrNull()?.isGroupConversation == false } } @@ -50,7 +53,8 @@ class ConversationsAdapter(activity: SimpleActivity, var conversations: ArrayLis when (id) { R.id.cab_add_number_to_contact -> addNumberToContact() R.id.cab_block_number -> askConfirmBlock() - R.id.cab_select_all -> selectAll() + R.id.cab_dial_number -> dialNumber() + R.id.cab_copy_number -> copyNumberToClipboard() R.id.cab_delete -> askConfirmDelete() } } @@ -110,6 +114,26 @@ class ConversationsAdapter(activity: SimpleActivity, var conversations: ArrayLis } } + private fun dialNumber() { + val conversation = getSelectedItems().firstOrNull() ?: return + Intent(Intent.ACTION_DIAL).apply { + data = Uri.fromParts("tel", conversation.phoneNumber, null) + + if (resolveActivity(activity.packageManager) != null) { + activity.startActivity(this) + finishActMode() + } else { + activity.toast(R.string.no_app_found) + } + } + } + + private fun copyNumberToClipboard() { + val conversation = getSelectedItems().firstOrNull() ?: return + activity.copyToClipboard(conversation.phoneNumber) + finishActMode() + } + private fun askConfirmDelete() { val itemsCnt = selectedKeys.size val items = resources.getQuantityString(R.plurals.delete_conversations, itemsCnt, itemsCnt) @@ -135,7 +159,11 @@ class ConversationsAdapter(activity: SimpleActivity, var conversations: ArrayLis activity.deleteConversation(it.thread_id) activity.notificationManager.cancel(it.thread_id) } - conversations.removeAll(conversationsToRemove) + + try { + conversations.removeAll(conversationsToRemove) + } catch (ignored: Exception) { + } activity.runOnUiThread { if (conversationsToRemove.isEmpty()) { 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 aa4cec77..dfef567b 100644 --- a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/adapters/ThreadAdapter.kt +++ b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/adapters/ThreadAdapter.kt @@ -29,17 +29,17 @@ import com.simplemobiletools.commons.views.FastScroller import com.simplemobiletools.commons.views.MyRecyclerView import com.simplemobiletools.smsmessenger.R import com.simplemobiletools.smsmessenger.activities.SimpleActivity +import com.simplemobiletools.smsmessenger.dialogs.SelectTextDialog import com.simplemobiletools.smsmessenger.extensions.deleteMessage import com.simplemobiletools.smsmessenger.helpers.* -import com.simplemobiletools.smsmessenger.models.Message -import com.simplemobiletools.smsmessenger.models.ThreadDateTime -import com.simplemobiletools.smsmessenger.models.ThreadError -import com.simplemobiletools.smsmessenger.models.ThreadItem +import com.simplemobiletools.smsmessenger.models.* import kotlinx.android.synthetic.main.item_attachment_image.view.* import kotlinx.android.synthetic.main.item_received_message.view.* import kotlinx.android.synthetic.main.item_received_unknown_attachment.view.* import kotlinx.android.synthetic.main.item_sent_unknown_attachment.view.* import kotlinx.android.synthetic.main.item_thread_date_time.view.* +import kotlinx.android.synthetic.main.item_thread_error.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) { @@ -60,6 +60,7 @@ class ThreadAdapter(activity: SimpleActivity, var messages: ArrayList copyToClipboard() R.id.cab_share -> shareText() - R.id.cab_select_all -> selectAll() + R.id.cab_select_text -> selectText() R.id.cab_delete -> askConfirmDelete() } } @@ -93,6 +94,7 @@ class ThreadAdapter(activity: SimpleActivity, var messages: ArrayList R.layout.item_thread_date_time THREAD_RECEIVED_MESSAGE -> R.layout.item_received_message THREAD_SENT_MESSAGE_ERROR -> R.layout.item_thread_error + THREAD_SENT_MESSAGE_SUCCESS -> R.layout.item_thread_success else -> R.layout.item_sent_message } return createViewHolder(layout, parent) @@ -101,10 +103,11 @@ class ThreadAdapter(activity: SimpleActivity, var messages: ArrayList - if (item is ThreadDateTime) { - setupDateTime(itemView, item) - } else if (item !is ThreadError) { - setupView(itemView, item as Message) + when (item) { + is ThreadDateTime -> setupDateTime(itemView, item) + is ThreadSuccess -> setupThreadSuccess(itemView) + is ThreadError -> setupThreadError(itemView) + else -> setupView(itemView, item as Message) } } bindViewHolder(holder) @@ -118,6 +121,7 @@ class ThreadAdapter(activity: SimpleActivity, var messages: ArrayList THREAD_DATE_TIME (messages[position] as? Message)?.isReceivedMessage() == true -> THREAD_RECEIVED_MESSAGE item is ThreadError -> THREAD_SENT_MESSAGE_ERROR + item is ThreadSuccess -> THREAD_SENT_MESSAGE_SUCCESS else -> THREAD_SENT_MESSAGE } } @@ -132,6 +136,13 @@ class ThreadAdapter(activity: SimpleActivity, var messages: ArrayList { } } + .create().apply { + activity.setupDialogStuff(view, this) + } + } +} diff --git a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/extensions/Context.kt b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/extensions/Context.kt index cc6d84eb..d9590a91 100644 --- a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/extensions/Context.kt +++ b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/extensions/Context.kt @@ -13,6 +13,8 @@ import android.media.AudioAttributes import android.media.AudioManager import android.media.RingtoneManager import android.net.Uri +import android.os.Handler +import android.os.Looper import android.provider.ContactsContract.PhoneLookup import android.provider.Telephony.* import android.text.TextUtils @@ -29,6 +31,7 @@ import com.simplemobiletools.smsmessenger.interfaces.ConversationsDao import com.simplemobiletools.smsmessenger.models.* import com.simplemobiletools.smsmessenger.receivers.DirectReplyReceiver import com.simplemobiletools.smsmessenger.receivers.MarkAsReadReceiver +import me.leolin.shortcutbadger.ShortcutBadger import java.util.* import kotlin.collections.ArrayList @@ -83,7 +86,7 @@ fun Context.getMessages(threadId: Int): ArrayList { val read = cursor.getIntValue(Sms.READ) == 1 val thread = cursor.getIntValue(Sms.THREAD_ID) val subscriptionId = cursor.getIntValue(Sms.SUBSCRIPTION_ID) - val participant = SimpleContact(0, 0, senderName, photoUri, senderNumber) + val participant = SimpleContact(0, 0, senderName, photoUri, arrayListOf(senderNumber), ArrayList(), ArrayList()) val isMMS = false val message = Message(id, body, type, arrayListOf(participant), date, read, thread, isMMS, null, senderName, photoUri, subscriptionId) messages.add(message) @@ -334,7 +337,7 @@ fun Context.getThreadParticipants(threadId: Int, contactsMap: HashMap): Arr return@queryCursor } else if (namePhoto.name == senderNumber) { if (privateContacts.isNotEmpty()) { - val privateContact = privateContacts.firstOrNull { it.phoneNumber == senderNumber } + val privateContact = privateContacts.firstOrNull { it.phoneNumbers.first() == senderNumber } if (privateContact != null) { senderName = privateContact.name photoUri = privateContact.photoUri @@ -415,8 +418,8 @@ fun Context.getSuggestedContacts(privateContacts: ArrayList): Arr } } - val contact = SimpleContact(0, 0, senderName, photoUri, senderNumber) - if (!contacts.map { it.phoneNumber.trimToComparableNumber() }.contains(senderNumber.trimToComparableNumber())) { + val contact = SimpleContact(0, 0, senderName, photoUri, arrayListOf(senderNumber), ArrayList(), ArrayList()) + if (!contacts.map { it.phoneNumbers.first().trimToComparableNumber() }.contains(senderNumber.trimToComparableNumber())) { contacts.add(contact) } } @@ -472,7 +475,11 @@ fun Context.deleteConversation(threadId: Int) { var uri = Sms.CONTENT_URI val selection = "${Sms.THREAD_ID} = ?" val selectionArgs = arrayOf(threadId.toString()) - contentResolver.delete(uri, selection, selectionArgs) + try { + contentResolver.delete(uri, selection, selectionArgs) + } catch (e: Exception) { + showErrorToast(e) + } uri = Mms.CONTENT_URI contentResolver.delete(uri, selection, selectionArgs) @@ -522,6 +529,15 @@ fun Context.markThreadMessagesUnread(threadId: Int) { } } +fun Context.updateUnreadCountBadge(conversations: List) { + val unreadCount = conversations.count { !it.read } + if (unreadCount == 0) { + ShortcutBadger.removeCount(this) + } else { + ShortcutBadger.applyCount(this, unreadCount) + } +} + @SuppressLint("NewApi") fun Context.getThreadId(address: String): Long { return if (isMarshmallowPlus()) { @@ -548,8 +564,23 @@ fun Context.getThreadId(addresses: Set): Long { } } -@SuppressLint("NewApi") fun Context.showReceivedMessageNotification(address: String, body: String, threadID: Int, bitmap: Bitmap?) { + val privateCursor = getMyContactsCursor().loadInBackground() + ensureBackgroundThread { + var sender = getNameAndPhotoFromPhoneNumber(address)?.name ?: "" + if (address == sender) { + val privateContacts = MyContactsContentProvider.getSimpleContacts(this, privateCursor) + sender = privateContacts.firstOrNull { it.doesContainPhoneNumber(address) }?.name ?: address + } + + Handler(Looper.getMainLooper()).post { + showMessageNotification(address, body, threadID, bitmap, sender) + } + } +} + +@SuppressLint("NewApi") +fun Context.showMessageNotification(address: String, body: String, threadID: Int, bitmap: Bitmap?, sender: String) { val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager val soundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION) if (isOreoPlus()) { @@ -576,8 +607,6 @@ fun Context.showReceivedMessageNotification(address: String, body: String, threa val pendingIntent = PendingIntent.getActivity(this, threadID, intent, PendingIntent.FLAG_UPDATE_CURRENT) val summaryText = getString(R.string.new_message) - val sender = getNameAndPhotoFromPhoneNumber(address)?.name ?: "" - val markAsReadIntent = Intent(this, MarkAsReadReceiver::class.java).apply { action = MARK_AS_READ putExtra(THREAD_ID, threadID) @@ -617,12 +646,11 @@ fun Context.showReceivedMessageNotification(address: String, body: String, threa .setCategory(Notification.CATEGORY_MESSAGE) .setAutoCancel(true) .setSound(soundUri, AudioManager.STREAM_NOTIFICATION) - .addAction(R.drawable.ic_check_vector, getString(R.string.mark_as_read), markAsReadPendingIntent) - .setChannelId(NOTIFICATION_CHANNEL) - if (replyAction != null) { builder.addAction(replyAction) } + builder.addAction(R.drawable.ic_check_vector, getString(R.string.mark_as_read), markAsReadPendingIntent) + .setChannelId(NOTIFICATION_CHANNEL) notificationManager.notify(threadID, builder.build()) } diff --git a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/helpers/Config.kt b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/helpers/Config.kt index c5e95e68..451fe60f 100644 --- a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/helpers/Config.kt +++ b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/helpers/Config.kt @@ -13,4 +13,8 @@ class Config(context: Context) : BaseConfig(context) { } fun getUseSIMIdAtNumber(number: String) = prefs.getInt(USE_SIM_ID_PREFIX + number, 0) + + var showCharacterCounter: Boolean + get() = prefs.getBoolean(SHOW_CHARACTER_COUNTER, false) + set(showCharacterCounter) = prefs.edit().putBoolean(SHOW_CHARACTER_COUNTER, showCharacterCounter).apply() } 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 e6b48d46..d4190f1a 100644 --- a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/helpers/Constants.kt +++ b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/helpers/Constants.kt @@ -11,6 +11,7 @@ const val THREAD_ATTACHMENT_URI = "thread_attachment_uri" const val THREAD_ATTACHMENT_URIS = "thread_attachment_uris" const val USE_SIM_ID_PREFIX = "use_sim_id_" const val NOTIFICATION_CHANNEL = "simple_sms_messenger" +const val SHOW_CHARACTER_COUNTER = "show_character_counter" private const val PATH = "com.simplemobiletools.smsmessenger.action." const val MARK_AS_READ = PATH + "mark_as_read" @@ -21,6 +22,7 @@ const val THREAD_DATE_TIME = 1 const val THREAD_RECEIVED_MESSAGE = 2 const val THREAD_SENT_MESSAGE = 3 const val THREAD_SENT_MESSAGE_ERROR = 4 +const val THREAD_SENT_MESSAGE_SUCCESS = 5 fun refreshMessages() { EventBus.getDefault().post(Events.RefreshMessages()) 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 72d69763..d50507f7 100644 --- a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/interfaces/ConversationsDao.kt +++ b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/interfaces/ConversationsDao.kt @@ -14,6 +14,9 @@ interface ConversationsDao { @Query("SELECT * FROM conversations") fun getAll(): List + @Query("SELECT * FROM conversations WHERE read = 0") + fun getUnreadConversations(): 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/models/ThreadSuccess.kt b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/models/ThreadSuccess.kt new file mode 100644 index 00000000..ec7a4d20 --- /dev/null +++ b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/models/ThreadSuccess.kt @@ -0,0 +1,4 @@ +package com.simplemobiletools.smsmessenger.models + +// show a check after the latest message, if it is a sent one and succeeded +data class ThreadSuccess(val messageID: Int) : ThreadItem() diff --git a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/receivers/MarkAsReadReceiver.kt b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/receivers/MarkAsReadReceiver.kt index be4c48e5..3ef30ed4 100644 --- a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/receivers/MarkAsReadReceiver.kt +++ b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/receivers/MarkAsReadReceiver.kt @@ -7,6 +7,7 @@ import com.simplemobiletools.commons.extensions.notificationManager import com.simplemobiletools.commons.helpers.ensureBackgroundThread import com.simplemobiletools.smsmessenger.extensions.conversationsDB import com.simplemobiletools.smsmessenger.extensions.markThreadMessagesRead +import com.simplemobiletools.smsmessenger.extensions.updateUnreadCountBadge import com.simplemobiletools.smsmessenger.helpers.MARK_AS_READ import com.simplemobiletools.smsmessenger.helpers.THREAD_ID @@ -19,6 +20,7 @@ class MarkAsReadReceiver : BroadcastReceiver() { ensureBackgroundThread { context.markThreadMessagesRead(threadId) context.conversationsDB.markRead(threadId.toLong()) + context.updateUnreadCountBadge(context.conversationsDB.getUnreadConversations()) } } } diff --git a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/receivers/MmsReceiver.kt b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/receivers/MmsReceiver.kt index b098bb99..e8ae7d76 100644 --- a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/receivers/MmsReceiver.kt +++ b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/receivers/MmsReceiver.kt @@ -2,20 +2,19 @@ package com.simplemobiletools.smsmessenger.receivers import android.content.Context import android.net.Uri +import android.os.Handler +import android.os.Looper import com.bumptech.glide.Glide import com.simplemobiletools.commons.extensions.isNumberBlocked import com.simplemobiletools.commons.helpers.ensureBackgroundThread import com.simplemobiletools.smsmessenger.R -import com.simplemobiletools.smsmessenger.extensions.conversationsDB -import com.simplemobiletools.smsmessenger.extensions.getConversations -import com.simplemobiletools.smsmessenger.extensions.getLatestMMS -import com.simplemobiletools.smsmessenger.extensions.showReceivedMessageNotification +import com.simplemobiletools.smsmessenger.extensions.* // more info at https://github.com/klinker41/android-smsmms class MmsReceiver : com.klinker.android.send_message.MmsReceivedReceiver() { override fun onMessageReceived(context: Context, messageUri: Uri) { val mms = context.getLatestMMS() ?: return - val address = mms.participants.firstOrNull()?.phoneNumber ?: "" + val address = mms.participants.firstOrNull()?.phoneNumbers?.first() ?: "" if (context.isNumberBlocked(address)) { return } @@ -33,9 +32,14 @@ class MmsReceiver : com.klinker.android.send_message.MmsReceivedReceiver() { null } - context.showReceivedMessageNotification(address, mms.body, mms.thread, glideBitmap) - val conversation = context.getConversations(mms.thread.toLong()).firstOrNull() ?: return@ensureBackgroundThread - context.conversationsDB.insertOrUpdate(conversation) + Handler(Looper.getMainLooper()).post { + context.showReceivedMessageNotification(address, mms.body, mms.thread, glideBitmap) + val conversation = context.getConversations(mms.thread.toLong()).firstOrNull() ?: return@post + ensureBackgroundThread { + context.conversationsDB.insertOrUpdate(conversation) + context.updateUnreadCountBadge(context.conversationsDB.getUnreadConversations()) + } + } } } 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 28daec33..a6e7e6d0 100644 --- a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/receivers/SmsReceiver.kt +++ b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/receivers/SmsReceiver.kt @@ -30,14 +30,16 @@ class SmsReceiver : BroadcastReceiver() { } if (!context.isNumberBlocked(address)) { - context.insertNewSMS(address, subject, body, date, read, threadId, type, subscriptionId) - context.showReceivedMessageNotification(address, body, threadId.toInt(), null) - refreshMessages() - ensureBackgroundThread { + 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()) } + + context.showReceivedMessageNotification(address, body, threadId.toInt(), null) + refreshMessages() } } } diff --git a/app/src/main/res/layout/activity_settings.xml b/app/src/main/res/layout/activity_settings.xml index 618b9b70..c71368f9 100644 --- a/app/src/main/res/layout/activity_settings.xml +++ b/app/src/main/res/layout/activity_settings.xml @@ -149,5 +149,28 @@ android:clickable="false" /> + + + + + + diff --git a/app/src/main/res/layout/activity_thread.xml b/app/src/main/res/layout/activity_thread.xml index 33ec03ed..240c0c39 100644 --- a/app/src/main/res/layout/activity_thread.xml +++ b/app/src/main/res/layout/activity_thread.xml @@ -66,6 +66,7 @@ android:layout_marginStart="@dimen/medium_margin" android:layout_marginEnd="@dimen/medium_margin" android:background="?selectableItemBackgroundBorderless" + android:contentDescription="@string/confirm_selection" android:paddingStart="@dimen/medium_margin" android:paddingEnd="@dimen/medium_margin" android:src="@drawable/ic_check_vector" @@ -125,6 +126,7 @@ android:layout_marginEnd="@dimen/small_margin" android:alpha="0.9" android:background="?selectableItemBackgroundBorderless" + android:contentDescription="@string/attachment" android:padding="@dimen/normal_margin" android:src="@drawable/ic_plus_vector" /> @@ -166,14 +168,17 @@ @@ -190,6 +195,21 @@ android:visibility="gone" tools:text="1" /> + + diff --git a/app/src/main/res/layout/dialog_select_text.xml b/app/src/main/res/layout/dialog_select_text.xml new file mode 100644 index 00000000..71f9cba7 --- /dev/null +++ b/app/src/main/res/layout/dialog_select_text.xml @@ -0,0 +1,12 @@ + + diff --git a/app/src/main/res/layout/item_received_message.xml b/app/src/main/res/layout/item_received_message.xml index 7d476239..c36e4b8c 100644 --- a/app/src/main/res/layout/item_received_message.xml +++ b/app/src/main/res/layout/item_received_message.xml @@ -18,7 +18,7 @@ app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" - app:layout_constraintWidth_percent="0.7"> + app:layout_constraintWidth_percent="0.8"> + app:layout_constraintWidth_percent="0.8"> + + + + + diff --git a/app/src/main/res/menu/cab_conversations.xml b/app/src/main/res/menu/cab_conversations.xml index 84e02dc5..3d73190f 100644 --- a/app/src/main/res/menu/cab_conversations.xml +++ b/app/src/main/res/menu/cab_conversations.xml @@ -12,10 +12,14 @@ android:title="@string/block_number" app:showAsAction="ifRoom" /> + + android:id="@+id/cab_select_text" + android:title="@string/select_text" + app:showAsAction="never" /> Schlichter SMS Messenger SMS Messenger schreibe eine Nachricht… - Nachricht wurde noch nicht gesendet - füge eine Person hinzu + Nachricht wurde nicht gesendet. + Person hinzufügen Anhang - keine gespeicherten Chats gefunden - einen neuen Chat beginnen - Reply + Keine gespeicherten Chats gefunden + Neuen Chat beginnen + Antworten + Show a character counter at writing messages - neuer Chat - Füge einen Kontakt oder eine Nummer hinzu… + Neuer Chat + Kontakt oder Nummer hinzufügen… Vorschläge Empfangene SMS - neue Nachricht - markiere als gelesen - Mark as Unread + Neue Nachricht + Als gelesen markieren + Als ungelesen markieren - Möchtest du wirklich alle Nachrichten dieses Chat löschen? + Möchtest du wirklich alle Nachrichten dieses Chats löschen? @@ -36,9 +37,9 @@ - Why does the app require access to the internet? - Sadly it is needed for sending MMS attachments. Not being able to send MMS would be a really huge disadvantage compared to other apps, so we decided to go this way. - However, as usually, there are no ads, tracking or analytics whatsoever, the internet is used only for sending MMS. + Warum benötigt diese App Internetzugriff? + Leider ist dies nötig, um MMS-Anhänge zu versenden. Es wäre ein großer Nachteil gegenüber anderen Apps, wenn keine MMS versendet werden könnten, also haben wir uns für diesen Weg entschieden. + Jedoch gibt es wie immer keine Werbung, Tracking oder Analytics, der Internetzugriff wird also nur für das Versenden von MMS verwendet. diff --git a/app/src/main/res/values-el/strings.xml b/app/src/main/res/values-el/strings.xml index b3c2dff0..7b4d27a0 100644 --- a/app/src/main/res/values-el/strings.xml +++ b/app/src/main/res/values-el/strings.xml @@ -7,7 +7,8 @@ Συνημμένο Δεν βρέθηκαν αποθηκευμένες συνομιλίες Έναρξη συνομιλίας - Reply + Απάντηση + Show a character counter at writing messages Νέα συνομιλία @@ -17,8 +18,8 @@ Ελήφθη SMS Νέο μήνυμα - Σήμανση ως αναγνωσμένου - Mark as Unread + Σήμανση ως αναγνωσμένο + Σήμανση ως μη αναγνωσμένο Είστε βέβαιοι ότι θέλετε να διαγράψετε όλα τα μηνύματα αυτής της συνομιλίας; diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index 627cd749..0cb67e3e 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -7,7 +7,8 @@ Archivo adjunto No se han encontrado conversaciones Inicia una conversación - Reply + Responder + Show a character counter at writing messages Nueva conversación @@ -18,7 +19,7 @@ Mensaje recibico Nuevo mensaje Marcar como leído - Mark as Unread + Marcar como no leído ¿Estás seguro que quieres eliminar todos los mensajes en esta conversación? @@ -37,7 +38,7 @@ ¿Por qué la aplicación requiere acceso a internet? - Tristemente es necesitado apra enviar archivos adjuntos MMS. El no poder enviar MMS sería una desventaja realmente enorme comparada con otras aplicaciones, así que decidimos tomar este camino. + Tristemente es necesitado para enviar archivos adjuntos MMS. El no poder enviar MMS sería una desventaja realmente enorme comparada con otras aplicaciones, así que decidimos tomar este camino. Sin embargo, como siempre, no hay anuncios, rastreo o análisis, por lo que el internet solo es usado para enviar MMS. diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml new file mode 100644 index 00000000..c5316090 --- /dev/null +++ b/app/src/main/res/values-fr/strings.xml @@ -0,0 +1,74 @@ + + Simple SMS Messenger + SMS Messenger + Écrivez un message... + Le message n\'a pas été envoyé. + Ajouter une personne + Pièce jointe + Aucune conversation enregistrée n\'a été trouvée + Commencer une conversation + Répondre + Show a character counter at writing messages + + + Nouvelle conversation + Ajouter un contact ou un numéro... + Suggestions + + + SMS reçu + Nouveau message + Marquer comme lu + Marquer comme non lu + + + Êtes-vous sûr de vouloir supprimer tous les messages de cette conversation ? + + + + %d conversation + %d conversations + + + + + %d message + %d messages + + + + Pourquoi cette application a besoin d\'un accès à internet ? + Malheureusement, cela est nécessaire pour envoyer des pièces jointes dans les MMS. Ne pas pouvoir envoyer de MMS serait un énorme désavantage comparé à d\'autres applications, nous avons donc décidé de faire ainsi. + Cependant, comme toujours, il n\'y a aucune publicité, traqueur ou analyseur de quelque sorte, internet n\'est utilisé que pour envoyer des MMS. + + + + Simple SMS Messenger - Gérez vos messages aisément + + Une façon simple et rapide de gérer ses SMS et MMS sans publicités. + + Une excellente façon de rester en contact avec vos proches, en envoyant à la fois des SMS et des MMS. L\'application gère parfaitement les messages de groupe, tout comme le blocage des numéros sur Android 7+. + + Elle offre un choix large de format de date, pour être confortable à utiliser. Vous pouvez choisir entre un format 12 et 24 heures. + + La taille de l\'application est très légère comparée à la concurrence, ce qui la rend rapide à télécharger. + + Avec un Material Design et un thème sombre par défaut, elle offre une excellente expérience utilisateur pour une utilisation facile. L\'absence d\'accès à internet vous donne plus de confidentialité, de sécurité et de stabilité que les autres applications. + + Ne contient aucune publicité ou autorisation inutile. Elle est entièrement open source, avec des couleurs personnalisables. + + Découvrez la suite complète des applications Simple Mobile Tools ici : + https://www.simplemobiletools.com + + Facebook: + https://www.facebook.com/simplemobiletools + + Reddit: + https://www.reddit.com/r/SimpleMobileTools + + + + diff --git a/app/src/main/res/values-gl b/app/src/main/res/values-gl new file mode 100644 index 00000000..ef3cabd1 --- /dev/null +++ b/app/src/main/res/values-gl @@ -0,0 +1,72 @@ + + Simple SMS Messenger + Mensaxe SMS + Escribir unha mensaxe… + Mensaxe non enviada + Engadir persoa + Anexo + Non se atoparon conversas + Iniciar unha conversa + Responder + + + Nova conversa + Engadir contacto ou número… + Suxerencias + + + SMS recibida + Nova mensaxe + Marcar como lida + Marcar como non lida + + + Ten a certeza de que desexa eliminar todas as mensaxes desta conversa? + + + + %d conversa + %d conversas + + + + + %d mensaxe + %d mensaxes + + + + Por que o aplicativo necesita acceder a Internet? + Infelizmente é a única forma para poder enviar anexos MMS. A incapacidade de non conseguir enviar MMS sería unha enorme desvantaxe comparativamente a outros aplicativos e, por iso, tomamos esta decisión. Pero, como habitualmente, o aplicativo non ten anuncios, non rastrea os utilizadores nin recolle datos persoais. Este permiso só é necesario para enviar as MMS. + + + + Simple SMS Messenger - Xestor de mensaxes + + Aplictivo simple para xestionar SMS e MMS sen anuncios. + + Unha excelente forma para manter o contacto cos seus amigos e familiares. Tamén pode ser usada para mensaxes de grupo e posibilita o bloqueo de números de teléfono nas versións superiores a Android 7. + + Permite a utilización de varios formatos de data e das horas. + + É un aplicativo pequeno, que fai que a súa descarga sexa moi rápida. + + Fai que estea dispoñible un deseño atractivo e un tema escuro por defecto. Como non necesita o acceso a Internet, tes máis privacidade, seguranza e estabilidade. + + Non ten anuncios nin permisos innecesarios. É de código aberto e permite a personalización das cores. + + Visita a páxina a través desta ligazón: + https://www.simplemobiletools.com + + Facebook: + https://www.facebook.com/simplemobiletools + + Reddit: + https://www.reddit.com/r/SimpleMobileTools + + + + diff --git a/app/src/main/res/values-lt/strings.xml b/app/src/main/res/values-lt/strings.xml index d56da48b..45372922 100644 --- a/app/src/main/res/values-lt/strings.xml +++ b/app/src/main/res/values-lt/strings.xml @@ -8,6 +8,7 @@ Nebuvo rasta išsaugotų pokalbių Pradėtipokalbį Reply + Show a character counter at writing messages Naujas pokalbis diff --git a/app/src/main/res/values-ml/strings.xml b/app/src/main/res/values-ml/strings.xml new file mode 100644 index 00000000..c6b7dffc --- /dev/null +++ b/app/src/main/res/values-ml/strings.xml @@ -0,0 +1,74 @@ + + Simple SMS Messenger + SMS മെസഞ്ചർ + മെസ്സേജ് ടൈപ്പ് ചെയ്യുക + മെസ്സേജ് അയച്ചിട്ടില്ല. + വ്യക്തിയെ ചേർക്കുക + അറ്റാച്ചുമെന്റ് + സ്റ്റോർ ചെയ്ത സംഭാഷണങ്ങളൊന്നും കണ്ടെത്തിയില്ല + ഒരു സംഭാഷണം ആരംഭിക്കുക + ഒരു സംഭാഷണം ആരംഭിക്കുക + Show a character counter at writing messages + + + പുതിയ സംഭാഷണം + കോൺടാക്റ്റ് അല്ലെങ്കിൽ നമ്പർ ചേർക്കുക… + നിർദ്ദേശങ്ങൾ + + + SMS ലഭിച്ചു + പുതിയ മെസ്സേജ് + വായിച്ചതായി അടയാളപ്പെടുത്തുക + വായിച്ചിട്ടില്ലെന്ന് അടയാളപ്പെടുത്തുക + + + ഈ സംഭാഷണത്തിന്റെ എല്ലാ സന്ദേശങ്ങൾ ഇല്ലാതാക്കാൻ നിങ്ങൾ ആഗ്രഹിക്കുന്നുണ്ടോ? + + + + %d conversation + %d conversations + + + + + %d message + %d messages + + + + അപ്ലിക്കേഷന് ഇന്റർനെറ്റിലേക്ക് ആവശ്യമായി വരുന്നത് എന്തുകൊണ്ട്? + നിർഭാഗ്യവശാൽ, MMS അറ്റാച്ചുമെന്റുകൾ അയക്കുന്നതിനു ഇത് ആവശ്യമാണ്. മറ്റ് ആപ്ലിക്കേഷനുകളുമായി താരതമ്യപ്പെടുത്തുമ്പോൾ MMS അയയ്ക്കാൻ കഴിയുന്നില്ല എന്നത് ഒരു വലിയ പോരായ്മയാണ്, അതിനാൽ ഞങ്ങൾ ഈ റൂട്ടിൽ പോകാൻ തീരുമാനിച്ചു. + എന്നിരുന്നാലും, സാധാരണപോലെ, പരസ്യങ്ങളോ ട്രാക്കിംഗ് അല്ലെങ്കിൽ അനലിറ്റിക്സുകളോ ഇല്ല. ഇന്റർനെറ്റ് MMS അയയ്ക്കുന്നതിന് മാത്രമാണ് ഉപയോഗിക്കുന്നത്. + + + + Simple SMS Messenger - മെസ്സേജുകൾ കൈകാര്യം ചെയ്യുക + + SMS, MMS സന്ദേശങ്ങൾ കൈകാര്യം ചെയ്യുന്നതിനുള്ള ഏറ്റവും എളുപ്പ മാർഗം. + + A great way to stay in touch with your relatives, by sending both SMS and MMS messages. The app properly handles group messaging too, just like blocking numbers from Android 7+. + + It offers many date formats to choose from, to make you feel comfortable at using it. You can toggle between 12 and 24 hours time format too. + + It has a really tiny app size compared to the competition, making it really fast to download. + + It comes with material design and dark theme by default, provides great user experience for easy usage. The lack of internet access gives you more privacy, security and stability than other apps. + + Contains no ads or unnecessary permissions. It is fully opensource, provides customizable colors. + + Check out the full suite of Simple Tools here: + https://www.simplemobiletools.com + + Facebook: + https://www.facebook.com/simplemobiletools + + Reddit: + https://www.reddit.com/r/SimpleMobileTools + + + + diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml index 34d570c0..87c66bf6 100644 --- a/app/src/main/res/values-nl/strings.xml +++ b/app/src/main/res/values-nl/strings.xml @@ -8,6 +8,7 @@ Geen opgeslagen berichten gevonden Een gesprek starten Beantwoorden + Show a character counter at writing messages Nieuw gesprek diff --git a/app/src/main/res/values-pt/strings.xml b/app/src/main/res/values-pt/strings.xml index 1e8cd40f..e91e9a06 100644 --- a/app/src/main/res/values-pt/strings.xml +++ b/app/src/main/res/values-pt/strings.xml @@ -1,13 +1,14 @@ Simple SMS Messenger SMS Messenger - Escreva uma mensagem… - Mensagem não enviada. + Escrever uma mensagem… + Mensagem não enviada Adicionar pessoa Anexo Não foram encontradas conversas Iniciar uma conversa - Reply + Responder + Show a character counter at writing messages Nova conversa @@ -18,7 +19,7 @@ SMS recebida Nova mensagem Marcar como lida - Mark as Unread + Marcar como não lida Tem a certeza de que deseja eliminar todas as mensagens desta conversa? diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index de374dbc..5b2531b9 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -8,6 +8,7 @@ Нет сохранённых переписок Начать переписку Ответ + Show a character counter at writing messages Новая переписка diff --git a/app/src/main/res/values-sk/strings.xml b/app/src/main/res/values-sk/strings.xml index 5964e8b0..48028ba9 100644 --- a/app/src/main/res/values-sk/strings.xml +++ b/app/src/main/res/values-sk/strings.xml @@ -8,6 +8,7 @@ Nenašli sa žiadne uložené konverzácie Začať konverzáciu Odpovedať + Zobraziť počítadlo znakov pri písaní správ Nová konverzácia diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml new file mode 100644 index 00000000..947cef63 --- /dev/null +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -0,0 +1,74 @@ + + 简易短信 + 短信 + 输入一个消息… + 消息尚未发送。 + 添加人 + 附件 + 未找到保存的对话 + 开始一个对话 + 回复 + Show a character counter at writing messages + + + 新的对话 + 添加联系人或者号码… + 建议 + + + 接收到的短信 + 新消息 + 标记为已读 + 标记为未读 + + + 您确定您想要删除这个对话的所有消息? + + + + %d 个对话 + %d 个对话 + + + + + %d 个消息 + %d 个消息 + + + + 为什么该应用需要访问互联网? + 很遗憾这对于发送彩信附件是必须的。如果不能发送彩信的话这相比其他应用会是一个巨大的劣势,所以我们决定这么采取现在的方式。 + 但是和其他应用一样,不包含广告、追踪或者任意的分析工具, 互联网访问仅用于发送彩信。 + + + + 简易短信 - 轻松管理消息 + + 无广告的管理短信和彩信的轻松和简便方式。 + + 发送短信和彩信是一个和您亲友保持联系的绝佳方式。这个应用也可以可以正确处理群消息,在 Android 7 以上版本亦可阻止号码。 + + 它提供多个日期格式以便选择,符合您使用习惯。您也可以在 12 和 24 时制格式之间选择。 + + 它相对于其他竞品有着极小的大小,使得其下载非常快。 + + 它遵循质感设计且默认应用黑暗模式,提供便于使用的极佳的用户体验。 + + 不包含广告及非必要的权限,而且完全开放源代码,并提供自定义颜色。 + + 于此查看简易工具系列全套: + https://www.simplemobiletools.com + + Facebook: + https://www.facebook.com/simplemobiletools + + Reddit: + https://www.reddit.com/r/SimpleMobileTools + + + + diff --git a/app/src/main/res/values/donottranslate.xml b/app/src/main/res/values/donottranslate.xml new file mode 100644 index 00000000..24f6140e --- /dev/null +++ b/app/src/main/res/values/donottranslate.xml @@ -0,0 +1,5 @@ + + + com.simplemobiletools.smsmessenger + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 81ac90b0..ce68413e 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -8,6 +8,7 @@ No stored conversations have been found Start a conversation Reply + Show a character counter at writing messages New conversation diff --git a/build.gradle b/build.gradle index ff843f13..b55955d2 100644 --- a/build.gradle +++ b/build.gradle @@ -1,14 +1,14 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { - ext.kotlin_version = '1.3.72' + ext.kotlin_version = '1.4.10' repositories { google() jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:3.6.3' + classpath 'com.android.tools.build:gradle:4.1.0' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" // NOTE: Do not place your application dependencies here; they belong diff --git a/fastlane/metadata/android/en-US/changelogs/11.txt b/fastlane/metadata/android/en-US/changelogs/11.txt new file mode 100644 index 00000000..10c574f6 --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/11.txt @@ -0,0 +1,3 @@ + * Show unread message badges on some devices that support it + * Added some improvements related to handling private contacts + * Other stability, UI and translation improvements diff --git a/fastlane/metadata/android/en-US/changelogs/12.txt b/fastlane/metadata/android/en-US/changelogs/12.txt new file mode 100644 index 00000000..5a138404 --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/12.txt @@ -0,0 +1,2 @@ + * Show a tick at successfully sent messages + * Properly show the sender name at incoming messages, if sent by a private contact diff --git a/fastlane/metadata/android/en-US/changelogs/13.txt b/fastlane/metadata/android/en-US/changelogs/13.txt new file mode 100644 index 00000000..48427789 --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/13.txt @@ -0,0 +1 @@ + * Fix incoming message notifications sometimes not being shown diff --git a/fastlane/metadata/android/en-US/changelogs/14.txt b/fastlane/metadata/android/en-US/changelogs/14.txt new file mode 100644 index 00000000..d1407a53 --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/14.txt @@ -0,0 +1 @@ + * Fixing a crash at receiving MMS diff --git a/fastlane/metadata/android/en-US/changelogs/15.txt b/fastlane/metadata/android/en-US/changelogs/15.txt new file mode 100644 index 00000000..d1407a53 --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/15.txt @@ -0,0 +1 @@ + * Fixing a crash at receiving MMS diff --git a/fastlane/metadata/android/en-US/changelogs/17.txt b/fastlane/metadata/android/en-US/changelogs/17.txt new file mode 100644 index 00000000..20f8c7b5 --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/17.txt @@ -0,0 +1 @@ + * Fixed some smaller glitches + translation improvements diff --git a/fastlane/metadata/android/en-US/changelogs/18.txt b/fastlane/metadata/android/en-US/changelogs/18.txt new file mode 100644 index 00000000..986a4467 --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/18.txt @@ -0,0 +1,4 @@ + * Allow dialing or copying selected conversation phone numbers + * Allow copying specific parts of messages into clipboard + * Adding an option to show character counter at outgoing messages + * Couple other UI, translation and stability improvements diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 1a1dba62..a99abc9d 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Fri Apr 03 09:58:13 CEST 2020 +#Tue Nov 03 16:00:32 CET 2020 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-bin.zip