Add message grouping by subject

This commit is contained in:
Christian Basler 2018-04-03 22:14:46 +02:00
parent 6a311a0346
commit 1426b786e8
7 changed files with 67 additions and 36 deletions

View File

@ -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)

View File

@ -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
}
} }

View File

@ -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"

View File

@ -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)

View File

@ -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>

View File

@ -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>

View File

@ -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"