Add message grouping by subject
This commit is contained in:
parent
6a311a0346
commit
1426b786e8
@ -114,7 +114,7 @@ class MainActivity : AppCompatActivity(), ListSelectionListener<Serializable> {
|
|||||||
val toolbar = findViewById<Toolbar>(R.id.toolbar)
|
val toolbar = findViewById<Toolbar>(R.id.toolbar)
|
||||||
setSupportActionBar(toolbar)
|
setSupportActionBar(toolbar)
|
||||||
|
|
||||||
val listFragment = MessageListFragment()
|
val listFragment = ConversationListFragment()
|
||||||
supportFragmentManager
|
supportFragmentManager
|
||||||
.beginTransaction()
|
.beginTransaction()
|
||||||
.replace(R.id.item_list, listFragment)
|
.replace(R.id.item_list, listFragment)
|
||||||
@ -303,6 +303,7 @@ class MainActivity : AppCompatActivity(), ListSelectionListener<Serializable> {
|
|||||||
currentLabel.value = intent.getSerializableExtra(EXTRA_SHOW_LABEL) as Label
|
currentLabel.value = intent.getSerializableExtra(EXTRA_SHOW_LABEL) as Label
|
||||||
} else if (currentLabel.value == null) {
|
} else if (currentLabel.value == null) {
|
||||||
currentLabel.value = labels[0]
|
currentLabel.value = labels[0]
|
||||||
|
|
||||||
}
|
}
|
||||||
for (label in labels) {
|
for (label in labels) {
|
||||||
addLabelEntry(label)
|
addLabelEntry(label)
|
||||||
|
@ -19,8 +19,11 @@ package ch.dissem.apps.abit.listener
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import ch.dissem.apps.abit.MainActivity
|
import ch.dissem.apps.abit.MainActivity
|
||||||
import ch.dissem.apps.abit.notification.NewMessageNotification
|
import ch.dissem.apps.abit.notification.NewMessageNotification
|
||||||
|
import ch.dissem.apps.abit.util.Preferences
|
||||||
import ch.dissem.bitmessage.BitmessageContext
|
import ch.dissem.bitmessage.BitmessageContext
|
||||||
import ch.dissem.bitmessage.entity.Plaintext
|
import ch.dissem.bitmessage.entity.Plaintext
|
||||||
|
import ch.dissem.bitmessage.ports.MessageRepository
|
||||||
|
import ch.dissem.bitmessage.utils.ConversationService
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import java.util.concurrent.Executors
|
import java.util.concurrent.Executors
|
||||||
|
|
||||||
@ -33,14 +36,26 @@ import java.util.concurrent.Executors
|
|||||||
* notifications should be combined.
|
* notifications should be combined.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
class MessageListener(ctx: Context) : BitmessageContext.Listener {
|
class MessageListener(ctx: Context) : BitmessageContext.Listener.WithContext {
|
||||||
|
override fun setContext(ctx: BitmessageContext) {
|
||||||
|
messageRepo = ctx.messages
|
||||||
|
conversationService = ConversationService(messageRepo)
|
||||||
|
}
|
||||||
|
|
||||||
private val unacknowledged = LinkedList<Plaintext>()
|
private val unacknowledged = LinkedList<Plaintext>()
|
||||||
private var numberOfUnacknowledgedMessages = 0
|
private var numberOfUnacknowledgedMessages = 0
|
||||||
private val notification = NewMessageNotification(ctx)
|
private val notification = NewMessageNotification(ctx)
|
||||||
private val pool = Executors.newSingleThreadExecutor()
|
private val pool = Executors.newSingleThreadExecutor()
|
||||||
|
private lateinit var messageRepo: MessageRepository
|
||||||
|
private lateinit var conversationService: ConversationService
|
||||||
|
|
||||||
|
init {
|
||||||
|
emulateConversations = Preferences.isEmulateConversations(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
override fun receive(plaintext: Plaintext) {
|
override fun receive(plaintext: Plaintext) {
|
||||||
pool.submit {
|
pool.submit {
|
||||||
|
updateConversation(plaintext)
|
||||||
unacknowledged.addFirst(plaintext)
|
unacknowledged.addFirst(plaintext)
|
||||||
numberOfUnacknowledgedMessages++
|
numberOfUnacknowledgedMessages++
|
||||||
if (unacknowledged.size > 5) {
|
if (unacknowledged.size > 5) {
|
||||||
@ -65,4 +80,17 @@ class MessageListener(ctx: Context) : BitmessageContext.Listener {
|
|||||||
numberOfUnacknowledgedMessages = 0
|
numberOfUnacknowledgedMessages = 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun updateConversation(plaintext: Plaintext) {
|
||||||
|
if (emulateConversations && plaintext.encoding != Plaintext.Encoding.EXTENDED) {
|
||||||
|
conversationService.getSubject(listOf(plaintext))?.let { subject ->
|
||||||
|
plaintext.conversationId = UUID.nameUUIDFromBytes(subject.toByteArray())
|
||||||
|
messageRepo.save(plaintext)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private var emulateConversations = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,7 @@ import java.util.regex.Pattern
|
|||||||
*/
|
*/
|
||||||
object Constants {
|
object Constants {
|
||||||
const val PREFERENCE_WIFI_ONLY = "wifi_only"
|
const val PREFERENCE_WIFI_ONLY = "wifi_only"
|
||||||
|
const val PREFERENCE_EMULATE_CONVERSATIONS = "emulate_conversations"
|
||||||
const val PREFERENCE_TRUSTED_NODE = "trusted_node"
|
const val PREFERENCE_TRUSTED_NODE = "trusted_node"
|
||||||
const val PREFERENCE_SYNC_TIMEOUT = "sync_timeout"
|
const val PREFERENCE_SYNC_TIMEOUT = "sync_timeout"
|
||||||
const val PREFERENCE_SERVER_POW = "server_pow"
|
const val PREFERENCE_SERVER_POW = "server_pow"
|
||||||
|
@ -17,15 +17,16 @@
|
|||||||
package ch.dissem.apps.abit.util
|
package ch.dissem.apps.abit.util
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.preference.PreferenceManager
|
|
||||||
import ch.dissem.apps.abit.R
|
import ch.dissem.apps.abit.R
|
||||||
import ch.dissem.apps.abit.notification.ErrorNotification
|
import ch.dissem.apps.abit.notification.ErrorNotification
|
||||||
|
import ch.dissem.apps.abit.util.Constants.PREFERENCE_EMULATE_CONVERSATIONS
|
||||||
import ch.dissem.apps.abit.util.Constants.PREFERENCE_FULL_NODE
|
import ch.dissem.apps.abit.util.Constants.PREFERENCE_FULL_NODE
|
||||||
import ch.dissem.apps.abit.util.Constants.PREFERENCE_REQUEST_ACK
|
import ch.dissem.apps.abit.util.Constants.PREFERENCE_REQUEST_ACK
|
||||||
import ch.dissem.apps.abit.util.Constants.PREFERENCE_SYNC_TIMEOUT
|
import ch.dissem.apps.abit.util.Constants.PREFERENCE_SYNC_TIMEOUT
|
||||||
import ch.dissem.apps.abit.util.Constants.PREFERENCE_TRUSTED_NODE
|
import ch.dissem.apps.abit.util.Constants.PREFERENCE_TRUSTED_NODE
|
||||||
import ch.dissem.apps.abit.util.Constants.PREFERENCE_WIFI_ONLY
|
import ch.dissem.apps.abit.util.Constants.PREFERENCE_WIFI_ONLY
|
||||||
import org.jetbrains.anko.connectivityManager
|
import org.jetbrains.anko.connectivityManager
|
||||||
|
import org.jetbrains.anko.defaultSharedPreferences
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
@ -70,57 +71,48 @@ object Preferences {
|
|||||||
return Integer.parseInt(portString)
|
return Integer.parseInt(portString)
|
||||||
} catch (e: NumberFormatException) {
|
} catch (e: NumberFormatException) {
|
||||||
ErrorNotification(ctx)
|
ErrorNotification(ctx)
|
||||||
.setError(R.string.error_invalid_sync_port, portString)
|
.setError(R.string.error_invalid_sync_port, portString)
|
||||||
.show()
|
.show()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 8444
|
return 8444
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getTimeoutInSeconds(ctx: Context): Long {
|
fun getTimeoutInSeconds(ctx: Context): Long =
|
||||||
val preference = getPreference(ctx, PREFERENCE_SYNC_TIMEOUT) ?: return 120
|
getPreference(ctx, PREFERENCE_SYNC_TIMEOUT)?.toLong() ?: 120
|
||||||
return preference.toLong()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getPreference(ctx: Context, name: String): String? {
|
private fun getPreference(ctx: Context, name: String): String? =
|
||||||
val preferences = PreferenceManager.getDefaultSharedPreferences(ctx)
|
ctx.defaultSharedPreferences.getString(name, null)
|
||||||
|
|
||||||
return preferences.getString(name, null)
|
fun isConnectionAllowed(ctx: Context) =
|
||||||
}
|
!isWifiOnly(ctx) || !ctx.connectivityManager.isActiveNetworkMetered
|
||||||
|
|
||||||
fun isConnectionAllowed(ctx: Context) = !isWifiOnly(ctx) || !ctx.connectivityManager.isActiveNetworkMetered
|
fun isWifiOnly(ctx: Context) =
|
||||||
|
ctx.defaultSharedPreferences.getBoolean(PREFERENCE_WIFI_ONLY, true)
|
||||||
fun isWifiOnly(ctx: Context): Boolean {
|
|
||||||
val preferences = PreferenceManager.getDefaultSharedPreferences(ctx)
|
|
||||||
return preferences.getBoolean(PREFERENCE_WIFI_ONLY, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setWifiOnly(ctx: Context, status: Boolean) {
|
fun setWifiOnly(ctx: Context, status: Boolean) {
|
||||||
val preferences = PreferenceManager.getDefaultSharedPreferences(ctx)
|
ctx.defaultSharedPreferences.edit()
|
||||||
preferences.edit().putBoolean(PREFERENCE_WIFI_ONLY, status).apply()
|
.putBoolean(PREFERENCE_WIFI_ONLY, status)
|
||||||
|
.apply()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isFullNodeActive(ctx: Context): Boolean {
|
fun isEmulateConversations(ctx: Context) =
|
||||||
val preferences = PreferenceManager.getDefaultSharedPreferences(ctx)
|
ctx.defaultSharedPreferences.getBoolean(PREFERENCE_EMULATE_CONVERSATIONS, true)
|
||||||
return preferences.getBoolean(PREFERENCE_FULL_NODE, false)
|
|
||||||
}
|
|
||||||
|
fun isFullNodeActive(ctx: Context) =
|
||||||
|
ctx.defaultSharedPreferences.getBoolean(PREFERENCE_FULL_NODE, false)
|
||||||
|
|
||||||
fun setFullNodeActive(ctx: Context, status: Boolean) {
|
fun setFullNodeActive(ctx: Context, status: Boolean) {
|
||||||
val preferences = PreferenceManager.getDefaultSharedPreferences(ctx)
|
ctx.defaultSharedPreferences.edit()
|
||||||
preferences.edit().putBoolean(PREFERENCE_FULL_NODE, status).apply()
|
.putBoolean(PREFERENCE_FULL_NODE, status)
|
||||||
|
.apply()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getExportDirectory(ctx: Context) = File(ctx.filesDir, "exports")
|
fun getExportDirectory(ctx: Context) = File(ctx.filesDir, "exports")
|
||||||
|
|
||||||
fun requestAcknowledgements(ctx: Context): Boolean {
|
fun requestAcknowledgements(ctx: Context) =
|
||||||
val preferences = PreferenceManager.getDefaultSharedPreferences(ctx)
|
ctx.defaultSharedPreferences.getBoolean(PREFERENCE_REQUEST_ACK, true)
|
||||||
return preferences.getBoolean(PREFERENCE_REQUEST_ACK, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setRequestAcknowledgements(ctx: Context, status: Boolean) {
|
|
||||||
val preferences = PreferenceManager.getDefaultSharedPreferences(ctx)
|
|
||||||
preferences.edit().putBoolean(PREFERENCE_REQUEST_ACK, status).apply()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun cleanupExportDirectory(ctx: Context) {
|
fun cleanupExportDirectory(ctx: Context) {
|
||||||
val exportDirectory = getExportDirectory(ctx)
|
val exportDirectory = getExportDirectory(ctx)
|
||||||
|
@ -137,4 +137,6 @@ Als Alternative kann in den Einstellungen ein vertrauenswürdiger Knoten konfigu
|
|||||||
<string name="broadcasts">Broadcasts</string>
|
<string name="broadcasts">Broadcasts</string>
|
||||||
<string name="encoding_simple">einfach</string>
|
<string name="encoding_simple">einfach</string>
|
||||||
<string name="encoding_extended">erweitert</string>
|
<string name="encoding_extended">erweitert</string>
|
||||||
|
<string name="emulate_conversations">Konversation erraten</string>
|
||||||
|
<string name="emulate_conversations_summary">Benutze Betreff um zu erraten welche Nachrichten zusammengehören. Die Reihenfolge stimmt häufig nicht.</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -137,4 +137,6 @@ As an alternative you could configure a trusted node in the settings, but as of
|
|||||||
<string name="encoding_simple">simple</string>
|
<string name="encoding_simple">simple</string>
|
||||||
<string name="encoding_extended">extended</string>
|
<string name="encoding_extended">extended</string>
|
||||||
<string name="context_menu">actions</string>
|
<string name="context_menu">actions</string>
|
||||||
|
<string name="emulate_conversations">Guess conversations</string>
|
||||||
|
<string name="emulate_conversations_summary">Use subject to determine which messages belong together. The order will likely be wrong.</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -5,6 +5,11 @@
|
|||||||
android:key="wifi_only"
|
android:key="wifi_only"
|
||||||
android:summary="@string/wifi_only_summary"
|
android:summary="@string/wifi_only_summary"
|
||||||
android:title="@string/wifi_only" />
|
android:title="@string/wifi_only" />
|
||||||
|
<android.support.v7.preference.SwitchPreferenceCompat
|
||||||
|
android:defaultValue="true"
|
||||||
|
android:key="emulate_conversations"
|
||||||
|
android:summary="@string/emulate_conversations_summary"
|
||||||
|
android:title="@string/emulate_conversations" />
|
||||||
<android.support.v7.preference.SwitchPreferenceCompat
|
<android.support.v7.preference.SwitchPreferenceCompat
|
||||||
android:defaultValue="true"
|
android:defaultValue="true"
|
||||||
android:key="request_acknowledgements"
|
android:key="request_acknowledgements"
|
||||||
|
Loading…
Reference in New Issue
Block a user