Improve utilities

This commit is contained in:
Christian Basler 2018-03-23 17:50:43 +01:00
parent 46e5bb7ece
commit 49e77199b0
17 changed files with 194 additions and 180 deletions

View File

@ -26,6 +26,7 @@ import android.view.*
import android.widget.Toast import android.widget.Toast
import ch.dissem.apps.abit.service.Singleton import ch.dissem.apps.abit.service.Singleton
import ch.dissem.apps.abit.util.Drawables import ch.dissem.apps.abit.util.Drawables
import ch.dissem.apps.abit.util.qrCode
import ch.dissem.bitmessage.entity.BitmessageAddress import ch.dissem.bitmessage.entity.BitmessageAddress
import ch.dissem.bitmessage.wif.WifExporter import ch.dissem.bitmessage.wif.WifExporter
import com.mikepenz.community_material_typeface_library.CommunityMaterial import com.mikepenz.community_material_typeface_library.CommunityMaterial
@ -185,7 +186,7 @@ class AddressDetailFragment : Fragment() {
} }
// QR code // QR code
qr_code.setImageBitmap(Drawables.qrCode(item)) qr_code.setImageBitmap(item.qrCode())
} }
} }

View File

@ -27,7 +27,6 @@ import android.widget.ArrayAdapter
import android.widget.ImageView import android.widget.ImageView
import android.widget.TextView import android.widget.TextView
import ch.dissem.apps.abit.service.Singleton import ch.dissem.apps.abit.service.Singleton
import ch.dissem.apps.abit.util.FabUtils
import ch.dissem.bitmessage.entity.BitmessageAddress import ch.dissem.bitmessage.entity.BitmessageAddress
import com.google.zxing.integration.android.IntentIntegrator import com.google.zxing.integration.android.IntentIntegrator
import io.github.kobakei.materialfabspeeddial.FabSpeedDialMenu import io.github.kobakei.materialfabspeeddial.FabSpeedDialMenu
@ -107,7 +106,7 @@ class AddressListFragment : AbstractItemListFragment<Void, BitmessageAddress>()
val menu = FabSpeedDialMenu(activity) val menu = FabSpeedDialMenu(activity)
menu.add(R.string.scan_qr_code).setIcon(R.drawable.ic_action_qr_code) menu.add(R.string.scan_qr_code).setIcon(R.drawable.ic_action_qr_code)
menu.add(R.string.create_contact).setIcon(R.drawable.ic_action_create_contact) menu.add(R.string.create_contact).setIcon(R.drawable.ic_action_create_contact)
FabUtils.initFab(activity, R.drawable.ic_action_add_contact, menu) activity.initFab(R.drawable.ic_action_add_contact, menu)
.addOnMenuItemClickListener { _, _, itemId -> .addOnMenuItemClickListener { _, _, itemId ->
when (itemId) { when (itemId) {
1 -> IntentIntegrator.forSupportFragment(this@AddressListFragment) 1 -> IntentIntegrator.forSupportFragment(this@AddressListFragment)

View File

@ -19,7 +19,6 @@ package ch.dissem.apps.abit
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.support.annotation.IdRes
import android.support.v4.app.Fragment import android.support.v4.app.Fragment
import android.support.v7.widget.LinearLayoutManager import android.support.v7.widget.LinearLayoutManager
import android.support.v7.widget.RecyclerView import android.support.v7.widget.RecyclerView
@ -28,9 +27,9 @@ import android.widget.ImageView
import android.widget.TextView import android.widget.TextView
import ch.dissem.apps.abit.adapter.ConversationAdapter import ch.dissem.apps.abit.adapter.ConversationAdapter
import ch.dissem.apps.abit.service.Singleton import ch.dissem.apps.abit.service.Singleton
import ch.dissem.apps.abit.util.Assets
import ch.dissem.apps.abit.util.Drawables import ch.dissem.apps.abit.util.Drawables
import ch.dissem.apps.abit.util.Strings.prepareMessageExtract import ch.dissem.apps.abit.util.Strings.prepareMessageExtract
import ch.dissem.apps.abit.util.getDrawable
import ch.dissem.bitmessage.entity.Conversation import ch.dissem.bitmessage.entity.Conversation
import ch.dissem.bitmessage.entity.Plaintext import ch.dissem.bitmessage.entity.Plaintext
import com.mikepenz.google_material_typeface_library.GoogleMaterial import com.mikepenz.google_material_typeface_library.GoogleMaterial
@ -148,7 +147,7 @@ class ConversationDetailFragment : Fragment() {
val message = messages[position] val message = messages[position]
viewHolder.avatar.setImageDrawable(Identicon(message.from)) viewHolder.avatar.setImageDrawable(Identicon(message.from))
viewHolder.status.setImageResource(Assets.getStatusDrawable(message.status)) viewHolder.status.setImageResource(message.status.getDrawable())
viewHolder.sender.text = message.from.toString() viewHolder.sender.text = message.from.toString()
viewHolder.extract.text = prepareMessageExtract(message.text) viewHolder.extract.text = prepareMessageExtract(message.text)
viewHolder.item = message viewHolder.item = message

View File

@ -33,7 +33,6 @@ import ch.dissem.apps.abit.listener.ListSelectionListener
import ch.dissem.apps.abit.repository.AndroidMessageRepository import ch.dissem.apps.abit.repository.AndroidMessageRepository
import ch.dissem.apps.abit.service.Singleton import ch.dissem.apps.abit.service.Singleton
import ch.dissem.apps.abit.service.Singleton.currentLabel import ch.dissem.apps.abit.service.Singleton.currentLabel
import ch.dissem.apps.abit.util.FabUtils
import ch.dissem.bitmessage.entity.Conversation import ch.dissem.bitmessage.entity.Conversation
import ch.dissem.bitmessage.entity.valueobject.Label import ch.dissem.bitmessage.entity.valueobject.Label
import ch.dissem.bitmessage.utils.ConversationService import ch.dissem.bitmessage.utils.ConversationService
@ -248,7 +247,7 @@ class ConversationListFragment : Fragment(), ListHolder<Label> {
val menu = FabSpeedDialMenu(context) val menu = FabSpeedDialMenu(context)
menu.add(R.string.broadcast).setIcon(R.drawable.ic_action_broadcast) menu.add(R.string.broadcast).setIcon(R.drawable.ic_action_broadcast)
menu.add(R.string.personal_message).setIcon(R.drawable.ic_action_personal) menu.add(R.string.personal_message).setIcon(R.drawable.ic_action_personal)
FabUtils.initFab(context, R.drawable.ic_action_compose_message, menu) context.initFab(R.drawable.ic_action_compose_message, menu)
.addOnMenuItemClickListener { _, _, itemId -> .addOnMenuItemClickListener { _, _, itemId ->
val identity = Singleton.getIdentity(context) val identity = Singleton.getIdentity(context)
if (identity == null) { if (identity == null) {

View File

@ -19,6 +19,7 @@ package ch.dissem.apps.abit
import android.content.Intent import android.content.Intent
import android.graphics.Point import android.graphics.Point
import android.os.Bundle import android.os.Bundle
import android.support.annotation.DrawableRes
import android.support.v4.app.Fragment import android.support.v4.app.Fragment
import android.support.v7.app.AppCompatActivity import android.support.v7.app.AppCompatActivity
import android.support.v7.widget.Toolbar import android.support.v7.widget.Toolbar
@ -54,6 +55,7 @@ import com.mikepenz.materialdrawer.model.interfaces.IDrawerItem
import com.mikepenz.materialdrawer.model.interfaces.IProfile import com.mikepenz.materialdrawer.model.interfaces.IProfile
import com.mikepenz.materialdrawer.model.interfaces.Nameable import com.mikepenz.materialdrawer.model.interfaces.Nameable
import io.github.kobakei.materialfabspeeddial.FabSpeedDial import io.github.kobakei.materialfabspeeddial.FabSpeedDial
import io.github.kobakei.materialfabspeeddial.FabSpeedDialMenu
import kotlinx.android.synthetic.main.activity_main.* import kotlinx.android.synthetic.main.activity_main.*
import org.jetbrains.anko.doAsync import org.jetbrains.anko.doAsync
import org.jetbrains.anko.uiThread import org.jetbrains.anko.uiThread
@ -538,6 +540,25 @@ class MainActivity : AppCompatActivity(), ListSelectionListener<Serializable> {
supportActionBar?.title = title supportActionBar?.title = title
} }
fun initFab(@DrawableRes drawableRes: Int, menu: FabSpeedDialMenu): FabSpeedDial {
val fab = floatingActionButton ?: throw IllegalStateException("Fab must not be null")
fab.removeAllOnMenuItemClickListeners()
fab.show()
fab.closeMenu()
val mainFab = fab.mainFab
mainFab.setImageResource(drawableRes)
fab.setMenu(menu)
fab.addOnStateChangeListener { isOpened: Boolean ->
if (isOpened) {
// It will be turned 45 degrees, which makes an x out of the +
mainFab.setImageResource(R.drawable.ic_action_add)
} else {
mainFab.setImageResource(drawableRes)
}
}
return fab
}
companion object { companion object {
const val EXTRA_SHOW_MESSAGE = "ch.dissem.abit.ShowMessage" const val EXTRA_SHOW_MESSAGE = "ch.dissem.abit.ShowMessage"
const val EXTRA_SHOW_LABEL = "ch.dissem.abit.ShowLabel" const val EXTRA_SHOW_LABEL = "ch.dissem.abit.ShowLabel"

View File

@ -31,16 +31,15 @@ import android.widget.ImageView
import android.widget.TextView import android.widget.TextView
import ch.dissem.apps.abit.adapter.LabelAdapter import ch.dissem.apps.abit.adapter.LabelAdapter
import ch.dissem.apps.abit.service.Singleton import ch.dissem.apps.abit.service.Singleton
import ch.dissem.apps.abit.util.Assets
import ch.dissem.apps.abit.util.Constants.BITMESSAGE_ADDRESS_PATTERN import ch.dissem.apps.abit.util.Constants.BITMESSAGE_ADDRESS_PATTERN
import ch.dissem.apps.abit.util.Constants.BITMESSAGE_URL_SCHEMA import ch.dissem.apps.abit.util.Constants.BITMESSAGE_URL_SCHEMA
import ch.dissem.apps.abit.util.Drawables import ch.dissem.apps.abit.util.Drawables
import ch.dissem.apps.abit.util.Labels
import ch.dissem.apps.abit.util.Strings.prepareMessageExtract 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.Plaintext
import ch.dissem.bitmessage.entity.valueobject.Label import ch.dissem.bitmessage.entity.valueobject.Label
import com.mikepenz.google_material_typeface_library.GoogleMaterial import com.mikepenz.google_material_typeface_library.GoogleMaterial
import com.mikepenz.iconics.view.IconicsImageView
import kotlinx.android.synthetic.main.fragment_message_detail.* import kotlinx.android.synthetic.main.fragment_message_detail.*
import java.util.* import java.util.*
@ -86,8 +85,8 @@ class MessageDetailFragment : Fragment() {
// Show the dummy content as text in a TextView. // Show the dummy content as text in a TextView.
item?.let { item -> item?.let { item ->
subject.text = item.subject subject.text = item.subject
status.setImageResource(Assets.getStatusDrawable(item.status)) status.setImageResource(item.status.getDrawable())
status.contentDescription = getString(Assets.getStatusString(item.status)) status.contentDescription = getString(item.status.getString())
avatar.setImageDrawable(Identicon(item.from)) avatar.setImageDrawable(Identicon(item.from))
val senderClickListener: (View) -> Unit = { val senderClickListener: (View) -> Unit = {
MainActivity.apply { MainActivity.apply {
@ -230,7 +229,7 @@ class MessageDetailFragment : Fragment() {
val message = messages[position] val message = messages[position]
viewHolder.avatar.setImageDrawable(Identicon(message.from)) viewHolder.avatar.setImageDrawable(Identicon(message.from))
viewHolder.status.setImageResource(Assets.getStatusDrawable(message.status)) viewHolder.status.setImageResource(message.status.getDrawable())
viewHolder.sender.text = message.from.toString() viewHolder.sender.text = message.from.toString()
viewHolder.extract.text = prepareMessageExtract(message.text) viewHolder.extract.text = prepareMessageExtract(message.text)
viewHolder.item = message viewHolder.item = message

View File

@ -33,7 +33,6 @@ import ch.dissem.apps.abit.listener.ListSelectionListener
import ch.dissem.apps.abit.repository.AndroidMessageRepository import ch.dissem.apps.abit.repository.AndroidMessageRepository
import ch.dissem.apps.abit.service.Singleton import ch.dissem.apps.abit.service.Singleton
import ch.dissem.apps.abit.service.Singleton.currentLabel import ch.dissem.apps.abit.service.Singleton.currentLabel
import ch.dissem.apps.abit.util.FabUtils
import ch.dissem.bitmessage.entity.Plaintext import ch.dissem.bitmessage.entity.Plaintext
import ch.dissem.bitmessage.entity.valueobject.Label import ch.dissem.bitmessage.entity.valueobject.Label
import com.h6ah4i.android.widget.advrecyclerview.animator.SwipeDismissItemAnimator import com.h6ah4i.android.widget.advrecyclerview.animator.SwipeDismissItemAnimator
@ -98,7 +97,11 @@ class MessageListFragment : Fragment(), ListHolder<Label> {
isLoading = true isLoading = true
swipeableMessageAdapter?.let { messageAdapter -> swipeableMessageAdapter?.let { messageAdapter ->
doAsync { doAsync {
val messages = messageRepo.findMessages(currentLabel.value, messageAdapter.itemCount, PAGE_SIZE) val messages = messageRepo.findMessages(
currentLabel.value,
messageAdapter.itemCount,
PAGE_SIZE
)
onUiThread { onUiThread {
messageAdapter.addAll(messages) messageAdapter.addAll(messages)
isLoading = false isLoading = false
@ -149,7 +152,11 @@ class MessageListFragment : Fragment(), ListHolder<Label> {
loadMoreItems() loadMoreItems()
} }
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View = override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View =
inflater.inflate(R.layout.fragment_message_list, container, false) inflater.inflate(R.layout.fragment_message_list, container, false)
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
@ -213,8 +220,11 @@ class MessageListFragment : Fragment(), ListHolder<Label> {
recycler_view.itemAnimator = animator recycler_view.itemAnimator = animator
recycler_view.addOnScrollListener(recyclerViewOnScrollListener) recycler_view.addOnScrollListener(recyclerViewOnScrollListener)
recycler_view.addItemDecoration(SimpleListDividerDecorator( recycler_view.addItemDecoration(
ContextCompat.getDrawable(context, R.drawable.list_divider_h), true)) SimpleListDividerDecorator(
ContextCompat.getDrawable(context, R.drawable.list_divider_h), true
)
)
// NOTE: // NOTE:
// The initialization order is very important! This order determines the priority of // The initialization order is very important! This order determines the priority of
@ -235,12 +245,14 @@ class MessageListFragment : Fragment(), ListHolder<Label> {
val menu = FabSpeedDialMenu(context) val menu = FabSpeedDialMenu(context)
menu.add(R.string.broadcast).setIcon(R.drawable.ic_action_broadcast) menu.add(R.string.broadcast).setIcon(R.drawable.ic_action_broadcast)
menu.add(R.string.personal_message).setIcon(R.drawable.ic_action_personal) menu.add(R.string.personal_message).setIcon(R.drawable.ic_action_personal)
FabUtils.initFab(context, R.drawable.ic_action_compose_message, menu) context.initFab(R.drawable.ic_action_compose_message, menu)
.addOnMenuItemClickListener { _, _, itemId -> .addOnMenuItemClickListener { _, _, itemId ->
val identity = Singleton.getIdentity(context) val identity = Singleton.getIdentity(context)
if (identity == null) { if (identity == null) {
Toast.makeText(activity, R.string.no_identity_warning, Toast.makeText(
Toast.LENGTH_LONG).show() activity, R.string.no_identity_warning,
Toast.LENGTH_LONG
).show()
} else { } else {
when (itemId) { when (itemId) {
1 -> { 1 -> {

View File

@ -13,8 +13,8 @@ import android.widget.ImageView
import android.widget.TextView import android.widget.TextView
import ch.dissem.apps.abit.* import ch.dissem.apps.abit.*
import ch.dissem.apps.abit.service.Singleton import ch.dissem.apps.abit.service.Singleton
import ch.dissem.apps.abit.util.Assets
import ch.dissem.apps.abit.util.Constants import ch.dissem.apps.abit.util.Constants
import ch.dissem.apps.abit.util.getDrawable
import ch.dissem.bitmessage.entity.Conversation import ch.dissem.bitmessage.entity.Conversation
import ch.dissem.bitmessage.entity.Plaintext import ch.dissem.bitmessage.entity.Plaintext
import ch.dissem.bitmessage.entity.valueobject.Label import ch.dissem.bitmessage.entity.valueobject.Label
@ -61,7 +61,7 @@ class ConversationAdapter internal constructor(
sender.setOnClickListener(senderClickListener) sender.setOnClickListener(senderClickListener)
recipient.text = message.to.toString() recipient.text = message.to.toString()
status.setImageResource(Assets.getStatusDrawable(message.status)) status.setImageResource(message.status.getDrawable())
text.text = message.text text.text = message.text
Linkify.addLinks(text, Linkify.WEB_URLS) Linkify.addLinks(text, Linkify.WEB_URLS)

View File

@ -29,8 +29,9 @@ import android.widget.TextView
import ch.dissem.apps.abit.Identicon import ch.dissem.apps.abit.Identicon
import ch.dissem.apps.abit.R import ch.dissem.apps.abit.R
import ch.dissem.apps.abit.repository.AndroidLabelRepository.Companion.LABEL_ARCHIVE import ch.dissem.apps.abit.repository.AndroidLabelRepository.Companion.LABEL_ARCHIVE
import ch.dissem.apps.abit.util.Assets
import ch.dissem.apps.abit.util.Strings.prepareMessageExtract 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.Plaintext
import ch.dissem.bitmessage.entity.valueobject.Label import ch.dissem.bitmessage.entity.valueobject.Label
import com.h6ah4i.android.widget.advrecyclerview.swipeable.SwipeableItemAdapter import com.h6ah4i.android.widget.advrecyclerview.swipeable.SwipeableItemAdapter
@ -48,7 +49,8 @@ import java.util.*
* @author Christian Basler * @author Christian Basler
* @see [https://github.com/h6ah4i/android-advancedrecyclerview](https://github.com/h6ah4i/android-advancedrecyclerview) * @see [https://github.com/h6ah4i/android-advancedrecyclerview](https://github.com/h6ah4i/android-advancedrecyclerview)
*/ */
class SwipeableMessageAdapter : RecyclerView.Adapter<SwipeableMessageAdapter.ViewHolder>(), SwipeableItemAdapter<SwipeableMessageAdapter.ViewHolder>, SwipeableItemConstants { class SwipeableMessageAdapter : RecyclerView.Adapter<SwipeableMessageAdapter.ViewHolder>(),
SwipeableItemAdapter<SwipeableMessageAdapter.ViewHolder>, SwipeableItemConstants {
private val data = LinkedList<Plaintext>() private val data = LinkedList<Plaintext>()
var eventListener: EventListener? = null var eventListener: EventListener? = null
@ -84,7 +86,8 @@ class SwipeableMessageAdapter : RecyclerView.Adapter<SwipeableMessageAdapter.Vie
init { init {
itemViewOnClickListener = View.OnClickListener { view -> onItemViewClick(view) } itemViewOnClickListener = View.OnClickListener { view -> onItemViewClick(view) }
swipeableViewContainerOnClickListener = View.OnClickListener { view -> onSwipeableViewContainerClick(view) } swipeableViewContainerOnClickListener =
View.OnClickListener { view -> onSwipeableViewContainerClick(view) }
// SwipeableItemAdapter requires stable ID, and also // SwipeableItemAdapter requires stable ID, and also
// have to implement the getItemId() method appropriately. // have to implement the getItemId() method appropriately.
@ -134,7 +137,8 @@ class SwipeableMessageAdapter : RecyclerView.Adapter<SwipeableMessageAdapter.Vie
private fun onSwipeableViewContainerClick(v: View) { private fun onSwipeableViewContainerClick(v: View) {
eventListener?.onItemViewClicked( eventListener?.onItemViewClicked(
RecyclerViewAdapterUtils.getParentViewHolderItemView(v)) RecyclerViewAdapterUtils.getParentViewHolderItemView(v)
)
} }
fun getItem(position: Int) = data[position] fun getItem(position: Int) = data[position]
@ -168,8 +172,8 @@ class SwipeableMessageAdapter : RecyclerView.Adapter<SwipeableMessageAdapter.Vie
// set data // set data
avatar.setImageDrawable(Identicon(item.from)) avatar.setImageDrawable(Identicon(item.from))
status.setImageResource(Assets.getStatusDrawable(item.status)) status.setImageResource(item.status.getDrawable())
status.contentDescription = holder.status.context.getString(Assets.getStatusString(item.status)) status.contentDescription = holder.status.context.getString(item.status.getString())
sender.text = item.from.toString() sender.text = item.from.toString()
subject.text = prepareMessageExtract(item.subject) subject.text = prepareMessageExtract(item.subject)
extract.text = prepareMessageExtract(item.text) extract.text = prepareMessageExtract(item.text)
@ -194,16 +198,18 @@ class SwipeableMessageAdapter : RecyclerView.Adapter<SwipeableMessageAdapter.Vie
@SuppressLint("SwitchIntDef") @SuppressLint("SwitchIntDef")
override fun onSetSwipeBackground(holder: ViewHolder, position: Int, type: Int) = override fun onSetSwipeBackground(holder: ViewHolder, position: Int, type: Int) =
holder.itemView.setBackgroundResource(when (type) { holder.itemView.setBackgroundResource(
DRAWABLE_SWIPE_NEUTRAL_BACKGROUND -> R.drawable.bg_swipe_item_neutral when (type) {
DRAWABLE_SWIPE_LEFT_BACKGROUND -> R.drawable.bg_swipe_item_left DRAWABLE_SWIPE_NEUTRAL_BACKGROUND -> R.drawable.bg_swipe_item_neutral
DRAWABLE_SWIPE_RIGHT_BACKGROUND -> if (label === LABEL_ARCHIVE || label?.type == Label.Type.TRASH) { DRAWABLE_SWIPE_LEFT_BACKGROUND -> R.drawable.bg_swipe_item_left
R.drawable.bg_swipe_item_neutral DRAWABLE_SWIPE_RIGHT_BACKGROUND -> if (label === LABEL_ARCHIVE || label?.type == Label.Type.TRASH) {
} else { R.drawable.bg_swipe_item_neutral
R.drawable.bg_swipe_item_right } else {
R.drawable.bg_swipe_item_right
}
else -> R.drawable.bg_swipe_item_neutral
} }
else -> R.drawable.bg_swipe_item_neutral )
})
@SuppressLint("SwitchIntDef") @SuppressLint("SwitchIntDef")
override fun onSwipeItem(holder: ViewHolder, position: Int, result: Int) = override fun onSwipeItem(holder: ViewHolder, position: Int, result: Int) =
@ -222,7 +228,10 @@ class SwipeableMessageAdapter : RecyclerView.Adapter<SwipeableMessageAdapter.Vie
notifyItemChanged(selectedPosition) notifyItemChanged(selectedPosition)
} }
private class SwipeLeftResultAction internal constructor(adapter: SwipeableMessageAdapter, position: Int) : SwipeResultActionMoveToSwipedDirection() { private class SwipeLeftResultAction internal constructor(
adapter: SwipeableMessageAdapter,
position: Int
) : SwipeResultActionMoveToSwipedDirection() {
private var adapter: SwipeableMessageAdapter? = adapter private var adapter: SwipeableMessageAdapter? = adapter
private val item = adapter.data[position] private val item = adapter.data[position]
@ -235,7 +244,10 @@ class SwipeableMessageAdapter : RecyclerView.Adapter<SwipeableMessageAdapter.Vie
} }
} }
private class SwipeRightResultAction internal constructor(adapter: SwipeableMessageAdapter, position: Int) : SwipeResultActionRemoveItem() { private class SwipeRightResultAction internal constructor(
adapter: SwipeableMessageAdapter,
position: Int
) : SwipeResultActionRemoveItem() {
private var adapter: SwipeableMessageAdapter? = adapter private var adapter: SwipeableMessageAdapter? = adapter
private val item = adapter.data[position] private val item = adapter.data[position]

View File

@ -10,7 +10,7 @@ import android.view.WindowManager
import android.widget.ImageView import android.widget.ImageView
import android.widget.RelativeLayout import android.widget.RelativeLayout
import ch.dissem.apps.abit.service.Singleton import ch.dissem.apps.abit.service.Singleton
import ch.dissem.apps.abit.util.Drawables import ch.dissem.apps.abit.util.qrCode
import com.mikepenz.materialdrawer.AccountHeader import com.mikepenz.materialdrawer.AccountHeader
import com.mikepenz.materialdrawer.model.interfaces.IProfile import com.mikepenz.materialdrawer.model.interfaces.IProfile
@ -23,7 +23,7 @@ class ProfileImageListener(private val ctx: Context) : AccountHeader.OnAccountHe
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE) dialog.requestWindowFeature(Window.FEATURE_NO_TITLE)
val imageView = ImageView(ctx) val imageView = ImageView(ctx)
imageView.setImageBitmap(Drawables.qrCode(Singleton.getIdentity(ctx))) imageView.setImageBitmap(Singleton.getIdentity(ctx)?.qrCode())
imageView.setOnClickListener { dialog.dismiss() } imageView.setOnClickListener { dialog.dismiss() }
dialog.addContentView( dialog.addContentView(
imageView, imageView,

View File

@ -17,6 +17,7 @@
package ch.dissem.apps.abit.notification package ch.dissem.apps.abit.notification
import android.app.PendingIntent import android.app.PendingIntent
import android.app.PendingIntent.FLAG_UPDATE_CURRENT
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.graphics.Typeface import android.graphics.Typeface
@ -27,18 +28,15 @@ import android.text.Spannable
import android.text.SpannableString import android.text.SpannableString
import android.text.Spanned import android.text.Spanned
import android.text.style.StyleSpan import android.text.style.StyleSpan
import ch.dissem.apps.abit.Identicon import ch.dissem.apps.abit.Identicon
import ch.dissem.apps.abit.MainActivity import ch.dissem.apps.abit.MainActivity
import ch.dissem.apps.abit.R
import ch.dissem.apps.abit.service.BitmessageIntentService
import ch.dissem.bitmessage.entity.Plaintext
import android.app.PendingIntent.FLAG_UPDATE_CURRENT
import ch.dissem.apps.abit.MainActivity.Companion.EXTRA_REPLY_TO_MESSAGE import ch.dissem.apps.abit.MainActivity.Companion.EXTRA_REPLY_TO_MESSAGE
import ch.dissem.apps.abit.MainActivity.Companion.EXTRA_SHOW_MESSAGE import ch.dissem.apps.abit.MainActivity.Companion.EXTRA_SHOW_MESSAGE
import ch.dissem.apps.abit.R
import ch.dissem.apps.abit.service.BitmessageIntentService
import ch.dissem.apps.abit.service.BitmessageIntentService.Companion.EXTRA_DELETE_MESSAGE import ch.dissem.apps.abit.service.BitmessageIntentService.Companion.EXTRA_DELETE_MESSAGE
import ch.dissem.apps.abit.util.Drawables.toBitmap import ch.dissem.apps.abit.util.toBitmap
import ch.dissem.bitmessage.entity.Plaintext
class NewMessageNotification(ctx: Context) : AbstractNotification(ctx) { class NewMessageNotification(ctx: Context) : AbstractNotification(ctx) {
@ -53,7 +51,7 @@ class NewMessageNotification(ctx: Context) : AbstractNotification(ctx) {
bigText.setSpan(SPAN_EMPHASIS, 0, subject.length, Spanned.SPAN_INCLUSIVE_EXCLUSIVE) bigText.setSpan(SPAN_EMPHASIS, 0, subject.length, Spanned.SPAN_INCLUSIVE_EXCLUSIVE)
} }
builder.setSmallIcon(R.drawable.ic_notification_new_message) builder.setSmallIcon(R.drawable.ic_notification_new_message)
.setLargeIcon(toBitmap(Identicon(plaintext.from), 192)) .setLargeIcon(Identicon(plaintext.from).toBitmap(192))
.setContentTitle(plaintext.from.toString()) .setContentTitle(plaintext.from.toString())
.setContentText(plaintext.subject) .setContentText(plaintext.subject)
.setStyle(BigTextStyle().bigText(bigText)) .setStyle(BigTextStyle().bigText(bigText))

View File

@ -20,7 +20,7 @@ import android.content.ContentValues
import android.content.Context import android.content.Context
import android.database.Cursor import android.database.Cursor
import android.database.DatabaseUtils import android.database.DatabaseUtils
import ch.dissem.apps.abit.util.Labels import ch.dissem.apps.abit.util.getText
import ch.dissem.bitmessage.entity.valueobject.Label import ch.dissem.bitmessage.entity.valueobject.Label
import ch.dissem.bitmessage.ports.AbstractLabelRepository import ch.dissem.bitmessage.ports.AbstractLabelRepository
import ch.dissem.bitmessage.ports.MessageRepository import ch.dissem.bitmessage.ports.MessageRepository
@ -30,7 +30,8 @@ import java.util.*
/** /**
* [MessageRepository] implementation using the Android SQL API. * [MessageRepository] implementation using the Android SQL API.
*/ */
class AndroidLabelRepository(private val sql: SqlHelper, private val context: Context) : AbstractLabelRepository() { class AndroidLabelRepository(private val sql: SqlHelper, private val context: Context) :
AbstractLabelRepository() {
override fun find(where: String): List<Label> { override fun find(where: String): List<Label> {
val result = LinkedList<Label>() val result = LinkedList<Label>()
@ -62,7 +63,12 @@ class AndroidLabelRepository(private val sql: SqlHelper, private val context: Co
db.update(TABLE_NAME, values, "id=?", arrayOf(label.id.toString())) db.update(TABLE_NAME, values, "id=?", arrayOf(label.id.toString()))
} else { } else {
db.transaction { db.transaction {
val exists = DatabaseUtils.queryNumEntries(db, TABLE_NAME, "label=?", arrayOf(label.toString())) > 0 val exists = DatabaseUtils.queryNumEntries(
db,
TABLE_NAME,
"label=?",
arrayOf(label.toString())
) > 0
if (exists) { if (exists) {
val values = ContentValues() val values = ContentValues()
@ -82,7 +88,8 @@ class AndroidLabelRepository(private val sql: SqlHelper, private val context: Co
} }
} }
internal fun findLabels(msgId: Any) = find("id IN (SELECT label_id FROM Message_Label WHERE message_id=$msgId)") internal fun findLabels(msgId: Any) =
find("id IN (SELECT label_id FROM Message_Label WHERE message_id=$msgId)")
companion object { companion object {
val LABEL_ARCHIVE = Label("archive", null, 0).apply { id = Long.MAX_VALUE } val LABEL_ARCHIVE = Label("archive", null, 0).apply { id = Long.MAX_VALUE }
@ -97,11 +104,12 @@ class AndroidLabelRepository(private val sql: SqlHelper, private val context: Co
internal fun getLabel(c: Cursor, context: Context): Label { internal fun getLabel(c: Cursor, context: Context): Label {
val typeName = c.getString(c.getColumnIndex(COLUMN_TYPE)) val typeName = c.getString(c.getColumnIndex(COLUMN_TYPE))
val type = if (typeName == null) null else Label.Type.valueOf(typeName) val type = if (typeName == null) null else Label.Type.valueOf(typeName)
val text: String? = Labels.getText(type, null, context) val text: String? = type?.getText(null, context)
val label = Label( val label = Label(
text ?: c.getString(c.getColumnIndex(COLUMN_LABEL)), text ?: c.getString(c.getColumnIndex(COLUMN_LABEL)),
type, type,
c.getInt(c.getColumnIndex(COLUMN_COLOR))) c.getInt(c.getColumnIndex(COLUMN_COLOR))
)
label.id = c.getLong(c.getColumnIndex(COLUMN_ID)) label.id = c.getLong(c.getColumnIndex(COLUMN_ID))
return label return label
} }

View File

@ -43,28 +43,25 @@ object Assets {
} catch (e: IOException) { } catch (e: IOException) {
throw RuntimeException(e) throw RuntimeException(e)
} }
}
@DrawableRes
fun getStatusDrawable(status: Plaintext.Status) = when (status) {
Plaintext.Status.RECEIVED -> 0
Plaintext.Status.DRAFT -> R.drawable.draft
Plaintext.Status.PUBKEY_REQUESTED -> R.drawable.public_key
Plaintext.Status.DOING_PROOF_OF_WORK -> R.drawable.ic_notification_proof_of_work
Plaintext.Status.SENT -> R.drawable.sent
Plaintext.Status.SENT_ACKNOWLEDGED -> R.drawable.sent_acknowledged
else -> 0
}
@StringRes
fun getStatusString(status: Plaintext.Status) = when (status) {
Plaintext.Status.RECEIVED -> R.string.status_received
Plaintext.Status.DRAFT -> R.string.status_draft
Plaintext.Status.PUBKEY_REQUESTED -> R.string.status_public_key
Plaintext.Status.DOING_PROOF_OF_WORK -> R.string.proof_of_work_title
Plaintext.Status.SENT -> R.string.status_sent
Plaintext.Status.SENT_ACKNOWLEDGED -> R.string.status_sent_acknowledged
else -> 0
} }
} }
fun Plaintext.Status.getDrawable() = when (this) {
Plaintext.Status.RECEIVED -> 0
Plaintext.Status.DRAFT -> R.drawable.draft
Plaintext.Status.PUBKEY_REQUESTED -> R.drawable.public_key
Plaintext.Status.DOING_PROOF_OF_WORK -> R.drawable.ic_notification_proof_of_work
Plaintext.Status.SENT -> R.drawable.sent
Plaintext.Status.SENT_ACKNOWLEDGED -> R.drawable.sent_acknowledged
else -> 0
}
fun Plaintext.Status.getString() = when (this) {
Plaintext.Status.RECEIVED -> R.string.status_received
Plaintext.Status.DRAFT -> R.string.status_draft
Plaintext.Status.PUBKEY_REQUESTED -> R.string.status_public_key
Plaintext.Status.DOING_PROOF_OF_WORK -> R.string.proof_of_work_title
Plaintext.Status.SENT -> R.string.status_sent
Plaintext.Status.SENT_ACKNOWLEDGED -> R.string.status_sent_acknowledged
else -> 0
}

View File

@ -21,13 +21,14 @@ import android.graphics.Bitmap
import android.graphics.Canvas import android.graphics.Canvas
import android.graphics.Color.BLACK import android.graphics.Color.BLACK
import android.graphics.Color.WHITE import android.graphics.Color.WHITE
import android.graphics.drawable.Drawable
import android.util.Base64 import android.util.Base64
import android.util.Base64.NO_WRAP import android.util.Base64.NO_WRAP
import android.util.Base64.URL_SAFE import android.util.Base64.URL_SAFE
import android.view.Menu import android.view.Menu
import android.view.MenuItem import android.view.MenuItem
import ch.dissem.apps.abit.Identicon
import ch.dissem.apps.abit.R import ch.dissem.apps.abit.R
import ch.dissem.apps.abit.util.Drawables.QR_CODE_SIZE
import ch.dissem.bitmessage.entity.BitmessageAddress import ch.dissem.bitmessage.entity.BitmessageAddress
import com.google.zxing.BarcodeFormat import com.google.zxing.BarcodeFormat
import com.google.zxing.MultiFormatWriter import com.google.zxing.MultiFormatWriter
@ -42,61 +43,61 @@ import java.io.ByteArrayOutputStream
* Some helper methods to work with drawables. * Some helper methods to work with drawables.
*/ */
object Drawables { object Drawables {
private val LOG = LoggerFactory.getLogger(Drawables::class.java) internal val LOG = LoggerFactory.getLogger(Drawables::class.java)
private const val QR_CODE_SIZE = 350 internal const val QR_CODE_SIZE = 350
fun addIcon(ctx: Context, menu: Menu, menuItem: Int, icon: IIcon): MenuItem { fun addIcon(ctx: Context, menu: Menu, menuItem: Int, icon: IIcon): MenuItem {
val item = menu.findItem(menuItem) val item = menu.findItem(menuItem)
item.icon = IconicsDrawable(ctx, icon).colorRes(R.color.colorPrimaryDarkText).actionBar() item.icon = IconicsDrawable(ctx, icon).colorRes(R.color.colorPrimaryDarkText).actionBar()
return item return item
} }
}
fun toBitmap(identicon: Identicon, width: Int, height: Int = width): Bitmap {
val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888) fun Drawable.toBitmap(width: Int, height: Int = width): Bitmap {
val canvas = Canvas(bitmap) val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
identicon.setBounds(0, 0, canvas.width, canvas.height) val canvas = Canvas(bitmap)
identicon.draw(canvas) setBounds(0, 0, canvas.width, canvas.height)
return bitmap draw(canvas)
} return bitmap
}
fun qrCode(address: BitmessageAddress?): Bitmap? {
if (address == null) { fun BitmessageAddress.qrCode(): Bitmap? {
return null val link = StringBuilder()
} link.append(Constants.BITMESSAGE_URL_SCHEMA)
val link = StringBuilder() link.append(address)
link.append(Constants.BITMESSAGE_URL_SCHEMA) if (alias != null) {
link.append(address.address) link.append("?label=").append(alias)
if (address.alias != null) { }
link.append("?label=").append(address.alias) pubkey?.apply {
} link.append(if (alias == null) '?' else '&')
address.pubkey?.apply { val pubkey = ByteArrayOutputStream()
link.append(if (address.alias == null) '?' else '&') writer().writeUnencrypted(pubkey)
val pubkey = ByteArrayOutputStream() link.append("pubkey=")
writer().writeUnencrypted(pubkey) .append(Base64.encodeToString(pubkey.toByteArray(), URL_SAFE or NO_WRAP))
link.append("pubkey=").append(Base64.encodeToString(pubkey.toByteArray(), URL_SAFE or NO_WRAP))
}
} val result: BitMatrix
val result: BitMatrix try {
try { result = MultiFormatWriter().encode(
result = MultiFormatWriter().encode(link.toString(), link.toString(),
BarcodeFormat.QR_CODE, QR_CODE_SIZE, QR_CODE_SIZE, null) BarcodeFormat.QR_CODE, QR_CODE_SIZE, QR_CODE_SIZE, null
} catch (e: WriterException) { )
LOG.error(e.message, e) } catch (e: WriterException) {
return null Drawables.LOG.error(e.message, e)
} return null
}
val w = result.width
val h = result.height val w = result.width
val pixels = IntArray(w * h) val h = result.height
for (y in 0 until h) { val pixels = IntArray(w * h)
val offset = y * w for (y in 0 until h) {
for (x in 0 until w) { val offset = y * w
pixels[offset + x] = if (result.get(x, y)) BLACK else WHITE for (x in 0 until w) {
} pixels[offset + x] = if (result.get(x, y)) BLACK else WHITE
} }
val bitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888) }
bitmap.setPixels(pixels, 0, QR_CODE_SIZE, 0, 0, w, h) val bitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888)
return bitmap bitmap.setPixels(pixels, 0, QR_CODE_SIZE, 0, 0, w, h)
} return bitmap
} }

View File

@ -1,31 +0,0 @@
package ch.dissem.apps.abit.util
import android.support.annotation.DrawableRes
import ch.dissem.apps.abit.MainActivity
import ch.dissem.apps.abit.R
import io.github.kobakei.materialfabspeeddial.FabSpeedDial
import io.github.kobakei.materialfabspeeddial.FabSpeedDialMenu
/**
* Utilities to work with the common floating action button in the main activity
*/
object FabUtils {
fun initFab(activity: MainActivity, @DrawableRes drawableRes: Int, menu: FabSpeedDialMenu): FabSpeedDial {
val fab = activity.floatingActionButton ?: throw IllegalStateException("Fab must not be null")
fab.removeAllOnMenuItemClickListeners()
fab.show()
fab.closeMenu()
val mainFab = fab.mainFab
mainFab.setImageResource(drawableRes)
fab.setMenu(menu)
fab.addOnStateChangeListener { isOpened: Boolean ->
if (isOpened) {
// It will be turned 45 degrees, which makes an x out of the +
mainFab.setImageResource(R.drawable.ic_action_add)
} else {
mainFab.setImageResource(drawableRes)
}
}
return fab
}
}

View File

@ -2,31 +2,27 @@ package ch.dissem.apps.abit.util
import android.content.Context import android.content.Context
import android.support.annotation.ColorInt import android.support.annotation.ColorInt
import ch.dissem.apps.abit.R
import ch.dissem.bitmessage.entity.valueobject.Label
import com.mikepenz.community_material_typeface_library.CommunityMaterial import com.mikepenz.community_material_typeface_library.CommunityMaterial
import com.mikepenz.google_material_typeface_library.GoogleMaterial import com.mikepenz.google_material_typeface_library.GoogleMaterial
import com.mikepenz.iconics.typeface.IIcon import com.mikepenz.iconics.typeface.IIcon
import ch.dissem.apps.abit.R
import ch.dissem.bitmessage.entity.valueobject.Label
/* /*
* Helper methods to help with translating the default labels, getting label colors and so on. * Helper methods to help with translating the default labels, getting label colors and so on.
*/ */
fun Label.getText(ctx: Context): String = Labels.getText(type, toString(), ctx)!! fun Label.getText(ctx: Context): String = type?.getText(toString(), ctx) ?: toString()
object Labels { fun Label.Type.getText(alternative: String?, ctx: Context) = when (this) {
fun getText(type: Label.Type?, alternative: String?, ctx: Context) = when (type) { Label.Type.INBOX -> ctx.getString(R.string.inbox)
Label.Type.INBOX -> ctx.getString(R.string.inbox) Label.Type.DRAFT -> ctx.getString(R.string.draft)
Label.Type.DRAFT -> ctx.getString(R.string.draft) Label.Type.OUTBOX -> ctx.getString(R.string.outbox)
Label.Type.OUTBOX -> ctx.getString(R.string.outbox) Label.Type.SENT -> ctx.getString(R.string.sent)
Label.Type.SENT -> ctx.getString(R.string.sent) Label.Type.UNREAD -> ctx.getString(R.string.unread)
Label.Type.UNREAD -> ctx.getString(R.string.unread) Label.Type.TRASH -> ctx.getString(R.string.trash)
Label.Type.TRASH -> ctx.getString(R.string.trash) Label.Type.BROADCAST -> ctx.getString(R.string.broadcasts)
Label.Type.BROADCAST -> ctx.getString(R.string.broadcasts) else -> alternative
else -> alternative
}
} }
fun Label.getIcon(): IIcon = when (type) { fun Label.getIcon(): IIcon = when (type) {

View File

@ -23,7 +23,7 @@ object PowStats {
powCount = preferences.getLong(PREFERENCE_POW_COUNT, 0L) powCount = preferences.getLong(PREFERENCE_POW_COUNT, 0L)
} }
} }
return (BigInteger.valueOf(averagePowUnitTime) * BigInteger(target) / TWO_POW_64).toLong() return (averagePowUnitTime * BigInteger(target) / TWO_POW_64).toLong()
} }
fun addPow(ctx: Context, time: Long, target: ByteArray) { fun addPow(ctx: Context, time: Long, target: ByteArray) {
@ -32,7 +32,7 @@ object PowStats {
synchronized(this) { synchronized(this) {
powCount++ powCount++
averagePowUnitTime = ( averagePowUnitTime = (
(BigInteger.valueOf(averagePowUnitTime) * powCountBefore + (BigInteger.valueOf(time) * TWO_POW_64 / targetBigInt)) / BigInteger.valueOf(powCount) (averagePowUnitTime * powCountBefore + (time * TWO_POW_64 / targetBigInt)) / powCount
).toLong() ).toLong()
val preferences = PreferenceManager.getDefaultSharedPreferences(ctx) val preferences = PreferenceManager.getDefaultSharedPreferences(ctx)
@ -42,4 +42,7 @@ object PowStats {
.apply() .apply()
} }
} }
private operator fun Long.times(other: BigInteger) = this.toBigInteger() * other
private operator fun BigInteger.div(other: Long) = this / other.toBigInteger()
} }