Merge branch 'feature/performance-improvements' into develop

This commit is contained in:
Christian Basler 2017-09-22 21:01:04 +02:00
commit f58a22dadb
19 changed files with 164 additions and 88 deletions

View File

@ -20,8 +20,8 @@ android {
applicationId "ch.dissem.apps." + appName.toLowerCase() applicationId "ch.dissem.apps." + appName.toLowerCase()
minSdkVersion 19 minSdkVersion 19
targetSdkVersion 25 targetSdkVersion 25
versionCode 16 versionCode 17
versionName "1.0-beta16" versionName "1.0-beta17"
multiDexEnabled true multiDexEnabled true
} }
compileOptions { compileOptions {
@ -39,7 +39,7 @@ android {
} }
//ext.jabitVersion = '2.0.4' //ext.jabitVersion = '2.0.4'
ext.jabitVersion = 'feature-exports-SNAPSHOT' ext.jabitVersion = 'development-SNAPSHOT'
ext.supportVersion = '25.3.1' ext.supportVersion = '25.3.1'
dependencies { dependencies {
compile fileTree(dir: 'libs', include: ['*.jar']) compile fileTree(dir: 'libs', include: ['*.jar'])

View File

@ -29,7 +29,6 @@ import ch.dissem.apps.abit.drawer.ProfileImageListener
import ch.dissem.apps.abit.drawer.ProfileSelectionListener import ch.dissem.apps.abit.drawer.ProfileSelectionListener
import ch.dissem.apps.abit.listener.ListSelectionListener import ch.dissem.apps.abit.listener.ListSelectionListener
import ch.dissem.apps.abit.repository.AndroidMessageRepository.Companion.LABEL_ARCHIVE import ch.dissem.apps.abit.repository.AndroidMessageRepository.Companion.LABEL_ARCHIVE
import ch.dissem.apps.abit.service.BitmessageService.Companion.isRunning
import ch.dissem.apps.abit.service.Singleton import ch.dissem.apps.abit.service.Singleton
import ch.dissem.apps.abit.synchronization.SyncAdapter import ch.dissem.apps.abit.synchronization.SyncAdapter
import ch.dissem.apps.abit.util.Labels import ch.dissem.apps.abit.util.Labels
@ -99,8 +98,8 @@ class MainActivity : AppCompatActivity(), ListSelectionListener<Serializable> {
private lateinit var drawer: Drawer private lateinit var drawer: Drawer
private lateinit var nodeSwitch: SwitchDrawerItem private lateinit var nodeSwitch: SwitchDrawerItem
val floatingActionButton: FabSpeedDial val floatingActionButton: FabSpeedDial?
get() = fab get() = findViewById(R.id.fab) as FabSpeedDial?
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
@ -241,7 +240,7 @@ class MainActivity : AppCompatActivity(), ListSelectionListener<Serializable> {
.withIdentifier(ID_NODE_SWITCH) .withIdentifier(ID_NODE_SWITCH)
.withName(R.string.full_node) .withName(R.string.full_node)
.withIcon(CommunityMaterial.Icon.cmd_cloud_outline) .withIcon(CommunityMaterial.Icon.cmd_cloud_outline)
.withChecked(isRunning) .withChecked(Preferences.isFullNodeActive(this))
.withOnCheckedChangeListener { _, _, isChecked -> .withOnCheckedChangeListener { _, _, isChecked ->
if (isChecked) { if (isChecked) {
NetworkUtils.enableNode(this@MainActivity) NetworkUtils.enableNode(this@MainActivity)
@ -359,12 +358,13 @@ class MainActivity : AppCompatActivity(), ListSelectionListener<Serializable> {
} }
override fun onRestoreInstanceState(savedInstanceState: Bundle) { override fun onRestoreInstanceState(savedInstanceState: Bundle) {
selectedLabel = savedInstanceState.getSerializable("selectedLabel") as Label selectedLabel = savedInstanceState.getSerializable("selectedLabel") as Label?
val selectedItem = drawer.getDrawerItem(selectedLabel) selectedLabel?.let { selectedLabel ->
if (selectedItem != null) { drawer.getDrawerItem(selectedLabel)?.let { selectedItem ->
drawer.setSelection(selectedItem) drawer.setSelection(selectedItem)
} }
}
super.onRestoreInstanceState(savedInstanceState) super.onRestoreInstanceState(savedInstanceState)
} }
@ -373,7 +373,6 @@ class MainActivity : AppCompatActivity(), ListSelectionListener<Serializable> {
if (Preferences.isFullNodeActive(this) && Preferences.isConnectionAllowed(this@MainActivity)) { if (Preferences.isFullNodeActive(this) && Preferences.isConnectionAllowed(this@MainActivity)) {
NetworkUtils.enableNode(this, false) NetworkUtils.enableNode(this, false)
} }
updateNodeSwitch()
Singleton.getMessageListener(this).resetNotification() Singleton.getMessageListener(this).resetNotification()
active = true active = true
super.onResume() super.onResume()

View File

@ -111,14 +111,7 @@ class MessageDetailFragment : Fragment() {
text.linksClickable = true text.linksClickable = true
text.setTextIsSelectable(true) text.setTextIsSelectable(true)
var removed = false val removed = item.labels.removeAll { it.type==Label.Type.UNREAD }
val labels = item.labels.iterator()
while (labels.hasNext()) {
if (labels.next().type == Label.Type.UNREAD) {
labels.remove()
removed = true
}
}
val messageRepo = Singleton.getMessageRepository(context) val messageRepo = Singleton.getMessageRepository(context)
if (removed) { if (removed) {
if (activity is MainActivity) { if (activity is MainActivity) {
@ -167,29 +160,29 @@ class MessageDetailFragment : Fragment() {
} }
R.id.delete -> { R.id.delete -> {
if (isInTrash(item)) { if (isInTrash(item)) {
Singleton.labeler.delete(item)
messageRepo.remove(item) messageRepo.remove(item)
} else { } else {
item.labels.clear() Singleton.labeler.delete(item)
item.addLabels(messageRepo.getLabels(Label.Type.TRASH))
messageRepo.save(item) messageRepo.save(item)
} }
(activity as? MainActivity)?.updateUnread()
activity.onBackPressed() activity.onBackPressed()
return true return true
} }
R.id.mark_unread -> { R.id.mark_unread -> {
item.addLabels(messageRepo.getLabels(Label.Type.UNREAD)) Singleton.labeler.markAsUnread(item)
messageRepo.save(item) messageRepo.save(item)
if (activity is MainActivity) { (activity as? MainActivity)?.updateUnread()
(activity as MainActivity).updateUnread()
}
return true return true
} }
R.id.archive -> { R.id.archive -> {
if (item.isUnread() && activity is MainActivity) { if (item.isUnread() && activity is MainActivity) {
(activity as MainActivity).updateUnread() (activity as MainActivity).updateUnread()
} }
item.labels.clear() Singleton.labeler.archive(item)
messageRepo.save(item) messageRepo.save(item)
(activity as? MainActivity)?.updateUnread()
return true return true
} }
else -> return false else -> return false

View File

@ -16,12 +16,14 @@
package ch.dissem.apps.abit package ch.dissem.apps.abit
import android.content.Intent import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.support.v4.app.Fragment import android.support.v4.app.Fragment
import android.support.v4.content.ContextCompat import android.support.v4.content.ContextCompat
import android.support.v7.widget.LinearLayoutManager import android.support.v7.widget.LinearLayoutManager
import android.support.v7.widget.RecyclerView import android.support.v7.widget.RecyclerView
import android.support.v7.widget.RecyclerView.OnScrollListener
import android.view.* import android.view.*
import android.widget.Toast import android.widget.Toast
import ch.dissem.apps.abit.ComposeMessageActivity.Companion.EXTRA_BROADCAST import ch.dissem.apps.abit.ComposeMessageActivity.Companion.EXTRA_BROADCAST
@ -41,9 +43,12 @@ import com.h6ah4i.android.widget.advrecyclerview.utils.WrapperAdapterUtils
import io.github.kobakei.materialfabspeeddial.FabSpeedDialMenu import io.github.kobakei.materialfabspeeddial.FabSpeedDialMenu
import kotlinx.android.synthetic.main.fragment_message_list.* import kotlinx.android.synthetic.main.fragment_message_list.*
import org.jetbrains.anko.doAsync import org.jetbrains.anko.doAsync
import org.jetbrains.anko.support.v4.onUiThread
import org.jetbrains.anko.uiThread import org.jetbrains.anko.uiThread
import java.util.* import java.util.*
private const val PAGE_SIZE = 15
/** /**
* A list fragment representing a list of Messages. This fragment * A list fragment representing a list of Messages. This fragment
* also supports tablet devices by allowing list items to be given an * also supports tablet devices by allowing list items to be given an
@ -56,12 +61,32 @@ import java.util.*
*/ */
class MessageListFragment : Fragment(), ListHolder<Label> { class MessageListFragment : Fragment(), ListHolder<Label> {
private var layoutManager: RecyclerView.LayoutManager? = null private var isLoading = false
private var isLastPage = false
private var layoutManager: LinearLayoutManager? = null
private var swipeableMessageAdapter: SwipeableMessageAdapter? = null private var swipeableMessageAdapter: SwipeableMessageAdapter? = null
private var wrappedAdapter: RecyclerView.Adapter<*>? = null private var wrappedAdapter: RecyclerView.Adapter<*>? = null
private var recyclerViewSwipeManager: RecyclerViewSwipeManager? = null private var recyclerViewSwipeManager: RecyclerViewSwipeManager? = null
private var recyclerViewTouchActionGuardManager: RecyclerViewTouchActionGuardManager? = null private var recyclerViewTouchActionGuardManager: RecyclerViewTouchActionGuardManager? = null
private val recyclerViewOnScrollListener = object : OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView?, dx: Int, dy: Int) {
layoutManager?.let { layoutManager ->
val visibleItemCount = layoutManager.childCount
val totalItemCount = layoutManager.itemCount
val firstVisibleItemPosition = layoutManager.findFirstVisibleItemPosition()
if (!isLoading && !isLastPage) {
if (visibleItemCount + firstVisibleItemPosition >= totalItemCount - 5
&& firstVisibleItemPosition >= 0) {
loadMoreItems()
}
}
}
}
}
override var currentLabel: Label? = null override var currentLabel: Label? = null
private var emptyTrashMenuItem: MenuItem? = null private var emptyTrashMenuItem: MenuItem? = null
@ -70,6 +95,20 @@ class MessageListFragment : Fragment(), ListHolder<Label> {
private val backStack = Stack<Label>() private val backStack = Stack<Label>()
fun loadMoreItems() {
isLoading = true
swipeableMessageAdapter?.let { messageAdapter ->
doAsync {
val messages = messageRepo.findMessages(currentLabel, messageAdapter.itemCount, PAGE_SIZE)
onUiThread {
messageAdapter.addAll(messages)
isLoading = false
isLastPage = messages.size < PAGE_SIZE
}
}
}
}
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
@ -82,10 +121,8 @@ class MessageListFragment : Fragment(), ListHolder<Label> {
initFab(activity) initFab(activity)
messageRepo = Singleton.getMessageRepository(activity) messageRepo = Singleton.getMessageRepository(activity)
if (backStack.isEmpty()) { if (backStack.isEmpty() && currentLabel == null) {
doUpdateList(activity.selectedLabel) doUpdateList(activity.selectedLabel)
} else {
doUpdateList(backStack.peek())
} }
} }
@ -119,13 +156,7 @@ class MessageListFragment : Fragment(), ListHolder<Label> {
} }
} }
doAsync { loadMoreItems()
messageRepo.findMessageIds(label)
.map { messageRepo.getMessage(it) }
.forEach { message ->
uiThread { swipeableMessageAdapter?.add(message) }
}
}
} }
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View = override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View =
@ -153,17 +184,18 @@ class MessageListFragment : Fragment(), ListHolder<Label> {
adapter.eventListener = object : SwipeableMessageAdapter.EventListener { adapter.eventListener = object : SwipeableMessageAdapter.EventListener {
override fun onItemDeleted(item: Plaintext) { override fun onItemDeleted(item: Plaintext) {
if (MessageDetailFragment.isInTrash(item)) { if (MessageDetailFragment.isInTrash(item)) {
Singleton.labeler.delete(item)
messageRepo.remove(item) messageRepo.remove(item)
} else { } else {
item.labels.clear() Singleton.labeler.delete(item)
item.addLabels(messageRepo.getLabels(Label.Type.TRASH))
messageRepo.save(item) messageRepo.save(item)
} }
recyclerViewOnScrollListener.onScrolled(null, 0, 0)
} }
override fun onItemArchived(item: Plaintext) { override fun onItemArchived(item: Plaintext) {
item.labels.clear() Singleton.labeler.archive(item)
messageRepo.save(item) recyclerViewOnScrollListener.onScrolled(null, 0, 0)
} }
override fun onItemViewClicked(v: View?) { override fun onItemViewClicked(v: View?) {
@ -189,6 +221,7 @@ class MessageListFragment : Fragment(), ListHolder<Label> {
recycler_view.layoutManager = layoutManager recycler_view.layoutManager = layoutManager
recycler_view.adapter = wrappedAdapter // requires *wrapped* swipeableMessageAdapter recycler_view.adapter = wrappedAdapter // requires *wrapped* swipeableMessageAdapter
recycler_view.itemAnimator = animator recycler_view.itemAnimator = animator
recycler_view.addOnScrollListener(recyclerViewOnScrollListener)
recycler_view.addItemDecoration(SimpleListDividerDecorator( recycler_view.addItemDecoration(SimpleListDividerDecorator(
ContextCompat.getDrawable(context, R.drawable.list_divider_h), true)) ContextCompat.getDrawable(context, R.drawable.list_divider_h), true))
@ -204,6 +237,33 @@ class MessageListFragment : Fragment(), ListHolder<Label> {
recyclerViewTouchActionGuardManager = touchActionGuardManager recyclerViewTouchActionGuardManager = touchActionGuardManager
recyclerViewSwipeManager = swipeManager recyclerViewSwipeManager = swipeManager
this.swipeableMessageAdapter = adapter this.swipeableMessageAdapter = adapter
Singleton.labeler.listener = { message, added, removed ->
when {
currentLabel?.type == Label.Type.TRASH && added.all { it.type == Label.Type.TRASH } && removed.any { it.type == Label.Type.TRASH } -> {
// work-around for messages that are deleted from trash
swipeableMessageAdapter?.remove(message)
recyclerViewOnScrollListener.onScrolled(null, 0, 0)
}
currentLabel?.type == Label.Type.UNREAD && added.all { it.type == Label.Type.TRASH } -> {
// work-around for messages that are deleted from unread, which already have the unread label removed
swipeableMessageAdapter?.remove(message)
recyclerViewOnScrollListener.onScrolled(null, 0, 0)
}
added.contains(currentLabel) -> {
// in most cases, top should be the correct position, but time will show if
// the message should be properly sorted in
swipeableMessageAdapter?.addFirst(message)
}
removed.contains(currentLabel) -> {
swipeableMessageAdapter?.remove(message)
recyclerViewOnScrollListener.onScrolled(null, 0, 0)
}
removed.any { it.type == Label.Type.UNREAD } || added.any { it.type == Label.Type.UNREAD } -> {
swipeableMessageAdapter?.update(message)
}
}
}
} }
private fun initFab(context: MainActivity) { private fun initFab(context: MainActivity) {

View File

@ -96,6 +96,35 @@ class SwipeableMessageAdapter : RecyclerView.Adapter<SwipeableMessageAdapter.Vie
notifyDataSetChanged() notifyDataSetChanged()
} }
fun addFirst(item: Plaintext) {
val index = data.size
data.addFirst(item)
notifyItemInserted(index)
}
fun addAll(items: Collection<Plaintext>) {
val index = data.size
data.addAll(items)
notifyItemRangeInserted(index, items.size)
}
fun remove(item: Plaintext) {
val index = data.indexOf(item)
data.removeIf { it.id == item.id }
notifyItemRemoved(index)
}
fun update(item: Plaintext) {
data.replaceAll {
if (it.id == item.id) {
item
} else {
it
}
}
notifyItemChanged(data.indexOf(item))
}
fun clear(newLabel: Label?) { fun clear(newLabel: Label?) {
label = newLabel label = newLabel
data.clear() data.clear()

View File

@ -17,16 +17,12 @@
package ch.dissem.apps.abit.listener package ch.dissem.apps.abit.listener
import android.content.Context import android.content.Context
import java.util.Deque
import java.util.LinkedList
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors
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.bitmessage.BitmessageContext import ch.dissem.bitmessage.BitmessageContext
import ch.dissem.bitmessage.entity.Plaintext import ch.dissem.bitmessage.entity.Plaintext
import java.util.*
import java.util.concurrent.Executors
/** /**
* Listens for decrypted Bitmessage messages. Does show a notification. * Listens for decrypted Bitmessage messages. Does show a notification.

View File

@ -19,42 +19,18 @@ package ch.dissem.apps.abit.listener
import android.content.BroadcastReceiver import android.content.BroadcastReceiver
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.net.ConnectivityManager
import android.net.NetworkInfo
import ch.dissem.apps.abit.service.BitmessageService import ch.dissem.apps.abit.service.BitmessageService
import ch.dissem.apps.abit.service.Singleton import ch.dissem.apps.abit.service.Singleton
import ch.dissem.apps.abit.util.Preferences import ch.dissem.apps.abit.util.Preferences
import org.jetbrains.anko.connectivityManager
class WifiReceiver : BroadcastReceiver() { class WifiReceiver : BroadcastReceiver() {
override fun onReceive(ctx: Context, intent: Intent) { override fun onReceive(ctx: Context, intent: Intent) {
if ("android.net.conn.CONNECTIVITY_CHANGE" == intent.action) { if ("android.net.conn.CONNECTIVITY_CHANGE" == intent.action) {
val bmc = Singleton.getBitmessageContext(ctx) val bmc = Singleton.getBitmessageContext(ctx)
if (Preferences.isWifiOnly(ctx) && isConnectedToMeteredNetwork(ctx) && bmc.isRunning()) { if (Preferences.isFullNodeActive(ctx) && !bmc.isRunning() && !(Preferences.isWifiOnly(ctx) && ctx.connectivityManager.isActiveNetworkMetered)) {
bmc.shutdown()
}
if (Preferences.isFullNodeActive(ctx) && !bmc.isRunning() && !(Preferences.isWifiOnly(ctx) && isConnectedToMeteredNetwork(ctx))) {
ctx.startService(Intent(ctx, BitmessageService::class.java)) ctx.startService(Intent(ctx, BitmessageService::class.java))
} }
} }
} }
companion object {
fun isConnectedToMeteredNetwork(ctx: Context): Boolean {
val netInfo = getNetworkInfo(ctx)
if (netInfo == null || !netInfo.isConnectedOrConnecting) {
return false
}
when (netInfo.type) {
ConnectivityManager.TYPE_ETHERNET, ConnectivityManager.TYPE_WIFI -> return false
else -> return true
}
}
private fun getNetworkInfo(ctx: Context): NetworkInfo? {
val conMan = ctx.getSystemService(Context
.CONNECTIVITY_SERVICE) as ConnectivityManager
return conMan.activeNetworkInfo
}
}
} }

View File

@ -42,10 +42,10 @@ import java.util.*
*/ */
class AndroidMessageRepository(private val sql: SqlHelper, private val context: Context) : AbstractMessageRepository() { class AndroidMessageRepository(private val sql: SqlHelper, private val context: Context) : AbstractMessageRepository() {
override fun findMessages(label: Label?) = if (label === LABEL_ARCHIVE) { override fun findMessages(label: Label?, offset: Int, limit: Int) = if (label === LABEL_ARCHIVE) {
super.findMessages(null as Label?) super.findMessages(null as Label?, offset, limit)
} else { } else {
super.findMessages(label) super.findMessages(label, offset, limit)
} }
fun findMessageIds(label: Label) = if (label === LABEL_ARCHIVE) { fun findMessageIds(label: Label) = if (label === LABEL_ARCHIVE) {
@ -224,7 +224,7 @@ class AndroidMessageRepository(private val sql: SqlHelper, private val context:
return result return result
} }
override fun find(where: String): List<Plaintext> { override fun find(where: String, offset: Int, limit: Int): List<Plaintext> {
val result = LinkedList<Plaintext>() val result = LinkedList<Plaintext>()
// Define a projection that specifies which columns from the database // Define a projection that specifies which columns from the database
@ -235,7 +235,8 @@ class AndroidMessageRepository(private val sql: SqlHelper, private val context:
db.query( db.query(
TABLE_NAME, projection, TABLE_NAME, projection,
where, null, null, null, where, null, null, null,
"$COLUMN_RECEIVED DESC, $COLUMN_SENT DESC" "$COLUMN_RECEIVED DESC, $COLUMN_SENT DESC",
if (limit == 0) null else "$offset, $limit"
).use { c -> ).use { c ->
while (c.moveToNext()) { while (c.moveToNext()) {
val iv = c.getBlob(c.getColumnIndex(COLUMN_IV)) val iv = c.getBlob(c.getColumnIndex(COLUMN_IV))

View File

@ -17,12 +17,17 @@
package ch.dissem.apps.abit.service package ch.dissem.apps.abit.service
import android.app.Service import android.app.Service
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.IntentFilter
import android.net.ConnectivityManager
import android.os.Handler import android.os.Handler
import ch.dissem.apps.abit.notification.NetworkNotification import ch.dissem.apps.abit.notification.NetworkNotification
import ch.dissem.apps.abit.notification.NetworkNotification.Companion.NETWORK_NOTIFICATION_ID import ch.dissem.apps.abit.notification.NetworkNotification.Companion.NETWORK_NOTIFICATION_ID
import ch.dissem.bitmessage.BitmessageContext import ch.dissem.bitmessage.BitmessageContext
import ch.dissem.bitmessage.utils.Property import ch.dissem.bitmessage.utils.Property
import org.jetbrains.anko.connectivityManager
/** /**
* Define a Service that returns an IBinder for the * Define a Service that returns an IBinder for the
@ -34,6 +39,14 @@ class BitmessageService : Service() {
private val bmc: BitmessageContext by lazy { Singleton.getBitmessageContext(this) } private val bmc: BitmessageContext by lazy { Singleton.getBitmessageContext(this) }
private lateinit var notification: NetworkNotification private lateinit var notification: NetworkNotification
private val connectivityReceiver: BroadcastReceiver = object: BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
if (bmc.isRunning() && connectivityManager.isActiveNetworkMetered){
bmc.shutdown()
}
}
}
private val cleanupHandler = Handler() private val cleanupHandler = Handler()
private val cleanupTask: Runnable = object : Runnable { private val cleanupTask: Runnable = object : Runnable {
override fun run() { override fun run() {
@ -45,6 +58,7 @@ class BitmessageService : Service() {
} }
override fun onCreate() { override fun onCreate() {
registerReceiver(connectivityReceiver, IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION))
notification = NetworkNotification(this) notification = NetworkNotification(this)
running = false running = false
} }

View File

@ -30,6 +30,7 @@ import ch.dissem.bitmessage.BitmessageContext
import ch.dissem.bitmessage.entity.BitmessageAddress import ch.dissem.bitmessage.entity.BitmessageAddress
import ch.dissem.bitmessage.entity.payload.Pubkey import ch.dissem.bitmessage.entity.payload.Pubkey
import ch.dissem.bitmessage.networking.nio.NioNetworkHandler import ch.dissem.bitmessage.networking.nio.NioNetworkHandler
import ch.dissem.bitmessage.ports.DefaultLabeler
import ch.dissem.bitmessage.utils.ConversationService import ch.dissem.bitmessage.utils.ConversationService
import ch.dissem.bitmessage.utils.TTL import ch.dissem.bitmessage.utils.TTL
import ch.dissem.bitmessage.utils.UnixTime.DAY import ch.dissem.bitmessage.utils.UnixTime.DAY
@ -40,6 +41,7 @@ import org.jetbrains.anko.uiThread
* Provides singleton objects across the application. * Provides singleton objects across the application.
*/ */
object Singleton { object Singleton {
val labeler = DefaultLabeler()
var bitmessageContext: BitmessageContext? = null var bitmessageContext: BitmessageContext? = null
private set private set
private var conversationService: ConversationService? = null private var conversationService: ConversationService? = null
@ -69,6 +71,7 @@ object Singleton {
.powRepo(powRepo) .powRepo(powRepo)
.networkHandler(NioNetworkHandler()) .networkHandler(NioNetworkHandler())
.listener(getMessageListener(ctx)) .listener(getMessageListener(ctx))
.labeler(labeler)
.doNotSendPubkeyOnIdentityCreation() .doNotSendPubkeyOnIdentityCreation()
.build() .build()
} }

View File

@ -26,7 +26,8 @@ class StartupNodeOnWifiService : JobService() {
override fun onStopJob(params: JobParameters?): Boolean { override fun onStopJob(params: JobParameters?): Boolean {
if (Preferences.isWifiOnly(this)) { if (Preferences.isWifiOnly(this)) {
Singleton.getBitmessageContext(this).shutdown() // Don't actually stop the service, otherwise it will be stopped after 1 or 10 minutes
// depending on Android version.
return Preferences.isFullNodeActive(this) return Preferences.isFullNodeActive(this)
} else { } else {
return false return false

View File

@ -11,7 +11,7 @@ import io.github.kobakei.materialfabspeeddial.FabSpeedDialMenu
*/ */
object FabUtils { object FabUtils {
fun initFab(activity: MainActivity, @DrawableRes drawableRes: Int, menu: FabSpeedDialMenu): FabSpeedDial { fun initFab(activity: MainActivity, @DrawableRes drawableRes: Int, menu: FabSpeedDialMenu): FabSpeedDial {
val fab = activity.floatingActionButton val fab = activity.floatingActionButton ?: throw IllegalStateException("Fab must not be null")
fab.removeAllOnMenuItemClickListeners() fab.removeAllOnMenuItemClickListeners()
fab.show() fab.show()
fab.closeMenu() fab.closeMenu()

View File

@ -26,6 +26,8 @@ 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.networkStatsManager
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import java.io.File import java.io.File
import java.io.IOException import java.io.IOException
@ -88,7 +90,7 @@ object Preferences {
return preferences.getString(name, null) return preferences.getString(name, null)
} }
fun isConnectionAllowed(ctx: Context) = !isWifiOnly(ctx) || !WifiReceiver.isConnectedToMeteredNetwork(ctx) fun isConnectionAllowed(ctx: Context) = !isWifiOnly(ctx) || ctx.connectivityManager.isActiveNetworkMetered
fun isWifiOnly(ctx: Context): Boolean { fun isWifiOnly(ctx: Context): Boolean {
val preferences = PreferenceManager.getDefaultSharedPreferences(ctx) val preferences = PreferenceManager.getDefaultSharedPreferences(ctx)

View File

@ -18,7 +18,6 @@
<RelativeLayout <RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:paddingBottom="18dp" android:paddingBottom="18dp"
@ -71,7 +70,7 @@
android:text="@string/ok" android:text="@string/ok"
android:textColor="@color/colorAccent" android:textColor="@color/colorAccent"
app:layout_constraintHorizontal_bias="1.0" app:layout_constraintHorizontal_bias="1.0"
android:layout_alignRight="@+id/radioGroup" android:layout_alignEnd="@+id/radioGroup"
android:layout_below="@+id/radioGroup"/> android:layout_below="@+id/radioGroup"/>
<Button <Button
@ -81,7 +80,7 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@string/cancel" android:text="@string/cancel"
android:textColor="@color/colorAccent" android:textColor="@color/colorAccent"
android:layout_toLeftOf="@+id/ok" android:layout_toStartOf="@+id/ok"
android:layout_below="@+id/radioGroup"/> android:layout_below="@+id/radioGroup"/>
</RelativeLayout> </RelativeLayout>

View File

@ -31,7 +31,6 @@
android:paddingEnd="8dp" android:paddingEnd="8dp"
android:paddingStart="16dp" android:paddingStart="16dp"
android:paddingTop="8dp" android:paddingTop="8dp"
android:text="CheckBox"
android:textAppearance="?android:attr/textAppearanceMedium" android:textAppearance="?android:attr/textAppearanceMedium"
tools:text="Name"/> tools:text="Name"/>

View File

@ -10,6 +10,6 @@
android:id="@+id/select_encoding" android:id="@+id/select_encoding"
app:showAsAction="never" app:showAsAction="never"
android:icon="@drawable/ic_action_encoding" android:icon="@drawable/ic_action_encoding"
android:title="Select encoding" android:title="@string/select_encoding"
/> />
</menu> </menu>

View File

@ -124,4 +124,7 @@ Als Alternative kann in den Einstellungen ein vertrauenswürdiger Knoten konfigu
<string name="request_acknowledgements">Bestätigungen verlangen</string> <string name="request_acknowledgements">Bestätigungen verlangen</string>
<string name="request_acknowledgements_summary">Bestätigungen stellen sicher dass eine Nachricht empfangen wurde, benötigen aber zusätzliche Zeit zum versenden</string> <string name="request_acknowledgements_summary">Bestätigungen stellen sicher dass eine Nachricht empfangen wurde, benötigen aber zusätzliche Zeit zum versenden</string>
<string name="got_it">Alles klar</string> <string name="got_it">Alles klar</string>
<string name="import_data">Import</string>
<string name="import_data_summary">Nachrichten und Kontakte importieren (aber keine Identitäten)</string>
<string name="select_encoding">Kodierung auswählen</string>
</resources> </resources>

View File

@ -125,4 +125,5 @@ As an alternative you could configure a trusted node in the settings, but as of
<string name="request_acknowledgements">Request acknowledgements</string> <string name="request_acknowledgements">Request acknowledgements</string>
<string name="request_acknowledgements_summary">Acknowledges allow making sure a message was received, but require additional time to send</string> <string name="request_acknowledgements_summary">Acknowledges allow making sure a message was received, but require additional time to send</string>
<string name="got_it">Got it</string> <string name="got_it">Got it</string>
<string name="select_encoding">Select encoding</string>
</resources> </resources>

View File

@ -5,7 +5,7 @@ configurations.all {
} }
buildscript { buildscript {
ext.kotlin_version = '1.1.4-2' ext.kotlin_version = '1.1.4-3'
ext.anko_version = '0.10.1' ext.anko_version = '0.10.1'
repositories { repositories {
jcenter() jcenter()