Skip to content

Commit

Permalink
Added RecipientDetailsFragment.| #1566
Browse files Browse the repository at this point in the history
  • Loading branch information
DenBond7 committed Nov 19, 2021
1 parent 57bddc7 commit 4676fc2
Show file tree
Hide file tree
Showing 11 changed files with 493 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ interface PubKeyDao : BaseDao<PublicKeyEntity> {
@Query("SELECT * FROM public_keys WHERE recipient = :recipient")
suspend fun getPublicKeysByRecipient(recipient: String): List<PublicKeyEntity>

@Query("SELECT * FROM public_keys WHERE recipient = :recipient")
fun getPublicKeysByRecipientFlow(recipient: String): Flow<List<PublicKeyEntity>>

@Query("SELECT * FROM public_keys WHERE fingerprint = :fingerprint")
suspend fun getPublicKeysByFingerprint(fingerprint: String): List<PublicKeyEntity>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,12 @@ class CachedPubKeysKeysViewModel(application: Application) : AccountViewModel(ap
val filteredList = fullList.filter {
(it.recipient + it.fingerprint) in setOfRecipientsAndFingerprintsStateFlow.value
}
filteredList.forEach {
withContext(Dispatchers.IO) {
val result = PgpKey.parseKeys(it.publicKey, false).pgpKeyDetailsList
it.pgpKeyDetails = result.firstOrNull()
}
}
emit(filteredList.associateBy({ it.recipient + it.fingerprint }, { it }))
}
}.stateIn(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* © 2016-present FlowCrypt a.s. Limitations apply. Contact [email protected]
* Contributors: DenBond7
*/

package com.flowcrypt.email.jetpack.viewmodel

import android.app.Application
import androidx.lifecycle.viewModelScope
import com.flowcrypt.email.database.entity.PublicKeyEntity
import com.flowcrypt.email.database.entity.RecipientEntity
import com.flowcrypt.email.security.pgp.PgpKey
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.mapLatest
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.withContext

/**
* @author Denis Bondarenko
* Date: 11/19/21
* Time: 2:04 PM
* E-mail: [email protected]
*/
class RecipientDetailsViewModel(
recipientEntity: RecipientEntity, application: Application
) : AccountViewModel(application) {
private val pureRecipientPubKeysFlow =
roomDatabase.pubKeyDao().getPublicKeysByRecipientFlow(recipientEntity.email)

val recipientPubKeysFlow: StateFlow<List<PublicKeyEntity>> =
pureRecipientPubKeysFlow.mapLatest { fullList ->
fullList.forEach {
withContext(Dispatchers.IO) {
it.pgpKeyDetails = try {
PgpKey.parseKeys(it.publicKey, false).pgpKeyDetailsList.firstOrNull()
} catch (e: Exception) {
e.printStackTrace()
null
}
}
}

fullList
}.stateIn(
scope = viewModelScope,
started = SharingStarted.WhileSubscribed(5000),
initialValue = emptyList()
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
/*
* © 2016-present FlowCrypt a.s. Limitations apply. Contact [email protected]
* Contributors: DenBond7
*/

package com.flowcrypt.email.ui.activity.fragment

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.viewModels
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import androidx.navigation.fragment.navArgs
import androidx.recyclerview.widget.LinearLayoutManager
import com.flowcrypt.email.R
import com.flowcrypt.email.database.entity.PublicKeyEntity
import com.flowcrypt.email.databinding.FragmentRecipientDetailsBinding
import com.flowcrypt.email.extensions.navController
import com.flowcrypt.email.jetpack.viewmodel.RecipientDetailsViewModel
import com.flowcrypt.email.ui.activity.fragment.base.BaseFragment
import com.flowcrypt.email.ui.activity.fragment.base.ListProgressBehaviour
import com.flowcrypt.email.ui.adapter.PubKeysRecyclerViewAdapter
import kotlinx.coroutines.flow.collect

/**
* @author Denis Bondarenko
* Date: 11/19/21
* Time: 1:03 PM
* E-mail: [email protected]
*/
class RecipientDetailsFragment : BaseFragment(), ListProgressBehaviour {
private val args by navArgs<RecipientDetailsFragmentArgs>()
private var binding: FragmentRecipientDetailsBinding? = null
private val recipientDetailsViewModel: RecipientDetailsViewModel by viewModels {
object : ViewModelProvider.AndroidViewModelFactory(requireActivity().application) {
@Suppress("UNCHECKED_CAST")
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
return RecipientDetailsViewModel(args.recipientEntity, requireActivity().application) as T
}
}
}
override val contentResourceId: Int = R.layout.fragment_recipient_details

override val emptyView: View?
get() = binding?.empty?.root
override val progressView: View?
get() = binding?.progress?.root
override val contentView: View?
get() = binding?.rVPubKeys
override val statusView: View?
get() = binding?.status?.root

private val pubKeysRecyclerViewAdapter = PubKeysRecyclerViewAdapter(
object : PubKeysRecyclerViewAdapter.OnPubKeyActionsListener {
override fun onPubKeyClick(publicKeyEntity: PublicKeyEntity) {
navController?.navigate(
RecipientDetailsFragmentDirections
.actionRecipientDetailsFragmentToPublicKeyDetailsFragment(args.recipientEntity)
)
}
})

override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
): View? {
binding = FragmentRecipientDetailsBinding.inflate(inflater, container, false)
return binding?.root
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
supportActionBar?.setTitle(R.string.recipient_detail)
initViews()
setupRecipientDetailsViewModel()
}

private fun setupRecipientDetailsViewModel() {
lifecycleScope.launchWhenStarted {
recipientDetailsViewModel.recipientPubKeysFlow.collect {
if (it.isNullOrEmpty()) {
showEmptyView()
} else {
pubKeysRecyclerViewAdapter.submitList(it)
showContent()
}
}
}
}

private fun initViews() {
binding?.tVName?.text = args.recipientEntity.name ?: "..."
binding?.tVEmail?.text = args.recipientEntity.email

binding?.rVPubKeys?.apply {
setHasFixedSize(true)
val manager = LinearLayoutManager(context)
layoutManager = manager
adapter = pubKeysRecyclerViewAdapter
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ class RecipientsListFragment : BaseFragment(), ListProgressBehaviour {
override fun onRecipientClick(recipientEntity: RecipientEntity) {
navController?.navigate(
RecipientsListFragmentDirections
.actionRecipientsListFragmentToPublicKeyDetailsFragment(recipientEntity)
.actionRecipientsListFragmentToRecipientDetailsFragment(recipientEntity)
)
}
})
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/*
* © 2016-present FlowCrypt a.s. Limitations apply. Contact [email protected]
* Contributors: DenBond7
*/

package com.flowcrypt.email.ui.adapter

import android.text.format.DateFormat
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import com.flowcrypt.email.R
import com.flowcrypt.email.database.entity.PublicKeyEntity
import com.flowcrypt.email.util.GeneralUtil
import java.util.Date

/**
* @author Denis Bondarenko
* Date: 11/19/21
* Time: 1:50 PM
* E-mail: [email protected]
*/
class PubKeysRecyclerViewAdapter(private val onPubKeyActionsListener: OnPubKeyActionsListener) :
ListAdapter<PublicKeyEntity, PubKeysRecyclerViewAdapter.ViewHolder>(DiffUtilCallBack()) {

private var dateFormat: java.text.DateFormat? = null

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view =
LayoutInflater.from(parent.context).inflate(R.layout.public_key_item, parent, false)
return ViewHolder(view)
}

override fun onBindViewHolder(holder: ViewHolder, position: Int) {
if (dateFormat == null) {
dateFormat = DateFormat.getMediumDateFormat(holder.itemView.context)
}

getItem(position)?.let { holder.bind(it, onPubKeyActionsListener) }
}

inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
private val tVPrimaryUser: TextView = itemView.findViewById(R.id.tVPrimaryUser)
private val tVFingerprint: TextView = itemView.findViewById(R.id.tVFingerprint)
private val tVCreationDate: TextView = itemView.findViewById(R.id.tVCreationDate)

fun bind(
publicKeyEntity: PublicKeyEntity,
onPubKeyActionsListener: OnPubKeyActionsListener?
) {
tVPrimaryUser.text = publicKeyEntity.pgpKeyDetails?.getUserIdsAsSingleString()
tVFingerprint.text = GeneralUtil.doSectionsInText(
originalString = publicKeyEntity.fingerprint, groupSize = 4
)

val timestamp = publicKeyEntity.pgpKeyDetails?.created ?: 0
if (timestamp != -1L) {
tVCreationDate.text = dateFormat?.format(Date(timestamp))
} else {
tVCreationDate.text = null
}

itemView.setOnClickListener {
onPubKeyActionsListener?.onPubKeyClick(publicKeyEntity)
}
}
}

interface OnPubKeyActionsListener {
fun onPubKeyClick(publicKeyEntity: PublicKeyEntity)
}

class DiffUtilCallBack : DiffUtil.ItemCallback<PublicKeyEntity>() {
override fun areItemsTheSame(oldItem: PublicKeyEntity, newItem: PublicKeyEntity) =
oldItem.recipient == newItem.recipient && oldItem.fingerprint == newItem.fingerprint

override fun areContentsTheSame(oldItem: PublicKeyEntity, newItem: PublicKeyEntity) =
oldItem == newItem
}
}
15 changes: 15 additions & 0 deletions FlowCrypt/src/main/res/drawable/ic_baseline_person_green_24.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<!--
~ © 2016-present FlowCrypt a.s. Limitations apply. Contact [email protected]
~ Contributors: DenBond7
-->

<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="@color/colorPrimary"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M12,12c2.21,0 4,-1.79 4,-4s-1.79,-4 -4,-4 -4,1.79 -4,4 1.79,4 4,4zM12,14c-2.67,0 -8,1.34 -8,4v2h16v-2c0,-2.66 -5.33,-4 -8,-4z" />
</vector>
Loading

0 comments on commit 4676fc2

Please sign in to comment.