Fully migrated to Kotlin
This commit is contained in:
292
app/src/main/java/ch/dissem/apps/abit/MessageDetailFragment.kt
Normal file
292
app/src/main/java/ch/dissem/apps/abit/MessageDetailFragment.kt
Normal file
@@ -0,0 +1,292 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
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 android.text.util.Linkify
|
||||
import android.view.LayoutInflater
|
||||
import android.view.Menu
|
||||
import android.view.MenuInflater
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
|
||||
import com.mikepenz.google_material_typeface_library.GoogleMaterial
|
||||
import com.mikepenz.iconics.view.IconicsImageView
|
||||
|
||||
import java.util.ArrayList
|
||||
|
||||
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.Labels
|
||||
import ch.dissem.bitmessage.entity.Plaintext
|
||||
import ch.dissem.bitmessage.entity.valueobject.Label
|
||||
|
||||
import android.text.util.Linkify.WEB_URLS
|
||||
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.Strings.prepareMessageExtract
|
||||
import kotlinx.android.synthetic.main.fragment_message_detail.*
|
||||
|
||||
/**
|
||||
* A fragment representing a single Message detail screen.
|
||||
* This fragment is either contained in a [MainActivity]
|
||||
* in two-pane mode (on tablets) or a [MessageDetailActivity]
|
||||
* on handsets.
|
||||
*/
|
||||
class MessageDetailFragment : Fragment() {
|
||||
|
||||
/**
|
||||
* The content this fragment is presenting.
|
||||
*/
|
||||
private var item: Plaintext? = null
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
if (arguments.containsKey(ARG_ITEM)) {
|
||||
// Load the dummy content specified by the fragment
|
||||
// arguments. In a real-world scenario, use a Loader
|
||||
// to load content from a content provider.
|
||||
item = arguments.getSerializable(ARG_ITEM) as Plaintext
|
||||
}
|
||||
setHasOptionsMenu(true)
|
||||
}
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View =
|
||||
inflater.inflate(R.layout.fragment_message_detail, container, false)
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
// Show the dummy content as text in a TextView.
|
||||
item?.let { item ->
|
||||
subject.text = item.subject
|
||||
status.setImageResource(Assets.getStatusDrawable(item.status))
|
||||
status.contentDescription = getString(Assets.getStatusString(item.status))
|
||||
avatar.setImageDrawable(Identicon(item.from))
|
||||
sender.text = item.from.toString()
|
||||
item.to?.let { to ->
|
||||
recipient.text = to.toString()
|
||||
} ?: {
|
||||
if (item.type == Plaintext.Type.BROADCAST) {
|
||||
recipient.setText(R.string.broadcast)
|
||||
}
|
||||
}.invoke()
|
||||
val labelAdapter = LabelAdapter(activity, item.labels)
|
||||
labels.adapter = labelAdapter
|
||||
labels.layoutManager = GridLayoutManager(activity, 2)
|
||||
|
||||
text.text = item.text
|
||||
|
||||
Linkify.addLinks(text, WEB_URLS)
|
||||
Linkify.addLinks(text, BITMESSAGE_ADDRESS_PATTERN, BITMESSAGE_URL_SCHEMA, null,
|
||||
Linkify.TransformFilter { match, _ -> match.group() }
|
||||
)
|
||||
|
||||
text.linksClickable = true
|
||||
text.setTextIsSelectable(true)
|
||||
|
||||
var removed = false
|
||||
val labels = item.labels.iterator()
|
||||
while (labels.hasNext()) {
|
||||
if (labels.next().type == Label.Type.UNREAD) {
|
||||
labels.remove()
|
||||
removed = true
|
||||
}
|
||||
}
|
||||
val messageRepo = Singleton.getMessageRepository(context)
|
||||
if (removed) {
|
||||
if (activity is MainActivity) {
|
||||
(activity as MainActivity).updateUnread()
|
||||
}
|
||||
messageRepo.save(item)
|
||||
}
|
||||
val parents = ArrayList<Plaintext>(item.parents.size)
|
||||
for (parentIV in item.parents) {
|
||||
val parent = messageRepo.getMessage(parentIV)
|
||||
if (parent != null) {
|
||||
parents.add(parent)
|
||||
}
|
||||
}
|
||||
showRelatedMessages(view, R.id.parents, parents)
|
||||
showRelatedMessages(view, R.id.responses, messageRepo.findResponses(item))
|
||||
}
|
||||
}
|
||||
|
||||
private fun showRelatedMessages(rootView: View, @IdRes id: Int, messages: List<Plaintext>) {
|
||||
val recyclerView = rootView.findViewById(id) as RecyclerView
|
||||
val adapter = RelatedMessageAdapter(activity, messages)
|
||||
recyclerView.adapter = adapter
|
||||
recyclerView.layoutManager = LinearLayoutManager(activity)
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater?) {
|
||||
inflater!!.inflate(R.menu.message, menu)
|
||||
|
||||
Drawables.addIcon(activity, menu, R.id.reply, GoogleMaterial.Icon.gmd_reply)
|
||||
Drawables.addIcon(activity, menu, R.id.delete, GoogleMaterial.Icon.gmd_delete)
|
||||
Drawables.addIcon(activity, menu, R.id.mark_unread, GoogleMaterial.Icon
|
||||
.gmd_markunread)
|
||||
Drawables.addIcon(activity, menu, R.id.archive, GoogleMaterial.Icon.gmd_archive)
|
||||
|
||||
super.onCreateOptionsMenu(menu, inflater)
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(menuItem: MenuItem): Boolean {
|
||||
val messageRepo = Singleton.getMessageRepository(context)
|
||||
item?.let { item ->
|
||||
when (menuItem.itemId) {
|
||||
R.id.reply -> {
|
||||
ComposeMessageActivity.launchReplyTo(this, item)
|
||||
return true
|
||||
}
|
||||
R.id.delete -> {
|
||||
if (isInTrash(item)) {
|
||||
messageRepo.remove(item)
|
||||
} else {
|
||||
item.labels.clear()
|
||||
item.addLabels(messageRepo.getLabels(Label.Type.TRASH))
|
||||
messageRepo.save(item)
|
||||
}
|
||||
activity.onBackPressed()
|
||||
return true
|
||||
}
|
||||
R.id.mark_unread -> {
|
||||
item.addLabels(messageRepo.getLabels(Label.Type.UNREAD))
|
||||
messageRepo.save(item)
|
||||
if (activity is MainActivity) {
|
||||
(activity as MainActivity).updateUnread()
|
||||
}
|
||||
return true
|
||||
}
|
||||
R.id.archive -> {
|
||||
if (item.isUnread() && activity is MainActivity) {
|
||||
(activity as MainActivity).updateUnread()
|
||||
}
|
||||
item.labels.clear()
|
||||
messageRepo.save(item)
|
||||
return true
|
||||
}
|
||||
else -> return false
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
private class RelatedMessageAdapter internal constructor(private val ctx: Context, private val messages: List<Plaintext>) : RecyclerView.Adapter<RelatedMessageAdapter.ViewHolder>() {
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RelatedMessageAdapter.ViewHolder {
|
||||
val context = parent.context
|
||||
val inflater = LayoutInflater.from(context)
|
||||
|
||||
// Inflate the custom layout
|
||||
val contactView = inflater.inflate(R.layout.item_message_minimized, parent, false)
|
||||
|
||||
// Return a new holder instance
|
||||
return ViewHolder(contactView)
|
||||
}
|
||||
|
||||
// Involves populating data into the item through holder
|
||||
override fun onBindViewHolder(viewHolder: RelatedMessageAdapter.ViewHolder, position: Int) {
|
||||
// Get the data model based on position
|
||||
val message = messages[position]
|
||||
|
||||
viewHolder.avatar.setImageDrawable(Identicon(message.from))
|
||||
viewHolder.status.setImageResource(Assets.getStatusDrawable(message.status))
|
||||
viewHolder.sender.text = message.from.toString()
|
||||
viewHolder.extract.text = prepareMessageExtract(message.text)
|
||||
viewHolder.item = message
|
||||
}
|
||||
|
||||
// Returns the total count of items in the list
|
||||
override fun getItemCount() = messages.size
|
||||
|
||||
internal inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
|
||||
internal val avatar = itemView.findViewById(R.id.avatar) as ImageView
|
||||
internal val status = itemView.findViewById(R.id.status) as ImageView
|
||||
internal val sender = itemView.findViewById(R.id.sender) as TextView
|
||||
internal val extract = itemView.findViewById(R.id.text) as TextView
|
||||
internal var item: Plaintext? = null
|
||||
|
||||
init {
|
||||
itemView.setOnClickListener {
|
||||
if (ctx is MainActivity) {
|
||||
item?.let { ctx.onItemSelected(it) }
|
||||
} else {
|
||||
val detailIntent = Intent(ctx, MessageDetailActivity::class.java)
|
||||
detailIntent.putExtra(MessageDetailFragment.ARG_ITEM, item)
|
||||
ctx.startActivity(detailIntent)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class LabelAdapter internal constructor(private val ctx: Context, labels: Set<Label>) : RecyclerView.Adapter<LabelAdapter.ViewHolder>() {
|
||||
|
||||
private val labels = labels.toMutableList()
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): LabelAdapter.ViewHolder {
|
||||
val context = parent.context
|
||||
val inflater = LayoutInflater.from(context)
|
||||
|
||||
// Inflate the custom layout
|
||||
val contactView = inflater.inflate(R.layout.item_label, parent, false)
|
||||
|
||||
// Return a new holder instance
|
||||
return ViewHolder(contactView)
|
||||
}
|
||||
|
||||
// Involves populating data into the item through holder
|
||||
override fun onBindViewHolder(viewHolder: LabelAdapter.ViewHolder, position: Int) {
|
||||
// Get the data model based on position
|
||||
val label = labels[position]
|
||||
|
||||
viewHolder.icon.setColor(Labels.getColor(label))
|
||||
viewHolder.icon.setIcon(Labels.getIcon(label))
|
||||
viewHolder.label.text = Labels.getText(label, ctx)
|
||||
}
|
||||
|
||||
override fun getItemCount() = labels.size
|
||||
|
||||
internal class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
|
||||
var icon = itemView.findViewById(R.id.icon) as IconicsImageView
|
||||
var label = itemView.findViewById(R.id.label) as TextView
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
/**
|
||||
* The fragment argument representing the item ID that this fragment
|
||||
* represents.
|
||||
*/
|
||||
val ARG_ITEM = "item"
|
||||
|
||||
fun isInTrash(item: Plaintext?) = item?.labels?.any { it.type == Label.Type.TRASH } ?: false
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user