🤯 Update dependencies, switch to AndroidX
This commit is contained in:
		@@ -13,8 +13,8 @@ if (project.hasProperty("project.configs")
 | 
			
		||||
 | 
			
		||||
//noinspection GroovyMissingReturnStatement
 | 
			
		||||
android {
 | 
			
		||||
    compileSdkVersion 27
 | 
			
		||||
    buildToolsVersion "27.0.3"
 | 
			
		||||
    compileSdkVersion 28
 | 
			
		||||
    buildToolsVersion "28.0.3"
 | 
			
		||||
 | 
			
		||||
    signingConfigs {
 | 
			
		||||
        release
 | 
			
		||||
@@ -22,7 +22,7 @@ android {
 | 
			
		||||
    defaultConfig {
 | 
			
		||||
        applicationId "ch.dissem.apps.${appName.toLowerCase()}"
 | 
			
		||||
        minSdkVersion 21
 | 
			
		||||
        targetSdkVersion 27
 | 
			
		||||
        targetSdkVersion 28
 | 
			
		||||
        versionCode 23
 | 
			
		||||
        versionName "1.0-rc1"
 | 
			
		||||
        multiDexEnabled true
 | 
			
		||||
@@ -62,13 +62,16 @@ dependencies {
 | 
			
		||||
    implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
 | 
			
		||||
    implementation "org.jetbrains.anko:anko:$anko_version"
 | 
			
		||||
 | 
			
		||||
    implementation "com.android.support:appcompat-v7:$supportVersion"
 | 
			
		||||
    implementation "com.android.support:preference-v7:$supportVersion"
 | 
			
		||||
    implementation "com.android.support:cardview-v7:$supportVersion"
 | 
			
		||||
    implementation "com.android.support:support-v13:$supportVersion"
 | 
			
		||||
    implementation "com.android.support:preference-v14:$supportVersion"
 | 
			
		||||
    implementation "com.android.support:design:$supportVersion"
 | 
			
		||||
    implementation "com.android.support:multidex:1.0.3"
 | 
			
		||||
    implementation 'androidx.appcompat:appcompat:1.0.0'
 | 
			
		||||
    implementation 'androidx.preference:preference:1.0.0'
 | 
			
		||||
    implementation 'androidx.cardview:cardview:1.0.0'
 | 
			
		||||
    implementation 'androidx.legacy:legacy-support-v13:1.0.0'
 | 
			
		||||
    implementation 'androidx.legacy:legacy-preference-v14:1.0.0'
 | 
			
		||||
    implementation 'com.google.android.material:material:1.0.0'
 | 
			
		||||
    implementation 'androidx.multidex:multidex:2.0.0'
 | 
			
		||||
    implementation 'androidx.core:core-ktx:1.0.0'
 | 
			
		||||
    implementation 'androidx.sqlite:sqlite-ktx:2.0.0-rc01'
 | 
			
		||||
    implementation 'androidx.fragment:fragment-ktx:1.0.0'
 | 
			
		||||
 | 
			
		||||
    implementation "ch.dissem.jabit:jabit-core:$jabitVersion"
 | 
			
		||||
    implementation "ch.dissem.jabit:jabit-networking:$jabitVersion"
 | 
			
		||||
@@ -80,15 +83,15 @@ dependencies {
 | 
			
		||||
 | 
			
		||||
    implementation 'org.slf4j:slf4j-android:1.7.25'
 | 
			
		||||
 | 
			
		||||
    implementation 'com.mikepenz:materialize:1.1.2@aar'
 | 
			
		||||
    implementation('com.mikepenz:materialdrawer:6.0.8@aar') {
 | 
			
		||||
    implementation 'com.mikepenz:materialize:1.2.0-rc01@aar'
 | 
			
		||||
    implementation('com.mikepenz:materialdrawer:6.1.0-rc01.2@aar') {
 | 
			
		||||
        transitive = true
 | 
			
		||||
    }
 | 
			
		||||
    implementation('com.mikepenz:aboutlibraries:6.0.9@aar') {
 | 
			
		||||
    implementation('com.mikepenz:aboutlibraries:6.2.0-rc01@aar') {
 | 
			
		||||
        transitive = true
 | 
			
		||||
    }
 | 
			
		||||
    implementation "com.mikepenz:iconics-core:3.0.4@aar"
 | 
			
		||||
    implementation "com.mikepenz:iconics-views:3.0.4@aar"
 | 
			
		||||
    implementation "com.mikepenz:iconics-core:3.1.0-rc01@aar"
 | 
			
		||||
    implementation "com.mikepenz:iconics-views:3.1.0-rc01@aar"
 | 
			
		||||
    implementation 'com.mikepenz:google-material-typeface:3.0.1.2.original@aar'
 | 
			
		||||
    implementation 'com.mikepenz:community-material-typeface:2.0.46.1@aar'
 | 
			
		||||
 | 
			
		||||
@@ -97,11 +100,12 @@ dependencies {
 | 
			
		||||
 | 
			
		||||
    implementation 'com.github.kobakei:MaterialFabSpeedDial:1.2.0'
 | 
			
		||||
    implementation 'com.github.deano2390:MaterialShowcaseView:1.2.0@aar'
 | 
			
		||||
    implementation('com.github.h6ah4i:android-advancedrecyclerview:0.11.0@aar') {
 | 
			
		||||
        transitive = true
 | 
			
		||||
    }
 | 
			
		||||
    implementation 'com.github.angads25:filepicker:1.1.1'
 | 
			
		||||
    implementation 'com.android.support.constraint:constraint-layout:1.1.2'
 | 
			
		||||
    implementation 'androidx.constraintlayout:constraintlayout:2.0.0-alpha2'
 | 
			
		||||
 | 
			
		||||
    implementation "io.reactivex.rxjava2:rxjava:2.2.2"
 | 
			
		||||
    implementation "io.reactivex.rxjava2:rxkotlin:2.3.0"
 | 
			
		||||
    implementation "io.reactivex.rxjava2:rxandroid:2.1.0"
 | 
			
		||||
 | 
			
		||||
    testImplementation 'junit:junit:4.12'
 | 
			
		||||
    testImplementation 'org.mockito:mockito-core:2.19.0'
 | 
			
		||||
@@ -111,7 +115,7 @@ dependencies {
 | 
			
		||||
    testImplementation 'org.robolectric:robolectric:3.7.1'
 | 
			
		||||
    testImplementation "org.robolectric:shadows-multidex:3.7.1"
 | 
			
		||||
 | 
			
		||||
    androidTestImplementation "com.android.support:multidex:1.0.3"
 | 
			
		||||
    androidTestImplementation "androidx.multidex:multidex:2.0.0"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
idea.module {
 | 
			
		||||
 
 | 
			
		||||
@@ -11,9 +11,10 @@
 | 
			
		||||
    <uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS" />
 | 
			
		||||
    <uses-permission android:name="android.permission.READ_SYNC_SETTINGS" />
 | 
			
		||||
    <uses-permission android:name="android.permission.WRITE_SYNC_SETTINGS" />
 | 
			
		||||
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
 | 
			
		||||
 | 
			
		||||
    <application
 | 
			
		||||
        android:name="android.support.multidex.MultiDexApplication"
 | 
			
		||||
        android:name="androidx.multidex.MultiDexApplication"
 | 
			
		||||
        android:allowBackup="false"
 | 
			
		||||
        android:icon="@mipmap/ic_launcher"
 | 
			
		||||
        android:label="@string/app_name"
 | 
			
		||||
@@ -124,7 +125,7 @@
 | 
			
		||||
 | 
			
		||||
        <!-- Exports -->
 | 
			
		||||
        <provider
 | 
			
		||||
            android:name="android.support.v4.content.FileProvider"
 | 
			
		||||
            android:name="androidx.core.content.FileProvider"
 | 
			
		||||
            android:authorities="ch.dissem.apps.abit.fileprovider"
 | 
			
		||||
            android:exported="false"
 | 
			
		||||
            android:grantUriPermissions="true">
 | 
			
		||||
 
 | 
			
		||||
@@ -18,7 +18,7 @@ package ch.dissem.apps.abit
 | 
			
		||||
 | 
			
		||||
import android.content.Context
 | 
			
		||||
import android.os.Bundle
 | 
			
		||||
import android.support.v4.app.ListFragment
 | 
			
		||||
import androidx.fragment.app.ListFragment
 | 
			
		||||
import android.view.View
 | 
			
		||||
import android.widget.ListView
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -19,7 +19,7 @@ package ch.dissem.apps.abit
 | 
			
		||||
import android.app.AlertDialog
 | 
			
		||||
import android.content.Intent
 | 
			
		||||
import android.os.Bundle
 | 
			
		||||
import android.support.v4.app.Fragment
 | 
			
		||||
import androidx.fragment.app.Fragment
 | 
			
		||||
import android.text.Editable
 | 
			
		||||
import android.text.TextWatcher
 | 
			
		||||
import android.view.*
 | 
			
		||||
 
 | 
			
		||||
@@ -28,7 +28,6 @@ import android.widget.ImageView
 | 
			
		||||
import android.widget.TextView
 | 
			
		||||
import ch.dissem.apps.abit.service.Singleton
 | 
			
		||||
import ch.dissem.bitmessage.entity.BitmessageAddress
 | 
			
		||||
import com.google.zxing.integration.android.IntentIntegrator
 | 
			
		||||
import io.github.kobakei.materialfabspeeddial.FabSpeedDialMenu
 | 
			
		||||
import org.jetbrains.anko.doAsync
 | 
			
		||||
import org.jetbrains.anko.uiThread
 | 
			
		||||
@@ -44,7 +43,7 @@ class AddressListFragment : AbstractItemListFragment<Void, BitmessageAddress>()
 | 
			
		||||
        super.onCreate(savedInstanceState)
 | 
			
		||||
 | 
			
		||||
        adapter = object : ArrayAdapter<BitmessageAddress>(
 | 
			
		||||
            activity,
 | 
			
		||||
            activity!!,
 | 
			
		||||
            R.layout.subscription_row,
 | 
			
		||||
            R.id.name,
 | 
			
		||||
            LinkedList()
 | 
			
		||||
@@ -109,9 +108,10 @@ class AddressListFragment : AbstractItemListFragment<Void, BitmessageAddress>()
 | 
			
		||||
        activity.initFab(R.drawable.ic_action_add_contact, menu)
 | 
			
		||||
            .addOnMenuItemClickListener { _, _, itemId ->
 | 
			
		||||
                when (itemId) {
 | 
			
		||||
                    1 -> IntentIntegrator.forSupportFragment(this@AddressListFragment)
 | 
			
		||||
                        .setDesiredBarcodeFormats(IntentIntegrator.QR_CODE)
 | 
			
		||||
                        .initiateScan()
 | 
			
		||||
                    // FIXME
 | 
			
		||||
//                    1 -> IntentIntegrator.forSupportFragment(this@AddressListFragment)
 | 
			
		||||
//                        .setDesiredBarcodeFormats(IntentIntegrator.QR_CODE)
 | 
			
		||||
//                        .initiateScan()
 | 
			
		||||
                    2 -> {
 | 
			
		||||
                        val intent = Intent(getActivity(), CreateAddressActivity::class.java)
 | 
			
		||||
                        startActivity(intent)
 | 
			
		||||
 
 | 
			
		||||
@@ -20,8 +20,8 @@ import android.app.Activity
 | 
			
		||||
import android.content.Context
 | 
			
		||||
import android.content.Intent
 | 
			
		||||
import android.os.Bundle
 | 
			
		||||
import android.support.v4.app.Fragment
 | 
			
		||||
import android.support.v7.app.AppCompatActivity
 | 
			
		||||
import androidx.fragment.app.Fragment
 | 
			
		||||
import androidx.appcompat.app.AppCompatActivity
 | 
			
		||||
import ch.dissem.apps.abit.service.Singleton
 | 
			
		||||
import ch.dissem.bitmessage.entity.Plaintext
 | 
			
		||||
import ch.dissem.bitmessage.entity.Plaintext.Encoding.EXTENDED
 | 
			
		||||
 
 | 
			
		||||
@@ -20,7 +20,7 @@ import android.app.Activity.RESULT_OK
 | 
			
		||||
import android.content.Context
 | 
			
		||||
import android.content.Intent
 | 
			
		||||
import android.os.Bundle
 | 
			
		||||
import android.support.v4.app.Fragment
 | 
			
		||||
import androidx.fragment.app.Fragment
 | 
			
		||||
import android.view.*
 | 
			
		||||
import android.widget.AdapterView
 | 
			
		||||
import android.widget.Toast
 | 
			
		||||
@@ -89,10 +89,10 @@ class ComposeMessageFragment : Fragment() {
 | 
			
		||||
                    recipient = getSerializable(EXTRA_RECIPIENT) as BitmessageAddress
 | 
			
		||||
                }
 | 
			
		||||
                if (containsKey(EXTRA_SUBJECT)) {
 | 
			
		||||
                    subject = getString(EXTRA_SUBJECT)
 | 
			
		||||
                    subject = getString(EXTRA_SUBJECT) ?: throw IllegalStateException("EXTRA_SUBJECT expected")
 | 
			
		||||
                }
 | 
			
		||||
                if (containsKey(EXTRA_CONTENT)) {
 | 
			
		||||
                    content = getString(EXTRA_CONTENT)
 | 
			
		||||
                    content = getString(EXTRA_CONTENT) ?: throw IllegalStateException("EXTRA_CONTENT expected")
 | 
			
		||||
                }
 | 
			
		||||
                encoding = getSerializable(EXTRA_ENCODING) as? Plaintext.Encoding ?: Plaintext.Encoding.SIMPLE
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -17,8 +17,8 @@
 | 
			
		||||
package ch.dissem.apps.abit
 | 
			
		||||
 | 
			
		||||
import android.os.Bundle
 | 
			
		||||
import android.support.v4.app.Fragment
 | 
			
		||||
import android.support.v7.widget.LinearLayoutManager
 | 
			
		||||
import androidx.fragment.app.Fragment
 | 
			
		||||
import androidx.recyclerview.widget.LinearLayoutManager
 | 
			
		||||
import android.view.*
 | 
			
		||||
import ch.dissem.apps.abit.adapter.ConversationAdapter
 | 
			
		||||
import ch.dissem.apps.abit.service.Singleton
 | 
			
		||||
@@ -74,8 +74,7 @@ class ConversationDetailFragment : Fragment() {
 | 
			
		||||
        item?.let { item ->
 | 
			
		||||
            subject.text = item.subject
 | 
			
		||||
            avatar.setImageDrawable(MultiIdenticon(item.participants))
 | 
			
		||||
            messages.adapter =
 | 
			
		||||
                ConversationAdapter(ctx, this@ConversationDetailFragment, item, Singleton.currentLabel.value)
 | 
			
		||||
            messages.adapter = ConversationAdapter(ctx, this@ConversationDetailFragment, item, Singleton.currentLabel)
 | 
			
		||||
            messages.layoutManager = LinearLayoutManager(activity)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -19,36 +19,29 @@ package ch.dissem.apps.abit
 | 
			
		||||
 | 
			
		||||
import android.content.Intent
 | 
			
		||||
import android.os.Bundle
 | 
			
		||||
import android.support.v4.app.Fragment
 | 
			
		||||
import android.support.v4.content.ContextCompat
 | 
			
		||||
import android.support.v7.widget.LinearLayoutManager
 | 
			
		||||
import android.support.v7.widget.RecyclerView
 | 
			
		||||
import android.support.v7.widget.RecyclerView.OnScrollListener
 | 
			
		||||
import android.view.*
 | 
			
		||||
import android.widget.Toast
 | 
			
		||||
import androidx.fragment.app.Fragment
 | 
			
		||||
import androidx.recyclerview.widget.ItemTouchHelper
 | 
			
		||||
import androidx.recyclerview.widget.LinearLayoutManager
 | 
			
		||||
import androidx.recyclerview.widget.RecyclerView
 | 
			
		||||
import androidx.recyclerview.widget.RecyclerView.OnScrollListener
 | 
			
		||||
import ch.dissem.apps.abit.ComposeMessageActivity.Companion.EXTRA_BROADCAST
 | 
			
		||||
import ch.dissem.apps.abit.ComposeMessageActivity.Companion.EXTRA_IDENTITY
 | 
			
		||||
import ch.dissem.apps.abit.adapter.EventListener
 | 
			
		||||
import ch.dissem.apps.abit.adapter.SwipeToDeleteCallback
 | 
			
		||||
import ch.dissem.apps.abit.adapter.SwipeableConversationAdapter
 | 
			
		||||
import ch.dissem.apps.abit.listener.ListSelectionListener
 | 
			
		||||
import ch.dissem.apps.abit.repository.AndroidMessageRepository
 | 
			
		||||
import ch.dissem.apps.abit.service.Singleton
 | 
			
		||||
import ch.dissem.apps.abit.service.Singleton.currentLabel
 | 
			
		||||
import ch.dissem.apps.abit.util.preferences
 | 
			
		||||
import ch.dissem.bitmessage.entity.Conversation
 | 
			
		||||
import ch.dissem.bitmessage.entity.valueobject.Label
 | 
			
		||||
import ch.dissem.bitmessage.utils.ConversationService
 | 
			
		||||
import com.h6ah4i.android.widget.advrecyclerview.animator.SwipeDismissItemAnimator
 | 
			
		||||
import com.h6ah4i.android.widget.advrecyclerview.decoration.SimpleListDividerDecorator
 | 
			
		||||
import com.h6ah4i.android.widget.advrecyclerview.swipeable.RecyclerViewSwipeManager
 | 
			
		||||
import com.h6ah4i.android.widget.advrecyclerview.touchguard.RecyclerViewTouchActionGuardManager
 | 
			
		||||
import com.h6ah4i.android.widget.advrecyclerview.utils.WrapperAdapterUtils
 | 
			
		||||
import io.github.kobakei.materialfabspeeddial.FabSpeedDialMenu
 | 
			
		||||
import io.reactivex.disposables.Disposable
 | 
			
		||||
import kotlinx.android.synthetic.main.fragment_message_list.*
 | 
			
		||||
import org.jetbrains.anko.cancelButton
 | 
			
		||||
import org.jetbrains.anko.doAsync
 | 
			
		||||
import org.jetbrains.anko.support.v4.alert
 | 
			
		||||
import org.jetbrains.anko.support.v4.onUiThread
 | 
			
		||||
import org.jetbrains.anko.uiThread
 | 
			
		||||
import org.jetbrains.anko.*
 | 
			
		||||
import java.util.*
 | 
			
		||||
 | 
			
		||||
private const val PAGE_SIZE = 15
 | 
			
		||||
@@ -70,12 +63,9 @@ class ConversationListFragment : Fragment(), ListHolder<Label> {
 | 
			
		||||
 | 
			
		||||
    private var layoutManager: LinearLayoutManager? = null
 | 
			
		||||
    private var swipeableConversationAdapter: SwipeableConversationAdapter? = null
 | 
			
		||||
    private var wrappedAdapter: RecyclerView.Adapter<*>? = null
 | 
			
		||||
    private var recyclerViewSwipeManager: RecyclerViewSwipeManager? = null
 | 
			
		||||
    private var recyclerViewTouchActionGuardManager: RecyclerViewTouchActionGuardManager? = null
 | 
			
		||||
 | 
			
		||||
    private val recyclerViewOnScrollListener = object : OnScrollListener() {
 | 
			
		||||
        override fun onScrolled(recyclerView: RecyclerView?, dx: Int, dy: Int) {
 | 
			
		||||
        override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
 | 
			
		||||
            layoutManager?.let { layoutManager ->
 | 
			
		||||
                val visibleItemCount = layoutManager.childCount
 | 
			
		||||
                val totalItemCount = layoutManager.itemCount
 | 
			
		||||
@@ -98,6 +88,13 @@ class ConversationListFragment : Fragment(), ListHolder<Label> {
 | 
			
		||||
    private lateinit var conversationService: ConversationService
 | 
			
		||||
    private var activateOnItemClick: Boolean = false
 | 
			
		||||
 | 
			
		||||
    private var subscription: Disposable? = null
 | 
			
		||||
 | 
			
		||||
    override fun setActivateOnItemClick(activateOnItemClick: Boolean) {
 | 
			
		||||
        swipeableConversationAdapter?.activateOnItemClick = activateOnItemClick
 | 
			
		||||
        this.activateOnItemClick = activateOnItemClick
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private val backStack = Stack<Label>()
 | 
			
		||||
 | 
			
		||||
    fun loadMoreItems() {
 | 
			
		||||
@@ -112,7 +109,7 @@ class ConversationListFragment : Fragment(), ListHolder<Label> {
 | 
			
		||||
                )
 | 
			
		||||
                conversationIds.forEach { conversationId ->
 | 
			
		||||
                    val conversation = conversationService.getConversation(conversationId)
 | 
			
		||||
                    onUiThread {
 | 
			
		||||
                    uiThread {
 | 
			
		||||
                        messageAdapter.add(conversation)
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
@@ -135,12 +132,12 @@ class ConversationListFragment : Fragment(), ListHolder<Label> {
 | 
			
		||||
        messageRepo = Singleton.getMessageRepository(activity)
 | 
			
		||||
        conversationService = Singleton.getConversationService(activity)
 | 
			
		||||
 | 
			
		||||
        currentLabel.addObserver(this) { new -> doUpdateList(new) }
 | 
			
		||||
        subscription = currentLabel.subscribe { new -> doUpdateList(new) }
 | 
			
		||||
        doUpdateList(currentLabel.value)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onPause() {
 | 
			
		||||
        currentLabel.removeObserver(this)
 | 
			
		||||
        subscription?.dispose()
 | 
			
		||||
        super.onPause()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -158,7 +155,7 @@ class ConversationListFragment : Fragment(), ListHolder<Label> {
 | 
			
		||||
        // I'm not yet sure if it's a good idea in conversation views, so it's off for now
 | 
			
		||||
        deleteAllMenuItem?.isVisible = false
 | 
			
		||||
 | 
			
		||||
        mainActivity?.apply {
 | 
			
		||||
        MainActivity.apply {
 | 
			
		||||
            if ("archive" == label.toString()) {
 | 
			
		||||
                updateTitle(getString(R.string.archive))
 | 
			
		||||
            } else {
 | 
			
		||||
@@ -181,75 +178,57 @@ class ConversationListFragment : Fragment(), ListHolder<Label> {
 | 
			
		||||
 | 
			
		||||
        val context = context ?: throw IllegalStateException("No context available")
 | 
			
		||||
 | 
			
		||||
        layoutManager = LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)
 | 
			
		||||
 | 
			
		||||
        // touch guard manager  (this class is required to suppress scrolling while swipe-dismiss
 | 
			
		||||
        // animation is running)
 | 
			
		||||
        val touchActionGuardManager = RecyclerViewTouchActionGuardManager().apply {
 | 
			
		||||
            setInterceptVerticalScrollingWhileAnimationRunning(true)
 | 
			
		||||
            isEnabled = true
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // swipe manager
 | 
			
		||||
        val swipeManager = RecyclerViewSwipeManager()
 | 
			
		||||
 | 
			
		||||
        //swipeableConversationAdapter
 | 
			
		||||
        val adapter = SwipeableConversationAdapter(context).apply {
 | 
			
		||||
            setActivateOnItemClick(activateOnItemClick)
 | 
			
		||||
        }
 | 
			
		||||
        adapter.eventListener = object : SwipeableConversationAdapter.EventListener {
 | 
			
		||||
            override fun onItemDeleted(item: Conversation) {
 | 
			
		||||
                item.messages.forEach {
 | 
			
		||||
                    Singleton.labeler.delete(it)
 | 
			
		||||
                    messageRepo.save(it)
 | 
			
		||||
        val listener = object : EventListener {
 | 
			
		||||
            override fun onItemDeleted(position: Int) {
 | 
			
		||||
                swipeableConversationAdapter?.getItem(position)?.let { item ->
 | 
			
		||||
                    item.messages.forEach {
 | 
			
		||||
                        Singleton.labeler.delete(it)
 | 
			
		||||
                        messageRepo.save(it)
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                swipeableConversationAdapter?.removeAt(position)
 | 
			
		||||
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            override fun onItemArchived(item: Conversation) {
 | 
			
		||||
                item.messages.forEach { Singleton.labeler.archive(it) }
 | 
			
		||||
            override fun onItemArchived(position: Int) {
 | 
			
		||||
                swipeableConversationAdapter?.getItem(position)?.let { item ->
 | 
			
		||||
                    item.messages.forEach {
 | 
			
		||||
                        Singleton.labeler.archive(it)
 | 
			
		||||
                        messageRepo.save(it)
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                swipeableConversationAdapter?.removeAt(position)
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            override fun onItemViewClicked(v: View?) {
 | 
			
		||||
                val position = recycler_view.getChildAdapterPosition(v)
 | 
			
		||||
                adapter.setSelectedPosition(position)
 | 
			
		||||
            override fun onItemSelected(position: Int) {
 | 
			
		||||
                swipeableConversationAdapter?.selectedPosition = position
 | 
			
		||||
                if (position != RecyclerView.NO_POSITION) {
 | 
			
		||||
                    MainActivity.apply { onItemSelected(adapter.getItem(position)) }
 | 
			
		||||
                    swipeableConversationAdapter?.getItem(position)?.let { item ->
 | 
			
		||||
                        MainActivity.apply { onItemSelected(item) }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // wrap for swiping
 | 
			
		||||
        wrappedAdapter = swipeManager.createWrappedAdapter(adapter)
 | 
			
		||||
 | 
			
		||||
        val animator = SwipeDismissItemAnimator()
 | 
			
		||||
 | 
			
		||||
        // Change animations are enabled by default since support-v7-recyclerview v22.
 | 
			
		||||
        // Disable the change animation in order to make turning back animation of swiped item
 | 
			
		||||
        // works properly.
 | 
			
		||||
        animator.supportsChangeAnimations = false
 | 
			
		||||
 | 
			
		||||
        layoutManager = LinearLayoutManager(context, RecyclerView.VERTICAL, false)
 | 
			
		||||
        recycler_view.layoutManager = layoutManager
 | 
			
		||||
        recycler_view.adapter = wrappedAdapter  // requires *wrapped* swipeableConversationAdapter
 | 
			
		||||
        recycler_view.itemAnimator = animator
 | 
			
		||||
        swipeableConversationAdapter = SwipeableConversationAdapter(context).apply {
 | 
			
		||||
            activateOnItemClick = this@ConversationListFragment.activateOnItemClick
 | 
			
		||||
            eventListener = listener
 | 
			
		||||
        }
 | 
			
		||||
        recycler_view.adapter = swipeableConversationAdapter
 | 
			
		||||
        recycler_view.addOnScrollListener(recyclerViewOnScrollListener)
 | 
			
		||||
 | 
			
		||||
        recycler_view.addItemDecoration(
 | 
			
		||||
            SimpleListDividerDecorator(
 | 
			
		||||
                ContextCompat.getDrawable(context, R.drawable.list_divider_h), true
 | 
			
		||||
            )
 | 
			
		||||
        )
 | 
			
		||||
        val dirs = when (currentLabel.value?.type) {
 | 
			
		||||
            Label.Type.TRASH -> ItemTouchHelper.LEFT
 | 
			
		||||
            else -> ItemTouchHelper.LEFT + ItemTouchHelper.RIGHT
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // NOTE:
 | 
			
		||||
        // The initialization order is very important! This order determines the priority of
 | 
			
		||||
        // touch event handling.
 | 
			
		||||
        //
 | 
			
		||||
        // priority: TouchActionGuard > Swipe > DragAndDrop
 | 
			
		||||
        touchActionGuardManager.attachRecyclerView(recycler_view)
 | 
			
		||||
        swipeManager.attachRecyclerView(recycler_view)
 | 
			
		||||
        val swipeHandler = SwipeToDeleteCallback(context, dirs, listener)
 | 
			
		||||
 | 
			
		||||
        recyclerViewTouchActionGuardManager = touchActionGuardManager
 | 
			
		||||
        recyclerViewSwipeManager = swipeManager
 | 
			
		||||
        swipeableConversationAdapter = adapter
 | 
			
		||||
        val itemTouchHelper = ItemTouchHelper(swipeHandler)
 | 
			
		||||
        itemTouchHelper.attachToRecyclerView(recycler_view)
 | 
			
		||||
 | 
			
		||||
//   FIXME     Singleton.updateMessageListAdapterInListener(adapter)
 | 
			
		||||
    }
 | 
			
		||||
@@ -287,18 +266,6 @@ class ConversationListFragment : Fragment(), ListHolder<Label> {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onDestroyView() {
 | 
			
		||||
        recyclerViewSwipeManager?.release()
 | 
			
		||||
        recyclerViewSwipeManager = null
 | 
			
		||||
 | 
			
		||||
        recyclerViewTouchActionGuardManager?.release()
 | 
			
		||||
        recyclerViewTouchActionGuardManager = null
 | 
			
		||||
 | 
			
		||||
        recycler_view.itemAnimator = null
 | 
			
		||||
        recycler_view.adapter = null
 | 
			
		||||
 | 
			
		||||
        wrappedAdapter?.let { WrapperAdapterUtils.releaseAll(it) }
 | 
			
		||||
        wrappedAdapter = null
 | 
			
		||||
 | 
			
		||||
        swipeableConversationAdapter = null
 | 
			
		||||
        layoutManager = null
 | 
			
		||||
 | 
			
		||||
@@ -324,15 +291,17 @@ class ConversationListFragment : Fragment(), ListHolder<Label> {
 | 
			
		||||
            }
 | 
			
		||||
            R.id.delete_all -> {
 | 
			
		||||
                currentLabel.value?.let { label ->
 | 
			
		||||
                    alert(
 | 
			
		||||
                        title = R.string.delete_all_messages_in_list,
 | 
			
		||||
                        message = R.string.delete_all_messages_in_list_ask
 | 
			
		||||
                    ) {
 | 
			
		||||
                        positiveButton(R.string.delete) {
 | 
			
		||||
                            deleteAllMessages(label)
 | 
			
		||||
                        }
 | 
			
		||||
                        cancelButton { }
 | 
			
		||||
                    }.show()
 | 
			
		||||
                    context?.apply {
 | 
			
		||||
                        alert(
 | 
			
		||||
                            R.string.delete_all_messages_in_list,
 | 
			
		||||
                            R.string.delete_all_messages_in_list_ask
 | 
			
		||||
                        ) {
 | 
			
		||||
                            positiveButton(R.string.delete) {
 | 
			
		||||
                                deleteAllMessages(label)
 | 
			
		||||
                            }
 | 
			
		||||
                            cancelButton { }
 | 
			
		||||
                        }.show()
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                return true
 | 
			
		||||
            }
 | 
			
		||||
@@ -351,18 +320,13 @@ class ConversationListFragment : Fragment(), ListHolder<Label> {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun updateList(label: Label) {
 | 
			
		||||
        currentLabel.value = label
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun setActivateOnItemClick(activateOnItemClick: Boolean) {
 | 
			
		||||
        swipeableConversationAdapter?.setActivateOnItemClick(activateOnItemClick)
 | 
			
		||||
        this.activateOnItemClick = activateOnItemClick
 | 
			
		||||
        currentLabel.onNext(label)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun showPreviousList() = if (backStack.isEmpty()) {
 | 
			
		||||
        false
 | 
			
		||||
    } else {
 | 
			
		||||
        currentLabel.value = backStack.pop()
 | 
			
		||||
        currentLabel.onNext(backStack.pop())
 | 
			
		||||
        true
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -19,7 +19,7 @@ package ch.dissem.apps.abit
 | 
			
		||||
import android.app.Activity
 | 
			
		||||
import android.net.Uri
 | 
			
		||||
import android.os.Bundle
 | 
			
		||||
import android.support.v7.app.AppCompatActivity
 | 
			
		||||
import androidx.appcompat.app.AppCompatActivity
 | 
			
		||||
import android.util.Base64
 | 
			
		||||
import android.util.Base64.URL_SAFE
 | 
			
		||||
import android.widget.Button
 | 
			
		||||
 
 | 
			
		||||
@@ -2,8 +2,8 @@ package ch.dissem.apps.abit
 | 
			
		||||
 | 
			
		||||
import android.content.Intent
 | 
			
		||||
import android.os.Bundle
 | 
			
		||||
import android.support.v4.app.NavUtils
 | 
			
		||||
import android.support.v7.app.AppCompatActivity
 | 
			
		||||
import androidx.core.app.NavUtils
 | 
			
		||||
import androidx.appcompat.app.AppCompatActivity
 | 
			
		||||
import android.view.MenuItem
 | 
			
		||||
import com.mikepenz.materialize.MaterializeBuilder
 | 
			
		||||
import kotlinx.android.synthetic.main.scrolling_toolbar_layout.*
 | 
			
		||||
 
 | 
			
		||||
@@ -18,7 +18,7 @@ package ch.dissem.apps.abit
 | 
			
		||||
 | 
			
		||||
import android.graphics.*
 | 
			
		||||
import android.graphics.drawable.Drawable
 | 
			
		||||
import android.support.annotation.ColorInt
 | 
			
		||||
import androidx.annotation.ColorInt
 | 
			
		||||
import android.text.TextPaint
 | 
			
		||||
import ch.dissem.bitmessage.entity.BitmessageAddress
 | 
			
		||||
import org.jetbrains.anko.collections.forEachWithIndex
 | 
			
		||||
@@ -68,8 +68,8 @@ class Identicon(input: BitmessageAddress) : Drawable() {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun draw(canvas: Canvas) {
 | 
			
		||||
        val width = canvas.width.toFloat()
 | 
			
		||||
        val height = canvas.height.toFloat()
 | 
			
		||||
        val width = bounds.width().toFloat()
 | 
			
		||||
        val height = bounds.height().toFloat()
 | 
			
		||||
        draw(canvas, 0f, 0f, width, height)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -124,11 +124,11 @@ class MultiIdenticon(input: List<BitmessageAddress>, @ColorInt private val backg
 | 
			
		||||
        color = backgroundColor
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private val identicons = input.sortedBy { it.isChan }.map { Identicon(it) }.take(4)
 | 
			
		||||
    private val identicons = input.asSequence().sortedBy { it.isChan }.map { Identicon(it) }.take(4).toList()
 | 
			
		||||
 | 
			
		||||
    override fun draw(canvas: Canvas) {
 | 
			
		||||
        val width = canvas.width.toFloat()
 | 
			
		||||
        val height = canvas.height.toFloat()
 | 
			
		||||
        val width = bounds.width().toFloat()
 | 
			
		||||
        val height = bounds.height().toFloat()
 | 
			
		||||
 | 
			
		||||
        when (identicons.size) {
 | 
			
		||||
            0 -> canvas.drawCircle(width / 2, height / 2, width / 2, paint)
 | 
			
		||||
 
 | 
			
		||||
@@ -16,19 +16,18 @@
 | 
			
		||||
 | 
			
		||||
package ch.dissem.apps.abit
 | 
			
		||||
 | 
			
		||||
import android.app.Fragment
 | 
			
		||||
import android.os.Bundle
 | 
			
		||||
import android.support.v4.content.ContextCompat
 | 
			
		||||
import android.support.v7.widget.LinearLayoutManager
 | 
			
		||||
import android.support.v7.widget.RecyclerView
 | 
			
		||||
import android.view.LayoutInflater
 | 
			
		||||
import android.view.View
 | 
			
		||||
import android.view.ViewGroup
 | 
			
		||||
import android.widget.Button
 | 
			
		||||
import androidx.fragment.app.Fragment
 | 
			
		||||
import androidx.recyclerview.widget.DividerItemDecoration
 | 
			
		||||
import androidx.recyclerview.widget.LinearLayoutManager
 | 
			
		||||
import androidx.recyclerview.widget.RecyclerView
 | 
			
		||||
import ch.dissem.apps.abit.adapter.AddressSelectorAdapter
 | 
			
		||||
import ch.dissem.apps.abit.service.Singleton
 | 
			
		||||
import ch.dissem.bitmessage.wif.WifImporter
 | 
			
		||||
import com.h6ah4i.android.widget.advrecyclerview.decoration.SimpleListDividerDecorator
 | 
			
		||||
import org.ini4j.InvalidFileFormatException
 | 
			
		||||
import org.jetbrains.anko.longToast
 | 
			
		||||
 | 
			
		||||
@@ -47,34 +46,31 @@ class ImportIdentitiesFragment : Fragment() {
 | 
			
		||||
        inflater.inflate(R.layout.fragment_import_select_identities, container, false)
 | 
			
		||||
 | 
			
		||||
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
 | 
			
		||||
        val ctx = activity ?: throw IllegalStateException("No activity available")
 | 
			
		||||
        super.onViewCreated(view, savedInstanceState)
 | 
			
		||||
 | 
			
		||||
        val wifData = arguments.getString(WIF_DATA)
 | 
			
		||||
        val bmc = Singleton.getBitmessageContext(activity)
 | 
			
		||||
        val wifData = arguments?.getString(WIF_DATA) ?: throw IllegalStateException("No WIF data")
 | 
			
		||||
        val bmc = Singleton.getBitmessageContext(ctx)
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
            importer = WifImporter(bmc, wifData)
 | 
			
		||||
        } catch (e: InvalidFileFormatException) {
 | 
			
		||||
            longToast(R.string.invalid_wif_file)
 | 
			
		||||
            activity.finish()
 | 
			
		||||
            ctx.longToast(R.string.invalid_wif_file)
 | 
			
		||||
            ctx.finish()
 | 
			
		||||
            return
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        adapter = AddressSelectorAdapter(importer.getIdentities())
 | 
			
		||||
        val layoutManager = LinearLayoutManager(
 | 
			
		||||
            activity,
 | 
			
		||||
            LinearLayoutManager.VERTICAL,
 | 
			
		||||
            RecyclerView.VERTICAL,
 | 
			
		||||
            false
 | 
			
		||||
        )
 | 
			
		||||
        val recyclerView = view.findViewById<RecyclerView>(R.id.recycler_view)
 | 
			
		||||
        recyclerView.layoutManager = layoutManager
 | 
			
		||||
        recyclerView.adapter = adapter
 | 
			
		||||
 | 
			
		||||
        recyclerView.addItemDecoration(
 | 
			
		||||
            SimpleListDividerDecorator(
 | 
			
		||||
                ContextCompat.getDrawable(activity, R.drawable.list_divider_h), true
 | 
			
		||||
            )
 | 
			
		||||
        )
 | 
			
		||||
        recyclerView.addItemDecoration(DividerItemDecoration(ctx, DividerItemDecoration.HORIZONTAL))
 | 
			
		||||
 | 
			
		||||
        view.findViewById<Button>(R.id.finish).setOnClickListener {
 | 
			
		||||
            importer.importAll(adapter.selected)
 | 
			
		||||
@@ -83,7 +79,7 @@ class ImportIdentitiesFragment : Fragment() {
 | 
			
		||||
                    addIdentityEntry(selected)
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            activity.finish()
 | 
			
		||||
            ctx.finish()
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -17,6 +17,7 @@
 | 
			
		||||
package ch.dissem.apps.abit
 | 
			
		||||
 | 
			
		||||
import android.os.Bundle
 | 
			
		||||
import androidx.fragment.app.transaction
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @author Christian Basler
 | 
			
		||||
@@ -29,19 +30,20 @@ class ImportIdentityActivity : DetailActivity() {
 | 
			
		||||
        val wifData: String? = savedInstanceState?.getString(ImportIdentitiesFragment.WIF_DATA)
 | 
			
		||||
 | 
			
		||||
        if (wifData == null) {
 | 
			
		||||
            fragmentManager.beginTransaction()
 | 
			
		||||
                    .replace(R.id.content, InputWifFragment())
 | 
			
		||||
                    .commit()
 | 
			
		||||
            supportFragmentManager.transaction {
 | 
			
		||||
                replace(R.id.content, InputWifFragment())
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            val bundle = Bundle()
 | 
			
		||||
            bundle.putString(ImportIdentitiesFragment.WIF_DATA, wifData)
 | 
			
		||||
 | 
			
		||||
            val fragment = ImportIdentitiesFragment()
 | 
			
		||||
            fragment.arguments = bundle
 | 
			
		||||
            val fragment = ImportIdentitiesFragment().apply {
 | 
			
		||||
                arguments = bundle
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            fragmentManager.beginTransaction()
 | 
			
		||||
                    .replace(R.id.content, fragment)
 | 
			
		||||
                    .commit()
 | 
			
		||||
            supportFragmentManager.transaction {
 | 
			
		||||
                replace(R.id.content, fragment)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -16,10 +16,11 @@
 | 
			
		||||
 | 
			
		||||
package ch.dissem.apps.abit
 | 
			
		||||
 | 
			
		||||
import android.app.Fragment
 | 
			
		||||
import android.os.Bundle
 | 
			
		||||
import android.view.*
 | 
			
		||||
import android.widget.Toast
 | 
			
		||||
import androidx.fragment.app.Fragment
 | 
			
		||||
import androidx.fragment.app.transaction
 | 
			
		||||
import com.github.angads25.filepicker.model.DialogConfigs
 | 
			
		||||
import com.github.angads25.filepicker.model.DialogProperties
 | 
			
		||||
import com.github.angads25.filepicker.view.FilePickerDialog
 | 
			
		||||
@@ -40,9 +41,9 @@ class InputWifFragment : Fragment() {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View =
 | 
			
		||||
            inflater.inflate(R.layout.fragment_import_input, container, false)
 | 
			
		||||
        inflater.inflate(R.layout.fragment_import_input, container, false)
 | 
			
		||||
 | 
			
		||||
    override fun onViewCreated(view: View?, savedInstanceState: Bundle?) {
 | 
			
		||||
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
 | 
			
		||||
        super.onViewCreated(view, savedInstanceState)
 | 
			
		||||
        next.setOnClickListener {
 | 
			
		||||
            val bundle = Bundle()
 | 
			
		||||
@@ -52,9 +53,9 @@ class InputWifFragment : Fragment() {
 | 
			
		||||
                arguments = bundle
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            fragmentManager.beginTransaction()
 | 
			
		||||
                    .replace(R.id.content, fragment)
 | 
			
		||||
                    .commit()
 | 
			
		||||
            fragmentManager?.transaction {
 | 
			
		||||
                replace(R.id.content, fragment)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -87,9 +88,9 @@ class InputWifFragment : Fragment() {
 | 
			
		||||
                    }
 | 
			
		||||
                } catch (e: IOException) {
 | 
			
		||||
                    Toast.makeText(
 | 
			
		||||
                            activity,
 | 
			
		||||
                            R.string.error_loading_data,
 | 
			
		||||
                            Toast.LENGTH_SHORT
 | 
			
		||||
                        activity,
 | 
			
		||||
                        R.string.error_loading_data,
 | 
			
		||||
                        Toast.LENGTH_SHORT
 | 
			
		||||
                    ).show()
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -20,11 +20,12 @@ import android.content.Intent
 | 
			
		||||
import android.graphics.Canvas
 | 
			
		||||
import android.graphics.Paint
 | 
			
		||||
import android.os.Bundle
 | 
			
		||||
import android.support.annotation.DrawableRes
 | 
			
		||||
import android.support.v4.app.Fragment
 | 
			
		||||
import android.support.v7.app.AppCompatActivity
 | 
			
		||||
import android.support.v7.widget.Toolbar
 | 
			
		||||
import android.view.View
 | 
			
		||||
import androidx.annotation.DrawableRes
 | 
			
		||||
import androidx.appcompat.app.AppCompatActivity
 | 
			
		||||
import androidx.appcompat.widget.Toolbar
 | 
			
		||||
import androidx.fragment.app.Fragment
 | 
			
		||||
import androidx.fragment.app.transaction
 | 
			
		||||
import ch.dissem.apps.abit.drawer.ProfileImageListener
 | 
			
		||||
import ch.dissem.apps.abit.drawer.ProfileSelectionListener
 | 
			
		||||
import ch.dissem.apps.abit.listener.ListSelectionListener
 | 
			
		||||
@@ -32,7 +33,10 @@ import ch.dissem.apps.abit.repository.AndroidLabelRepository.Companion.LABEL_ARC
 | 
			
		||||
import ch.dissem.apps.abit.repository.AndroidMessageRepository
 | 
			
		||||
import ch.dissem.apps.abit.service.Singleton
 | 
			
		||||
import ch.dissem.apps.abit.service.Singleton.currentLabel
 | 
			
		||||
import ch.dissem.apps.abit.util.*
 | 
			
		||||
import ch.dissem.apps.abit.util.getColor
 | 
			
		||||
import ch.dissem.apps.abit.util.getIcon
 | 
			
		||||
import ch.dissem.apps.abit.util.network
 | 
			
		||||
import ch.dissem.apps.abit.util.preferences
 | 
			
		||||
import ch.dissem.bitmessage.BitmessageContext
 | 
			
		||||
import ch.dissem.bitmessage.entity.BitmessageAddress
 | 
			
		||||
import ch.dissem.bitmessage.entity.Conversation
 | 
			
		||||
@@ -51,6 +55,7 @@ import com.mikepenz.materialdrawer.model.interfaces.IProfile
 | 
			
		||||
import com.mikepenz.materialdrawer.model.interfaces.Nameable
 | 
			
		||||
import io.github.kobakei.materialfabspeeddial.FabSpeedDial
 | 
			
		||||
import io.github.kobakei.materialfabspeeddial.FabSpeedDialMenu
 | 
			
		||||
import io.reactivex.disposables.Disposable
 | 
			
		||||
import kotlinx.android.synthetic.main.activity_main.*
 | 
			
		||||
import org.jetbrains.anko.doAsync
 | 
			
		||||
import org.jetbrains.anko.uiThread
 | 
			
		||||
@@ -92,6 +97,8 @@ class MainActivity : AppCompatActivity(), ListSelectionListener<Serializable> {
 | 
			
		||||
    var hasDetailPane: Boolean = false
 | 
			
		||||
        private set
 | 
			
		||||
 | 
			
		||||
    private var subscription: Disposable? = null
 | 
			
		||||
 | 
			
		||||
    private lateinit var bmc: BitmessageContext
 | 
			
		||||
    private lateinit var messageRepo: AndroidMessageRepository
 | 
			
		||||
    private lateinit var accountHeader: AccountHeader
 | 
			
		||||
@@ -294,11 +301,11 @@ class MainActivity : AppCompatActivity(), ListSelectionListener<Serializable> {
 | 
			
		||||
 | 
			
		||||
            uiThread {
 | 
			
		||||
                if (intent.hasExtra(EXTRA_SHOW_LABEL)) {
 | 
			
		||||
                    currentLabel.value = intent.getSerializableExtra(EXTRA_SHOW_LABEL) as Label
 | 
			
		||||
                    currentLabel.onNext(intent.getSerializableExtra(EXTRA_SHOW_LABEL) as Label)
 | 
			
		||||
                } else if (currentLabel.value == null) {
 | 
			
		||||
                    currentLabel.value = labels[0]
 | 
			
		||||
 | 
			
		||||
                    currentLabel.onNext(labels[0])
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                for (label in labels) {
 | 
			
		||||
                    addLabelEntry(label)
 | 
			
		||||
                }
 | 
			
		||||
@@ -322,7 +329,7 @@ class MainActivity : AppCompatActivity(), ListSelectionListener<Serializable> {
 | 
			
		||||
            val itemList = supportFragmentManager.findFragmentById(R.id.item_list)
 | 
			
		||||
            val tag = item.tag
 | 
			
		||||
            if (tag is Label) {
 | 
			
		||||
                currentLabel.value = tag
 | 
			
		||||
                currentLabel.onNext(tag)
 | 
			
		||||
                if (tag.type == Label.Type.INBOX || tag == LABEL_ARCHIVE) {
 | 
			
		||||
                    if (itemList !is ConversationListFragment) {
 | 
			
		||||
                        changeList(ConversationListFragment())
 | 
			
		||||
@@ -344,11 +351,10 @@ class MainActivity : AppCompatActivity(), ListSelectionListener<Serializable> {
 | 
			
		||||
                        return false
 | 
			
		||||
                    }
 | 
			
		||||
                    R.string.settings -> {
 | 
			
		||||
                        supportFragmentManager
 | 
			
		||||
                            .beginTransaction()
 | 
			
		||||
                            .replace(R.id.item_list, SettingsFragment())
 | 
			
		||||
                            .addToBackStack(null)
 | 
			
		||||
                            .commit()
 | 
			
		||||
                        supportFragmentManager?.transaction {
 | 
			
		||||
                            replace(R.id.item_list, SettingsFragment())
 | 
			
		||||
                            addToBackStack(null)
 | 
			
		||||
                        }
 | 
			
		||||
                        return false
 | 
			
		||||
                    }
 | 
			
		||||
                    R.string.full_node -> return true
 | 
			
		||||
@@ -363,9 +369,9 @@ class MainActivity : AppCompatActivity(), ListSelectionListener<Serializable> {
 | 
			
		||||
        network.enableNode(false)
 | 
			
		||||
        updateUnread()
 | 
			
		||||
        Singleton.getMessageListener(this).resetNotification()
 | 
			
		||||
        currentLabel.addObserver(this) { label ->
 | 
			
		||||
            if (label != null && label.id is Long) {
 | 
			
		||||
                drawer.setSelection(label.id as Long)
 | 
			
		||||
        subscription = currentLabel.subscribe { label ->
 | 
			
		||||
            if (label.id is Long) {
 | 
			
		||||
                drawer.setSelection(label.id as Long, false)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        active = true
 | 
			
		||||
@@ -373,7 +379,7 @@ class MainActivity : AppCompatActivity(), ListSelectionListener<Serializable> {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onPause() {
 | 
			
		||||
        currentLabel.removeObserver(this)
 | 
			
		||||
        subscription?.dispose()
 | 
			
		||||
        super.onPause()
 | 
			
		||||
        active = false
 | 
			
		||||
    }
 | 
			
		||||
@@ -537,9 +543,8 @@ class MainActivity : AppCompatActivity(), ListSelectionListener<Serializable> {
 | 
			
		||||
 | 
			
		||||
    fun initFab(@DrawableRes drawableRes: Int, menu: FabSpeedDialMenu): FabSpeedDial {
 | 
			
		||||
        val fab = floatingActionButton ?: throw IllegalStateException("Fab must not be null")
 | 
			
		||||
        fab.hide()
 | 
			
		||||
        fab.removeAllOnMenuItemClickListeners()
 | 
			
		||||
        fab.show()
 | 
			
		||||
        fab.closeMenu()
 | 
			
		||||
        val mainFab = fab.mainFab
 | 
			
		||||
        mainFab.setImageResource(drawableRes)
 | 
			
		||||
        fab.setMenu(menu)
 | 
			
		||||
@@ -551,6 +556,8 @@ class MainActivity : AppCompatActivity(), ListSelectionListener<Serializable> {
 | 
			
		||||
                mainFab.setImageResource(drawableRes)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        fab.show()
 | 
			
		||||
        fab.closeMenu()
 | 
			
		||||
        return fab
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,7 @@ package ch.dissem.apps.abit
 | 
			
		||||
 | 
			
		||||
import android.content.Intent
 | 
			
		||||
import android.os.Bundle
 | 
			
		||||
import android.support.v4.app.NavUtils
 | 
			
		||||
import androidx.core.app.NavUtils
 | 
			
		||||
import android.view.MenuItem
 | 
			
		||||
import ch.dissem.bitmessage.entity.Plaintext
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -19,11 +19,11 @@ package ch.dissem.apps.abit
 | 
			
		||||
import android.content.Context
 | 
			
		||||
import android.content.Intent
 | 
			
		||||
import android.os.Bundle
 | 
			
		||||
import android.support.annotation.IdRes
 | 
			
		||||
import android.support.v4.app.Fragment
 | 
			
		||||
import android.support.v7.widget.GridLayoutManager
 | 
			
		||||
import android.support.v7.widget.LinearLayoutManager
 | 
			
		||||
import android.support.v7.widget.RecyclerView
 | 
			
		||||
import androidx.annotation.IdRes
 | 
			
		||||
import androidx.fragment.app.Fragment
 | 
			
		||||
import androidx.recyclerview.widget.GridLayoutManager
 | 
			
		||||
import androidx.recyclerview.widget.LinearLayoutManager
 | 
			
		||||
import androidx.recyclerview.widget.RecyclerView
 | 
			
		||||
import android.text.util.Linkify
 | 
			
		||||
import android.text.util.Linkify.WEB_URLS
 | 
			
		||||
import android.view.*
 | 
			
		||||
 
 | 
			
		||||
@@ -19,33 +19,28 @@ package ch.dissem.apps.abit
 | 
			
		||||
 | 
			
		||||
import android.content.Intent
 | 
			
		||||
import android.os.Bundle
 | 
			
		||||
import android.support.v4.app.Fragment
 | 
			
		||||
import android.support.v4.content.ContextCompat
 | 
			
		||||
import android.support.v7.widget.LinearLayoutManager
 | 
			
		||||
import android.support.v7.widget.RecyclerView
 | 
			
		||||
import android.support.v7.widget.RecyclerView.OnScrollListener
 | 
			
		||||
import androidx.fragment.app.Fragment
 | 
			
		||||
import androidx.recyclerview.widget.ItemTouchHelper
 | 
			
		||||
import androidx.recyclerview.widget.LinearLayoutManager
 | 
			
		||||
import androidx.recyclerview.widget.RecyclerView
 | 
			
		||||
import androidx.recyclerview.widget.RecyclerView.OnScrollListener
 | 
			
		||||
import android.view.*
 | 
			
		||||
import android.widget.Toast
 | 
			
		||||
import ch.dissem.apps.abit.ComposeMessageActivity.Companion.EXTRA_BROADCAST
 | 
			
		||||
import ch.dissem.apps.abit.ComposeMessageActivity.Companion.EXTRA_IDENTITY
 | 
			
		||||
import ch.dissem.apps.abit.adapter.EventListener
 | 
			
		||||
import ch.dissem.apps.abit.adapter.SwipeToDeleteCallback
 | 
			
		||||
import ch.dissem.apps.abit.adapter.SwipeableMessageAdapter
 | 
			
		||||
import ch.dissem.apps.abit.listener.ListSelectionListener
 | 
			
		||||
import ch.dissem.apps.abit.repository.AndroidMessageRepository
 | 
			
		||||
import ch.dissem.apps.abit.service.Singleton
 | 
			
		||||
import ch.dissem.apps.abit.service.Singleton.currentLabel
 | 
			
		||||
import ch.dissem.apps.abit.util.preferences
 | 
			
		||||
import ch.dissem.bitmessage.entity.Plaintext
 | 
			
		||||
import ch.dissem.bitmessage.entity.valueobject.Label
 | 
			
		||||
import com.h6ah4i.android.widget.advrecyclerview.animator.SwipeDismissItemAnimator
 | 
			
		||||
import com.h6ah4i.android.widget.advrecyclerview.decoration.SimpleListDividerDecorator
 | 
			
		||||
import com.h6ah4i.android.widget.advrecyclerview.swipeable.RecyclerViewSwipeManager
 | 
			
		||||
import com.h6ah4i.android.widget.advrecyclerview.touchguard.RecyclerViewTouchActionGuardManager
 | 
			
		||||
import com.h6ah4i.android.widget.advrecyclerview.utils.WrapperAdapterUtils
 | 
			
		||||
import io.github.kobakei.materialfabspeeddial.FabSpeedDialMenu
 | 
			
		||||
import io.reactivex.disposables.Disposable
 | 
			
		||||
import kotlinx.android.synthetic.main.fragment_message_list.*
 | 
			
		||||
import org.jetbrains.anko.*
 | 
			
		||||
import org.jetbrains.anko.support.v4.alert
 | 
			
		||||
import org.jetbrains.anko.support.v4.onUiThread
 | 
			
		||||
import java.util.*
 | 
			
		||||
 | 
			
		||||
private const val PAGE_SIZE = 15
 | 
			
		||||
@@ -65,21 +60,20 @@ class MessageListFragment : Fragment(), ListHolder<Label> {
 | 
			
		||||
    private var isLoading = false
 | 
			
		||||
    private var isLastPage = false
 | 
			
		||||
 | 
			
		||||
    private var subscription: Disposable? = null
 | 
			
		||||
 | 
			
		||||
    private var layoutManager: LinearLayoutManager? = null
 | 
			
		||||
    private var swipeableMessageAdapter: SwipeableMessageAdapter? = null
 | 
			
		||||
    private var wrappedAdapter: RecyclerView.Adapter<*>? = null
 | 
			
		||||
    private var recyclerViewSwipeManager: RecyclerViewSwipeManager? = null
 | 
			
		||||
    private var recyclerViewTouchActionGuardManager: RecyclerViewTouchActionGuardManager? = null
 | 
			
		||||
 | 
			
		||||
    private val recyclerViewOnScrollListener = object : OnScrollListener() {
 | 
			
		||||
        override fun onScrolled(recyclerView: RecyclerView?, dx: Int, dy: Int) {
 | 
			
		||||
        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
 | 
			
		||||
                    if (visibleItemCount + firstVisibleItemPosition >= totalItemCount - PAGE_SIZE
 | 
			
		||||
                        && firstVisibleItemPosition >= 0
 | 
			
		||||
                    ) {
 | 
			
		||||
                        loadMoreItems()
 | 
			
		||||
@@ -94,6 +88,11 @@ class MessageListFragment : Fragment(), ListHolder<Label> {
 | 
			
		||||
    private lateinit var messageRepo: AndroidMessageRepository
 | 
			
		||||
    private var activateOnItemClick: Boolean = false
 | 
			
		||||
 | 
			
		||||
    override fun setActivateOnItemClick(activateOnItemClick: Boolean) {
 | 
			
		||||
        swipeableMessageAdapter?.activateOnItemClick = activateOnItemClick
 | 
			
		||||
        this.activateOnItemClick = activateOnItemClick
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private val backStack = Stack<Label>()
 | 
			
		||||
 | 
			
		||||
    fun loadMoreItems() {
 | 
			
		||||
@@ -107,7 +106,7 @@ class MessageListFragment : Fragment(), ListHolder<Label> {
 | 
			
		||||
                    PAGE_SIZE,
 | 
			
		||||
                    context?.preferences?.separateIdentities == true && label?.type != Label.Type.BROADCAST
 | 
			
		||||
                )
 | 
			
		||||
                onUiThread {
 | 
			
		||||
                uiThread {
 | 
			
		||||
                    messageAdapter.addAll(messages)
 | 
			
		||||
                    isLoading = false
 | 
			
		||||
                    isLastPage = messages.size < PAGE_SIZE
 | 
			
		||||
@@ -128,12 +127,12 @@ class MessageListFragment : Fragment(), ListHolder<Label> {
 | 
			
		||||
        initFab(activity)
 | 
			
		||||
        messageRepo = Singleton.getMessageRepository(activity)
 | 
			
		||||
 | 
			
		||||
        currentLabel.addObserver(this) { new -> doUpdateList(new) }
 | 
			
		||||
        subscription = currentLabel.subscribe { new -> doUpdateList(new) }
 | 
			
		||||
        doUpdateList(currentLabel.value)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onPause() {
 | 
			
		||||
        currentLabel.removeObserver(this)
 | 
			
		||||
        subscription?.dispose()
 | 
			
		||||
        super.onPause()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -151,7 +150,7 @@ class MessageListFragment : Fragment(), ListHolder<Label> {
 | 
			
		||||
                return
 | 
			
		||||
            }
 | 
			
		||||
            menuItem.isVisible = label.type == Label.Type.TRASH
 | 
			
		||||
            mainActivity?.apply {
 | 
			
		||||
            MainActivity.apply {
 | 
			
		||||
                if ("archive" == label.toString()) {
 | 
			
		||||
                    updateTitle(getString(R.string.archive))
 | 
			
		||||
                } else {
 | 
			
		||||
@@ -176,81 +175,37 @@ class MessageListFragment : Fragment(), ListHolder<Label> {
 | 
			
		||||
 | 
			
		||||
        val context = context ?: throw IllegalStateException("No context available")
 | 
			
		||||
 | 
			
		||||
        layoutManager = LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)
 | 
			
		||||
 | 
			
		||||
        // touch guard manager  (this class is required to suppress scrolling while swipe-dismiss
 | 
			
		||||
        // animation is running)
 | 
			
		||||
        val touchActionGuardManager = RecyclerViewTouchActionGuardManager().apply {
 | 
			
		||||
            setInterceptVerticalScrollingWhileAnimationRunning(true)
 | 
			
		||||
            isEnabled = true
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // swipe manager
 | 
			
		||||
        val swipeManager = RecyclerViewSwipeManager()
 | 
			
		||||
 | 
			
		||||
        //swipeableMessageAdapter
 | 
			
		||||
        val adapter = SwipeableMessageAdapter().apply {
 | 
			
		||||
            setActivateOnItemClick(activateOnItemClick)
 | 
			
		||||
        }
 | 
			
		||||
        adapter.eventListener = object : SwipeableMessageAdapter.EventListener {
 | 
			
		||||
            override fun onItemDeleted(item: Plaintext) {
 | 
			
		||||
                if (MessageDetailFragment.isInTrash(item)) {
 | 
			
		||||
                    Singleton.labeler.delete(item)
 | 
			
		||||
                    messageRepo.remove(item)
 | 
			
		||||
                } else {
 | 
			
		||||
                    Singleton.labeler.delete(item)
 | 
			
		||||
                    messageRepo.save(item)
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            override fun onItemArchived(item: Plaintext) {
 | 
			
		||||
                Singleton.labeler.archive(item)
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            override fun onItemViewClicked(v: View?) {
 | 
			
		||||
                val position = recycler_view.getChildAdapterPosition(v)
 | 
			
		||||
                adapter.setSelectedPosition(position)
 | 
			
		||||
                if (position != RecyclerView.NO_POSITION) {
 | 
			
		||||
                    val item = adapter.getItem(position)
 | 
			
		||||
                    MainActivity.apply { onItemSelected(item) }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // wrap for swiping
 | 
			
		||||
        wrappedAdapter = swipeManager.createWrappedAdapter(adapter)
 | 
			
		||||
 | 
			
		||||
        val animator = SwipeDismissItemAnimator()
 | 
			
		||||
 | 
			
		||||
        // Change animations are enabled by default since support-v7-recyclerview v22.
 | 
			
		||||
        // Disable the change animation in order to make turning back animation of swiped item
 | 
			
		||||
        // works properly.
 | 
			
		||||
        animator.supportsChangeAnimations = false
 | 
			
		||||
 | 
			
		||||
        layoutManager = LinearLayoutManager(context, RecyclerView.VERTICAL, false)
 | 
			
		||||
        recycler_view.layoutManager = layoutManager
 | 
			
		||||
        recycler_view.adapter = wrappedAdapter  // requires *wrapped* swipeableMessageAdapter
 | 
			
		||||
        recycler_view.itemAnimator = animator
 | 
			
		||||
        swipeableMessageAdapter = SwipeableMessageAdapter(context).apply {
 | 
			
		||||
            activateOnItemClick = this@MessageListFragment.activateOnItemClick
 | 
			
		||||
        }
 | 
			
		||||
        recycler_view.adapter = swipeableMessageAdapter  // requires *wrapped* swipeableMessageAdapter
 | 
			
		||||
        recycler_view.addOnScrollListener(recyclerViewOnScrollListener)
 | 
			
		||||
 | 
			
		||||
        recycler_view.addItemDecoration(
 | 
			
		||||
            SimpleListDividerDecorator(
 | 
			
		||||
                ContextCompat.getDrawable(context, R.drawable.list_divider_h), true
 | 
			
		||||
            )
 | 
			
		||||
        )
 | 
			
		||||
        val dirs = when (currentLabel.value?.type) {
 | 
			
		||||
            Label.Type.TRASH -> ItemTouchHelper.LEFT
 | 
			
		||||
            else -> ItemTouchHelper.LEFT + ItemTouchHelper.RIGHT
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // NOTE:
 | 
			
		||||
        // The initialization order is very important! This order determines the priority of
 | 
			
		||||
        // touch event handling.
 | 
			
		||||
        //
 | 
			
		||||
        // priority: TouchActionGuard > Swipe > DragAndDrop
 | 
			
		||||
        touchActionGuardManager.attachRecyclerView(recycler_view)
 | 
			
		||||
        swipeManager.attachRecyclerView(recycler_view)
 | 
			
		||||
        val swipeHandler = SwipeToDeleteCallback(context, dirs, object : EventListener {
 | 
			
		||||
            override fun onItemDeleted(position: Int) {
 | 
			
		||||
                context.toast("Deleted")
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        recyclerViewTouchActionGuardManager = touchActionGuardManager
 | 
			
		||||
        recyclerViewSwipeManager = swipeManager
 | 
			
		||||
        swipeableMessageAdapter = adapter
 | 
			
		||||
            override fun onItemArchived(position: Int) {
 | 
			
		||||
                context.toast("Archived")
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        Singleton.updateMessageListAdapterInListener(adapter)
 | 
			
		||||
            override fun onItemSelected(position: Int) {
 | 
			
		||||
                context.toast("Selected")
 | 
			
		||||
            }
 | 
			
		||||
        })
 | 
			
		||||
 | 
			
		||||
        val itemTouchHelper = ItemTouchHelper(swipeHandler)
 | 
			
		||||
        itemTouchHelper.attachToRecyclerView(recycler_view)
 | 
			
		||||
 | 
			
		||||
//   FIXME     Singleton.updateMessageListAdapterInListener(adapter)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun initFab(context: MainActivity) {
 | 
			
		||||
@@ -286,18 +241,6 @@ class MessageListFragment : Fragment(), ListHolder<Label> {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onDestroyView() {
 | 
			
		||||
        recyclerViewSwipeManager?.release()
 | 
			
		||||
        recyclerViewSwipeManager = null
 | 
			
		||||
 | 
			
		||||
        recyclerViewTouchActionGuardManager?.release()
 | 
			
		||||
        recyclerViewTouchActionGuardManager = null
 | 
			
		||||
 | 
			
		||||
        recycler_view.itemAnimator = null
 | 
			
		||||
        recycler_view.adapter = null
 | 
			
		||||
 | 
			
		||||
        wrappedAdapter?.let { WrapperAdapterUtils.releaseAll(it) }
 | 
			
		||||
        wrappedAdapter = null
 | 
			
		||||
 | 
			
		||||
        swipeableMessageAdapter = null
 | 
			
		||||
        layoutManager = null
 | 
			
		||||
 | 
			
		||||
@@ -308,7 +251,7 @@ class MessageListFragment : Fragment(), ListHolder<Label> {
 | 
			
		||||
        inflater.inflate(R.menu.message_list, menu)
 | 
			
		||||
        emptyTrashMenuItem = menu.findItem(R.id.empty_trash)
 | 
			
		||||
        deleteAllMenuItem = menu.findItem(R.id.delete_all)
 | 
			
		||||
        currentLabel.value?.let { doUpdateList(it) }
 | 
			
		||||
//        currentLabel.value?.let { doUpdateList(it) }
 | 
			
		||||
        super.onCreateOptionsMenu(menu, inflater)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -324,15 +267,17 @@ class MessageListFragment : Fragment(), ListHolder<Label> {
 | 
			
		||||
            }
 | 
			
		||||
            R.id.delete_all -> {
 | 
			
		||||
                currentLabel.value?.let { label ->
 | 
			
		||||
                    alert(
 | 
			
		||||
                        title = R.string.delete_all_messages_in_list,
 | 
			
		||||
                        message = R.string.delete_all_messages_in_list_ask
 | 
			
		||||
                    ) {
 | 
			
		||||
                        positiveButton(R.string.delete) {
 | 
			
		||||
                            deleteAllMessages(label)
 | 
			
		||||
                        }
 | 
			
		||||
                        cancelButton { }
 | 
			
		||||
                    }.show()
 | 
			
		||||
                    context?.apply {
 | 
			
		||||
                        alert(
 | 
			
		||||
                            R.string.delete_all_messages_in_list,
 | 
			
		||||
                            R.string.delete_all_messages_in_list_ask
 | 
			
		||||
                        ) {
 | 
			
		||||
                            positiveButton(R.string.delete) {
 | 
			
		||||
                                deleteAllMessages(label)
 | 
			
		||||
                            }
 | 
			
		||||
                            cancelButton { }
 | 
			
		||||
                        }.show()
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                return true
 | 
			
		||||
            }
 | 
			
		||||
@@ -351,18 +296,13 @@ class MessageListFragment : Fragment(), ListHolder<Label> {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun updateList(label: Label) {
 | 
			
		||||
        currentLabel.value = label
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun setActivateOnItemClick(activateOnItemClick: Boolean) {
 | 
			
		||||
        swipeableMessageAdapter?.setActivateOnItemClick(activateOnItemClick)
 | 
			
		||||
        this.activateOnItemClick = activateOnItemClick
 | 
			
		||||
        currentLabel.onNext(label)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun showPreviousList() = if (backStack.isEmpty()) {
 | 
			
		||||
        false
 | 
			
		||||
    } else {
 | 
			
		||||
        currentLabel.value = backStack.pop()
 | 
			
		||||
        currentLabel.onNext(backStack.pop())
 | 
			
		||||
        true
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -23,16 +23,11 @@ import android.content.Intent
 | 
			
		||||
import android.content.ServiceConnection
 | 
			
		||||
import android.os.Bundle
 | 
			
		||||
import android.os.IBinder
 | 
			
		||||
import android.support.v4.app.Fragment
 | 
			
		||||
import android.support.v4.content.ContextCompat
 | 
			
		||||
import android.support.v4.content.FileProvider.getUriForFile
 | 
			
		||||
import android.support.v7.preference.Preference
 | 
			
		||||
import android.support.v7.preference.Preference.OnPreferenceChangeListener
 | 
			
		||||
import android.support.v7.preference.PreferenceFragmentCompat
 | 
			
		||||
import android.support.v7.preference.PreferenceScreen
 | 
			
		||||
import android.support.v7.preference.SwitchPreferenceCompat
 | 
			
		||||
import android.view.View
 | 
			
		||||
import android.widget.Toast
 | 
			
		||||
import androidx.core.content.FileProvider.getUriForFile
 | 
			
		||||
import androidx.preference.Preference
 | 
			
		||||
import androidx.preference.PreferenceFragmentCompat
 | 
			
		||||
import androidx.preference.SwitchPreferenceCompat
 | 
			
		||||
import ch.dissem.apps.abit.service.BatchProcessorService
 | 
			
		||||
import ch.dissem.apps.abit.service.SimpleJob
 | 
			
		||||
import ch.dissem.apps.abit.service.Singleton
 | 
			
		||||
@@ -43,15 +38,15 @@ import ch.dissem.bitmessage.entity.Plaintext
 | 
			
		||||
import com.mikepenz.aboutlibraries.Libs
 | 
			
		||||
import com.mikepenz.aboutlibraries.LibsBuilder
 | 
			
		||||
import org.jetbrains.anko.doAsync
 | 
			
		||||
import org.jetbrains.anko.support.v4.indeterminateProgressDialog
 | 
			
		||||
import org.jetbrains.anko.support.v4.startActivity
 | 
			
		||||
import org.jetbrains.anko.indeterminateProgressDialog
 | 
			
		||||
import org.jetbrains.anko.startActivity
 | 
			
		||||
import org.jetbrains.anko.uiThread
 | 
			
		||||
import java.util.*
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @author Christian Basler
 | 
			
		||||
 */
 | 
			
		||||
class SettingsFragment : PreferenceFragmentCompat(), PreferenceFragmentCompat.OnPreferenceStartScreenCallback {
 | 
			
		||||
class SettingsFragment : PreferenceFragmentCompat() {
 | 
			
		||||
 | 
			
		||||
    override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
 | 
			
		||||
        setPreferencesFromResource(R.xml.preferences, rootKey)
 | 
			
		||||
@@ -117,9 +112,9 @@ class SettingsFragment : PreferenceFragmentCompat(), PreferenceFragmentCompat.On
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun exportClickListener() = Preference.OnPreferenceClickListener {
 | 
			
		||||
        val ctx = context ?: throw IllegalStateException("No context available")
 | 
			
		||||
        val ctx = activity ?: throw IllegalStateException("No context available")
 | 
			
		||||
 | 
			
		||||
        indeterminateProgressDialog(R.string.export_data_summary, R.string.export_data).apply {
 | 
			
		||||
        ctx.indeterminateProgressDialog(R.string.export_data_summary, R.string.export_data).apply {
 | 
			
		||||
            doAsync {
 | 
			
		||||
                val exportDirectory = ctx.preferences.exportDirectory
 | 
			
		||||
                exportDirectory.mkdirs()
 | 
			
		||||
@@ -152,20 +147,20 @@ class SettingsFragment : PreferenceFragmentCompat(), PreferenceFragmentCompat.On
 | 
			
		||||
        if (activity.hasDetailPane) {
 | 
			
		||||
            activity.setDetailView(StatusFragment())
 | 
			
		||||
        } else {
 | 
			
		||||
            startActivity<StatusActivity>()
 | 
			
		||||
            activity.startActivity<StatusActivity>()
 | 
			
		||||
        }
 | 
			
		||||
        return@OnPreferenceClickListener true
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
 | 
			
		||||
        val ctx = context ?: throw IllegalStateException("No context available")
 | 
			
		||||
        val ctx = activity ?: throw IllegalStateException("No context available")
 | 
			
		||||
        when (requestCode) {
 | 
			
		||||
            WRITE_EXPORT_REQUEST_CODE -> ctx.preferences.cleanupExportDirectory()
 | 
			
		||||
            READ_IMPORT_REQUEST_CODE -> {
 | 
			
		||||
                if (resultCode == Activity.RESULT_OK && data?.data != null) {
 | 
			
		||||
                    indeterminateProgressDialog(R.string.import_data_summary, R.string.import_data).apply {
 | 
			
		||||
                    ctx.indeterminateProgressDialog(R.string.import_data_summary, R.string.import_data).apply {
 | 
			
		||||
                        doAsync {
 | 
			
		||||
                            Exports.importData(data.data, ctx)
 | 
			
		||||
                            Exports.importData(data.data!!, ctx)
 | 
			
		||||
                            uiThread {
 | 
			
		||||
                                dismiss()
 | 
			
		||||
                            }
 | 
			
		||||
@@ -224,40 +219,41 @@ class SettingsFragment : PreferenceFragmentCompat(), PreferenceFragmentCompat.On
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun emulateConversationChangeListener(conversationInit: Preference?) =
 | 
			
		||||
        OnPreferenceChangeListener { _, newValue ->
 | 
			
		||||
        Preference.OnPreferenceChangeListener { _, newValue ->
 | 
			
		||||
            conversationInit?.isEnabled = newValue as Boolean
 | 
			
		||||
            true
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    private fun connectivityChangeListener() =
 | 
			
		||||
        OnPreferenceChangeListener { _, _ ->
 | 
			
		||||
            context?.network?.scheduleNodeStart()
 | 
			
		||||
        Preference.OnPreferenceChangeListener { _, _ ->
 | 
			
		||||
            activity?.network?.scheduleNodeStart()
 | 
			
		||||
            true
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    // The why-is-it-so-damn-hard-to-group-preferences section
 | 
			
		||||
    override fun getCallbackFragment(): Fragment = this
 | 
			
		||||
 | 
			
		||||
    override fun onPreferenceStartScreen(
 | 
			
		||||
        preferenceFragmentCompat: PreferenceFragmentCompat,
 | 
			
		||||
        preferenceScreen: PreferenceScreen
 | 
			
		||||
    ): Boolean {
 | 
			
		||||
        fragmentManager?.beginTransaction()?.let { ft ->
 | 
			
		||||
            val fragment = SettingsFragment()
 | 
			
		||||
            fragment.arguments = Bundle().apply {
 | 
			
		||||
                putString(PreferenceFragmentCompat.ARG_PREFERENCE_ROOT, preferenceScreen.key)
 | 
			
		||||
            }
 | 
			
		||||
            ft.add(R.id.item_list, fragment, preferenceScreen.key)
 | 
			
		||||
            ft.addToBackStack(preferenceScreen.key)
 | 
			
		||||
            ft.commit()
 | 
			
		||||
        }
 | 
			
		||||
        return true
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
 | 
			
		||||
        super.onViewCreated(view, savedInstanceState)
 | 
			
		||||
        context?.let { ctx -> view.setBackgroundColor(ContextCompat.getColor(ctx, R.color.contentBackground)) }
 | 
			
		||||
    }
 | 
			
		||||
    // FIXME: maybe this is once again necessary, maybe not. Test!
 | 
			
		||||
//    override fun getCallbackFragment(): Fragment = this
 | 
			
		||||
//
 | 
			
		||||
//    override fun onPreferenceStartScreen(
 | 
			
		||||
//        preferenceFragmentCompat: PreferenceFragment,
 | 
			
		||||
//        preferenceScreen: PreferenceScreen
 | 
			
		||||
//    ): Boolean {
 | 
			
		||||
//        fragmentManager?.beginTransaction()?.let { ft ->
 | 
			
		||||
//            val fragment = SettingsFragment()
 | 
			
		||||
//            fragment.arguments = Bundle().apply {
 | 
			
		||||
//                putString(PreferenceFragment.ARG_PREFERENCE_ROOT, preferenceScreen.key)
 | 
			
		||||
//            }
 | 
			
		||||
//            ft.add(R.id.item_list, fragment, preferenceScreen.key)
 | 
			
		||||
//            ft.addToBackStack(preferenceScreen.key)
 | 
			
		||||
//            ft.commit()
 | 
			
		||||
//        }
 | 
			
		||||
//        return true
 | 
			
		||||
//    }
 | 
			
		||||
//
 | 
			
		||||
//    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
 | 
			
		||||
//        super.onViewCreated(view, savedInstanceState)
 | 
			
		||||
//        context?.let { ctx -> view.setBackgroundColor(ContextCompat.getColor(ctx, R.color.contentBackground)) }
 | 
			
		||||
//    }
 | 
			
		||||
    // End of the why-is-it-so-damn-hard-to-group-preferences section
 | 
			
		||||
    // Afterthought: here it looks so simple: https://developer.android.com/guide/topics/ui/settings.html
 | 
			
		||||
    // Remind me, why do we need to use PreferenceFragmentCompat?
 | 
			
		||||
 
 | 
			
		||||
@@ -17,7 +17,7 @@
 | 
			
		||||
package ch.dissem.apps.abit
 | 
			
		||||
 | 
			
		||||
import android.os.Bundle
 | 
			
		||||
import android.support.v7.app.AppCompatActivity
 | 
			
		||||
import androidx.appcompat.app.AppCompatActivity
 | 
			
		||||
import ch.dissem.apps.abit.service.Singleton
 | 
			
		||||
import com.mikepenz.materialize.MaterializeBuilder
 | 
			
		||||
import kotlinx.android.synthetic.main.activity_status.*
 | 
			
		||||
 
 | 
			
		||||
@@ -17,7 +17,7 @@
 | 
			
		||||
package ch.dissem.apps.abit
 | 
			
		||||
 | 
			
		||||
import android.os.Bundle
 | 
			
		||||
import android.support.v4.app.Fragment
 | 
			
		||||
import androidx.fragment.app.Fragment
 | 
			
		||||
import android.view.LayoutInflater
 | 
			
		||||
import android.view.View
 | 
			
		||||
import android.view.ViewGroup
 | 
			
		||||
 
 | 
			
		||||
@@ -16,7 +16,7 @@
 | 
			
		||||
 | 
			
		||||
package ch.dissem.apps.abit.adapter
 | 
			
		||||
 | 
			
		||||
import android.support.v7.widget.RecyclerView
 | 
			
		||||
import androidx.recyclerview.widget.RecyclerView
 | 
			
		||||
import android.view.LayoutInflater
 | 
			
		||||
import android.view.View
 | 
			
		||||
import android.view.ViewGroup
 | 
			
		||||
@@ -31,7 +31,7 @@ import java.util.*
 | 
			
		||||
 */
 | 
			
		||||
class AddressSelectorAdapter(identities: List<BitmessageAddress>) : RecyclerView.Adapter<AddressSelectorAdapter.ViewHolder>() {
 | 
			
		||||
 | 
			
		||||
    private val data = identities.map { Selectable(it) }.toMutableList()
 | 
			
		||||
    private val data = identities.asSequence().map { Selectable(it) }.toMutableList()
 | 
			
		||||
 | 
			
		||||
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
 | 
			
		||||
        val inflater = LayoutInflater.from(parent.context)
 | 
			
		||||
@@ -63,7 +63,7 @@ class AddressSelectorAdapter(identities: List<BitmessageAddress>) : RecyclerView
 | 
			
		||||
 | 
			
		||||
    val selected: List<BitmessageAddress>
 | 
			
		||||
        get() {
 | 
			
		||||
            return data
 | 
			
		||||
            return data.asSequence()
 | 
			
		||||
                .filter { it.selected }
 | 
			
		||||
                .mapTo(LinkedList()) { it.data }
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -142,5 +142,4 @@ class ContactAdapter(
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun indexOf(element: BitmessageAddress) = originalData.indexOf(element)
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,16 +1,16 @@
 | 
			
		||||
package ch.dissem.apps.abit.adapter
 | 
			
		||||
 | 
			
		||||
import android.content.Context
 | 
			
		||||
import android.support.v4.app.Fragment
 | 
			
		||||
import android.support.v7.widget.GridLayoutManager
 | 
			
		||||
import android.support.v7.widget.PopupMenu
 | 
			
		||||
import android.support.v7.widget.RecyclerView
 | 
			
		||||
import android.text.util.Linkify
 | 
			
		||||
import android.view.LayoutInflater
 | 
			
		||||
import android.view.View
 | 
			
		||||
import android.view.ViewGroup
 | 
			
		||||
import android.widget.ImageView
 | 
			
		||||
import android.widget.TextView
 | 
			
		||||
import androidx.appcompat.widget.PopupMenu
 | 
			
		||||
import androidx.fragment.app.Fragment
 | 
			
		||||
import androidx.recyclerview.widget.GridLayoutManager
 | 
			
		||||
import androidx.recyclerview.widget.RecyclerView
 | 
			
		||||
import ch.dissem.apps.abit.*
 | 
			
		||||
import ch.dissem.apps.abit.service.Singleton
 | 
			
		||||
import ch.dissem.apps.abit.util.Constants
 | 
			
		||||
@@ -19,18 +19,19 @@ import ch.dissem.bitmessage.entity.Conversation
 | 
			
		||||
import ch.dissem.bitmessage.entity.Plaintext
 | 
			
		||||
import ch.dissem.bitmessage.entity.valueobject.Label
 | 
			
		||||
import ch.dissem.bitmessage.ports.MessageRepository
 | 
			
		||||
import io.reactivex.subjects.BehaviorSubject
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ConversationAdapter internal constructor(
 | 
			
		||||
    ctx: Context,
 | 
			
		||||
    private val parent: Fragment,
 | 
			
		||||
    conversation: Conversation,
 | 
			
		||||
    private val label: Label?
 | 
			
		||||
    label: BehaviorSubject<Label>
 | 
			
		||||
) : RecyclerView.Adapter<ConversationAdapter.ViewHolder>() {
 | 
			
		||||
 | 
			
		||||
    private val messageRepo = Singleton.getMessageRepository(ctx)
 | 
			
		||||
 | 
			
		||||
    private var filteredMessages = conversation.messages.filter { label == null || it.labels.any { it == label } }
 | 
			
		||||
    private var filteredMessages = label.value?.let { l -> conversation.messages.filter { m -> m.labels.any { it == l } } } ?: emptyList()
 | 
			
		||||
 | 
			
		||||
    override fun onCreateViewHolder(
 | 
			
		||||
        parent: ViewGroup,
 | 
			
		||||
@@ -98,51 +99,54 @@ class ConversationAdapter internal constructor(
 | 
			
		||||
        val sender = itemView.findViewById<TextView>(R.id.sender)!!
 | 
			
		||||
        val recipient = itemView.findViewById<TextView>(R.id.recipient)!!
 | 
			
		||||
        val status = itemView.findViewById<ImageView>(R.id.status)!!
 | 
			
		||||
        val menu = itemView.findViewById<ImageView>(R.id.menu)!!.also { view ->
 | 
			
		||||
            view.setOnClickListener {
 | 
			
		||||
                val popup = PopupMenu(itemView.context, view)
 | 
			
		||||
                popup.menuInflater.inflate(R.menu.message, popup.menu)
 | 
			
		||||
                popup.setOnMenuItemClickListener {
 | 
			
		||||
                    item?.let { item ->
 | 
			
		||||
                        when (it.itemId) {
 | 
			
		||||
                            R.id.reply -> {
 | 
			
		||||
                                ComposeMessageActivity.launchReplyTo(parent, item)
 | 
			
		||||
                                true
 | 
			
		||||
                            }
 | 
			
		||||
                            R.id.delete -> {
 | 
			
		||||
                                if (MessageDetailFragment.isInTrash(item)) {
 | 
			
		||||
                                    Singleton.labeler.delete(item)
 | 
			
		||||
                                    messageRepo.remove(item)
 | 
			
		||||
                                } else {
 | 
			
		||||
                                    Singleton.labeler.delete(item)
 | 
			
		||||
        val menu = itemView.findViewById<ImageView>(R.id.menu)!!.apply {
 | 
			
		||||
            setOnClickListener { view ->
 | 
			
		||||
                PopupMenu(itemView.context, view).apply {
 | 
			
		||||
 | 
			
		||||
                    menuInflater.inflate(R.menu.message, menu)
 | 
			
		||||
                    setOnMenuItemClickListener { menuItem ->
 | 
			
		||||
                        item?.let { item ->
 | 
			
		||||
                            when (menuItem.itemId) {
 | 
			
		||||
                                R.id.reply -> {
 | 
			
		||||
                                    ComposeMessageActivity.launchReplyTo(parent, item)
 | 
			
		||||
                                    true
 | 
			
		||||
                                }
 | 
			
		||||
                                R.id.delete -> {
 | 
			
		||||
                                    if (MessageDetailFragment.isInTrash(item)) {
 | 
			
		||||
                                        Singleton.labeler.delete(item)
 | 
			
		||||
                                        messageRepo.remove(item)
 | 
			
		||||
                                    } else {
 | 
			
		||||
                                        Singleton.labeler.delete(item)
 | 
			
		||||
                                        messageRepo.save(item)
 | 
			
		||||
                                    }
 | 
			
		||||
                                    filteredMessages.indexOf(item).let { i ->
 | 
			
		||||
                                        filteredMessages -= item
 | 
			
		||||
                                        notifyItemRemoved(i)
 | 
			
		||||
                                    }
 | 
			
		||||
                                    MainActivity.apply {
 | 
			
		||||
                                        updateUnread()
 | 
			
		||||
                                    }
 | 
			
		||||
                                    true
 | 
			
		||||
                                }
 | 
			
		||||
                                R.id.mark_unread -> {
 | 
			
		||||
                                    Singleton.labeler.markAsUnread(item)
 | 
			
		||||
                                    messageRepo.save(item)
 | 
			
		||||
                                    MainActivity.apply { updateUnread() }
 | 
			
		||||
                                    true
 | 
			
		||||
                                }
 | 
			
		||||
                                filteredMessages.indexOf(item).let { i ->
 | 
			
		||||
                                    filteredMessages -= item
 | 
			
		||||
                                    notifyItemRemoved(i)
 | 
			
		||||
                                R.id.archive -> {
 | 
			
		||||
                                    Singleton.labeler.archive(item)
 | 
			
		||||
                                    messageRepo.save(item)
 | 
			
		||||
                                    MainActivity.apply { updateUnread() }
 | 
			
		||||
                                    true
 | 
			
		||||
                                }
 | 
			
		||||
                                MainActivity.apply {
 | 
			
		||||
                                    updateUnread()
 | 
			
		||||
                                }
 | 
			
		||||
                                true
 | 
			
		||||
                                else -> false
 | 
			
		||||
                            }
 | 
			
		||||
                            R.id.mark_unread -> {
 | 
			
		||||
                                Singleton.labeler.markAsUnread(item)
 | 
			
		||||
                                messageRepo.save(item)
 | 
			
		||||
                                MainActivity.apply { updateUnread() }
 | 
			
		||||
                                true
 | 
			
		||||
                            }
 | 
			
		||||
                            R.id.archive -> {
 | 
			
		||||
                                Singleton.labeler.archive(item)
 | 
			
		||||
                                messageRepo.save(item)
 | 
			
		||||
                                MainActivity.apply { updateUnread() }
 | 
			
		||||
                                true
 | 
			
		||||
                            }
 | 
			
		||||
                            else -> false
 | 
			
		||||
                        }
 | 
			
		||||
                    } ?: false
 | 
			
		||||
                        } ?: false
 | 
			
		||||
                    }
 | 
			
		||||
                    show()
 | 
			
		||||
 | 
			
		||||
                }
 | 
			
		||||
                popup.show()
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        val text = itemView.findViewById<TextView>(R.id.text)!!.apply {
 | 
			
		||||
 
 | 
			
		||||
@@ -2,8 +2,8 @@ package ch.dissem.apps.abit.adapter
 | 
			
		||||
 | 
			
		||||
import android.content.Context
 | 
			
		||||
import android.content.res.ColorStateList
 | 
			
		||||
import android.support.annotation.ColorInt
 | 
			
		||||
import android.support.v7.widget.RecyclerView
 | 
			
		||||
import androidx.annotation.ColorInt
 | 
			
		||||
import androidx.recyclerview.widget.RecyclerView
 | 
			
		||||
import android.view.LayoutInflater
 | 
			
		||||
import android.view.View
 | 
			
		||||
import android.view.ViewGroup
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,312 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright 2015 Haruki Hasegawa
 | 
			
		||||
 * Copyright 2016 Christian Basler
 | 
			
		||||
 *
 | 
			
		||||
 * Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
 * you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 *
 | 
			
		||||
 *     http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
 * See the License for the specific language governing permissions and
 | 
			
		||||
 * limitations under the License.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
package ch.dissem.apps.abit.adapter
 | 
			
		||||
 | 
			
		||||
import android.content.Context
 | 
			
		||||
import android.graphics.*
 | 
			
		||||
import android.view.LayoutInflater
 | 
			
		||||
import android.view.View
 | 
			
		||||
import android.view.ViewGroup
 | 
			
		||||
import android.widget.FrameLayout
 | 
			
		||||
import android.widget.ImageView
 | 
			
		||||
import android.widget.TextView
 | 
			
		||||
import androidx.core.content.ContextCompat
 | 
			
		||||
import androidx.recyclerview.widget.ItemTouchHelper
 | 
			
		||||
import androidx.recyclerview.widget.RecyclerView
 | 
			
		||||
import ch.dissem.apps.abit.Identicon
 | 
			
		||||
import ch.dissem.apps.abit.MultiIdenticon
 | 
			
		||||
import ch.dissem.apps.abit.R
 | 
			
		||||
import ch.dissem.apps.abit.util.Strings.prepareMessageExtract
 | 
			
		||||
import ch.dissem.apps.abit.util.getDrawable
 | 
			
		||||
import ch.dissem.apps.abit.util.getString
 | 
			
		||||
import ch.dissem.bitmessage.entity.Conversation
 | 
			
		||||
import ch.dissem.bitmessage.entity.Plaintext
 | 
			
		||||
import ch.dissem.bitmessage.entity.valueobject.Label
 | 
			
		||||
import java.util.*
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Adapted from the basic swipeable example by Haruki Hasegawa. See
 | 
			
		||||
 *
 | 
			
		||||
 * @author Christian Basler
 | 
			
		||||
 * @see [https://github.com/h6ah4i/android-advancedrecyclerview](https://github.com/h6ah4i/android-advancedrecyclerview)
 | 
			
		||||
 */
 | 
			
		||||
abstract class SwipeableAdapter<T, H>(val ctx: Context) :
 | 
			
		||||
    RecyclerView.Adapter<H>() where H : SwipeableAdapter.AbstractViewHolder {
 | 
			
		||||
 | 
			
		||||
    protected val data = LinkedList<T>()
 | 
			
		||||
    var eventListener: EventListener? = null
 | 
			
		||||
 | 
			
		||||
    protected var label: Label? = null
 | 
			
		||||
    var selectedPosition = -1
 | 
			
		||||
        set(value) {
 | 
			
		||||
            val oldPosition = field
 | 
			
		||||
            field = value
 | 
			
		||||
            notifyItemChanged(oldPosition)
 | 
			
		||||
            notifyItemChanged(value)
 | 
			
		||||
        }
 | 
			
		||||
    var activateOnItemClick: Boolean = false
 | 
			
		||||
 | 
			
		||||
    protected val labelUnknown: String = ctx.getString(R.string.unknown)
 | 
			
		||||
 | 
			
		||||
    open class AbstractViewHolder(v: View, adapter: SwipeableAdapter<*, *>) : RecyclerView.ViewHolder(v) {
 | 
			
		||||
 | 
			
		||||
        val container = v.findViewById<FrameLayout>(R.id.container)!!
 | 
			
		||||
 | 
			
		||||
        init {
 | 
			
		||||
            itemView.setOnClickListener { adapter.eventListener?.onItemSelected(adapterPosition) }
 | 
			
		||||
            container.setOnClickListener { adapter.eventListener?.onItemSelected(adapterPosition) }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    init {
 | 
			
		||||
        // SwipeableItemAdapter requires stable ID, and also
 | 
			
		||||
        // have to implement the getItemId() method appropriately.
 | 
			
		||||
        setHasStableIds(true)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onBindViewHolder(holder: H, position: Int) {
 | 
			
		||||
        val item = data[position]
 | 
			
		||||
 | 
			
		||||
        holder.apply {
 | 
			
		||||
            if (activateOnItemClick) {
 | 
			
		||||
                container.setBackgroundResource(
 | 
			
		||||
                    if (position == selectedPosition)
 | 
			
		||||
                        R.drawable.bg_item_selected_state
 | 
			
		||||
                    else
 | 
			
		||||
                        R.drawable.bg_item_normal_state
 | 
			
		||||
                )
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            setData(holder, item)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    abstract fun setData(holder: H, item: T)
 | 
			
		||||
 | 
			
		||||
    fun add(item: T) {
 | 
			
		||||
        val index = data.size
 | 
			
		||||
        data.add(item)
 | 
			
		||||
        notifyItemInserted(index)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun addFirst(item: T) {
 | 
			
		||||
        data.addFirst(item)
 | 
			
		||||
        notifyItemInserted(0)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun addAll(items: Collection<T>) {
 | 
			
		||||
        val index = data.size
 | 
			
		||||
        data.addAll(items)
 | 
			
		||||
        notifyItemRangeInserted(index, items.size)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun remove(item: T) {
 | 
			
		||||
        val itemId = getItemId(item)
 | 
			
		||||
        val index = data.indexOfFirst { getItemId(it) == itemId }
 | 
			
		||||
        if (index >= 0) {
 | 
			
		||||
            removeAt(index)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun removeAt(index: Int) {
 | 
			
		||||
        data.removeAt(index)
 | 
			
		||||
        notifyItemRemoved(index)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun getItemId(position: Int): Long {
 | 
			
		||||
        return getItemId(data[position])
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    abstract fun getItemId(item: T): Long
 | 
			
		||||
 | 
			
		||||
    abstract fun update(item: T)
 | 
			
		||||
 | 
			
		||||
    fun clear(newLabel: Label?) {
 | 
			
		||||
        label = newLabel
 | 
			
		||||
        data.clear()
 | 
			
		||||
        notifyDataSetChanged()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun getItem(position: Int) = data[position]
 | 
			
		||||
 | 
			
		||||
    override fun getItemCount() = data.size
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class SwipeableConversationAdapter(ctx: Context) : SwipeableAdapter<Conversation, SwipeableConversationAdapter.ViewHolder>(ctx) {
 | 
			
		||||
    override fun getItemId(item: Conversation) = item.id.leastSignificantBits
 | 
			
		||||
 | 
			
		||||
    override fun update(item: Conversation) {
 | 
			
		||||
        val index = data.indexOfFirst { it.id == item.id }
 | 
			
		||||
        if (index >= 0) {
 | 
			
		||||
            data[index] = item
 | 
			
		||||
            notifyItemChanged(index)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
 | 
			
		||||
        val inflater = LayoutInflater.from(parent.context)
 | 
			
		||||
        val v = inflater.inflate(R.layout.conversation_row, parent, false)
 | 
			
		||||
        return ViewHolder(v, this)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun setData(holder: ViewHolder, item: Conversation) {
 | 
			
		||||
        holder.apply {
 | 
			
		||||
            avatar.setImageDrawable(MultiIdenticon(item.participants))
 | 
			
		||||
 | 
			
		||||
            sender.text = item.participants.sortedBy {
 | 
			
		||||
                (it.alias?.let { 0 } ?: 1) + if (it.isChan) 2 else 0
 | 
			
		||||
            }.map { it.alias ?: labelUnknown }.distinct().joinToString()
 | 
			
		||||
            subject.text = prepareMessageExtract(item.subject)
 | 
			
		||||
            extract.text = prepareMessageExtract(item.extract)
 | 
			
		||||
            item.messages.count { it.labels.contains(label) }.let { size ->
 | 
			
		||||
                if (size <= 1) {
 | 
			
		||||
                    count.text = ""
 | 
			
		||||
                } else {
 | 
			
		||||
                    count.text = size.toString()
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            if (item.hasUnread()) {
 | 
			
		||||
                sender.typeface = Typeface.DEFAULT_BOLD
 | 
			
		||||
                subject.typeface = Typeface.DEFAULT_BOLD
 | 
			
		||||
            } else {
 | 
			
		||||
                sender.typeface = Typeface.DEFAULT
 | 
			
		||||
                subject.typeface = Typeface.DEFAULT
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    class ViewHolder(v: View, adapter: SwipeableConversationAdapter) : AbstractViewHolder(v, adapter) {
 | 
			
		||||
        val avatar = v.findViewById<ImageView>(R.id.avatar)!!
 | 
			
		||||
        val status = v.findViewById<ImageView>(R.id.status)!!
 | 
			
		||||
        val sender = v.findViewById<TextView>(R.id.sender)!!
 | 
			
		||||
        val subject = v.findViewById<TextView>(R.id.subject)!!
 | 
			
		||||
        val extract = v.findViewById<TextView>(R.id.text)!!
 | 
			
		||||
        val count = v.findViewById<TextView>(R.id.count)!!
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class SwipeableMessageAdapter(ctx: Context) : SwipeableAdapter<Plaintext, SwipeableMessageAdapter.ViewHolder>(ctx) {
 | 
			
		||||
    override fun getItemId(item: Plaintext) = item.id as Long
 | 
			
		||||
 | 
			
		||||
    override fun update(item: Plaintext) {
 | 
			
		||||
        val index = data.indexOfFirst { it.id == item.id }
 | 
			
		||||
        if (index >= 0) {
 | 
			
		||||
            data[index] = item
 | 
			
		||||
            notifyItemChanged(index)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
 | 
			
		||||
        val inflater = LayoutInflater.from(parent.context)
 | 
			
		||||
        val v = inflater.inflate(R.layout.message_row, parent, false)
 | 
			
		||||
        return ViewHolder(v, this)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun setData(holder: ViewHolder, item: Plaintext) {
 | 
			
		||||
        holder.apply {
 | 
			
		||||
            avatar.setImageDrawable(Identicon(item.from))
 | 
			
		||||
            status.setImageResource(item.status.getDrawable())
 | 
			
		||||
            status.contentDescription = holder.status.context.getString(item.status.getString())
 | 
			
		||||
 | 
			
		||||
            sender.text = item.from.toString()
 | 
			
		||||
            subject.text = prepareMessageExtract(item.subject)
 | 
			
		||||
            extract.text = prepareMessageExtract(item.text)
 | 
			
		||||
            if (item.isUnread()) {
 | 
			
		||||
                sender.typeface = Typeface.DEFAULT_BOLD
 | 
			
		||||
                subject.typeface = Typeface.DEFAULT_BOLD
 | 
			
		||||
            } else {
 | 
			
		||||
                sender.typeface = Typeface.DEFAULT
 | 
			
		||||
                subject.typeface = Typeface.DEFAULT
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    class ViewHolder(v: View, adapter: SwipeableMessageAdapter) : AbstractViewHolder(v, adapter) {
 | 
			
		||||
        val avatar = v.findViewById<ImageView>(R.id.avatar)!!
 | 
			
		||||
        val status = v.findViewById<ImageView>(R.id.status)!!
 | 
			
		||||
        val sender = v.findViewById<TextView>(R.id.sender)!!
 | 
			
		||||
        val subject = v.findViewById<TextView>(R.id.subject)!!
 | 
			
		||||
        val extract = v.findViewById<TextView>(R.id.text)!!
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class SwipeToDeleteCallback(ctx: Context, swipeDirs: Int, private val eventListener: EventListener) : ItemTouchHelper.SimpleCallback(0, swipeDirs) {
 | 
			
		||||
 | 
			
		||||
    private val backgroundLeft = ContextCompat.getDrawable(ctx, R.drawable.bg_swipe_item_left)!!
 | 
			
		||||
    private val backgroundRight = ContextCompat.getDrawable(ctx, R.drawable.bg_swipe_item_right)!!
 | 
			
		||||
    private val clearPaint = Paint().apply { xfermode = PorterDuffXfermode(PorterDuff.Mode.CLEAR) }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    override fun getMovementFlags(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder): Int {
 | 
			
		||||
        /**
 | 
			
		||||
         * To disable "swipe" for specific item return 0 here.
 | 
			
		||||
         * For example:
 | 
			
		||||
         * if (viewHolder?.itemViewType == YourAdapter.SOME_TYPE) return 0
 | 
			
		||||
         * if (viewHolder?.adapterPosition == 0) return 0
 | 
			
		||||
         */
 | 
			
		||||
        if (viewHolder.adapterPosition == 10) return 0
 | 
			
		||||
        return super.getMovementFlags(recyclerView, viewHolder)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onMove(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, target: RecyclerView.ViewHolder) = false
 | 
			
		||||
 | 
			
		||||
    override fun onChildDraw(
 | 
			
		||||
        c: Canvas, recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder,
 | 
			
		||||
        dX: Float, dY: Float, actionState: Int, isCurrentlyActive: Boolean
 | 
			
		||||
    ) {
 | 
			
		||||
 | 
			
		||||
        val itemView = viewHolder.itemView
 | 
			
		||||
        val isCanceled = dX == 0f && !isCurrentlyActive
 | 
			
		||||
 | 
			
		||||
        if (isCanceled) {
 | 
			
		||||
            clearCanvas(c, itemView.right + dX, itemView.top.toFloat(), itemView.right.toFloat(), itemView.bottom.toFloat())
 | 
			
		||||
            super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive)
 | 
			
		||||
            return
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (dX < 0) {
 | 
			
		||||
            backgroundLeft.setBounds(itemView.right + dX.toInt(), itemView.top, itemView.right, itemView.bottom)
 | 
			
		||||
            backgroundLeft.draw(c)
 | 
			
		||||
        } else {
 | 
			
		||||
            backgroundRight.setBounds(itemView.left, itemView.top, itemView.left + dX.toInt(), itemView.bottom)
 | 
			
		||||
            backgroundRight.draw(c)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun clearCanvas(c: Canvas?, left: Float, top: Float, right: Float, bottom: Float) {
 | 
			
		||||
        c?.drawRect(left, top, right, bottom, clearPaint)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
 | 
			
		||||
        when (direction) {
 | 
			
		||||
            ItemTouchHelper.LEFT -> eventListener.onItemDeleted(viewHolder.adapterPosition)
 | 
			
		||||
            ItemTouchHelper.RIGHT -> eventListener.onItemArchived(viewHolder.adapterPosition)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
interface EventListener {
 | 
			
		||||
    fun onItemDeleted(position: Int)
 | 
			
		||||
 | 
			
		||||
    fun onItemArchived(position: Int)
 | 
			
		||||
 | 
			
		||||
    fun onItemSelected(position: Int)
 | 
			
		||||
}
 | 
			
		||||
@@ -1,275 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright 2015 Haruki Hasegawa
 | 
			
		||||
 * Copyright 2016 Christian Basler
 | 
			
		||||
 *
 | 
			
		||||
 * Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
 * you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 *
 | 
			
		||||
 *     http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
 * See the License for the specific language governing permissions and
 | 
			
		||||
 * limitations under the License.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
package ch.dissem.apps.abit.adapter
 | 
			
		||||
 | 
			
		||||
import android.annotation.SuppressLint
 | 
			
		||||
import android.content.Context
 | 
			
		||||
import android.graphics.Typeface
 | 
			
		||||
import android.support.v7.widget.RecyclerView
 | 
			
		||||
import android.view.LayoutInflater
 | 
			
		||||
import android.view.View
 | 
			
		||||
import android.view.ViewGroup
 | 
			
		||||
import android.widget.FrameLayout
 | 
			
		||||
import android.widget.ImageView
 | 
			
		||||
import android.widget.TextView
 | 
			
		||||
import ch.dissem.apps.abit.MultiIdenticon
 | 
			
		||||
import ch.dissem.apps.abit.R
 | 
			
		||||
import ch.dissem.apps.abit.repository.AndroidLabelRepository.Companion.LABEL_ARCHIVE
 | 
			
		||||
import ch.dissem.apps.abit.util.Strings.prepareMessageExtract
 | 
			
		||||
import ch.dissem.bitmessage.entity.Conversation
 | 
			
		||||
import ch.dissem.bitmessage.entity.valueobject.Label
 | 
			
		||||
import com.h6ah4i.android.widget.advrecyclerview.swipeable.SwipeableItemAdapter
 | 
			
		||||
import com.h6ah4i.android.widget.advrecyclerview.swipeable.SwipeableItemConstants
 | 
			
		||||
import com.h6ah4i.android.widget.advrecyclerview.swipeable.SwipeableItemConstants.*
 | 
			
		||||
import com.h6ah4i.android.widget.advrecyclerview.swipeable.action.SwipeResultActionMoveToSwipedDirection
 | 
			
		||||
import com.h6ah4i.android.widget.advrecyclerview.swipeable.action.SwipeResultActionRemoveItem
 | 
			
		||||
import com.h6ah4i.android.widget.advrecyclerview.utils.AbstractSwipeableItemViewHolder
 | 
			
		||||
import com.h6ah4i.android.widget.advrecyclerview.utils.RecyclerViewAdapterUtils
 | 
			
		||||
import java.util.*
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Adapted from the basic swipeable example by Haruki Hasegawa. See
 | 
			
		||||
 *
 | 
			
		||||
 * @author Christian Basler
 | 
			
		||||
 * @see [https://github.com/h6ah4i/android-advancedrecyclerview](https://github.com/h6ah4i/android-advancedrecyclerview)
 | 
			
		||||
 */
 | 
			
		||||
class SwipeableConversationAdapter(ctx: Context) :
 | 
			
		||||
    RecyclerView.Adapter<SwipeableConversationAdapter.ViewHolder>(),
 | 
			
		||||
    SwipeableItemAdapter<SwipeableConversationAdapter.ViewHolder>, SwipeableItemConstants {
 | 
			
		||||
 | 
			
		||||
    private val data = LinkedList<Conversation>()
 | 
			
		||||
    var eventListener: EventListener? = null
 | 
			
		||||
    private val itemViewOnClickListener: View.OnClickListener
 | 
			
		||||
    private val swipeableViewContainerOnClickListener: View.OnClickListener
 | 
			
		||||
 | 
			
		||||
    private var label: Label? = null
 | 
			
		||||
    private var selectedPosition = -1
 | 
			
		||||
    private var activateOnItemClick: Boolean = false
 | 
			
		||||
 | 
			
		||||
    private val labelUnknown = ctx.getString(R.string.unknown)
 | 
			
		||||
 | 
			
		||||
    fun setActivateOnItemClick(activateOnItemClick: Boolean) {
 | 
			
		||||
        this.activateOnItemClick = activateOnItemClick
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    interface EventListener {
 | 
			
		||||
        fun onItemDeleted(item: Conversation)
 | 
			
		||||
 | 
			
		||||
        fun onItemArchived(item: Conversation)
 | 
			
		||||
 | 
			
		||||
        fun onItemViewClicked(v: View?)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    class ViewHolder(v: View) : AbstractSwipeableItemViewHolder(v) {
 | 
			
		||||
        val container = v.findViewById<FrameLayout>(R.id.container)!!
 | 
			
		||||
        val avatar = v.findViewById<ImageView>(R.id.avatar)!!
 | 
			
		||||
        val status = v.findViewById<ImageView>(R.id.status)!!
 | 
			
		||||
        val sender = v.findViewById<TextView>(R.id.sender)!!
 | 
			
		||||
        val subject = v.findViewById<TextView>(R.id.subject)!!
 | 
			
		||||
        val extract = v.findViewById<TextView>(R.id.text)!!
 | 
			
		||||
        val count = v.findViewById<TextView>(R.id.count)!!
 | 
			
		||||
 | 
			
		||||
        override fun getSwipeableContainerView() = container
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    init {
 | 
			
		||||
        itemViewOnClickListener = View.OnClickListener { view -> onItemViewClick(view) }
 | 
			
		||||
        swipeableViewContainerOnClickListener =
 | 
			
		||||
            View.OnClickListener { view -> onSwipeableViewContainerClick(view) }
 | 
			
		||||
 | 
			
		||||
        // SwipeableItemAdapter requires stable ID, and also
 | 
			
		||||
        // have to implement the getItemId() method appropriately.
 | 
			
		||||
        setHasStableIds(true)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun add(item: Conversation) {
 | 
			
		||||
        data.add(item)
 | 
			
		||||
        notifyDataSetChanged()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun addFirst(item: Conversation) {
 | 
			
		||||
        val index = data.size
 | 
			
		||||
        data.addFirst(item)
 | 
			
		||||
        notifyItemInserted(index)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun addAll(items: Collection<Conversation>) {
 | 
			
		||||
        val index = data.size
 | 
			
		||||
        data.addAll(items)
 | 
			
		||||
        notifyItemRangeInserted(index, items.size)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun remove(item: Conversation) {
 | 
			
		||||
        val index = data.indexOf(item)
 | 
			
		||||
        data.removeAll { it.id == item.id }
 | 
			
		||||
        notifyItemRemoved(index)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun update(item: Conversation) {
 | 
			
		||||
        val index = data.indexOfFirst { it.id == item.id }
 | 
			
		||||
        if (index >= 0) {
 | 
			
		||||
            data[index] = item
 | 
			
		||||
            notifyItemChanged(index)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun clear(newLabel: Label?) {
 | 
			
		||||
        label = newLabel
 | 
			
		||||
        data.clear()
 | 
			
		||||
        notifyDataSetChanged()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun onItemViewClick(v: View) {
 | 
			
		||||
        eventListener?.onItemViewClicked(v)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun onSwipeableViewContainerClick(v: View) {
 | 
			
		||||
        eventListener?.onItemViewClicked(
 | 
			
		||||
            RecyclerViewAdapterUtils.getParentViewHolderItemView(v)
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun getItem(position: Int) = data[position]
 | 
			
		||||
 | 
			
		||||
    override fun getItemId(position: Int) = data[position].id.leastSignificantBits
 | 
			
		||||
 | 
			
		||||
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
 | 
			
		||||
        val inflater = LayoutInflater.from(parent.context)
 | 
			
		||||
        val v = inflater.inflate(R.layout.conversation_row, parent, false)
 | 
			
		||||
        return ViewHolder(v)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
 | 
			
		||||
        val item = data[position]
 | 
			
		||||
 | 
			
		||||
        holder.apply {
 | 
			
		||||
            if (activateOnItemClick) {
 | 
			
		||||
                container.setBackgroundResource(
 | 
			
		||||
                    if (position == selectedPosition)
 | 
			
		||||
                        R.drawable.bg_item_selected_state
 | 
			
		||||
                    else
 | 
			
		||||
                        R.drawable.bg_item_normal_state
 | 
			
		||||
                )
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // set listeners
 | 
			
		||||
            // (if the item is *pinned*, click event comes to the itemView)
 | 
			
		||||
            itemView.setOnClickListener(itemViewOnClickListener)
 | 
			
		||||
            // (if the item is *not pinned*, click event comes to the container)
 | 
			
		||||
            container.setOnClickListener(swipeableViewContainerOnClickListener)
 | 
			
		||||
 | 
			
		||||
            // set data
 | 
			
		||||
            avatar.setImageDrawable(MultiIdenticon(item.participants))
 | 
			
		||||
 | 
			
		||||
            sender.text = item.participants.sortedBy {
 | 
			
		||||
                (it.alias?.let { 0 } ?: 1) + if (it.isChan) 2 else 0
 | 
			
		||||
            }.map { it.alias ?: labelUnknown }.distinct().joinToString()
 | 
			
		||||
            subject.text = prepareMessageExtract(item.subject)
 | 
			
		||||
            extract.text = prepareMessageExtract(item.extract)
 | 
			
		||||
            item.messages.count { it.labels.contains(label) }.let { size ->
 | 
			
		||||
                if (size <= 1) {
 | 
			
		||||
                    count.text = ""
 | 
			
		||||
                } else {
 | 
			
		||||
                    count.text = size.toString()
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            if (item.hasUnread()) {
 | 
			
		||||
                sender.typeface = Typeface.DEFAULT_BOLD
 | 
			
		||||
                subject.typeface = Typeface.DEFAULT_BOLD
 | 
			
		||||
            } else {
 | 
			
		||||
                sender.typeface = Typeface.DEFAULT
 | 
			
		||||
                subject.typeface = Typeface.DEFAULT
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun getItemCount() = data.size
 | 
			
		||||
 | 
			
		||||
    override fun onGetSwipeReactionType(holder: ViewHolder, position: Int, x: Int, y: Int): Int =
 | 
			
		||||
        if (label === LABEL_ARCHIVE || label?.type == Label.Type.TRASH) {
 | 
			
		||||
            REACTION_CAN_SWIPE_LEFT or REACTION_CAN_NOT_SWIPE_RIGHT_WITH_RUBBER_BAND_EFFECT
 | 
			
		||||
        } else {
 | 
			
		||||
            REACTION_CAN_SWIPE_BOTH_H
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    @SuppressLint("SwitchIntDef")
 | 
			
		||||
    override fun onSetSwipeBackground(holder: ViewHolder, position: Int, type: Int) =
 | 
			
		||||
        holder.itemView.setBackgroundResource(
 | 
			
		||||
            when (type) {
 | 
			
		||||
                DRAWABLE_SWIPE_NEUTRAL_BACKGROUND -> R.drawable.bg_swipe_item_neutral
 | 
			
		||||
                DRAWABLE_SWIPE_LEFT_BACKGROUND -> R.drawable.bg_swipe_item_left
 | 
			
		||||
                DRAWABLE_SWIPE_RIGHT_BACKGROUND -> if (label === LABEL_ARCHIVE || label?.type == Label.Type.TRASH) {
 | 
			
		||||
                    R.drawable.bg_swipe_item_neutral
 | 
			
		||||
                } else {
 | 
			
		||||
                    R.drawable.bg_swipe_item_right
 | 
			
		||||
                }
 | 
			
		||||
                else -> R.drawable.bg_swipe_item_neutral
 | 
			
		||||
            }
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
    @SuppressLint("SwitchIntDef")
 | 
			
		||||
    override fun onSwipeItem(holder: ViewHolder, position: Int, result: Int) =
 | 
			
		||||
        when (result) {
 | 
			
		||||
            RESULT_SWIPED_RIGHT -> SwipeRightResultAction(this, position)
 | 
			
		||||
            RESULT_SWIPED_LEFT -> SwipeLeftResultAction(this, position)
 | 
			
		||||
            else -> null
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    override fun onSwipeItemStarted(holder: ViewHolder?, position: Int) = Unit
 | 
			
		||||
 | 
			
		||||
    fun setSelectedPosition(selectedPosition: Int) {
 | 
			
		||||
        val oldPosition = this.selectedPosition
 | 
			
		||||
        this.selectedPosition = selectedPosition
 | 
			
		||||
        notifyItemChanged(oldPosition)
 | 
			
		||||
        notifyItemChanged(selectedPosition)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private class SwipeLeftResultAction internal constructor(
 | 
			
		||||
        adapter: SwipeableConversationAdapter,
 | 
			
		||||
        position: Int
 | 
			
		||||
    ) : SwipeResultActionMoveToSwipedDirection() {
 | 
			
		||||
        private var adapter: SwipeableConversationAdapter? = adapter
 | 
			
		||||
        private val item = adapter.data[position]
 | 
			
		||||
 | 
			
		||||
        override fun onPerformAction() {
 | 
			
		||||
            adapter?.eventListener?.onItemDeleted(item)
 | 
			
		||||
            adapter?.remove(item)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        override fun onCleanUp() {
 | 
			
		||||
            adapter = null
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private class SwipeRightResultAction internal constructor(
 | 
			
		||||
        adapter: SwipeableConversationAdapter,
 | 
			
		||||
        position: Int
 | 
			
		||||
    ) : SwipeResultActionRemoveItem() {
 | 
			
		||||
        private var adapter: SwipeableConversationAdapter? = adapter
 | 
			
		||||
        private val item = adapter.data[position]
 | 
			
		||||
 | 
			
		||||
        override fun onPerformAction() {
 | 
			
		||||
            adapter?.eventListener?.onItemArchived(item)
 | 
			
		||||
            adapter?.remove(item)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        override fun onCleanUp() {
 | 
			
		||||
            adapter = null
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,262 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright 2015 Haruki Hasegawa
 | 
			
		||||
 * Copyright 2016 Christian Basler
 | 
			
		||||
 *
 | 
			
		||||
 * Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
 * you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 *
 | 
			
		||||
 *     http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
 * See the License for the specific language governing permissions and
 | 
			
		||||
 * limitations under the License.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
package ch.dissem.apps.abit.adapter
 | 
			
		||||
 | 
			
		||||
import android.annotation.SuppressLint
 | 
			
		||||
import android.graphics.Typeface
 | 
			
		||||
import android.support.v7.widget.RecyclerView
 | 
			
		||||
import android.view.LayoutInflater
 | 
			
		||||
import android.view.View
 | 
			
		||||
import android.view.ViewGroup
 | 
			
		||||
import android.widget.FrameLayout
 | 
			
		||||
import android.widget.ImageView
 | 
			
		||||
import android.widget.TextView
 | 
			
		||||
import ch.dissem.apps.abit.Identicon
 | 
			
		||||
import ch.dissem.apps.abit.R
 | 
			
		||||
import ch.dissem.apps.abit.repository.AndroidLabelRepository.Companion.LABEL_ARCHIVE
 | 
			
		||||
import ch.dissem.apps.abit.util.Strings.prepareMessageExtract
 | 
			
		||||
import ch.dissem.apps.abit.util.getDrawable
 | 
			
		||||
import ch.dissem.apps.abit.util.getString
 | 
			
		||||
import ch.dissem.bitmessage.entity.Plaintext
 | 
			
		||||
import ch.dissem.bitmessage.entity.valueobject.Label
 | 
			
		||||
import com.h6ah4i.android.widget.advrecyclerview.swipeable.SwipeableItemAdapter
 | 
			
		||||
import com.h6ah4i.android.widget.advrecyclerview.swipeable.SwipeableItemConstants
 | 
			
		||||
import com.h6ah4i.android.widget.advrecyclerview.swipeable.SwipeableItemConstants.*
 | 
			
		||||
import com.h6ah4i.android.widget.advrecyclerview.swipeable.action.SwipeResultActionMoveToSwipedDirection
 | 
			
		||||
import com.h6ah4i.android.widget.advrecyclerview.swipeable.action.SwipeResultActionRemoveItem
 | 
			
		||||
import com.h6ah4i.android.widget.advrecyclerview.utils.AbstractSwipeableItemViewHolder
 | 
			
		||||
import com.h6ah4i.android.widget.advrecyclerview.utils.RecyclerViewAdapterUtils
 | 
			
		||||
import java.util.*
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Adapted from the basic swipeable example by Haruki Hasegawa. See
 | 
			
		||||
 *
 | 
			
		||||
 * @author Christian Basler
 | 
			
		||||
 * @see [https://github.com/h6ah4i/android-advancedrecyclerview](https://github.com/h6ah4i/android-advancedrecyclerview)
 | 
			
		||||
 */
 | 
			
		||||
class SwipeableMessageAdapter : RecyclerView.Adapter<SwipeableMessageAdapter.ViewHolder>(),
 | 
			
		||||
    SwipeableItemAdapter<SwipeableMessageAdapter.ViewHolder>, SwipeableItemConstants {
 | 
			
		||||
 | 
			
		||||
    private val data = LinkedList<Plaintext>()
 | 
			
		||||
    var eventListener: EventListener? = null
 | 
			
		||||
    private val itemViewOnClickListener: View.OnClickListener
 | 
			
		||||
    private val swipeableViewContainerOnClickListener: View.OnClickListener
 | 
			
		||||
 | 
			
		||||
    private var label: Label? = null
 | 
			
		||||
    private var selectedPosition = -1
 | 
			
		||||
    private var activateOnItemClick: Boolean = false
 | 
			
		||||
 | 
			
		||||
    fun setActivateOnItemClick(activateOnItemClick: Boolean) {
 | 
			
		||||
        this.activateOnItemClick = activateOnItemClick
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    interface EventListener {
 | 
			
		||||
        fun onItemDeleted(item: Plaintext)
 | 
			
		||||
 | 
			
		||||
        fun onItemArchived(item: Plaintext)
 | 
			
		||||
 | 
			
		||||
        fun onItemViewClicked(v: View?)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    class ViewHolder(v: View) : AbstractSwipeableItemViewHolder(v) {
 | 
			
		||||
        val container = v.findViewById<FrameLayout>(R.id.container)!!
 | 
			
		||||
        val avatar = v.findViewById<ImageView>(R.id.avatar)!!
 | 
			
		||||
        val status = v.findViewById<ImageView>(R.id.status)!!
 | 
			
		||||
        val sender = v.findViewById<TextView>(R.id.sender)!!
 | 
			
		||||
        val subject = v.findViewById<TextView>(R.id.subject)!!
 | 
			
		||||
        val extract = v.findViewById<TextView>(R.id.text)!!
 | 
			
		||||
 | 
			
		||||
        override fun getSwipeableContainerView() = container
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    init {
 | 
			
		||||
        itemViewOnClickListener = View.OnClickListener { view -> onItemViewClick(view) }
 | 
			
		||||
        swipeableViewContainerOnClickListener =
 | 
			
		||||
            View.OnClickListener { view -> onSwipeableViewContainerClick(view) }
 | 
			
		||||
 | 
			
		||||
        // SwipeableItemAdapter requires stable ID, and also
 | 
			
		||||
        // have to implement the getItemId() method appropriately.
 | 
			
		||||
        setHasStableIds(true)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun add(item: Plaintext) {
 | 
			
		||||
        data.add(item)
 | 
			
		||||
        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.removeAll { it.id == item.id }
 | 
			
		||||
        notifyItemRemoved(index)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun update(item: Plaintext) {
 | 
			
		||||
        val index = data.indexOfFirst { it.id == item.id }
 | 
			
		||||
        if (index >= 0) {
 | 
			
		||||
            data[index] = item
 | 
			
		||||
            notifyItemChanged(index)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun clear(newLabel: Label?) {
 | 
			
		||||
        label = newLabel
 | 
			
		||||
        data.clear()
 | 
			
		||||
        notifyDataSetChanged()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun onItemViewClick(v: View) {
 | 
			
		||||
        eventListener?.onItemViewClicked(v)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun onSwipeableViewContainerClick(v: View) {
 | 
			
		||||
        eventListener?.onItemViewClicked(
 | 
			
		||||
            RecyclerViewAdapterUtils.getParentViewHolderItemView(v)
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun getItem(position: Int) = data[position]
 | 
			
		||||
 | 
			
		||||
    override fun getItemId(position: Int) = data[position].id as Long
 | 
			
		||||
 | 
			
		||||
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
 | 
			
		||||
        val inflater = LayoutInflater.from(parent.context)
 | 
			
		||||
        val v = inflater.inflate(R.layout.message_row, parent, false)
 | 
			
		||||
        return ViewHolder(v)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
 | 
			
		||||
        val item = data[position]
 | 
			
		||||
 | 
			
		||||
        holder.apply {
 | 
			
		||||
            if (activateOnItemClick) {
 | 
			
		||||
                container.setBackgroundResource(
 | 
			
		||||
                    if (position == selectedPosition)
 | 
			
		||||
                        R.drawable.bg_item_selected_state
 | 
			
		||||
                    else
 | 
			
		||||
                        R.drawable.bg_item_normal_state
 | 
			
		||||
                )
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // set listeners
 | 
			
		||||
            // (if the item is *pinned*, click event comes to the itemView)
 | 
			
		||||
            itemView.setOnClickListener(itemViewOnClickListener)
 | 
			
		||||
            // (if the item is *not pinned*, click event comes to the container)
 | 
			
		||||
            container.setOnClickListener(swipeableViewContainerOnClickListener)
 | 
			
		||||
 | 
			
		||||
            // set data
 | 
			
		||||
            avatar.setImageDrawable(Identicon(item.from))
 | 
			
		||||
            status.setImageResource(item.status.getDrawable())
 | 
			
		||||
            status.contentDescription = holder.status.context.getString(item.status.getString())
 | 
			
		||||
            sender.text = item.from.toString()
 | 
			
		||||
            subject.text = prepareMessageExtract(item.subject)
 | 
			
		||||
            extract.text = prepareMessageExtract(item.text)
 | 
			
		||||
            if (item.isUnread()) {
 | 
			
		||||
                sender.typeface = Typeface.DEFAULT_BOLD
 | 
			
		||||
                subject.typeface = Typeface.DEFAULT_BOLD
 | 
			
		||||
            } else {
 | 
			
		||||
                sender.typeface = Typeface.DEFAULT
 | 
			
		||||
                subject.typeface = Typeface.DEFAULT
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun getItemCount() = data.size
 | 
			
		||||
 | 
			
		||||
    override fun onGetSwipeReactionType(holder: ViewHolder, position: Int, x: Int, y: Int): Int =
 | 
			
		||||
        if (label === LABEL_ARCHIVE || label?.type == Label.Type.TRASH) {
 | 
			
		||||
            REACTION_CAN_SWIPE_LEFT or REACTION_CAN_NOT_SWIPE_RIGHT_WITH_RUBBER_BAND_EFFECT
 | 
			
		||||
        } else {
 | 
			
		||||
            REACTION_CAN_SWIPE_BOTH_H
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    @SuppressLint("SwitchIntDef")
 | 
			
		||||
    override fun onSetSwipeBackground(holder: ViewHolder, position: Int, type: Int) =
 | 
			
		||||
        holder.itemView.setBackgroundResource(
 | 
			
		||||
            when (type) {
 | 
			
		||||
                DRAWABLE_SWIPE_NEUTRAL_BACKGROUND -> R.drawable.bg_swipe_item_neutral
 | 
			
		||||
                DRAWABLE_SWIPE_LEFT_BACKGROUND -> R.drawable.bg_swipe_item_left
 | 
			
		||||
                DRAWABLE_SWIPE_RIGHT_BACKGROUND -> if (label === LABEL_ARCHIVE || label?.type == Label.Type.TRASH) {
 | 
			
		||||
                    R.drawable.bg_swipe_item_neutral
 | 
			
		||||
                } else {
 | 
			
		||||
                    R.drawable.bg_swipe_item_right
 | 
			
		||||
                }
 | 
			
		||||
                else -> R.drawable.bg_swipe_item_neutral
 | 
			
		||||
            }
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
    @SuppressLint("SwitchIntDef")
 | 
			
		||||
    override fun onSwipeItem(holder: ViewHolder, position: Int, result: Int) =
 | 
			
		||||
        when (result) {
 | 
			
		||||
            RESULT_SWIPED_RIGHT -> SwipeRightResultAction(this, position)
 | 
			
		||||
            RESULT_SWIPED_LEFT -> SwipeLeftResultAction(this, position)
 | 
			
		||||
            else -> null
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    override fun onSwipeItemStarted(holder: ViewHolder?, position: Int) = Unit
 | 
			
		||||
 | 
			
		||||
    fun setSelectedPosition(selectedPosition: Int) {
 | 
			
		||||
        val oldPosition = this.selectedPosition
 | 
			
		||||
        this.selectedPosition = selectedPosition
 | 
			
		||||
        notifyItemChanged(oldPosition)
 | 
			
		||||
        notifyItemChanged(selectedPosition)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private class SwipeLeftResultAction internal constructor(
 | 
			
		||||
        adapter: SwipeableMessageAdapter,
 | 
			
		||||
        position: Int
 | 
			
		||||
    ) : SwipeResultActionMoveToSwipedDirection() {
 | 
			
		||||
        private var adapter: SwipeableMessageAdapter? = adapter
 | 
			
		||||
        private val item = adapter.data[position]
 | 
			
		||||
 | 
			
		||||
        override fun onPerformAction() {
 | 
			
		||||
            adapter?.eventListener?.onItemDeleted(item)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        override fun onCleanUp() {
 | 
			
		||||
            adapter = null
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private class SwipeRightResultAction internal constructor(
 | 
			
		||||
        adapter: SwipeableMessageAdapter,
 | 
			
		||||
        position: Int
 | 
			
		||||
    ) : SwipeResultActionRemoveItem() {
 | 
			
		||||
        private var adapter: SwipeableMessageAdapter? = adapter
 | 
			
		||||
        private val item = adapter.data[position]
 | 
			
		||||
 | 
			
		||||
        override fun onPerformAction() {
 | 
			
		||||
            adapter?.eventListener?.onItemArchived(item)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        override fun onCleanUp() {
 | 
			
		||||
            adapter = null
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -19,12 +19,12 @@ package ch.dissem.apps.abit.dialog
 | 
			
		||||
import android.app.AlertDialog
 | 
			
		||||
import android.content.Context
 | 
			
		||||
import android.os.Bundle
 | 
			
		||||
import android.support.v7.app.AppCompatDialogFragment
 | 
			
		||||
import android.view.LayoutInflater
 | 
			
		||||
import android.view.View
 | 
			
		||||
import android.view.ViewGroup
 | 
			
		||||
import android.widget.TextView
 | 
			
		||||
import android.widget.Toast
 | 
			
		||||
import androidx.appcompat.app.AppCompatDialogFragment
 | 
			
		||||
import ch.dissem.apps.abit.ImportIdentityActivity
 | 
			
		||||
import ch.dissem.apps.abit.MainActivity
 | 
			
		||||
import ch.dissem.apps.abit.R
 | 
			
		||||
@@ -33,7 +33,7 @@ import ch.dissem.bitmessage.BitmessageContext
 | 
			
		||||
import ch.dissem.bitmessage.entity.payload.Pubkey
 | 
			
		||||
import kotlinx.android.synthetic.main.dialog_add_identity.*
 | 
			
		||||
import org.jetbrains.anko.doAsync
 | 
			
		||||
import org.jetbrains.anko.support.v4.startActivity
 | 
			
		||||
import org.jetbrains.anko.startActivity
 | 
			
		||||
import org.jetbrains.anko.uiThread
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@@ -77,7 +77,7 @@ class AddIdentityDialogFragment : AppCompatDialogFragment() {
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                R.id.import_identity -> startActivity<ImportIdentityActivity>()
 | 
			
		||||
                R.id.import_identity -> ctx.startActivity<ImportIdentityActivity>()
 | 
			
		||||
                R.id.add_chan -> addChanDialog()
 | 
			
		||||
                R.id.add_deterministic_address -> DeterministicIdentityDialogFragment().show(fragmentManager, "dialog")
 | 
			
		||||
                else -> return@OnClickListener
 | 
			
		||||
 
 | 
			
		||||
@@ -18,7 +18,7 @@ package ch.dissem.apps.abit.dialog
 | 
			
		||||
 | 
			
		||||
import android.content.Context
 | 
			
		||||
import android.os.Bundle
 | 
			
		||||
import android.support.v7.app.AppCompatDialogFragment
 | 
			
		||||
import androidx.appcompat.app.AppCompatDialogFragment
 | 
			
		||||
import android.view.LayoutInflater
 | 
			
		||||
import android.view.View
 | 
			
		||||
import android.view.ViewGroup
 | 
			
		||||
 
 | 
			
		||||
@@ -19,7 +19,7 @@ package ch.dissem.apps.abit.dialog
 | 
			
		||||
import android.app.Activity.RESULT_OK
 | 
			
		||||
import android.content.Intent
 | 
			
		||||
import android.os.Bundle
 | 
			
		||||
import android.support.v7.app.AppCompatDialogFragment
 | 
			
		||||
import androidx.appcompat.app.AppCompatDialogFragment
 | 
			
		||||
import android.view.LayoutInflater
 | 
			
		||||
import android.view.View
 | 
			
		||||
import android.view.ViewGroup
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,7 @@ package ch.dissem.apps.abit.drawer
 | 
			
		||||
 | 
			
		||||
import android.content.Context
 | 
			
		||||
import android.content.Intent
 | 
			
		||||
import android.support.v4.app.FragmentManager
 | 
			
		||||
import androidx.fragment.app.FragmentManager
 | 
			
		||||
import android.view.View
 | 
			
		||||
import android.widget.Toast
 | 
			
		||||
import android.widget.Toast.LENGTH_LONG
 | 
			
		||||
 
 | 
			
		||||
@@ -21,8 +21,8 @@ import android.app.NotificationChannel
 | 
			
		||||
import android.app.NotificationManager
 | 
			
		||||
import android.content.Context
 | 
			
		||||
import android.os.Build
 | 
			
		||||
import android.support.annotation.ColorRes
 | 
			
		||||
import android.support.v4.content.ContextCompat
 | 
			
		||||
import androidx.annotation.ColorRes
 | 
			
		||||
import androidx.core.content.ContextCompat
 | 
			
		||||
import ch.dissem.apps.abit.R
 | 
			
		||||
import org.jetbrains.anko.notificationManager
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -17,7 +17,7 @@
 | 
			
		||||
package ch.dissem.apps.abit.notification
 | 
			
		||||
 | 
			
		||||
import android.content.Context
 | 
			
		||||
import android.support.v4.app.NotificationCompat
 | 
			
		||||
import androidx.core.app.NotificationCompat
 | 
			
		||||
import ch.dissem.apps.abit.R
 | 
			
		||||
import ch.dissem.apps.abit.service.Job
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -17,8 +17,8 @@
 | 
			
		||||
package ch.dissem.apps.abit.notification
 | 
			
		||||
 | 
			
		||||
import android.content.Context
 | 
			
		||||
import android.support.annotation.StringRes
 | 
			
		||||
import android.support.v4.app.NotificationCompat
 | 
			
		||||
import androidx.annotation.StringRes
 | 
			
		||||
import androidx.core.app.NotificationCompat
 | 
			
		||||
 | 
			
		||||
import ch.dissem.apps.abit.R
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -21,7 +21,7 @@ import android.app.PendingIntent
 | 
			
		||||
import android.app.PendingIntent.FLAG_UPDATE_CURRENT
 | 
			
		||||
import android.content.Context
 | 
			
		||||
import android.content.Intent
 | 
			
		||||
import android.support.v4.app.NotificationCompat
 | 
			
		||||
import androidx.core.app.NotificationCompat
 | 
			
		||||
import ch.dissem.apps.abit.MainActivity
 | 
			
		||||
import ch.dissem.apps.abit.R
 | 
			
		||||
import ch.dissem.apps.abit.service.BitmessageIntentService
 | 
			
		||||
 
 | 
			
		||||
@@ -21,9 +21,9 @@ import android.app.PendingIntent.FLAG_UPDATE_CURRENT
 | 
			
		||||
import android.content.Context
 | 
			
		||||
import android.content.Intent
 | 
			
		||||
import android.graphics.Typeface
 | 
			
		||||
import android.support.v4.app.NotificationCompat
 | 
			
		||||
import android.support.v4.app.NotificationCompat.BigTextStyle
 | 
			
		||||
import android.support.v4.app.NotificationCompat.InboxStyle
 | 
			
		||||
import androidx.core.app.NotificationCompat
 | 
			
		||||
import androidx.core.app.NotificationCompat.BigTextStyle
 | 
			
		||||
import androidx.core.app.NotificationCompat.InboxStyle
 | 
			
		||||
import android.text.Spannable
 | 
			
		||||
import android.text.SpannableString
 | 
			
		||||
import android.text.Spanned
 | 
			
		||||
 
 | 
			
		||||
@@ -19,7 +19,7 @@ package ch.dissem.apps.abit.notification
 | 
			
		||||
import android.app.PendingIntent
 | 
			
		||||
import android.content.Context
 | 
			
		||||
import android.content.Intent
 | 
			
		||||
import android.support.v4.app.NotificationCompat
 | 
			
		||||
import androidx.core.app.NotificationCompat
 | 
			
		||||
 | 
			
		||||
import ch.dissem.apps.abit.MainActivity
 | 
			
		||||
import ch.dissem.apps.abit.R
 | 
			
		||||
 
 | 
			
		||||
@@ -176,7 +176,7 @@ class AndroidMessageRepository(private val sql: SqlHelper, private val prefs: Pr
 | 
			
		||||
 | 
			
		||||
    override fun find(where: String, offset: Int, limit: Int) = find(where, offset, limit, false)
 | 
			
		||||
 | 
			
		||||
    fun find(where: String, offset: Int, limit: Int, separateIdentities: Boolean): List<Plaintext> {
 | 
			
		||||
    private fun find(where: String, offset: Int, limit: Int, separateIdentities: Boolean): List<Plaintext> {
 | 
			
		||||
        val result = LinkedList<Plaintext>()
 | 
			
		||||
        val (selectIdentityQuery, selectIdentityArgs) = getSelectIdentity(separateIdentities)
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -3,9 +3,9 @@ package ch.dissem.apps.abit.service
 | 
			
		||||
import android.app.Service
 | 
			
		||||
import android.content.Intent
 | 
			
		||||
import android.os.Binder
 | 
			
		||||
import android.support.annotation.DrawableRes
 | 
			
		||||
import android.support.annotation.StringRes
 | 
			
		||||
import android.support.v4.content.ContextCompat
 | 
			
		||||
import androidx.annotation.DrawableRes
 | 
			
		||||
import androidx.annotation.StringRes
 | 
			
		||||
import androidx.core.content.ContextCompat
 | 
			
		||||
import ch.dissem.apps.abit.notification.BatchNotification
 | 
			
		||||
import ch.dissem.apps.abit.notification.BatchNotification.Companion.ONGOING_NOTIFICATION_ID
 | 
			
		||||
import org.jetbrains.anko.doAsync
 | 
			
		||||
 
 | 
			
		||||
@@ -48,6 +48,7 @@ class NodeStartupService : JobService() {
 | 
			
		||||
                    addAction(Intent.ACTION_BATTERY_CHANGED)
 | 
			
		||||
                }
 | 
			
		||||
            )
 | 
			
		||||
            startForeground(0, notification.notification)
 | 
			
		||||
            NodeStartupService.running = false
 | 
			
		||||
 | 
			
		||||
            if (!isRunning) {
 | 
			
		||||
 
 | 
			
		||||
@@ -19,7 +19,7 @@ package ch.dissem.apps.abit.service
 | 
			
		||||
import android.app.Service
 | 
			
		||||
import android.content.Intent
 | 
			
		||||
import android.os.Binder
 | 
			
		||||
import android.support.v4.content.ContextCompat
 | 
			
		||||
import androidx.core.content.ContextCompat
 | 
			
		||||
import ch.dissem.apps.abit.notification.ProofOfWorkNotification
 | 
			
		||||
import ch.dissem.apps.abit.notification.ProofOfWorkNotification.Companion.ONGOING_NOTIFICATION_ID
 | 
			
		||||
import ch.dissem.apps.abit.util.PowStats
 | 
			
		||||
 
 | 
			
		||||
@@ -23,19 +23,18 @@ import ch.dissem.apps.abit.R
 | 
			
		||||
import ch.dissem.apps.abit.adapter.SwipeableMessageAdapter
 | 
			
		||||
import ch.dissem.apps.abit.listener.MessageListener
 | 
			
		||||
import ch.dissem.apps.abit.repository.*
 | 
			
		||||
import ch.dissem.apps.abit.util.Observable
 | 
			
		||||
import ch.dissem.apps.abit.util.preferences
 | 
			
		||||
import ch.dissem.bitmessage.BitmessageContext
 | 
			
		||||
import ch.dissem.bitmessage.cryptography.sc.SpongyCryptography
 | 
			
		||||
import ch.dissem.bitmessage.entity.BitmessageAddress
 | 
			
		||||
import ch.dissem.bitmessage.entity.payload.Pubkey
 | 
			
		||||
import ch.dissem.bitmessage.entity.valueobject.Label
 | 
			
		||||
import ch.dissem.bitmessage.factory.BufferPool
 | 
			
		||||
import ch.dissem.bitmessage.networking.nio.NioNetworkHandler
 | 
			
		||||
import ch.dissem.bitmessage.ports.DefaultLabeler
 | 
			
		||||
import ch.dissem.bitmessage.utils.ConversationService
 | 
			
		||||
import ch.dissem.bitmessage.utils.TTL
 | 
			
		||||
import ch.dissem.bitmessage.utils.UnixTime.DAY
 | 
			
		||||
import io.reactivex.subjects.BehaviorSubject
 | 
			
		||||
import org.jetbrains.anko.doAsync
 | 
			
		||||
import org.jetbrains.anko.uiThread
 | 
			
		||||
import java.lang.ref.WeakReference
 | 
			
		||||
@@ -44,7 +43,7 @@ import java.lang.ref.WeakReference
 | 
			
		||||
 * Provides singleton objects across the application.
 | 
			
		||||
 */
 | 
			
		||||
object Singleton {
 | 
			
		||||
    var currentLabel = Observable<Label?>(null)
 | 
			
		||||
    var currentLabel = BehaviorSubject.create<Label>()
 | 
			
		||||
 | 
			
		||||
    private var swipeableMessageAdapter: WeakReference<SwipeableMessageAdapter>? = null
 | 
			
		||||
    val labeler = DefaultLabeler().apply {
 | 
			
		||||
@@ -52,7 +51,7 @@ object Singleton {
 | 
			
		||||
            MainActivity.apply {
 | 
			
		||||
                runOnUiThread {
 | 
			
		||||
                    swipeableMessageAdapter?.get()?.let { swipeableMessageAdapter ->
 | 
			
		||||
                        currentLabel.value?.let { label ->
 | 
			
		||||
                        currentLabel.value?.let {label ->
 | 
			
		||||
                            when {
 | 
			
		||||
                                label.type == Label.Type.TRASH
 | 
			
		||||
                                    && added.all { it.type == Label.Type.TRASH }
 | 
			
		||||
@@ -100,7 +99,6 @@ object Singleton {
 | 
			
		||||
 | 
			
		||||
    fun getBitmessageContext(context: Context): BitmessageContext =
 | 
			
		||||
        init({ bitmessageContext }, { bitmessageContext = it }) {
 | 
			
		||||
            BufferPool.setLimit(4)
 | 
			
		||||
            BitmessageContext.build {
 | 
			
		||||
                TTL.pubkey = 2 * DAY
 | 
			
		||||
                val ctx = context.applicationContext
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
package ch.dissem.apps.abit.util
 | 
			
		||||
 | 
			
		||||
import android.content.Context
 | 
			
		||||
import android.support.annotation.ColorInt
 | 
			
		||||
import androidx.annotation.ColorInt
 | 
			
		||||
import ch.dissem.apps.abit.R
 | 
			
		||||
import ch.dissem.bitmessage.entity.valueobject.Label
 | 
			
		||||
import com.mikepenz.community_material_typeface_library.CommunityMaterial
 | 
			
		||||
 
 | 
			
		||||
@@ -1,37 +0,0 @@
 | 
			
		||||
package ch.dissem.apps.abit.util
 | 
			
		||||
 | 
			
		||||
import kotlin.properties.Delegates
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * A simple observable implementation that should be mostly
 | 
			
		||||
 */
 | 
			
		||||
class Observable<T>(value: T) {
 | 
			
		||||
    private val observers = mutableMapOf<Any, (T) -> Unit>()
 | 
			
		||||
 | 
			
		||||
    var value: T by Delegates.observable(value) { _, old, new ->
 | 
			
		||||
        if (old != new) {
 | 
			
		||||
            observers.values.forEach { it.invoke(new) }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * The key will make sure the observer can easily be removed. Usually the key should be either
 | 
			
		||||
     * the object that created the observer, or the observer itself, if it's easily available.
 | 
			
		||||
     *
 | 
			
		||||
     * Note that a map is used for observers, so if you define more than one observer with the same
 | 
			
		||||
     * key, all previous ones will be removed. Also, the observers will be notified in no specific
 | 
			
		||||
     * order.
 | 
			
		||||
     *
 | 
			
		||||
     * To prevent memory leaks, the observer must be removed if it isn't used anymore.
 | 
			
		||||
     */
 | 
			
		||||
    fun addObserver(key: Any, observer: (T) -> Unit) {
 | 
			
		||||
        observers[key] = observer
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Remove the observer that was registered with the given key.
 | 
			
		||||
     */
 | 
			
		||||
    fun removeObserver(key: Any) {
 | 
			
		||||
        observers.remove(key)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -57,7 +57,7 @@ class Preferences internal constructor(private val ctx: Context) {
 | 
			
		||||
            ctx.batteryManager.isCharging
 | 
			
		||||
        } else {
 | 
			
		||||
            val intent = ctx.registerReceiver(null, IntentFilter(Intent.ACTION_BATTERY_CHANGED))
 | 
			
		||||
            val status = intent.getIntExtra(BatteryManager.EXTRA_STATUS, -1)
 | 
			
		||||
            val status = intent?.getIntExtra(BatteryManager.EXTRA_STATUS, -1)
 | 
			
		||||
            status == BatteryManager.BATTERY_STATUS_CHARGING || status == BatteryManager.BATTERY_STATUS_FULL
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										13
									
								
								app/src/main/res/drawable/ic_battery_charging.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								app/src/main/res/drawable/ic_battery_charging.xml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,13 @@
 | 
			
		||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
 | 
			
		||||
        android:width="24dp"
 | 
			
		||||
        android:height="24dp"
 | 
			
		||||
        android:viewportWidth="24.0"
 | 
			
		||||
        android:viewportHeight="24.0">
 | 
			
		||||
    <path
 | 
			
		||||
        android:fillColor="#FF000000"
 | 
			
		||||
        android:pathData="M15.67,4H14V2h-4v2H8.33C7.6,4 7,4.6 7,5.33V8h5.47L13,7v1h4V5.33C17,4.6 16.4,4 15.67,4z"
 | 
			
		||||
        android:fillAlpha=".3"/>
 | 
			
		||||
    <path
 | 
			
		||||
        android:fillColor="#FF000000"
 | 
			
		||||
        android:pathData="M13,12.5h2L11,20v-5.5H9L12.47,8H7v12.67C7,21.4 7.6,22 8.33,22h7.33c0.74,0 1.34,-0.6 1.34,-1.33V8h-4v4.5z"/>
 | 
			
		||||
</vector>
 | 
			
		||||
							
								
								
									
										8
									
								
								app/src/main/res/drawable/ic_broom.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								app/src/main/res/drawable/ic_broom.xml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,8 @@
 | 
			
		||||
<!-- drawable/broom.xml -->
 | 
			
		||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
 | 
			
		||||
    android:height="24dp"
 | 
			
		||||
    android:width="24dp"
 | 
			
		||||
    android:viewportWidth="24"
 | 
			
		||||
    android:viewportHeight="24">
 | 
			
		||||
    <path android:fillColor="#000" android:pathData="M19.36,2.72L20.78,4.14L15.06,9.85C16.13,11.39 16.28,13.24 15.38,14.44L9.06,8.12C10.26,7.22 12.11,7.37 13.65,8.44L19.36,2.72M5.93,17.57C3.92,15.56 2.69,13.16 2.35,10.92L7.23,8.83L14.67,16.27L12.58,21.15C10.34,20.81 7.94,19.58 5.93,17.57Z" />
 | 
			
		||||
</vector>
 | 
			
		||||
							
								
								
									
										9
									
								
								app/src/main/res/drawable/ic_bug_report.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								app/src/main/res/drawable/ic_bug_report.xml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
			
		||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
 | 
			
		||||
        android:width="24dp"
 | 
			
		||||
        android:height="24dp"
 | 
			
		||||
        android:viewportWidth="24.0"
 | 
			
		||||
        android:viewportHeight="24.0">
 | 
			
		||||
    <path
 | 
			
		||||
        android:fillColor="#FF000000"
 | 
			
		||||
        android:pathData="M20,8h-2.81c-0.45,-0.78 -1.07,-1.45 -1.82,-1.96L17,4.41 15.59,3l-2.17,2.17C12.96,5.06 12.49,5 12,5c-0.49,0 -0.96,0.06 -1.41,0.17L8.41,3 7,4.41l1.62,1.63C7.88,6.55 7.26,7.22 6.81,8L4,8v2h2.09c-0.05,0.33 -0.09,0.66 -0.09,1v1L4,12v2h2v1c0,0.34 0.04,0.67 0.09,1L4,16v2h2.81c1.04,1.79 2.97,3 5.19,3s4.15,-1.21 5.19,-3L20,18v-2h-2.09c0.05,-0.33 0.09,-0.66 0.09,-1v-1h2v-2h-2v-1c0,-0.34 -0.04,-0.67 -0.09,-1L20,10L20,8zM14,16h-4v-2h4v2zM14,12h-4v-2h4v2z"/>
 | 
			
		||||
</vector>
 | 
			
		||||
							
								
								
									
										8
									
								
								app/src/main/res/drawable/ic_check_all.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								app/src/main/res/drawable/ic_check_all.xml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,8 @@
 | 
			
		||||
<!-- drawable/check_all.xml -->
 | 
			
		||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
 | 
			
		||||
    android:height="24dp"
 | 
			
		||||
    android:width="24dp"
 | 
			
		||||
    android:viewportWidth="24"
 | 
			
		||||
    android:viewportHeight="24">
 | 
			
		||||
    <path android:fillColor="#000" android:pathData="M0.41,13.41L6,19L7.41,17.58L1.83,12M22.24,5.58L11.66,16.17L7.5,12L6.07,13.41L11.66,19L23.66,7M18,7L16.59,5.58L10.24,11.93L11.66,13.34L18,7Z" />
 | 
			
		||||
</vector>
 | 
			
		||||
							
								
								
									
										9
									
								
								app/src/main/res/drawable/ic_emulate_conversations.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								app/src/main/res/drawable/ic_emulate_conversations.xml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
			
		||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
 | 
			
		||||
        android:width="24dp"
 | 
			
		||||
        android:height="24dp"
 | 
			
		||||
        android:viewportWidth="24.0"
 | 
			
		||||
        android:viewportHeight="24.0">
 | 
			
		||||
    <path
 | 
			
		||||
        android:fillColor="#FF000000"
 | 
			
		||||
        android:pathData="M20,2L4,2c-1.1,0 -1.99,0.9 -1.99,2L2,22l4,-4h14c1.1,0 2,-0.9 2,-2L22,4c0,-1.1 -0.9,-2 -2,-2zM8,14L6,14v-2h2v2zM8,11L6,11L6,9h2v2zM8,8L6,8L6,6h2v2zM15,14h-5v-2h5v2zM18,11h-8L10,9h8v2zM18,8h-8L10,6h8v2z"/>
 | 
			
		||||
</vector>
 | 
			
		||||
							
								
								
									
										9
									
								
								app/src/main/res/drawable/ic_export.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								app/src/main/res/drawable/ic_export.xml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
			
		||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
 | 
			
		||||
        android:width="24dp"
 | 
			
		||||
        android:height="24dp"
 | 
			
		||||
        android:viewportWidth="24.0"
 | 
			
		||||
        android:viewportHeight="24.0">
 | 
			
		||||
    <path
 | 
			
		||||
        android:fillColor="#FF000000"
 | 
			
		||||
        android:pathData="M9,16h6v-6h4l-7,-7 -7,7h4zM5,18h14v2L5,20z"/>
 | 
			
		||||
</vector>
 | 
			
		||||
							
								
								
									
										9
									
								
								app/src/main/res/drawable/ic_import.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								app/src/main/res/drawable/ic_import.xml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
			
		||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
 | 
			
		||||
        android:width="24dp"
 | 
			
		||||
        android:height="24dp"
 | 
			
		||||
        android:viewportWidth="24.0"
 | 
			
		||||
        android:viewportHeight="24.0">
 | 
			
		||||
    <path
 | 
			
		||||
        android:fillColor="#FF000000"
 | 
			
		||||
        android:pathData="M19,9h-4V3H9v6H5l7,7 7,-7zM5,18v2h14v-2H5z"/>
 | 
			
		||||
</vector>
 | 
			
		||||
							
								
								
									
										9
									
								
								app/src/main/res/drawable/ic_info.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								app/src/main/res/drawable/ic_info.xml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
			
		||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
 | 
			
		||||
        android:width="24dp"
 | 
			
		||||
        android:height="24dp"
 | 
			
		||||
        android:viewportWidth="24.0"
 | 
			
		||||
        android:viewportHeight="24.0">
 | 
			
		||||
    <path
 | 
			
		||||
        android:fillColor="#FF000000"
 | 
			
		||||
        android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM13,17h-2v-6h2v6zM13,9h-2L11,7h2v2z"/>
 | 
			
		||||
</vector>
 | 
			
		||||
							
								
								
									
										13
									
								
								app/src/main/res/drawable/ic_network_wifi.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								app/src/main/res/drawable/ic_network_wifi.xml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,13 @@
 | 
			
		||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
 | 
			
		||||
        android:width="24dp"
 | 
			
		||||
        android:height="24dp"
 | 
			
		||||
        android:viewportWidth="24.0"
 | 
			
		||||
        android:viewportHeight="24.0">
 | 
			
		||||
    <path
 | 
			
		||||
        android:fillColor="#FF000000"
 | 
			
		||||
        android:pathData="M12.01,21.49L23.64,7c-0.45,-0.34 -4.93,-4 -11.64,-4C5.28,3 0.81,6.66 0.36,7l11.63,14.49 0.01,0.01 0.01,-0.01z"
 | 
			
		||||
        android:fillAlpha=".3"/>
 | 
			
		||||
    <path
 | 
			
		||||
        android:fillColor="#FF000000"
 | 
			
		||||
        android:pathData="M3.53,10.95l8.46,10.54 0.01,0.01 0.01,-0.01 8.46,-10.54C20.04,10.62 16.81,8 12,8c-4.81,0 -8.04,2.62 -8.47,2.95z"/>
 | 
			
		||||
</vector>
 | 
			
		||||
							
								
								
									
										9
									
								
								app/src/main/res/drawable/ic_port.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								app/src/main/res/drawable/ic_port.xml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
			
		||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
 | 
			
		||||
        android:width="24dp"
 | 
			
		||||
        android:height="24dp"
 | 
			
		||||
        android:viewportWidth="24.0"
 | 
			
		||||
        android:viewportHeight="24.0">
 | 
			
		||||
    <path
 | 
			
		||||
        android:fillColor="#FF000000"
 | 
			
		||||
        android:pathData="M7.77,6.76L6.23,5.48 0.82,12l5.41,6.52 1.54,-1.28L3.42,12l4.35,-5.24zM7,13h2v-2L7,11v2zM17,11h-2v2h2v-2zM11,13h2v-2h-2v2zM17.77,5.48l-1.54,1.28L20.58,12l-4.35,5.24 1.54,1.28L23.18,12l-5.41,-6.52z"/>
 | 
			
		||||
</vector>
 | 
			
		||||
							
								
								
									
										9
									
								
								app/src/main/res/drawable/ic_separate_identities.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								app/src/main/res/drawable/ic_separate_identities.xml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
			
		||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
 | 
			
		||||
        android:width="24dp"
 | 
			
		||||
        android:height="24dp"
 | 
			
		||||
        android:viewportWidth="24.0"
 | 
			
		||||
        android:viewportHeight="24.0">
 | 
			
		||||
    <path
 | 
			
		||||
        android:fillColor="#FF000000"
 | 
			
		||||
        android:pathData="M16,11c1.66,0 2.99,-1.34 2.99,-3S17.66,5 16,5c-1.66,0 -3,1.34 -3,3s1.34,3 3,3zM8,11c1.66,0 2.99,-1.34 2.99,-3S9.66,5 8,5C6.34,5 5,6.34 5,8s1.34,3 3,3zM8,13c-2.33,0 -7,1.17 -7,3.5L1,19h14v-2.5c0,-2.33 -4.67,-3.5 -7,-3.5zM16,13c-0.29,0 -0.62,0.02 -0.97,0.05 1.16,0.84 1.97,1.97 1.97,3.45L17,19h6v-2.5c0,-2.33 -4.67,-3.5 -7,-3.5z"/>
 | 
			
		||||
</vector>
 | 
			
		||||
							
								
								
									
										9
									
								
								app/src/main/res/drawable/ic_support_app.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								app/src/main/res/drawable/ic_support_app.xml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
			
		||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
 | 
			
		||||
        android:width="24dp"
 | 
			
		||||
        android:height="24dp"
 | 
			
		||||
        android:viewportWidth="24.0"
 | 
			
		||||
        android:viewportHeight="24.0">
 | 
			
		||||
    <path
 | 
			
		||||
        android:fillColor="#FF000000"
 | 
			
		||||
        android:pathData="M9,11.24L9,7.5C9,6.12 10.12,5 11.5,5S14,6.12 14,7.5v3.74c1.21,-0.81 2,-2.18 2,-3.74C16,5.01 13.99,3 11.5,3S7,5.01 7,7.5c0,1.56 0.79,2.93 2,3.74zM18.84,15.87l-4.54,-2.26c-0.17,-0.07 -0.35,-0.11 -0.54,-0.11L13,13.5v-6c0,-0.83 -0.67,-1.5 -1.5,-1.5S10,6.67 10,7.5v10.74l-3.43,-0.72c-0.08,-0.01 -0.15,-0.03 -0.24,-0.03 -0.31,0 -0.59,0.13 -0.79,0.33l-0.79,0.8 4.94,4.94c0.27,0.27 0.65,0.44 1.06,0.44h6.79c0.75,0 1.33,-0.55 1.44,-1.28l0.75,-5.27c0.01,-0.07 0.02,-0.14 0.02,-0.2 0,-0.62 -0.38,-1.16 -0.91,-1.38z"/>
 | 
			
		||||
</vector>
 | 
			
		||||
@@ -1,22 +0,0 @@
 | 
			
		||||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<!--
 | 
			
		||||
       Copyright (C) 2015 Haruki Hasegawa
 | 
			
		||||
 | 
			
		||||
       Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
       you may not use this file except in compliance with the License.
 | 
			
		||||
       You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
           http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
       Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
       distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
       WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
       See the License for the specific language governing permissions and
 | 
			
		||||
       limitations under the License.
 | 
			
		||||
-->
 | 
			
		||||
<shape
 | 
			
		||||
    android:shape="rectangle"
 | 
			
		||||
    xmlns:android="http://schemas.android.com/apk/res/android">
 | 
			
		||||
    <size android:height="1px"/>
 | 
			
		||||
    <solid android:color="@color/divider"/>
 | 
			
		||||
</shape>
 | 
			
		||||
@@ -1,11 +1,11 @@
 | 
			
		||||
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
 | 
			
		||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
 | 
			
		||||
    xmlns:app="http://schemas.android.com/apk/res-auto"
 | 
			
		||||
    xmlns:tools="http://schemas.android.com/tools"
 | 
			
		||||
    android:layout_width="match_parent"
 | 
			
		||||
    android:layout_height="match_parent"
 | 
			
		||||
    android:gravity="center">
 | 
			
		||||
 | 
			
		||||
    <android.support.v7.widget.Toolbar
 | 
			
		||||
    <androidx.appcompat.widget.Toolbar
 | 
			
		||||
        android:id="@+id/toolbar"
 | 
			
		||||
        android:layout_width="0dp"
 | 
			
		||||
        android:layout_height="64dp"
 | 
			
		||||
@@ -19,7 +19,7 @@
 | 
			
		||||
        tools:ignore="UnusedAttribute"
 | 
			
		||||
        tools:layout_editor_absoluteX="0dp" />
 | 
			
		||||
 | 
			
		||||
    <android.support.constraint.Guideline
 | 
			
		||||
    <androidx.constraintlayout.widget.Guideline
 | 
			
		||||
        android:id="@+id/guideline"
 | 
			
		||||
        android:layout_width="wrap_content"
 | 
			
		||||
        android:layout_height="wrap_content"
 | 
			
		||||
@@ -74,4 +74,4 @@
 | 
			
		||||
        tools:ignore="UnusedAttribute"
 | 
			
		||||
        tools:layout_editor_absoluteX="8dp" />
 | 
			
		||||
 | 
			
		||||
</android.support.constraint.ConstraintLayout>
 | 
			
		||||
</androidx.constraintlayout.widget.ConstraintLayout>
 | 
			
		||||
 
 | 
			
		||||
@@ -4,7 +4,7 @@
 | 
			
		||||
    android:layout_height="wrap_content"
 | 
			
		||||
    android:padding="24dp">
 | 
			
		||||
 | 
			
		||||
    <android.support.design.widget.TextInputLayout
 | 
			
		||||
    <com.google.android.material.textfield.TextInputLayout
 | 
			
		||||
        android:id="@+id/address_wrapper"
 | 
			
		||||
        android:layout_width="match_parent"
 | 
			
		||||
        android:layout_height="wrap_content"
 | 
			
		||||
@@ -17,16 +17,17 @@
 | 
			
		||||
            android:layout_width="match_parent"
 | 
			
		||||
            android:layout_height="wrap_content"
 | 
			
		||||
            android:hint="@string/address"
 | 
			
		||||
            android:importantForAutofill="no"
 | 
			
		||||
            android:inputType="textNoSuggestions" />
 | 
			
		||||
 | 
			
		||||
    </android.support.design.widget.TextInputLayout>
 | 
			
		||||
    </com.google.android.material.textfield.TextInputLayout>
 | 
			
		||||
 | 
			
		||||
    <android.support.design.widget.TextInputLayout
 | 
			
		||||
    <com.google.android.material.textfield.TextInputLayout
 | 
			
		||||
        android:id="@+id/label_wrapper"
 | 
			
		||||
        android:layout_width="match_parent"
 | 
			
		||||
        android:layout_height="wrap_content"
 | 
			
		||||
        android:layout_alignStart="@+id/address_wrapper"
 | 
			
		||||
        android:layout_below="@+id/address_wrapper"
 | 
			
		||||
        android:layout_alignStart="@+id/address_wrapper"
 | 
			
		||||
        android:layout_marginTop="16dp">
 | 
			
		||||
 | 
			
		||||
        <EditText
 | 
			
		||||
@@ -34,18 +35,19 @@
 | 
			
		||||
            android:layout_width="match_parent"
 | 
			
		||||
            android:layout_height="wrap_content"
 | 
			
		||||
            android:hint="@string/label"
 | 
			
		||||
            android:importantForAutofill="no"
 | 
			
		||||
            android:inputType="textPersonName" />
 | 
			
		||||
 | 
			
		||||
    </android.support.design.widget.TextInputLayout>
 | 
			
		||||
    </com.google.android.material.textfield.TextInputLayout>
 | 
			
		||||
 | 
			
		||||
    <Switch
 | 
			
		||||
        android:id="@+id/subscribe"
 | 
			
		||||
        android:layout_width="match_parent"
 | 
			
		||||
        android:layout_height="wrap_content"
 | 
			
		||||
        android:layout_alignStart="@+id/address_wrapper"
 | 
			
		||||
        android:layout_below="@+id/label_wrapper"
 | 
			
		||||
        android:layout_marginBottom="8dp"
 | 
			
		||||
        android:layout_alignStart="@+id/address_wrapper"
 | 
			
		||||
        android:layout_marginTop="8dp"
 | 
			
		||||
        android:layout_marginBottom="8dp"
 | 
			
		||||
        android:text="@string/subscribe" />
 | 
			
		||||
 | 
			
		||||
    <Button
 | 
			
		||||
@@ -53,10 +55,10 @@
 | 
			
		||||
        style="?android:attr/borderlessButtonStyle"
 | 
			
		||||
        android:layout_width="wrap_content"
 | 
			
		||||
        android:layout_height="wrap_content"
 | 
			
		||||
        android:layout_alignParentEnd="true"
 | 
			
		||||
        android:layout_below="@+id/subscribe"
 | 
			
		||||
        android:layout_marginBottom="12dp"
 | 
			
		||||
        android:layout_alignParentEnd="true"
 | 
			
		||||
        android:layout_marginTop="12dp"
 | 
			
		||||
        android:layout_marginBottom="12dp"
 | 
			
		||||
        android:text="@string/do_import" />
 | 
			
		||||
 | 
			
		||||
    <Button
 | 
			
		||||
 
 | 
			
		||||
@@ -5,7 +5,7 @@
 | 
			
		||||
    android:layout_height="match_parent"
 | 
			
		||||
    android:gravity="center">
 | 
			
		||||
 | 
			
		||||
    <android.support.v7.widget.Toolbar
 | 
			
		||||
    <androidx.appcompat.widget.Toolbar
 | 
			
		||||
        android:id="@+id/toolbar"
 | 
			
		||||
        android:layout_width="match_parent"
 | 
			
		||||
        android:layout_height="?attr/actionBarSize"
 | 
			
		||||
 
 | 
			
		||||
@@ -14,7 +14,7 @@
 | 
			
		||||
        android:textSize="10dp"
 | 
			
		||||
        tools:ignore="SpUsage" />
 | 
			
		||||
 | 
			
		||||
    <android.support.design.widget.TextInputLayout
 | 
			
		||||
    <com.google.android.material.textfield.TextInputLayout
 | 
			
		||||
        android:id="@+id/label_wrapper"
 | 
			
		||||
        android:layout_width="match_parent"
 | 
			
		||||
        android:layout_height="wrap_content"
 | 
			
		||||
@@ -27,9 +27,10 @@
 | 
			
		||||
            android:layout_width="match_parent"
 | 
			
		||||
            android:layout_height="wrap_content"
 | 
			
		||||
            android:hint="@string/label"
 | 
			
		||||
            android:importantForAutofill="no"
 | 
			
		||||
            android:inputType="textPersonName" />
 | 
			
		||||
 | 
			
		||||
    </android.support.design.widget.TextInputLayout>
 | 
			
		||||
    </com.google.android.material.textfield.TextInputLayout>
 | 
			
		||||
 | 
			
		||||
    <Switch
 | 
			
		||||
        android:id="@+id/subscribe"
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,5 @@
 | 
			
		||||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<android.support.design.widget.CoordinatorLayout
 | 
			
		||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
 | 
			
		||||
    xmlns:android="http://schemas.android.com/apk/res/android"
 | 
			
		||||
    xmlns:app="http://schemas.android.com/apk/res-auto"
 | 
			
		||||
    xmlns:tools="http://schemas.android.com/tools"
 | 
			
		||||
@@ -19,11 +19,11 @@
 | 
			
		||||
        app:layout_behavior="@string/appbar_scrolling_view_behavior">
 | 
			
		||||
    </TextView>
 | 
			
		||||
 | 
			
		||||
    <android.support.design.widget.AppBarLayout
 | 
			
		||||
    <com.google.android.material.appbar.AppBarLayout
 | 
			
		||||
        android:layout_width="match_parent"
 | 
			
		||||
        android:layout_height="wrap_content">
 | 
			
		||||
 | 
			
		||||
        <android.support.v7.widget.Toolbar
 | 
			
		||||
        <androidx.appcompat.widget.Toolbar
 | 
			
		||||
            android:id="@+id/toolbar"
 | 
			
		||||
            android:layout_width="match_parent"
 | 
			
		||||
            android:layout_height="?attr/actionBarSize"
 | 
			
		||||
@@ -36,6 +36,6 @@
 | 
			
		||||
            app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
 | 
			
		||||
            tools:ignore="UnusedAttribute"/>
 | 
			
		||||
 | 
			
		||||
    </android.support.design.widget.AppBarLayout>
 | 
			
		||||
    </com.google.android.material.appbar.AppBarLayout>
 | 
			
		||||
 | 
			
		||||
</android.support.design.widget.CoordinatorLayout>
 | 
			
		||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
 | 
			
		||||
 
 | 
			
		||||
@@ -14,15 +14,15 @@
 | 
			
		||||
  ~ limitations under the License.
 | 
			
		||||
  -->
 | 
			
		||||
 | 
			
		||||
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
 | 
			
		||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
 | 
			
		||||
    xmlns:app="http://schemas.android.com/apk/res-auto"
 | 
			
		||||
    xmlns:tools="http://schemas.android.com/tools"
 | 
			
		||||
    android:layout_width="match_parent"
 | 
			
		||||
    android:layout_height="match_parent"
 | 
			
		||||
    android:paddingBottom="18dp"
 | 
			
		||||
    android:paddingEnd="24dp"
 | 
			
		||||
    android:paddingStart="24dp"
 | 
			
		||||
    android:paddingTop="18dp">
 | 
			
		||||
    android:paddingTop="18dp"
 | 
			
		||||
    android:paddingEnd="24dp"
 | 
			
		||||
    android:paddingBottom="18dp">
 | 
			
		||||
 | 
			
		||||
    <TextView
 | 
			
		||||
        android:id="@+id/description"
 | 
			
		||||
@@ -34,7 +34,7 @@
 | 
			
		||||
        tools:layout_constraintLeft_creator="1"
 | 
			
		||||
        tools:layout_constraintTop_creator="1" />
 | 
			
		||||
 | 
			
		||||
    <android.support.design.widget.TextInputLayout
 | 
			
		||||
    <com.google.android.material.textfield.TextInputLayout
 | 
			
		||||
        android:id="@+id/label_wrapper"
 | 
			
		||||
        android:layout_width="match_parent"
 | 
			
		||||
        android:layout_height="wrap_content"
 | 
			
		||||
@@ -47,11 +47,12 @@
 | 
			
		||||
            android:layout_width="match_parent"
 | 
			
		||||
            android:layout_height="wrap_content"
 | 
			
		||||
            android:hint="@string/label"
 | 
			
		||||
            android:autofillHints="label"
 | 
			
		||||
            android:inputType="text" />
 | 
			
		||||
 | 
			
		||||
    </android.support.design.widget.TextInputLayout>
 | 
			
		||||
    </com.google.android.material.textfield.TextInputLayout>
 | 
			
		||||
 | 
			
		||||
    <android.support.design.widget.TextInputLayout
 | 
			
		||||
    <com.google.android.material.textfield.TextInputLayout
 | 
			
		||||
        android:id="@+id/passphrase_wrapper"
 | 
			
		||||
        android:layout_width="match_parent"
 | 
			
		||||
        android:layout_height="wrap_content"
 | 
			
		||||
@@ -63,11 +64,12 @@
 | 
			
		||||
            android:layout_width="match_parent"
 | 
			
		||||
            android:layout_height="wrap_content"
 | 
			
		||||
            android:hint="@string/passphrase"
 | 
			
		||||
            android:autofillHints="passphrase"
 | 
			
		||||
            android:inputType="textMultiLine" />
 | 
			
		||||
 | 
			
		||||
    </android.support.design.widget.TextInputLayout>
 | 
			
		||||
    </com.google.android.material.textfield.TextInputLayout>
 | 
			
		||||
 | 
			
		||||
    <android.support.design.widget.TextInputLayout
 | 
			
		||||
    <com.google.android.material.textfield.TextInputLayout
 | 
			
		||||
        android:id="@+id/number_of_identities_wrapper"
 | 
			
		||||
        android:layout_width="match_parent"
 | 
			
		||||
        android:layout_height="wrap_content"
 | 
			
		||||
@@ -80,11 +82,12 @@
 | 
			
		||||
            android:layout_height="wrap_content"
 | 
			
		||||
            android:ems="10"
 | 
			
		||||
            android:hint="@string/number_of_identities"
 | 
			
		||||
            android:autofillHints="numberOfIdentities"
 | 
			
		||||
            android:inputType="number"
 | 
			
		||||
            android:text="1"
 | 
			
		||||
            tools:ignore="HardcodedText" />
 | 
			
		||||
 | 
			
		||||
    </android.support.design.widget.TextInputLayout>
 | 
			
		||||
    </com.google.android.material.textfield.TextInputLayout>
 | 
			
		||||
 | 
			
		||||
    <Switch
 | 
			
		||||
        android:id="@+id/shorter"
 | 
			
		||||
@@ -115,4 +118,4 @@
 | 
			
		||||
        app:layout_constraintBottom_toBottomOf="@id/ok"
 | 
			
		||||
        app:layout_constraintRight_toLeftOf="@id/ok" />
 | 
			
		||||
 | 
			
		||||
</android.support.constraint.ConstraintLayout>
 | 
			
		||||
</androidx.constraintlayout.widget.ConstraintLayout>
 | 
			
		||||
 
 | 
			
		||||
@@ -15,7 +15,7 @@
 | 
			
		||||
  ~ limitations under the License.
 | 
			
		||||
  -->
 | 
			
		||||
 | 
			
		||||
<android.support.constraint.ConstraintLayout
 | 
			
		||||
<androidx.constraintlayout.widget.ConstraintLayout
 | 
			
		||||
    xmlns:android="http://schemas.android.com/apk/res/android"
 | 
			
		||||
    xmlns:app="http://schemas.android.com/apk/res-auto"
 | 
			
		||||
    xmlns:tools="http://schemas.android.com/tools"
 | 
			
		||||
@@ -98,4 +98,4 @@
 | 
			
		||||
        android:textColor="@color/colorAccent"
 | 
			
		||||
        app:layout_constraintRight_toLeftOf="@+id/ok"
 | 
			
		||||
        app:layout_constraintTop_toBottomOf="@+id/radioGroup"/>
 | 
			
		||||
</android.support.constraint.ConstraintLayout>
 | 
			
		||||
</androidx.constraintlayout.widget.ConstraintLayout>
 | 
			
		||||
 
 | 
			
		||||
@@ -15,7 +15,7 @@
 | 
			
		||||
  ~ limitations under the License.
 | 
			
		||||
  -->
 | 
			
		||||
 | 
			
		||||
<android.support.constraint.ConstraintLayout
 | 
			
		||||
<androidx.constraintlayout.widget.ConstraintLayout
 | 
			
		||||
    xmlns:android="http://schemas.android.com/apk/res/android"
 | 
			
		||||
    xmlns:app="http://schemas.android.com/apk/res-auto"
 | 
			
		||||
    xmlns:tools="http://schemas.android.com/tools"
 | 
			
		||||
@@ -56,4 +56,4 @@
 | 
			
		||||
        app:layout_constraintEnd_toEndOf="@id/description"
 | 
			
		||||
        app:layout_constraintTop_toBottomOf="@+id/ok"
 | 
			
		||||
        tools:layout_editor_absoluteX="8dp"/>
 | 
			
		||||
</android.support.constraint.ConstraintLayout>
 | 
			
		||||
</androidx.constraintlayout.widget.ConstraintLayout>
 | 
			
		||||
 
 | 
			
		||||
@@ -14,5 +14,6 @@
 | 
			
		||||
        android:layout_height="wrap_content"
 | 
			
		||||
        android:layout_gravity="center_horizontal"
 | 
			
		||||
        android:hint="@string/passphrase"
 | 
			
		||||
        android:autofillHints="passphrase"
 | 
			
		||||
        android:inputType="textMultiLine"/>
 | 
			
		||||
</LinearLayout>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,4 @@
 | 
			
		||||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<!--
 | 
			
		||||
<?xml version="1.0" encoding="utf-8"?><!--
 | 
			
		||||
  ~ Copyright 2015 Christian Basler
 | 
			
		||||
  ~
 | 
			
		||||
  ~ Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
@@ -16,9 +15,9 @@
 | 
			
		||||
  -->
 | 
			
		||||
 | 
			
		||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
 | 
			
		||||
                xmlns:tools="http://schemas.android.com/tools"
 | 
			
		||||
                android:layout_width="match_parent"
 | 
			
		||||
                android:layout_height="match_parent">
 | 
			
		||||
    xmlns:tools="http://schemas.android.com/tools"
 | 
			
		||||
    android:layout_width="match_parent"
 | 
			
		||||
    android:layout_height="match_parent">
 | 
			
		||||
 | 
			
		||||
    <ImageView
 | 
			
		||||
        android:id="@+id/avatar"
 | 
			
		||||
@@ -28,19 +27,20 @@
 | 
			
		||||
        android:layout_alignParentTop="true"
 | 
			
		||||
        android:layout_margin="16dp"
 | 
			
		||||
        android:src="@color/colorAccent"
 | 
			
		||||
        tools:ignore="ContentDescription"/>
 | 
			
		||||
        tools:ignore="ContentDescription" />
 | 
			
		||||
 | 
			
		||||
    <EditText
 | 
			
		||||
        android:id="@+id/name"
 | 
			
		||||
        android:layout_width="0dp"
 | 
			
		||||
        android:layout_height="wrap_content"
 | 
			
		||||
        android:layout_alignParentEnd="true"
 | 
			
		||||
        android:layout_alignTop="@+id/avatar"
 | 
			
		||||
        android:layout_alignParentEnd="true"
 | 
			
		||||
        android:layout_marginEnd="16dp"
 | 
			
		||||
        android:layout_toEndOf="@+id/avatar"
 | 
			
		||||
        android:importantForAutofill="no"
 | 
			
		||||
        android:inputType="textPersonName"
 | 
			
		||||
        android:text=""
 | 
			
		||||
        tools:ignore="LabelFor"/>
 | 
			
		||||
        tools:ignore="LabelFor" />
 | 
			
		||||
 | 
			
		||||
    <TextView
 | 
			
		||||
        android:id="@+id/address"
 | 
			
		||||
@@ -52,7 +52,7 @@
 | 
			
		||||
        android:paddingRight="16dp"
 | 
			
		||||
        android:textAppearance="?android:attr/textAppearanceSmall"
 | 
			
		||||
        android:textStyle="bold"
 | 
			
		||||
        tools:text="BM-XyYxXyYxXyYxXyYxXyYx"/>
 | 
			
		||||
        tools:text="BM-XyYxXyYxXyYxXyYxXyYx" />
 | 
			
		||||
 | 
			
		||||
    <TextView
 | 
			
		||||
        android:id="@+id/stream_number"
 | 
			
		||||
@@ -64,7 +64,7 @@
 | 
			
		||||
        android:paddingLeft="16dp"
 | 
			
		||||
        android:paddingRight="16dp"
 | 
			
		||||
        android:textAppearance="?android:attr/textAppearanceSmall"
 | 
			
		||||
        tools:text="Stream #"/>
 | 
			
		||||
        tools:text="Stream #" />
 | 
			
		||||
 | 
			
		||||
    <Switch
 | 
			
		||||
        android:id="@+id/active"
 | 
			
		||||
@@ -72,21 +72,21 @@
 | 
			
		||||
        android:layout_height="wrap_content"
 | 
			
		||||
        android:layout_below="@+id/stream_number"
 | 
			
		||||
        android:paddingLeft="16dp"
 | 
			
		||||
        android:paddingRight="16dp"
 | 
			
		||||
        android:paddingTop="16dp"
 | 
			
		||||
        android:text="@string/subscribed"/>
 | 
			
		||||
        android:paddingRight="16dp"
 | 
			
		||||
        android:text="@string/subscribed" />
 | 
			
		||||
 | 
			
		||||
    <ImageView
 | 
			
		||||
        android:id="@+id/pubkey_available"
 | 
			
		||||
        android:layout_width="wrap_content"
 | 
			
		||||
        android:layout_height="wrap_content"
 | 
			
		||||
        android:layout_alignParentStart="true"
 | 
			
		||||
        android:layout_below="@+id/active"
 | 
			
		||||
        android:paddingEnd="4dp"
 | 
			
		||||
        android:layout_alignParentStart="true"
 | 
			
		||||
        android:paddingStart="16dp"
 | 
			
		||||
        android:paddingTop="16dp"
 | 
			
		||||
        android:paddingEnd="4dp"
 | 
			
		||||
        android:src="@drawable/public_key"
 | 
			
		||||
        tools:ignore="ContentDescription"/>
 | 
			
		||||
        tools:ignore="ContentDescription" />
 | 
			
		||||
 | 
			
		||||
    <TextView
 | 
			
		||||
        android:id="@+id/pubkey_available_desc"
 | 
			
		||||
@@ -95,25 +95,25 @@
 | 
			
		||||
        android:layout_alignBottom="@id/pubkey_available"
 | 
			
		||||
        android:layout_alignParentEnd="true"
 | 
			
		||||
        android:layout_toEndOf="@id/pubkey_available"
 | 
			
		||||
        android:paddingEnd="16dp"
 | 
			
		||||
        android:paddingStart="0dp"
 | 
			
		||||
        android:paddingEnd="16dp"
 | 
			
		||||
        android:text="@string/pubkey_available"
 | 
			
		||||
        android:textAppearance="?android:attr/textAppearanceSmall"/>
 | 
			
		||||
        android:textAppearance="?android:attr/textAppearanceSmall" />
 | 
			
		||||
 | 
			
		||||
    <ImageView
 | 
			
		||||
        android:id="@+id/qr_code"
 | 
			
		||||
        android:layout_width="0dp"
 | 
			
		||||
        android:layout_height="0dp"
 | 
			
		||||
        android:layout_alignParentBottom="true"
 | 
			
		||||
        android:layout_alignParentEnd="true"
 | 
			
		||||
        android:layout_alignParentStart="true"
 | 
			
		||||
        android:layout_below="@+id/pubkey_available"
 | 
			
		||||
        android:layout_marginBottom="64dp"
 | 
			
		||||
        android:layout_marginEnd="16dp"
 | 
			
		||||
        android:layout_alignParentStart="true"
 | 
			
		||||
        android:layout_alignParentEnd="true"
 | 
			
		||||
        android:layout_alignParentBottom="true"
 | 
			
		||||
        android:layout_marginStart="16dp"
 | 
			
		||||
        android:layout_marginTop="24dp"
 | 
			
		||||
        android:layout_marginEnd="16dp"
 | 
			
		||||
        android:layout_marginBottom="64dp"
 | 
			
		||||
        android:contentDescription="@string/alt_qr_code"
 | 
			
		||||
        android:elevation="2dp"
 | 
			
		||||
        tools:ignore="UnusedAttribute"
 | 
			
		||||
        tools:src="@drawable/public_key"/>
 | 
			
		||||
        tools:src="@drawable/public_key" />
 | 
			
		||||
</RelativeLayout>
 | 
			
		||||
 
 | 
			
		||||
@@ -4,7 +4,7 @@
 | 
			
		||||
    android:layout_height="match_parent">
 | 
			
		||||
 | 
			
		||||
    <ListView
 | 
			
		||||
        android:id="@id/android:list"
 | 
			
		||||
        android:id="@android:id/list"
 | 
			
		||||
        android:layout_width="wrap_content"
 | 
			
		||||
        android:layout_height="wrap_content"
 | 
			
		||||
        android:layout_alignParentBottom="true"
 | 
			
		||||
 
 | 
			
		||||
@@ -24,7 +24,7 @@
 | 
			
		||||
            android:layout_width="match_parent"
 | 
			
		||||
            android:layout_height="wrap_content" />
 | 
			
		||||
 | 
			
		||||
        <android.support.design.widget.TextInputLayout
 | 
			
		||||
        <com.google.android.material.textfield.TextInputLayout
 | 
			
		||||
            android:layout_width="match_parent"
 | 
			
		||||
            android:layout_height="wrap_content"
 | 
			
		||||
            android:paddingTop="4dp">
 | 
			
		||||
@@ -33,13 +33,14 @@
 | 
			
		||||
                android:id="@+id/recipient_input"
 | 
			
		||||
                android:layout_width="match_parent"
 | 
			
		||||
                android:layout_height="wrap_content"
 | 
			
		||||
                android:autofillHints="bitmessageAddress"
 | 
			
		||||
                android:hint="@string/to"
 | 
			
		||||
                android:inputType="textNoSuggestions"
 | 
			
		||||
                android:maxLines="1" />
 | 
			
		||||
 | 
			
		||||
        </android.support.design.widget.TextInputLayout>
 | 
			
		||||
        </com.google.android.material.textfield.TextInputLayout>
 | 
			
		||||
 | 
			
		||||
        <android.support.design.widget.TextInputLayout
 | 
			
		||||
        <com.google.android.material.textfield.TextInputLayout
 | 
			
		||||
            android:layout_width="match_parent"
 | 
			
		||||
            android:layout_height="wrap_content">
 | 
			
		||||
 | 
			
		||||
@@ -47,17 +48,19 @@
 | 
			
		||||
                android:id="@+id/subject_input"
 | 
			
		||||
                android:layout_width="match_parent"
 | 
			
		||||
                android:layout_height="wrap_content"
 | 
			
		||||
                android:autofillHints="subject"
 | 
			
		||||
                android:hint="@string/subject"
 | 
			
		||||
                android:inputType="textEmailSubject"
 | 
			
		||||
                android:textAppearance="?android:attr/textAppearanceLarge" />
 | 
			
		||||
 | 
			
		||||
        </android.support.design.widget.TextInputLayout>
 | 
			
		||||
        </com.google.android.material.textfield.TextInputLayout>
 | 
			
		||||
 | 
			
		||||
        <EditText
 | 
			
		||||
            android:id="@+id/body_input"
 | 
			
		||||
            android:layout_width="match_parent"
 | 
			
		||||
            android:layout_height="wrap_content"
 | 
			
		||||
            android:layout_weight="1"
 | 
			
		||||
            android:autofillHints="body, message"
 | 
			
		||||
            android:gravity="start|top"
 | 
			
		||||
            android:hint="@string/compose_body_hint"
 | 
			
		||||
            android:inputType="textMultiLine|textCapSentences"
 | 
			
		||||
 
 | 
			
		||||
@@ -41,7 +41,7 @@
 | 
			
		||||
        android:layout_below="@id/subject"
 | 
			
		||||
        android:background="@color/divider" />
 | 
			
		||||
 | 
			
		||||
    <android.support.v7.widget.RecyclerView
 | 
			
		||||
    <androidx.recyclerview.widget.RecyclerView
 | 
			
		||||
        android:id="@+id/messages"
 | 
			
		||||
        android:layout_width="fill_parent"
 | 
			
		||||
        android:layout_height="wrap_content"
 | 
			
		||||
 
 | 
			
		||||
@@ -15,7 +15,7 @@
 | 
			
		||||
  ~ limitations under the License.
 | 
			
		||||
  -->
 | 
			
		||||
 | 
			
		||||
<android.support.constraint.ConstraintLayout
 | 
			
		||||
<androidx.constraintlayout.widget.ConstraintLayout
 | 
			
		||||
    xmlns:android="http://schemas.android.com/apk/res/android"
 | 
			
		||||
    xmlns:app="http://schemas.android.com/apk/res-auto"
 | 
			
		||||
    android:layout_width="match_parent"
 | 
			
		||||
@@ -41,6 +41,7 @@
 | 
			
		||||
        android:gravity="start|top"
 | 
			
		||||
        android:hint="@string/wif_string"
 | 
			
		||||
        android:inputType="textMultiLine|text"
 | 
			
		||||
        android:autofillHints="wif, comment, data"
 | 
			
		||||
        app:layout_constraintBottom_toTopOf="@+id/next"
 | 
			
		||||
        app:layout_constraintEnd_toEndOf="parent"
 | 
			
		||||
        app:layout_constraintStart_toStartOf="parent"
 | 
			
		||||
@@ -57,4 +58,4 @@
 | 
			
		||||
        app:layout_constraintBottom_toBottomOf="parent"
 | 
			
		||||
        app:layout_constraintRight_toRightOf="parent"/>
 | 
			
		||||
 | 
			
		||||
</android.support.constraint.ConstraintLayout>
 | 
			
		||||
</androidx.constraintlayout.widget.ConstraintLayout>
 | 
			
		||||
 
 | 
			
		||||
@@ -15,7 +15,7 @@
 | 
			
		||||
  ~ limitations under the License.
 | 
			
		||||
  -->
 | 
			
		||||
 | 
			
		||||
<android.support.constraint.ConstraintLayout
 | 
			
		||||
<androidx.constraintlayout.widget.ConstraintLayout
 | 
			
		||||
    xmlns:android="http://schemas.android.com/apk/res/android"
 | 
			
		||||
    xmlns:app="http://schemas.android.com/apk/res-auto"
 | 
			
		||||
    android:layout_width="match_parent"
 | 
			
		||||
@@ -33,7 +33,7 @@
 | 
			
		||||
        app:layout_constraintLeft_toLeftOf="parent"
 | 
			
		||||
        app:layout_constraintTop_toTopOf="parent"/>
 | 
			
		||||
 | 
			
		||||
    <android.support.v7.widget.RecyclerView
 | 
			
		||||
    <androidx.recyclerview.widget.RecyclerView
 | 
			
		||||
        android:id="@+id/recycler_view"
 | 
			
		||||
        android:layout_width="match_parent"
 | 
			
		||||
        android:layout_height="0dp"
 | 
			
		||||
@@ -55,4 +55,4 @@
 | 
			
		||||
        app:layout_constraintBottom_toBottomOf="parent"
 | 
			
		||||
        app:layout_constraintRight_toRightOf="parent"/>
 | 
			
		||||
 | 
			
		||||
</android.support.constraint.ConstraintLayout>
 | 
			
		||||
</androidx.constraintlayout.widget.ConstraintLayout>
 | 
			
		||||
 
 | 
			
		||||
@@ -78,7 +78,7 @@
 | 
			
		||||
            android:paddingRight="8dp"
 | 
			
		||||
            tools:text="Recipient" />
 | 
			
		||||
 | 
			
		||||
        <android.support.v7.widget.RecyclerView
 | 
			
		||||
        <androidx.recyclerview.widget.RecyclerView
 | 
			
		||||
            android:id="@+id/parents"
 | 
			
		||||
            android:layout_width="fill_parent"
 | 
			
		||||
            android:layout_height="wrap_content"
 | 
			
		||||
@@ -99,7 +99,7 @@
 | 
			
		||||
            tools:text="Message Body"
 | 
			
		||||
            android:textIsSelectable="true" />
 | 
			
		||||
 | 
			
		||||
        <android.support.v7.widget.RecyclerView
 | 
			
		||||
        <androidx.recyclerview.widget.RecyclerView
 | 
			
		||||
            android:id="@+id/labels"
 | 
			
		||||
            android:layout_width="fill_parent"
 | 
			
		||||
            android:layout_height="wrap_content"
 | 
			
		||||
@@ -108,7 +108,7 @@
 | 
			
		||||
            android:layout_marginRight="16dp"
 | 
			
		||||
            android:layout_marginBottom="16dp"/>
 | 
			
		||||
 | 
			
		||||
        <android.support.v7.widget.RecyclerView
 | 
			
		||||
        <androidx.recyclerview.widget.RecyclerView
 | 
			
		||||
            android:id="@+id/responses"
 | 
			
		||||
            android:layout_width="fill_parent"
 | 
			
		||||
            android:layout_height="wrap_content"
 | 
			
		||||
 
 | 
			
		||||
@@ -4,7 +4,7 @@
 | 
			
		||||
                android:layout_width="match_parent"
 | 
			
		||||
                android:layout_height="match_parent">
 | 
			
		||||
 | 
			
		||||
    <android.support.v7.widget.RecyclerView
 | 
			
		||||
    <androidx.recyclerview.widget.RecyclerView
 | 
			
		||||
        android:id="@+id/recycler_view"
 | 
			
		||||
        android:layout_width="match_parent"
 | 
			
		||||
        android:layout_height="0dp"
 | 
			
		||||
 
 | 
			
		||||
@@ -88,7 +88,7 @@
 | 
			
		||||
            android:textIsSelectable="true"
 | 
			
		||||
            tools:text="Message Body" />
 | 
			
		||||
 | 
			
		||||
        <android.support.v7.widget.RecyclerView
 | 
			
		||||
        <androidx.recyclerview.widget.RecyclerView
 | 
			
		||||
            android:id="@+id/labels"
 | 
			
		||||
            android:layout_width="fill_parent"
 | 
			
		||||
            android:layout_height="wrap_content"
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,5 @@
 | 
			
		||||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
 | 
			
		||||
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
 | 
			
		||||
                                                 xmlns:app="http://schemas.android.com/apk/res-auto"
 | 
			
		||||
                                                 xmlns:tools="http://schemas.android.com/tools"
 | 
			
		||||
                                                 android:layout_width="match_parent"
 | 
			
		||||
@@ -16,11 +16,11 @@
 | 
			
		||||
                 tools:context=".ComposeMessageActivity"
 | 
			
		||||
                 tools:layout="@layout/fragment_compose_message"/>
 | 
			
		||||
 | 
			
		||||
    <android.support.design.widget.AppBarLayout
 | 
			
		||||
    <com.google.android.material.appbar.AppBarLayout
 | 
			
		||||
        android:layout_width="match_parent"
 | 
			
		||||
        android:layout_height="wrap_content">
 | 
			
		||||
 | 
			
		||||
        <android.support.v7.widget.Toolbar
 | 
			
		||||
        <androidx.appcompat.widget.Toolbar
 | 
			
		||||
            android:id="@+id/toolbar"
 | 
			
		||||
            android:layout_width="match_parent"
 | 
			
		||||
            android:layout_height="?attr/actionBarSize"
 | 
			
		||||
@@ -30,7 +30,7 @@
 | 
			
		||||
            app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
 | 
			
		||||
            tools:ignore="UnusedAttribute"/>
 | 
			
		||||
 | 
			
		||||
    </android.support.design.widget.AppBarLayout>
 | 
			
		||||
    </com.google.android.material.appbar.AppBarLayout>
 | 
			
		||||
 | 
			
		||||
</android.support.design.widget.CoordinatorLayout>
 | 
			
		||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,5 @@
 | 
			
		||||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
 | 
			
		||||
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
 | 
			
		||||
                                                 xmlns:app="http://schemas.android.com/apk/res-auto"
 | 
			
		||||
                                                 xmlns:tools="http://schemas.android.com/tools"
 | 
			
		||||
                                                 android:layout_width="match_parent"
 | 
			
		||||
@@ -16,11 +16,11 @@
 | 
			
		||||
                 tools:context=".ComposeMessageActivity"
 | 
			
		||||
                 tools:layout="@layout/fragment_compose_message"/>
 | 
			
		||||
 | 
			
		||||
    <android.support.design.widget.AppBarLayout
 | 
			
		||||
    <com.google.android.material.appbar.AppBarLayout
 | 
			
		||||
        android:layout_width="match_parent"
 | 
			
		||||
        android:layout_height="wrap_content">
 | 
			
		||||
 | 
			
		||||
        <android.support.v7.widget.Toolbar
 | 
			
		||||
        <androidx.appcompat.widget.Toolbar
 | 
			
		||||
            android:id="@+id/toolbar"
 | 
			
		||||
            android:layout_width="match_parent"
 | 
			
		||||
            android:layout_height="?attr/actionBarSize"
 | 
			
		||||
@@ -31,7 +31,7 @@
 | 
			
		||||
            app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
 | 
			
		||||
            tools:ignore="UnusedAttribute"/>
 | 
			
		||||
 | 
			
		||||
    </android.support.design.widget.AppBarLayout>
 | 
			
		||||
    </com.google.android.material.appbar.AppBarLayout>
 | 
			
		||||
 | 
			
		||||
</android.support.design.widget.CoordinatorLayout>
 | 
			
		||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -141,9 +141,8 @@ Als Alternative kann in den Einstellungen ein vertrauenswürdiger Knoten konfigu
 | 
			
		||||
    <string name="emulate_conversations_initialize">Bestehende Nachrichten nach Betreff gruppieren</string>
 | 
			
		||||
    <string name="preference_group_advanced">Erweitert</string>
 | 
			
		||||
    <string name="preference_group_network_and_performance">Netzwerk & Performanz</string>
 | 
			
		||||
    <string name="preference_group_network_and_performance_summary">Feineinstellungen für Netzwerk und Protokoll-Details</string>
 | 
			
		||||
    <string name="preference_group_user_experience">Verhalten</string>
 | 
			
		||||
    <string name="preference_group_user_experience_summary">Ändern, wie Nachrichten dargestellt werden</string>
 | 
			
		||||
    <string name="preference_group_app">App</string>
 | 
			
		||||
    <string name="bitmessage_service_description">Hält die Verbindung zum Bitmessage-Netzwerk.</string>
 | 
			
		||||
    <string name="preference_port">Port</string>
 | 
			
		||||
</resources>
 | 
			
		||||
 
 | 
			
		||||
@@ -37,10 +37,6 @@
 | 
			
		||||
    <string name="archive">Archive</string>
 | 
			
		||||
    <string name="empty_trash">Empty Trash</string>
 | 
			
		||||
    <string name="stream_number">Stream #%d</string>
 | 
			
		||||
    <string name="trusted_node">Trusted node</string>
 | 
			
		||||
    <string name="trusted_node_summary">Use this node for synchronization</string>
 | 
			
		||||
    <string name="sync_timeout">Synchronization Timeout</string>
 | 
			
		||||
    <string name="sync_timeout_summary">Timeout in seconds</string>
 | 
			
		||||
    <string name="write_message">Write message</string>
 | 
			
		||||
    <string name="full_node">Full node</string>
 | 
			
		||||
    <string name="send">Send</string>
 | 
			
		||||
@@ -49,12 +45,9 @@
 | 
			
		||||
    <string name="proof_of_work_title">Proof of Work</string>
 | 
			
		||||
    <string name="proof_of_work_text_0">Doing work to send message</string>
 | 
			
		||||
    <string name="proof_of_work_text_n" tools:ignore="PluralsCandidate">Doing work to send message (%1$d queued)</string>
 | 
			
		||||
    <string name="error_invalid_sync_port">Invalid port in synchronization settings: %s</string>
 | 
			
		||||
    <string name="compose_body_hint">Write message</string>
 | 
			
		||||
    <string name="contacts_and_subscriptions">Contacts</string>
 | 
			
		||||
    <string name="subscribed">Subscribed</string>
 | 
			
		||||
    <string name="server_pow">Server POW</string>
 | 
			
		||||
    <string name="server_pow_summary">Trusted node does proof of work</string>
 | 
			
		||||
    <string name="full_node_warning">Running a full Bitmessage node uses a lot of traffic, which could be expensive on a mobile network. Are you sure you want to start a full node?</string>
 | 
			
		||||
    <string name="about">About Abit</string>
 | 
			
		||||
    <string name="about_summary">Open source dependencies.</string>
 | 
			
		||||
@@ -142,13 +135,10 @@ As an alternative you could configure a trusted node in the settings, but as of
 | 
			
		||||
    <string name="emulate_conversations_initialize">Group existing messages by subject</string>
 | 
			
		||||
    <string name="emulate_conversations_batch">Grouping existing messages by subject</string>
 | 
			
		||||
    <string name="preference_group_user_experience">Behaviour</string>
 | 
			
		||||
    <string name="preference_group_user_experience_summary">Change how messages are displayed</string>
 | 
			
		||||
    <string name="preference_group_network_and_performance">Network & Performance</string>
 | 
			
		||||
    <string name="preference_group_network_and_performance_summary">Tweak network usage and protocol details</string>
 | 
			
		||||
    <string name="preference_group_advanced">Advanced</string>
 | 
			
		||||
    <string name="preference_group_advanced_summary"></string>
 | 
			
		||||
    <string name="preference_group_experimental">Experimental</string>
 | 
			
		||||
    <string name="preference_group_experimental_summary">Only change if you know what you\'re doing</string>
 | 
			
		||||
    <string name="preference_group_app">App</string>
 | 
			
		||||
    <string name="require_charging">Require charging</string>
 | 
			
		||||
    <string name="require_charging_summary">Only connect when device is plugged in</string>
 | 
			
		||||
    <string name="unknown">Unknown</string>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,97 +1,100 @@
 | 
			
		||||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
 | 
			
		||||
 | 
			
		||||
    <PreferenceScreen
 | 
			
		||||
        android:key="preference_ux"
 | 
			
		||||
        android:persistent="false"
 | 
			
		||||
        android:summary="@string/preference_group_user_experience_summary"
 | 
			
		||||
        android:title="@string/preference_group_user_experience">
 | 
			
		||||
    <PreferenceCategory android:title="@string/preference_group_user_experience">
 | 
			
		||||
 | 
			
		||||
        <SwitchPreferenceCompat
 | 
			
		||||
            android:defaultValue="false"
 | 
			
		||||
            android:icon="@drawable/ic_separate_identities"
 | 
			
		||||
            android:key="separate_identities"
 | 
			
		||||
            android:summary="@string/preference_separate_identities_summary"
 | 
			
		||||
            android:title="@string/preference_separate_identities" />
 | 
			
		||||
        <SwitchPreferenceCompat
 | 
			
		||||
            android:defaultValue="true"
 | 
			
		||||
            android:icon="@drawable/ic_emulate_conversations"
 | 
			
		||||
            android:key="emulate_conversations"
 | 
			
		||||
            android:summary="@string/emulate_conversations_summary"
 | 
			
		||||
            android:title="@string/emulate_conversations" />
 | 
			
		||||
        <Preference
 | 
			
		||||
            android:defaultValue="true"
 | 
			
		||||
            android:icon="@drawable/ic_emulate_conversations"
 | 
			
		||||
            android:key="emulate_conversations_initialize"
 | 
			
		||||
            android:summary="@string/emulate_conversations_summary"
 | 
			
		||||
            android:title="@string/emulate_conversations_initialize" />
 | 
			
		||||
 | 
			
		||||
    </PreferenceScreen>
 | 
			
		||||
    </PreferenceCategory>
 | 
			
		||||
 | 
			
		||||
    <PreferenceScreen
 | 
			
		||||
        android:key="preference_network_and_performance"
 | 
			
		||||
        android:persistent="false"
 | 
			
		||||
        android:summary="@string/preference_group_network_and_performance_summary"
 | 
			
		||||
        android:title="@string/preference_group_network_and_performance">
 | 
			
		||||
    <PreferenceCategory android:title="@string/preference_group_network_and_performance">
 | 
			
		||||
 | 
			
		||||
        <SwitchPreferenceCompat
 | 
			
		||||
            android:defaultValue="true"
 | 
			
		||||
            android:icon="@drawable/ic_network_wifi"
 | 
			
		||||
            android:key="wifi_only"
 | 
			
		||||
            android:summary="@string/wifi_only_summary"
 | 
			
		||||
            android:title="@string/wifi_only" />
 | 
			
		||||
        <SwitchPreferenceCompat
 | 
			
		||||
            android:defaultValue="false"
 | 
			
		||||
            android:icon="@drawable/ic_battery_charging"
 | 
			
		||||
            android:key="require_charging"
 | 
			
		||||
            android:summary="@string/require_charging_summary"
 | 
			
		||||
            android:title="@string/require_charging" />
 | 
			
		||||
        <SwitchPreferenceCompat
 | 
			
		||||
            android:defaultValue="true"
 | 
			
		||||
            android:icon="@drawable/ic_check_all"
 | 
			
		||||
            android:key="request_acknowledgements"
 | 
			
		||||
            android:summary="@string/request_acknowledgements_summary"
 | 
			
		||||
            android:title="@string/request_acknowledgements" />
 | 
			
		||||
 | 
			
		||||
    </PreferenceScreen>
 | 
			
		||||
    </PreferenceCategory>
 | 
			
		||||
 | 
			
		||||
    <PreferenceScreen
 | 
			
		||||
        android:key="preference_advanced"
 | 
			
		||||
        android:persistent="false"
 | 
			
		||||
        android:summary="@string/preference_group_advanced_summary"
 | 
			
		||||
        android:title="@string/preference_group_advanced">
 | 
			
		||||
    <PreferenceCategory android:title="@string/preference_group_advanced">
 | 
			
		||||
 | 
			
		||||
        <Preference
 | 
			
		||||
            android:icon="@drawable/ic_broom"
 | 
			
		||||
            android:key="cleanup"
 | 
			
		||||
            android:summary="@string/cleanup_summary"
 | 
			
		||||
            android:title="@string/cleanup" />
 | 
			
		||||
        <Preference
 | 
			
		||||
            android:icon="@drawable/ic_export"
 | 
			
		||||
            android:key="export"
 | 
			
		||||
            android:summary="@string/export_data_summary"
 | 
			
		||||
            android:title="@string/export_data" />
 | 
			
		||||
        <Preference
 | 
			
		||||
            android:icon="@drawable/ic_import"
 | 
			
		||||
            android:key="import"
 | 
			
		||||
            android:summary="@string/import_data_summary"
 | 
			
		||||
            android:title="@string/import_data" />
 | 
			
		||||
 | 
			
		||||
        <Preference
 | 
			
		||||
            android:icon="@drawable/ic_bug_report"
 | 
			
		||||
            android:key="status"
 | 
			
		||||
            android:summary="@string/status_summary"
 | 
			
		||||
            android:title="@string/status" />
 | 
			
		||||
 | 
			
		||||
        <EditTextPreference
 | 
			
		||||
            android:defaultValue="8444"
 | 
			
		||||
            android:icon="@drawable/ic_port"
 | 
			
		||||
            android:key="listening_port"
 | 
			
		||||
            android:numeric="integer"
 | 
			
		||||
            android:summary="@string/preference_port_summary"
 | 
			
		||||
            android:title="@string/preference_port"
 | 
			
		||||
            android:numeric="integer"/>
 | 
			
		||||
            android:title="@string/preference_port" />
 | 
			
		||||
 | 
			
		||||
    </PreferenceScreen>
 | 
			
		||||
    </PreferenceCategory>
 | 
			
		||||
 | 
			
		||||
    <Preference
 | 
			
		||||
        android:key="about"
 | 
			
		||||
        android:summary="@string/about_summary"
 | 
			
		||||
        android:title="@string/about" />
 | 
			
		||||
    <Preference
 | 
			
		||||
        android:key="help_out"
 | 
			
		||||
        android:summary="@string/help_out_summary"
 | 
			
		||||
        android:title="@string/help_out">
 | 
			
		||||
        <intent
 | 
			
		||||
            android:action="android.intent.action.VIEW"
 | 
			
		||||
            android:data="@string/help_out_link" />
 | 
			
		||||
    </Preference>
 | 
			
		||||
    <PreferenceCategory android:title="@string/preference_group_app">
 | 
			
		||||
        <Preference
 | 
			
		||||
            android:icon="@drawable/ic_info"
 | 
			
		||||
            android:key="about"
 | 
			
		||||
            android:summary="@string/about_summary"
 | 
			
		||||
            android:title="@string/about" />
 | 
			
		||||
        <Preference
 | 
			
		||||
            android:icon="@drawable/ic_support_app"
 | 
			
		||||
            android:key="help_out"
 | 
			
		||||
            android:summary="@string/help_out_summary"
 | 
			
		||||
            android:title="@string/help_out">
 | 
			
		||||
            <intent
 | 
			
		||||
                android:action="android.intent.action.VIEW"
 | 
			
		||||
                android:data="@string/help_out_link" />
 | 
			
		||||
        </Preference>
 | 
			
		||||
    </PreferenceCategory>
 | 
			
		||||
</PreferenceScreen>
 | 
			
		||||
 
 | 
			
		||||
@@ -21,6 +21,7 @@ import ch.dissem.apps.abit.repository.AndroidAddressRepository
 | 
			
		||||
import ch.dissem.apps.abit.repository.AndroidLabelRepository
 | 
			
		||||
import ch.dissem.apps.abit.repository.AndroidMessageRepository
 | 
			
		||||
import ch.dissem.apps.abit.repository.SqlHelper
 | 
			
		||||
import ch.dissem.apps.abit.util.preferences
 | 
			
		||||
import ch.dissem.bitmessage.cryptography.bc.BouncyCryptography
 | 
			
		||||
import ch.dissem.bitmessage.entity.BitmessageAddress
 | 
			
		||||
import ch.dissem.bitmessage.entity.ObjectMessage
 | 
			
		||||
@@ -67,7 +68,7 @@ class AndroidMessageRepositoryTest : TestBase() {
 | 
			
		||||
 | 
			
		||||
        val addressRepo = AndroidAddressRepository(sqlHelper)
 | 
			
		||||
        val labelRepo = AndroidLabelRepository(sqlHelper, RuntimeEnvironment.application)
 | 
			
		||||
        repo = AndroidMessageRepository(sqlHelper)
 | 
			
		||||
        repo = AndroidMessageRepository(sqlHelper, RuntimeEnvironment.application.preferences)
 | 
			
		||||
        mockedInternalContext(
 | 
			
		||||
            cryptography = BouncyCryptography(),
 | 
			
		||||
            addressRepository = addressRepo,
 | 
			
		||||
 
 | 
			
		||||
@@ -18,6 +18,7 @@ package ch.dissem.bitmessage.repository
 | 
			
		||||
 | 
			
		||||
import android.os.Build.VERSION_CODES.LOLLIPOP
 | 
			
		||||
import ch.dissem.apps.abit.repository.*
 | 
			
		||||
import ch.dissem.apps.abit.util.preferences
 | 
			
		||||
import ch.dissem.bitmessage.entity.BitmessageAddress
 | 
			
		||||
import ch.dissem.bitmessage.entity.ObjectMessage
 | 
			
		||||
import ch.dissem.bitmessage.entity.Plaintext
 | 
			
		||||
@@ -60,7 +61,7 @@ class AndroidProofOfWorkRepositoryTest : TestBase() {
 | 
			
		||||
        RuntimeEnvironment.application.deleteDatabase(SqlHelper.DATABASE_NAME)
 | 
			
		||||
        val sqlHelper = SqlHelper(RuntimeEnvironment.application)
 | 
			
		||||
        addressRepo = AndroidAddressRepository(sqlHelper)
 | 
			
		||||
        messageRepo = AndroidMessageRepository(sqlHelper)
 | 
			
		||||
        messageRepo = AndroidMessageRepository(sqlHelper, RuntimeEnvironment.application.preferences)
 | 
			
		||||
        repo = AndroidProofOfWorkRepository(sqlHelper)
 | 
			
		||||
        mockedInternalContext(
 | 
			
		||||
            addressRepository = addressRepo,
 | 
			
		||||
 
 | 
			
		||||
@@ -1,12 +1,12 @@
 | 
			
		||||
buildscript {
 | 
			
		||||
    ext.kotlin_version = '1.2.51'
 | 
			
		||||
    ext.kotlin_version = '1.2.71'
 | 
			
		||||
    ext.anko_version = '0.10.5'
 | 
			
		||||
    repositories {
 | 
			
		||||
        jcenter()
 | 
			
		||||
        google()
 | 
			
		||||
        jcenter()
 | 
			
		||||
    }
 | 
			
		||||
    dependencies {
 | 
			
		||||
        classpath 'com.android.tools.build:gradle:3.1.3'
 | 
			
		||||
        classpath 'com.android.tools.build:gradle:3.2.1'
 | 
			
		||||
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
 | 
			
		||||
        classpath 'com.github.ben-manes:gradle-versions-plugin:0.20.0'
 | 
			
		||||
 | 
			
		||||
@@ -21,7 +21,6 @@ allprojects {
 | 
			
		||||
    repositories {
 | 
			
		||||
        google()
 | 
			
		||||
        jcenter()
 | 
			
		||||
        mavenCentral()
 | 
			
		||||
        maven { url 'https://oss.sonatype.org/content/repositories/snapshots/' }
 | 
			
		||||
        maven { url "https://jitpack.io" }
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -10,6 +10,8 @@
 | 
			
		||||
# Specifies the JVM arguments used for the daemon process.
 | 
			
		||||
# The setting is particularly useful for tweaking memory settings.
 | 
			
		||||
# Default value: -Xmx10248m -XX:MaxPermSize=256m
 | 
			
		||||
android.enableJetifier=true
 | 
			
		||||
android.useAndroidX=true
 | 
			
		||||
org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
 | 
			
		||||
 | 
			
		||||
# When configured, Gradle will run in incubating parallel mode.
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										4
									
								
								gradle/wrapper/gradle-wrapper.properties
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								gradle/wrapper/gradle-wrapper.properties
									
									
									
									
										vendored
									
									
								
							@@ -1,6 +1,6 @@
 | 
			
		||||
#Sat Mar 03 14:35:52 CET 2018
 | 
			
		||||
#Tue Aug 28 16:14:32 CEST 2018
 | 
			
		||||
distributionBase=GRADLE_USER_HOME
 | 
			
		||||
distributionPath=wrapper/dists
 | 
			
		||||
zipStoreBase=GRADLE_USER_HOME
 | 
			
		||||
zipStorePath=wrapper/dists
 | 
			
		||||
distributionUrl=https\://services.gradle.org/distributions/gradle-4.5-all.zip
 | 
			
		||||
distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user