Commit 246b10ea authored by Adrien Béraud's avatar Adrien Béraud
Browse files

requests: use new swarm APIs

Change-Id: I703eadb58d7bf33cd61492b2268d00ad246f8525
parent 8bd4a150
......@@ -240,6 +240,14 @@ class ContactDetailsActivity : AppCompatActivity() {
return
}
JamiApplication.instance?.startDaemon()
val conversation = try {
mConversationFacade
.startConversation(path.accountId, path.conversationUri)
.blockingGet()
} catch (e: Throwable) {
finish()
return
}
binding = ActivityContactDetailsBinding.inflate(layoutInflater)
setContentView(binding!!.root)
//JamiApplication.getInstance().getInjectionComponent().inject(this);
......@@ -254,17 +262,12 @@ class ContactDetailsActivity : AppCompatActivity() {
//fab.setOnClickListener(view -> goToConversationActivity(mConversation.getAccountId(), mConversation.getUri()));
colorActionPosition = 0
symbolActionPosition = 1
val conversation = mConversationFacade
.startConversation(path.accountId, path.conversationUri)
.blockingGet()
val preferences = getConversationPreferences(this, conversation.accountId, conversation.uri)
binding!!.contactImage.setImageDrawable(
AvatarDrawable.Builder()
.withConversation(conversation)
.withPresence(false)
.withCircleCrop(true)
.build(this)
)
binding!!.contactImage.setImageDrawable(AvatarDrawable.Builder()
.withConversation(conversation)
.withPresence(false)
.withCircleCrop(true)
.build(this))
/*Map<String, String> details = Ringservice.getCertificateDetails(conversation.getContact().getUri().getRawRingId());
for (Map.Entry<String, String> e : details.entrySet()) {
......
......@@ -56,7 +56,7 @@ class ConversationActivity : AppCompatActivity(), Colorable {
finish()
return
}
conversationPath = path;
conversationPath = path
val isBubble = getIntent().getBooleanExtra(NotificationServiceImpl.EXTRA_BUBBLE, false)
JamiApplication.instance?.startDaemon()
val binding = ActivityConversationBinding.inflate(layoutInflater)
......@@ -66,10 +66,11 @@ class ConversationActivity : AppCompatActivity(), Colorable {
ab?.setDisplayHomeAsUpEnabled(true)
binding.contactImage.setOnClickListener { v: View? -> if (mConversationFragment != null) mConversationFragment!!.openContact() }
if (mConversationFragment == null) {
val bundle = conversationPath.toBundle()
bundle.putBoolean(NotificationServiceImpl.EXTRA_BUBBLE, isBubble)
mConversationFragment = ConversationFragment()
mConversationFragment!!.arguments = bundle
mConversationFragment = ConversationFragment().apply {
arguments = conversationPath.toBundle().apply {
putBoolean(NotificationServiceImpl.EXTRA_BUBBLE, isBubble)
}
}
supportFragmentManager.beginTransaction()
.replace(R.id.main_frame, mConversationFragment!!, null)
.commitNow()
......@@ -80,14 +81,14 @@ class ConversationActivity : AppCompatActivity(), Colorable {
}
override fun onContextMenuClosed(menu: Menu) {
mConversationFragment!!.updateAdapterItem()
mConversationFragment?.updateAdapterItem()
super.onContextMenuClosed(menu)
}
override fun onStart() {
super.onStart()
if (mPendingIntent != null) {
handleShareIntent(mPendingIntent!!)
mPendingIntent?.let { pendingIntent ->
handleShareIntent(pendingIntent)
mPendingIntent = null
}
}
......@@ -109,7 +110,7 @@ class ConversationActivity : AppCompatActivity(), Colorable {
override fun dispatchKeyEvent(event: KeyEvent): Boolean {
if (event.action == KeyEvent.ACTION_DOWN && event.isCtrlPressed) {
if (event.keyCode == KeyEvent.KEYCODE_ENTER) {
if (mConversationFragment != null) mConversationFragment!!.sendMessageText()
mConversationFragment?.sendMessageText()
return true
}
}
......
......@@ -89,7 +89,6 @@ class ConversationPresenter @Inject constructor(
if (mConversation == conversation) return
mConversation = conversation
mConversationSubject.onNext(conversation)
val view = view
view?.let { initView(account, conversation, it) }
}
......@@ -112,9 +111,11 @@ class ConversationPresenter @Inject constructor(
private fun initContact(account: Account, conversation: Conversation, mode: Conversation.Mode, view: ConversationView) {
if (account.isJami) {
Log.w(TAG, "initContact " + conversation.uri)
Log.w(TAG, "initContact " + conversation.uri + " mode: " + mode)
if (mode === Conversation.Mode.Syncing) {
view.switchToSyncingView()
} else if (mode == Conversation.Mode.Request) {
view.switchToIncomingTrustRequestView(conversation.contact?.displayName ?: conversation.uri.uri)
} else if (conversation.isSwarm || account.isContact(conversation)) {
//if (conversation.isEnded())
// conversation.s
......@@ -125,7 +126,7 @@ class ConversationPresenter @Inject constructor(
if (req == null) {
view.switchToUnknownView(uri.rawUriString)
} else {
view.switchToIncomingTrustRequestView(req.displayname)
view.switchToIncomingTrustRequestView(req.displayName)
}
}
} else {
......@@ -135,7 +136,7 @@ class ConversationPresenter @Inject constructor(
}
private fun initView(account: Account, c: Conversation, view: ConversationView) {
Log.w(TAG, "initView " + c.uri + " " + c.mode)
Log.w(TAG, "initView " + c.uri)
val disposable = mConversationDisposable?.apply { clear() } ?: CompositeDisposable().apply {
mConversationDisposable = this
mCompositeDisposable.add(this)
......@@ -150,11 +151,13 @@ class ConversationPresenter @Inject constructor(
}
.subscribe())
disposable.add(c.mode
.switchMap { mode: Conversation.Mode -> if (mode === Conversation.Mode.Legacy || mode === Conversation.Mode.OneToOne) c.contact!!.conversationUri else Observable.empty() }
.switchMap { mode: Conversation.Mode ->
if (mode === Conversation.Mode.Legacy || mode === Conversation.Mode.Request)
c.contact!!.conversationUri else Observable.empty() }
.observeOn(mUiScheduler)
.subscribe { uri: Uri -> init(uri, account.accountId) })
disposable.add(Observable.combineLatest(mHardwareService.connectivityState, mAccountService.getObservableAccount(account),
{ isConnected: Boolean, a: Account -> isConnected || a.isRegistered })
disposable.add(Observable.combineLatest(mHardwareService.connectivityState, mAccountService.getObservableAccount(account))
{ isConnected: Boolean, a: Account -> isConnected || a.isRegistered }
.observeOn(mUiScheduler)
.subscribe { isOk: Boolean ->
this.view?.let { v ->
......@@ -361,6 +364,11 @@ class ConversationPresenter @Inject constructor(
fun onAcceptIncomingContactRequest() {
mConversation?.let { conversation ->
if (conversation.mode.blockingFirst() == Conversation.Mode.Request) {
conversation.loaded = null
conversation.clearHistory(true)
conversation.setMode(Conversation.Mode.Syncing)
}
mConversationFacade.acceptRequest(conversation.accountId, conversation.uri)
}
view?.switchToConversationView()
......
......@@ -22,6 +22,7 @@ package net.jami.model
import io.reactivex.rxjava3.core.*
import io.reactivex.rxjava3.core.Observable
import io.reactivex.rxjava3.schedulers.Schedulers
import io.reactivex.rxjava3.subjects.BehaviorSubject
import io.reactivex.rxjava3.subjects.PublishSubject
import io.reactivex.rxjava3.subjects.Subject
......@@ -32,6 +33,7 @@ import net.jami.utils.Log
import net.jami.utils.StringUtils
import java.lang.IllegalStateException
import java.util.*
import kotlin.collections.ArrayList
class Account(
val accountId: String,
......@@ -103,9 +105,14 @@ class Account(
fun conversationStarted(conversation: Conversation) {
Log.w(TAG, "conversationStarted " + conversation.accountId + " " + conversation.uri + " " + conversation.isSwarm + " " + conversation.contacts.size + " " + conversation.mode.blockingFirst())
synchronized(conversations) {
if (conversation.isSwarm) {
removeRequest(conversation.uri)
swarmConversations[conversation.uri.rawRingId] = conversation
}
conversations[conversation.uri.uri] = conversation
if (conversation.isSwarm && conversation.mode.blockingFirst() === Conversation.Mode.OneToOne) {
val contact = conversation.contact
val key = contact!!.uri.uri
val contact = conversation.contact!!
val key = contact.uri.uri
val removed = cache.remove(key)
conversations.remove(key)
//Conversation contactConversation = getByUri(contact.getPrimaryUri());
......@@ -115,7 +122,6 @@ class Account(
}*/
contact.setConversationUri(conversation.uri)
}
conversations[conversation.uri.uri] = conversation
conversationChanged()
}
}
......@@ -373,20 +379,15 @@ class Account(
}
val bannedContactsUpdates: Observable<Collection<Contact>>
get() = contactListSubject.concatMapSingle { list: Collection<Contact> ->
Observable.fromIterable(list).filter(Contact::isBanned).toList(list.size)
}
get() = contactListSubject.map { list -> list.filterTo(ArrayList(list.size), Contact::isBanned) }
fun getContactFromCache(key: String): Contact {
if (key.isEmpty()) throw IllegalStateException()
synchronized(mContactCache) {
var contact = mContactCache[key]
if (contact == null) {
contact = if (isSip) Contact.buildSIP(Uri.fromString(key))
return mContactCache.getOrPut(key) {
if (isSip) Contact.buildSIP(Uri.fromString(key))
else Contact.build(key, username == key)
mContactCache[key] = contact
}
return contact
}
}
......@@ -469,7 +470,7 @@ class Account(
val isJami: Boolean
get() = config[ConfigKey.ACCOUNT_TYPE] == AccountConfig.ACCOUNT_TYPE_RING
private fun getDetail(key: ConfigKey): String {
private fun getDetail(key: ConfigKey): String? {
return config[key]
}
......@@ -563,9 +564,9 @@ class Account(
}
val deviceId: String
get() = getDetail(ConfigKey.ACCOUNT_DEVICE_ID)
get() = getDetail(ConfigKey.ACCOUNT_DEVICE_ID)!!
val deviceName: String
get() = getDetail(ConfigKey.ACCOUNT_DEVICE_NAME)
get() = getDetail(ConfigKey.ACCOUNT_DEVICE_NAME)!!
val contacts: Map<String, Contact>
get() = mContacts
val bannedContacts: List<Contact>
......@@ -584,21 +585,10 @@ class Account(
}
fun addContact(id: String, confirmed: Boolean) {
var contact = mContacts[id]
if (contact == null) {
contact = getContactFromCache(Uri.fromId(id))
mContacts[id] = contact
}
val contact = mContacts.getOrPut(id) { getContactFromCache(Uri.fromId(id)) }
contact.addedDate = Date()
if (confirmed) {
contact.status = Contact.Status.CONFIRMED
} else {
contact.status = Contact.Status.REQUEST_SENT
}
val req = mRequests[id]
if (req != null) {
mRequests.remove(id)
}
contact.status = if (confirmed) Contact.Status.CONFIRMED else Contact.Status.REQUEST_SENT
mRequests.remove(id)
contactAdded(contact)
contactListSubject.onNext(mContacts.values)
}
......@@ -635,12 +625,11 @@ class Account(
if (contact.containsKey(CONTACT_BANNED) && contact[CONTACT_BANNED] == "true") {
callContact.status = Contact.Status.BANNED
} else if (contact.containsKey(CONTACT_CONFIRMED)) {
callContact.status =
if (java.lang.Boolean.parseBoolean(contact[CONTACT_CONFIRMED])) Contact.Status.CONFIRMED else Contact.Status.REQUEST_SENT
callContact.status = if (contact[CONTACT_CONFIRMED].toBoolean()) Contact.Status.CONFIRMED else Contact.Status.REQUEST_SENT
}
val conversationUri = contact[CONTACT_CONVERSATION]
if (!StringUtils.isEmpty(conversationUri)) {
callContact.setConversationUri(Uri(Uri.SWARM_SCHEME, conversationUri!!))
if (conversationUri != null && conversationUri.isNotEmpty()) {
callContact.setConversationUri(Uri(Uri.SWARM_SCHEME, conversationUri))
}
mContacts[contactId] = callContact
contactAdded(callContact)
......@@ -654,48 +643,36 @@ class Account(
contactListSubject.onNext(mContacts.values)
}
var requests: List<TrustRequest>
get() {
val requests = ArrayList<TrustRequest>(mRequests.size)
for (request in mRequests.values) {
if (request.isNameResolved) {
requests.add(request)
}
}
return requests
}
set(requests) {
Log.w(TAG, "setRequests " + requests.size)
synchronized(pending) {
for (request in requests) {
val key = request.uri.uri
mRequests[key] = request
var conversation = pending[key]
if (conversation == null) {
conversation = getByKey(key)
pending[key] = conversation
val contact = getContactFromCache(request.uri)
conversation.addRequestEvent(request, contact)
}
}
pendingChanged()
}
}
fun getRequest(uri: Uri): TrustRequest? {
return mRequests[uri.uri]
}
fun addRequest(request: TrustRequest) {
synchronized(pending) {
val key = request.uri.uri
val key = request.conversationUri?.uri ?: request.from.uri
mRequests[key] = request
var conversation = pending[key]
if (conversation == null) {
conversation = getByKey(key)
if (pending[key] == null) {
val conversation = if (request.conversationUri?.isSwarm == true)
Conversation(accountId, request.conversationUri, Conversation.Mode.Request).apply {
val contact = getContactFromCache(request.from).apply {
if (!conversationUri.blockingFirst().isSwarm)
setConversationUri(request.conversationUri)
}
addContact(contact)
addContactEvent(ContactEvent(contact, request))
}
else
getByKey(key)
// Apply request profile to contact
request.profile?.let { p -> conversation.contact?.let { c ->
p.observeOn(Schedulers.computation()).subscribe { profile -> c.setProfile(profile) }
} }
Log.w(TAG, "pendingRequestAdded $key")
pending[key] = conversation
if (!conversation.isSwarm) {
val contact = getContactFromCache(request.uri)
val contact = getContactFromCache(request.from)
conversation.addRequestEvent(request, contact)
}
pendingChanged()
......@@ -714,17 +691,6 @@ class Account(
}
}
fun removeRequestPerConvId(conversationId: String) {
synchronized(pending) {
for ((_, request) in mRequests) {
if (request.conversationId != null && request.conversationId == conversationId) {
removeRequest(request.uri)
return
}
}
}
}
fun registeredNameFound(state: Int, address: String, name: String?): Boolean {
val uri = Uri.fromString(address)
val key = uri.uri
......@@ -740,9 +706,9 @@ class Account(
}
fun getByUri(uri: Uri?): Conversation? {
//Log.w(TAG, "getByUri " + getAccountID() + " " + uri);
Log.w(TAG, "getByUri $accountId $uri");
if (uri == null || uri.isEmpty) return null
return if (uri.isSwarm) getSwarm(uri.rawRingId) else getByKey(uri.uri)
return if (uri.isSwarm) getSwarm(uri.rawRingId) ?: pending[uri.uri] else getByKey(uri.uri)
}
fun getByUri(uri: String?): Conversation? {
......@@ -750,12 +716,7 @@ class Account(
}
private fun getByKey(key: String): Conversation {
cache[key]?.let { return it }
val contact = getContactFromCache(key)
val conversation = Conversation(accountId, contact)
//Log.w(TAG, "getByKey " + getAccountID() + " contact " + key);
cache[key] = conversation
return conversation
return cache.getOrPut(key) { Conversation(accountId, getContactFromCache(key)) }
}
fun setHistoryLoaded(conversations: List<Conversation>) {
......
......@@ -190,10 +190,9 @@ class Conversation : ConversationHistory {
var loading: SingleSubject<Conversation>?
get() = mLoadingSubject
set(l) {
if (mLoadingSubject != null) {
if (!mLoadingSubject!!.hasValue() && !mLoadingSubject!!.hasThrowable()) mLoadingSubject!!.onError(
IllegalStateException()
)
mLoadingSubject?.let { loading ->
if (!loading.hasValue() && !loading.hasThrowable())
loading.onError(IllegalStateException())
}
mLoadingSubject = l
}
......@@ -308,15 +307,8 @@ class Conversation : ConversationHistory {
}
fun addTextMessage(txt: TextMessage) {
if (mVisible) {
if (mVisible)
txt.read()
}
if (txt.conversation == null) {
Log.e(
TAG,
"Error in conversation class... No conversation is attached to this interaction"
)
}
setInteractionProperties(txt)
rawHistory[txt.timestamp] = txt
mDirty = true
......@@ -413,9 +405,7 @@ class Conversation : ConversationHistory {
if (mDirty) {
Log.w(TAG, "sortHistory()")
synchronized(aggregateHistory) {
aggregateHistory.sortWith { c1: Interaction, c2: Interaction ->
java.lang.Long.compare(c1.timestamp, c2.timestamp)
}
aggregateHistory.sortWith { c1, c2 -> c1.timestamp.compareTo(c2.timestamp) }
}
mDirty = false
}
......@@ -499,7 +489,8 @@ class Conversation : ConversationHistory {
aggregateHistory.clear()
rawHistory.clear()
mDirty = false
if (!delete && contacts.size == 1) aggregateHistory.add(ContactEvent(contacts[0]))
if (!delete && contacts.size == 1)
aggregateHistory.add(ContactEvent(contacts[0]))
clearedSubject.onNext(aggregateHistory)
}
......@@ -638,7 +629,7 @@ class Conversation : ConversationHistory {
enum class Mode {
OneToOne, AdminInvitesOnly, InvitesOnly, // Non-daemon modes
Syncing, Public, Legacy
Syncing, Public, Legacy, Request
}
interface ConversationActionCallback {
......
......@@ -21,58 +21,25 @@ package net.jami.model
import ezvcard.Ezvcard
import ezvcard.VCard
import net.jami.utils.StringUtils
class TrustRequest {
val accountId: String
private var mContactUsername: String? = null
val uri: Uri
var conversationId: String?
var vCard: VCard? = null
import io.reactivex.rxjava3.core.Single
class TrustRequest(
val accountId: String,
val from: Uri,
val timestamp: Long,
payload: String?,
val conversationUri: Uri?)
{
var vCard: VCard? = if (payload == null) null else Ezvcard.parse(payload).first()
var profile: Single<Profile>? = null
var message: String? = null
val timestamp: Long
var isNameResolved = false
private set
constructor(accountId: String, uri: Uri, received: Long, payload: String?, conversationId: String?) {
this.accountId = accountId
this.uri = uri
this.conversationId = if (StringUtils.isEmpty(conversationId)) null else conversationId
timestamp = received
vCard = if (payload == null) null else Ezvcard.parse(payload).first()
message = null
}
constructor(accountId: String, info: Map<String, String>) : this(accountId, Uri.fromId(info["from"]!!),
java.lang.Long.decode(info["received"]) * 1000L, info["payload"], info["conversationId"])
constructor(accountId: String, contactUri: Uri, conversationId: String?) {
this.accountId = accountId
uri = contactUri
this.conversationId = conversationId
timestamp = 0
}
val fullname: String
get() {
var fullname = ""
if (vCard != null && vCard!!.formattedName != null) {
fullname = vCard!!.formattedName.value
}
return fullname
}
val displayname: String
get() {
val username = mContactUsername
return if (username != null && username.isNotEmpty()) username else uri.toString()
}
info["received"]!!.toLong() * 1000L, info["payload"], info["conversationId"]?.let { uriString -> if (uriString.isEmpty()) null else Uri(Uri.SWARM_SCHEME, uriString) })
fun setUsername(username: String?) {
mContactUsername = username
isNameResolved = true
}
val fullName: String?
get() = vCard?.formattedName?.value
companion object {
private val TAG = TrustRequest::class.simpleName!!
}
}
\ No newline at end of file
val displayName: String
get() = fullName ?: from.toString()
}
......@@ -23,7 +23,7 @@ import io.reactivex.rxjava3.disposables.CompositeDisposable
import java.lang.ref.WeakReference
abstract class RootPresenter<T> {
protected var mCompositeDisposable = CompositeDisposable()
protected val mCompositeDisposable = CompositeDisposable()
private var mView: WeakReference<T>? = null
open fun bindView(view: T) {
......
......@@ -247,7 +247,6 @@ class AccountService(
}
private fun refreshAccountsCacheFromDaemon() {
Log.w(TAG, "refreshAccountsCacheFromDaemon")
var hasSip = false
var hasJami = false
val curList: List<Account> = mAccountList
......@@ -286,14 +285,20 @@ class AccountService(
hasJami = true
val enabled = account.isEnabled
account.devices = JamiService.getKnownRingDevices(accountId).toNative()
Log.w(TAG, "$accountId loading contacts")
account.setContacts(JamiService.getContacts(accountId).toNative())
val requests: List<Map<String, String>> = JamiService.getTrustRequests(accountId).toNative()
Log.w(TAG, "$accountId loading ${requests.size} trust requests")
for (requestInfo in requests) {
val request = TrustRequest(accountId, requestInfo)
request.vCard?.let { vcard ->
request.profile = mVCardService.loadVCardProfile(vcard)
}
account.addRequest(request)
}
val conversations: List<String> = JamiService.getConversations(account.accountId)
Log.w(TAG, accountId + " loading conversations: " + conversations.size)
Log.w(TAG, "$accountId loading ${conversations.size} conversations: ")
for (conversationId in conversations) {
try {
val info: Map<String, String> = JamiService.conversationInfos(accountId, conversationId).toNative()