Fix conversations list

Signed-off-by: Mario Danic <mario@lovelyhq.com>
This commit is contained in:
Mario Danic 2020-02-16 11:33:12 +01:00
parent e079601dad
commit eb832fb26a
No known key found for this signature in database
GPG Key ID: CDE0BBD2738C4CC0
28 changed files with 225 additions and 88 deletions

View File

@ -23,12 +23,10 @@ package com.nextcloud.talk.activities
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.content.Context import android.content.Context
import android.os.Build import android.os.Build
import android.os.Bundle
import android.util.Log import android.util.Log
import android.view.WindowManager import android.view.WindowManager
import android.webkit.SslErrorHandler import android.webkit.SslErrorHandler
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.app.AppCompatDelegate
import com.nextcloud.talk.R import com.nextcloud.talk.R
import com.nextcloud.talk.events.CertificateEvent import com.nextcloud.talk.events.CertificateEvent
import com.nextcloud.talk.utils.SecurityUtils import com.nextcloud.talk.utils.SecurityUtils

View File

@ -34,8 +34,6 @@ import java.io.IOException;
import at.bitfire.dav4jvm.Property; import at.bitfire.dav4jvm.Property;
import at.bitfire.dav4jvm.PropertyFactory; import at.bitfire.dav4jvm.PropertyFactory;
import at.bitfire.dav4jvm.XmlUtils; import at.bitfire.dav4jvm.XmlUtils;
import lombok.Getter;
import lombok.Setter;
public class NCEncrypted implements Property { public class NCEncrypted implements Property {
public static final Name NAME = public static final Name NAME =
@ -43,14 +41,14 @@ public class NCEncrypted implements Property {
private boolean ncEncrypted; private boolean ncEncrypted;
public boolean isNcEncrypted() {
return ncEncrypted;
}
private NCEncrypted(boolean isEncrypted) { private NCEncrypted(boolean isEncrypted) {
ncEncrypted = isEncrypted; ncEncrypted = isEncrypted;
} }
public boolean isNcEncrypted() {
return ncEncrypted;
}
public static class Factory implements PropertyFactory { public static class Factory implements PropertyFactory {
@Nullable @Nullable

View File

@ -34,8 +34,6 @@ import java.io.IOException;
import at.bitfire.dav4jvm.Property; import at.bitfire.dav4jvm.Property;
import at.bitfire.dav4jvm.PropertyFactory; import at.bitfire.dav4jvm.PropertyFactory;
import at.bitfire.dav4jvm.XmlUtils; import at.bitfire.dav4jvm.XmlUtils;
import lombok.Getter;
import lombok.Setter;
public class NCPreview implements Property { public class NCPreview implements Property {
public static final Property.Name NAME = public static final Property.Name NAME =
@ -43,14 +41,14 @@ public class NCPreview implements Property {
private boolean ncPreview; private boolean ncPreview;
public boolean isNcPreview() {
return ncPreview;
}
private NCPreview(boolean hasPreview) { private NCPreview(boolean hasPreview) {
ncPreview = hasPreview; ncPreview = hasPreview;
} }
public boolean isNcPreview() {
return ncPreview;
}
public static class Factory implements PropertyFactory { public static class Factory implements PropertyFactory {
@Nullable @Nullable

View File

@ -34,8 +34,6 @@ import java.io.IOException;
import at.bitfire.dav4jvm.Property; import at.bitfire.dav4jvm.Property;
import at.bitfire.dav4jvm.PropertyFactory; import at.bitfire.dav4jvm.PropertyFactory;
import at.bitfire.dav4jvm.XmlUtils; import at.bitfire.dav4jvm.XmlUtils;
import lombok.Getter;
import lombok.Setter;
public class OCFavorite implements Property { public class OCFavorite implements Property {
public static final Property.Name NAME = public static final Property.Name NAME =
@ -43,14 +41,14 @@ public class OCFavorite implements Property {
private boolean ocFavorite; private boolean ocFavorite;
public boolean isOcFavorite() {
return ocFavorite;
}
OCFavorite(boolean isFavorite) { OCFavorite(boolean isFavorite) {
ocFavorite = isFavorite; ocFavorite = isFavorite;
} }
public boolean isOcFavorite() {
return ocFavorite;
}
public static class Factory implements PropertyFactory { public static class Factory implements PropertyFactory {
@Nullable @Nullable

View File

@ -34,8 +34,6 @@ import java.io.IOException;
import at.bitfire.dav4jvm.Property; import at.bitfire.dav4jvm.Property;
import at.bitfire.dav4jvm.PropertyFactory; import at.bitfire.dav4jvm.PropertyFactory;
import at.bitfire.dav4jvm.XmlUtils; import at.bitfire.dav4jvm.XmlUtils;
import lombok.Getter;
import lombok.Setter;
public class OCId implements Property { public class OCId implements Property {
public static final Name NAME = public static final Name NAME =
@ -43,14 +41,14 @@ public class OCId implements Property {
private String ocId; private String ocId;
public String getOcId() {
return ocId;
}
private OCId(String id) { private OCId(String id) {
ocId = id; ocId = id;
} }
public String getOcId() {
return ocId;
}
public static class Factory implements PropertyFactory { public static class Factory implements PropertyFactory {
@Nullable @Nullable

View File

@ -34,8 +34,6 @@ import java.io.IOException;
import at.bitfire.dav4jvm.Property; import at.bitfire.dav4jvm.Property;
import at.bitfire.dav4jvm.PropertyFactory; import at.bitfire.dav4jvm.PropertyFactory;
import at.bitfire.dav4jvm.XmlUtils; import at.bitfire.dav4jvm.XmlUtils;
import lombok.Getter;
import lombok.Setter;
public class OCSize implements Property { public class OCSize implements Property {
public static final Property.Name NAME = public static final Property.Name NAME =
@ -43,14 +41,14 @@ public class OCSize implements Property {
private long ocSize; private long ocSize;
public long getOcSize() {
return ocSize;
}
private OCSize(long size) { private OCSize(long size) {
ocSize = size; ocSize = size;
} }
public long getOcSize() {
return ocSize;
}
public static class Factory implements PropertyFactory { public static class Factory implements PropertyFactory {
@Nullable @Nullable

View File

@ -116,7 +116,8 @@ class MessageNotificationWorker(
} }
} }
val adjustedConversationType = conversationType ?: Conversation.ConversationType.ONE_TO_ONE_CONVERSATION val adjustedConversationType = conversationType
?: Conversation.ConversationType.ONE_TO_ONE_CONVERSATION
val pendingIntent: PendingIntent? = PendingIntent.getActivity(applicationContext, val pendingIntent: PendingIntent? = PendingIntent.getActivity(applicationContext,
0, intent, 0) 0, intent, 0)
@ -222,6 +223,7 @@ class MessageNotificationWorker(
NotificationManagerCompat.from(applicationContext).notify(notificationId, notificationBuilder.build()) NotificationManagerCompat.from(applicationContext).notify(notificationId, notificationBuilder.build())
} }
} }
private fun getStyle( private fun getStyle(
decryptedPushMessage: DecryptedPushMessage, decryptedPushMessage: DecryptedPushMessage,
conversationType: Conversation.ConversationType, conversationType: Conversation.ConversationType,

View File

@ -211,15 +211,15 @@ class ChatMessage : IMessage, MessageContentType, MessageContentType.Image {
if (!TextUtils.isEmpty(actorDisplayName)) actorDisplayName else sharedApplication if (!TextUtils.isEmpty(actorDisplayName)) actorDisplayName else sharedApplication
!!.getString(R.string.nc_guest)) !!.getString(R.string.nc_guest))
} }
/*} else if (messageType == MessageType.SINGLE_LINK_MESSAGE) { /*} else if (messageType == MessageType.SINGLE_LINK_MESSAGE) {
return if (actorId.equals(activeUser!!.userId)) { return if (actorId.equals(activeUser!!.userId)) {
sharedApplication!!.resources.getString(R.string.nc_sent_a_link_you) sharedApplication!!.resources.getString(R.string.nc_sent_a_link_you)
} else { } else {
String.format(sharedApplication String.format(sharedApplication
!!.resources !!.resources
.getString(R.string.nc_sent_a_link), .getString(R.string.nc_sent_a_link),
if (!TextUtils.isEmpty(actorDisplayName)) actorDisplayName else sharedApplication!!.getString(R.string.nc_guest)) if (!TextUtils.isEmpty(actorDisplayName)) actorDisplayName else sharedApplication!!.getString(R.string.nc_guest))
}*/ }*/
} else if (messageType == MessageType.SINGLE_LINK_AUDIO_MESSAGE) { } else if (messageType == MessageType.SINGLE_LINK_AUDIO_MESSAGE) {
return if (actorId.equals(activeUser!!.userId)) { return if (actorId.equals(activeUser!!.userId)) {
sharedApplication!!.resources.getString(R.string.nc_sent_an_audio_you) sharedApplication!!.resources.getString(R.string.nc_sent_an_audio_you)

View File

@ -33,7 +33,6 @@ import com.nextcloud.talk.models.json.participants.ParticipantsOverall
import com.nextcloud.talk.models.json.push.PushRegistrationOverall import com.nextcloud.talk.models.json.push.PushRegistrationOverall
import com.nextcloud.talk.models.json.signaling.settings.SignalingSettingsOverall import com.nextcloud.talk.models.json.signaling.settings.SignalingSettingsOverall
import com.nextcloud.talk.models.json.userprofile.UserProfileOverall import com.nextcloud.talk.models.json.userprofile.UserProfileOverall
import io.reactivex.Observable
import retrofit2.http.* import retrofit2.http.*
interface ApiService { interface ApiService {
@ -43,7 +42,7 @@ interface ApiService {
@GET @GET
suspend fun getNotification(@Header("Authorization") authorization: String, suspend fun getNotification(@Header("Authorization") authorization: String,
@Url url: String): NotificationOverall @Url url: String): NotificationOverall
@FormUrlEncoded @FormUrlEncoded
@PUT @PUT

View File

@ -88,7 +88,7 @@ val NetworkModule = module {
single { createOkHttpClient(androidContext(), get(), get(), get(), get(), get(), get(), get()) } single { createOkHttpClient(androidContext(), get(), get(), get(), get(), get(), get(), get()) }
factory { createApiErrorHandler() } factory { createApiErrorHandler() }
single { createNextcloudTalkRepository(get()) } single { createNextcloudTalkRepository(get()) }
single { createNexcloudRepositoryWithNoCookies(get(), get())} single { createNexcloudRepositoryWithNoCookies(get(), get()) }
single { createImageLoader(androidApplication(), get()) } single { createImageLoader(androidApplication(), get()) }
} }

View File

@ -57,12 +57,12 @@ val UseCasesModule = module {
} }
fun getNotificationUseCase(nextcloudTalkRepository: NextcloudTalkRepository, fun getNotificationUseCase(nextcloudTalkRepository: NextcloudTalkRepository,
apiErrorHandler: ApiErrorHandler): GetNotificationUseCase { apiErrorHandler: ApiErrorHandler): GetNotificationUseCase {
return GetNotificationUseCase(nextcloudTalkRepository, apiErrorHandler) return GetNotificationUseCase(nextcloudTalkRepository, apiErrorHandler)
} }
fun getPeersForCallUseCase(nextcloudTalkRepository: NextcloudTalkRepository, fun getPeersForCallUseCase(nextcloudTalkRepository: NextcloudTalkRepository,
apiErrorHandler: ApiErrorHandler): GetPeersForCallUseCase { apiErrorHandler: ApiErrorHandler): GetPeersForCallUseCase {
return GetPeersForCallUseCase(nextcloudTalkRepository, apiErrorHandler) return GetPeersForCallUseCase(nextcloudTalkRepository, apiErrorHandler)
} }

View File

@ -28,6 +28,7 @@ enum class ContactsViewOperationState {
WAITING, WAITING,
PROCESSING, PROCESSING,
OK, OK,
LOADING_FAILED,
CONVERSATION_CREATION_FAILED, CONVERSATION_CREATION_FAILED,
CONVERSATION_CREATED_WITH_MISSING_TOKEN, CONVERSATION_CREATED_WITH_MISSING_TOKEN,
CONVERSATION_PASSWORD_NOT_SET CONVERSATION_PASSWORD_NOT_SET

View File

@ -22,8 +22,6 @@
package com.nextcloud.talk.newarch.features.contactsflow package com.nextcloud.talk.newarch.features.contactsflow
import com.nextcloud.talk.models.json.participants.Participant
data class ParticipantElement( data class ParticipantElement(
val data: Any, val data: Any,
val elementType: Int val elementType: Int

View File

@ -27,6 +27,7 @@ import android.view.ViewGroup
import androidx.core.view.isVisible import androidx.core.view.isVisible
import coil.api.load import coil.api.load
import com.nextcloud.talk.R import com.nextcloud.talk.R
import com.nextcloud.talk.models.json.conversations.Conversation
import com.nextcloud.talk.models.json.participants.Participant import com.nextcloud.talk.models.json.participants.Participant
import com.nextcloud.talk.newarch.features.contactsflow.ParticipantElement import com.nextcloud.talk.newarch.features.contactsflow.ParticipantElement
import com.nextcloud.talk.newarch.local.models.getCredentials import com.nextcloud.talk.newarch.local.models.getCredentials
@ -101,15 +102,20 @@ open class ContactPresenter<T : Any>(context: Context, onElementClick: ((Page, H
when (participant.source) { when (participant.source) {
"users" -> { "users" -> {
val conversation = Conversation()
conversation.type = Conversation.ConversationType.ONE_TO_ONE_CONVERSATION
when (participant.type) { when (participant.type) {
Participant.ParticipantType.GUEST, Participant.ParticipantType.GUEST_AS_MODERATOR, Participant.ParticipantType.USER_FOLLOWING_LINK -> { Participant.ParticipantType.GUEST, Participant.ParticipantType.GUEST_AS_MODERATOR, Participant.ParticipantType.USER_FOLLOWING_LINK -> {
holder.itemView.avatarImageView.load(ApiUtils.getUrlForAvatarWithNameForGuests(user?.baseUrl, participant.userId, R.dimen.avatar_size)) { holder.itemView.avatarImageView.load(ApiUtils.getUrlForAvatarWithNameForGuests(user?.baseUrl, participant.userId, R.dimen.avatar_size)) {
user?.getCredentials()?.let { addHeader("Authorization", it) } user?.getCredentials()?.let { addHeader("Authorization", it) }
fallback(Images().getImageForConversation(context, conversation, true))
} }
} }
else -> { else -> {
holder.itemView.avatarImageView.load(ApiUtils.getUrlForAvatarWithName(user?.baseUrl, participant.userId, R.dimen.avatar_size)) { holder.itemView.avatarImageView.load(ApiUtils.getUrlForAvatarWithName(user?.baseUrl, participant.userId, R.dimen.avatar_size)) {
user?.getCredentials()?.let { addHeader("Authorization", it) } user?.getCredentials()?.let { addHeader("Authorization", it) }
fallback(Images().getImageForConversation(context, conversation, true))
} }
} }
} }

View File

@ -47,7 +47,6 @@ import com.nextcloud.talk.newarch.features.search.DebouncingTextWatcher
import com.nextcloud.talk.newarch.mvvm.BaseView import com.nextcloud.talk.newarch.mvvm.BaseView
import com.nextcloud.talk.newarch.mvvm.ext.initRecyclerView import com.nextcloud.talk.newarch.mvvm.ext.initRecyclerView
import com.nextcloud.talk.newarch.utils.ElementPayload import com.nextcloud.talk.newarch.utils.ElementPayload
import com.nextcloud.talk.newarch.utils.dp
import com.nextcloud.talk.newarch.utils.px import com.nextcloud.talk.newarch.utils.px
import com.nextcloud.talk.utils.bundle.BundleKeys import com.nextcloud.talk.utils.bundle.BundleKeys
import com.otaliastudios.elements.Adapter import com.otaliastudios.elements.Adapter
@ -61,6 +60,7 @@ import kotlinx.android.synthetic.main.message_state.view.*
import kotlinx.android.synthetic.main.search_layout.* import kotlinx.android.synthetic.main.search_layout.*
import kotlinx.android.synthetic.main.search_layout.view.* import kotlinx.android.synthetic.main.search_layout.view.*
import org.koin.android.ext.android.inject import org.koin.android.ext.android.inject
class ContactsView(private val bundle: Bundle? = null) : BaseView() { class ContactsView(private val bundle: Bundle? = null) : BaseView() {
override val scopeProvider: LifecycleScopeProvider<*> = ControllerScopeProvider.from(this) override val scopeProvider: LifecycleScopeProvider<*> = ControllerScopeProvider.from(this)
@ -86,8 +86,9 @@ class ContactsView(private val bundle: Bundle? = null) : BaseView() {
viewModel = viewModelProvider(factory).get(ContactsViewModel::class.java) viewModel = viewModelProvider(factory).get(ContactsViewModel::class.java)
val view = super.onCreateView(inflater, container) val view = super.onCreateView(inflater, container)
val contactsViewSource = ContactsViewSource(data = viewModel.contactsLiveData)
val participantsAdapterBuilder = Adapter.builder(this) val participantsAdapterBuilder = Adapter.builder(this)
.addSource(ContactsViewSource(data = viewModel.contactsLiveData)) .addSource(contactsViewSource)
.addSource(ContactsHeaderSource(activity as Context, ParticipantElementType.PARTICIPANT_HEADER.ordinal)) .addSource(ContactsHeaderSource(activity as Context, ParticipantElementType.PARTICIPANT_HEADER.ordinal))
.addSource(ContactsViewFooterSource(activity as Context, ParticipantElementType.PARTICIPANT_FOOTER.ordinal)) .addSource(ContactsViewFooterSource(activity as Context, ParticipantElementType.PARTICIPANT_FOOTER.ordinal))
.addPresenter(ContactPresenter(activity as Context, ::onElementClick)) .addPresenter(ContactPresenter(activity as Context, ::onElementClick))
@ -102,9 +103,13 @@ class ContactsView(private val bundle: Bundle? = null) : BaseView() {
view.messageStateImageView.imageTintList = null view.messageStateImageView.imageTintList = null
}) })
.addPresenter(Presenter.forErrorIndicator(activity as Context, R.layout.message_state) { view, throwable -> .addPresenter(Presenter.forErrorIndicator(activity as Context, R.layout.message_state) { view, throwable ->
val layoutParams = view.messageStateImageView.layoutParams as RelativeLayout.LayoutParams
layoutParams.height = 128.px
layoutParams.width = 128.px
view.messageStateImageView.layoutParams = layoutParams
view.messageStateTextView.setText(R.string.nc_oops) view.messageStateTextView.setText(R.string.nc_oops)
view.messageStateImageView.load((activity as Context).getDrawable(R.drawable.ic_announcement_white_24dp)) view.messageStateImageView.load((activity as Context).getDrawable(R.drawable.ic_undraw_server_down_s4lk))
view.messageStateImageView.imageTintList = resources?.getColor(R.color.colorPrimary)?.let { ColorStateList.valueOf(it) } view.messageStateImageView.imageTintList = null
}) })
.setAutoScrollMode(Adapter.AUTOSCROLL_POSITION_0, true) .setAutoScrollMode(Adapter.AUTOSCROLL_POSITION_0, true)
@ -191,6 +196,10 @@ class ContactsView(private val bundle: Bundle? = null) : BaseView() {
// dunno what to do yet, an error message somewhere // dunno what to do yet, an error message somewhere
searchLayout?.searchProgressBar?.isVisible = false searchLayout?.searchProgressBar?.isVisible = false
} }
ContactsViewOperationState.LOADING_FAILED -> {
searchLayout?.searchProgressBar?.isVisible = false
contactsViewSource.postError(Exception(operationState.errorMessage))
}
else -> { else -> {
// do nothing, we're waiting // do nothing, we're waiting
} }

View File

@ -24,7 +24,6 @@ package com.nextcloud.talk.newarch.features.contactsflow.contacts
import android.content.Context import android.content.Context
import com.nextcloud.talk.R import com.nextcloud.talk.R
import com.nextcloud.talk.models.json.participants.Participant
import com.nextcloud.talk.newarch.features.contactsflow.ParticipantElement import com.nextcloud.talk.newarch.features.contactsflow.ParticipantElement
import com.otaliastudios.elements.Page import com.otaliastudios.elements.Page
import com.otaliastudios.elements.Source import com.otaliastudios.elements.Source

View File

@ -42,31 +42,31 @@ class ContactsHeaderSource(private val context: Context, private val elementType
headersAlreadyAdded = mutableListOf() headersAlreadyAdded = mutableListOf()
for (participantElement in list) { for (participantElement in list) {
if (participantElement.data is Participant) { if (participantElement.data is Participant) {
val participant = participantElement.data val participant = participantElement.data
val header = when (participant.source) { val header = when (participant.source) {
"users" -> { "users" -> {
context.getString(R.string.nc_contacts) context.getString(R.string.nc_contacts)
}
"groups" -> {
context.getString(R.string.nc_groups)
}
"emails" -> {
context.getString(R.string.nc_emails)
}
"circles" -> {
context.getString(R.string.nc_circles)
}
else -> {
context.getString(R.string.nc_others)
}
} }
"groups" -> {
context.getString(R.string.nc_groups)
}
"emails" -> {
context.getString(R.string.nc_emails)
}
"circles" -> {
context.getString(R.string.nc_circles)
}
else -> {
context.getString(R.string.nc_others)
if (!headersAlreadyAdded.contains(header)) {
results.add(Data(participantElement, header))
headersAlreadyAdded.add(header)
} }
} }
if (!headersAlreadyAdded.contains(header)) {
results.add(Data(participantElement, header))
headersAlreadyAdded.add(header)
}
}
} }
return results return results

View File

@ -23,7 +23,10 @@
package com.nextcloud.talk.newarch.features.contactsflow.contacts package com.nextcloud.talk.newarch.features.contactsflow.contacts
import android.app.Application import android.app.Application
import androidx.lifecycle.* import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.distinctUntilChanged
import androidx.lifecycle.viewModelScope
import com.nextcloud.talk.R import com.nextcloud.talk.R
import com.nextcloud.talk.models.json.conversations.Conversation import com.nextcloud.talk.models.json.conversations.Conversation
import com.nextcloud.talk.models.json.conversations.ConversationOverall import com.nextcloud.talk.models.json.conversations.ConversationOverall
@ -167,7 +170,8 @@ class ContactsViewModel constructor(
} }
override suspend fun onError(errorModel: ErrorModel?) { override suspend fun onError(errorModel: ErrorModel?) {
// handle errors here _operationState.postValue(ContactsViewOperationStateWrapper(ContactsViewOperationState.LOADING_FAILED, errorModel?.getErrorMessage(), conversationToken))
} }
}) })
} }

View File

@ -29,16 +29,24 @@ import com.otaliastudios.elements.Element
import com.otaliastudios.elements.Page import com.otaliastudios.elements.Page
import com.otaliastudios.elements.Source import com.otaliastudios.elements.Source
import com.otaliastudios.elements.extensions.MainSource import com.otaliastudios.elements.extensions.MainSource
import java.lang.Exception
class ContactsViewSource<T : ParticipantElement>(private val data: LiveData<List<T>>, loadingIndicatorsEnabled: Boolean = true, errorIndicatorEnabled: Boolean = true, emptyIndicatorEnabled: Boolean = true) : MainSource<T>(loadingIndicatorsEnabled, errorIndicatorEnabled, emptyIndicatorEnabled) { class ContactsViewSource<T : ParticipantElement>(private val data: LiveData<List<T>>, loadingIndicatorsEnabled: Boolean = true, errorIndicatorEnabled: Boolean = true, emptyIndicatorEnabled: Boolean = true) : MainSource<T>(loadingIndicatorsEnabled, errorIndicatorEnabled, emptyIndicatorEnabled) {
private var currentPage: Page? = null
override fun onPageOpened(page: Page, dependencies: List<Element<*>>) { override fun onPageOpened(page: Page, dependencies: List<Element<*>>) {
super.onPageOpened(page, dependencies) super.onPageOpened(page, dependencies)
if (page.previous() == null) { if (page.previous() == null) {
currentPage = page
postResult(page, data) postResult(page, data)
} }
} }
fun postError(exception: Exception){
currentPage?.let { page ->
postResult(page, exception)
}
}
override fun getElementType(data: T): Int { override fun getElementType(data: T): Int {
return data.elementType return data.elementType
} }

View File

@ -154,6 +154,7 @@ open class ConversationPresenter(context: Context, onElementClick: ((Page, Holde
{ {
addHeader("Authorization", user.getCredentials()) addHeader("Authorization", user.getCredentials())
transformations(CircleCropTransformation()) transformations(CircleCropTransformation())
fallback(Images().getImageForConversation(context, conversation, true))
} }
} }
} }

View File

@ -34,8 +34,6 @@ import androidx.recyclerview.widget.LinearLayoutManager
import com.afollestad.materialdialogs.LayoutMode import com.afollestad.materialdialogs.LayoutMode
import com.afollestad.materialdialogs.MaterialDialog import com.afollestad.materialdialogs.MaterialDialog
import com.afollestad.materialdialogs.bottomsheets.BottomSheet import com.afollestad.materialdialogs.bottomsheets.BottomSheet
import com.bluelinelabs.conductor.ControllerChangeHandler
import com.bluelinelabs.conductor.ControllerChangeType
import com.bluelinelabs.conductor.RouterTransaction import com.bluelinelabs.conductor.RouterTransaction
import com.bluelinelabs.conductor.autodispose.ControllerScopeProvider import com.bluelinelabs.conductor.autodispose.ControllerScopeProvider
import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler
@ -52,7 +50,6 @@ import com.nextcloud.talk.newarch.features.contactsflow.contacts.ContactsView
import com.nextcloud.talk.newarch.features.search.DebouncingTextWatcher import com.nextcloud.talk.newarch.features.search.DebouncingTextWatcher
import com.nextcloud.talk.newarch.mvvm.BaseView import com.nextcloud.talk.newarch.mvvm.BaseView
import com.nextcloud.talk.newarch.mvvm.ext.initRecyclerView import com.nextcloud.talk.newarch.mvvm.ext.initRecyclerView
import com.nextcloud.talk.newarch.utils.px
import com.nextcloud.talk.utils.ConductorRemapping import com.nextcloud.talk.utils.ConductorRemapping
import com.nextcloud.talk.utils.DisplayUtils import com.nextcloud.talk.utils.DisplayUtils
import com.nextcloud.talk.utils.animations.SharedElementTransition import com.nextcloud.talk.utils.animations.SharedElementTransition
@ -148,6 +145,7 @@ class ConversationsListView : BaseView() {
override fun onAttach(view: View) { override fun onAttach(view: View) {
super.onAttach(view) super.onAttach(view)
floatingActionButton?.isVisible = true floatingActionButton?.isVisible = true
appBar?.isVisible = true
} }
private fun setSearchQuery(query: CharSequence?) { private fun setSearchQuery(query: CharSequence?) {

View File

@ -88,7 +88,7 @@ class Images {
} }
// returns null if it's one-to-one that you need to fetch yourself // returns null if it's one-to-one that you need to fetch yourself
fun getImageForConversation(context: Context, conversation: Conversation): Drawable? { fun getImageForConversation(context: Context, conversation: Conversation, fallback: Boolean = false): Drawable? {
conversation.objectType?.let { objectType -> conversation.objectType?.let { objectType ->
when (objectType) { when (objectType) {
"share:password" -> { "share:password" -> {
@ -104,6 +104,10 @@ class Images {
when (conversation.type) { when (conversation.type) {
Conversation.ConversationType.ONE_TO_ONE_CONVERSATION -> { Conversation.ConversationType.ONE_TO_ONE_CONVERSATION -> {
if (fallback) {
return DisplayUtils.getRoundedDrawableFromBitmap(getImageWithBackground(context, R.drawable.ic_baseline_person_24))
}
return null return null
} }
Conversation.ConversationType.GROUP_CONVERSATION -> { Conversation.ConversationType.GROUP_CONVERSATION -> {

View File

@ -31,7 +31,6 @@ import android.net.Uri
import android.os.Build import android.os.Build
import android.service.notification.StatusBarNotification import android.service.notification.StatusBarNotification
import android.text.TextUtils import android.text.TextUtils
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat import androidx.core.app.NotificationManagerCompat
import com.bluelinelabs.logansquare.LoganSquare import com.bluelinelabs.logansquare.LoganSquare
import com.nextcloud.talk.R import com.nextcloud.talk.R
@ -58,7 +57,7 @@ object NotificationUtils {
} }
} }
fun getCallSoundUri(context: Context, appPreferences: AppPreferences) : Uri? { fun getCallSoundUri(context: Context, appPreferences: AppPreferences): Uri? {
val ringtonePreferencesString: String? = appPreferences.callRingtoneUri val ringtonePreferencesString: String? = appPreferences.callRingtoneUri
return if (TextUtils.isEmpty(ringtonePreferencesString)) { return if (TextUtils.isEmpty(ringtonePreferencesString)) {
@ -74,7 +73,7 @@ object NotificationUtils {
} }
} }
fun getMessageSoundUri(context: Context, appPreferences: AppPreferences) : Uri? { fun getMessageSoundUri(context: Context, appPreferences: AppPreferences): Uri? {
val ringtonePreferencesString: String? = appPreferences.messageRingtoneUri val ringtonePreferencesString: String? = appPreferences.messageRingtoneUri
return if (TextUtils.isEmpty(ringtonePreferencesString)) { return if (TextUtils.isEmpty(ringtonePreferencesString)) {
@ -131,6 +130,7 @@ object NotificationUtils {
notificationManagerCompat.createNotificationChannel(channel) notificationManagerCompat.createNotificationChannel(channel)
} }
} }
@TargetApi(Build.VERSION_CODES.O) @TargetApi(Build.VERSION_CODES.O)
fun createNotificationChannelGroup( fun createNotificationChannelGroup(
context: Context, context: Context,

View File

@ -0,0 +1,27 @@
<!--
~ /*
~ * Nextcloud Talk application
~ *
~ * @author Mario Danic
~ * Copyright (C) 2017-2020 Mario Danic <mario@lovelyhq.com>
~ *
~ * This program is free software: you can redistribute it and/or modify
~ * it under the terms of the GNU General Public License as published by
~ * the Free Software Foundation, either version 3 of the License, or
~ * at your option) any later version.
~ *
~ * This program is distributed in the hope that it will be useful,
~ * but WITHOUT ANY WARRANTY; without even the implied warranty of
~ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ * GNU General Public License for more details.
~ *
~ * You should have received a copy of the GNU General Public License
~ * along with this program. If not, see <http://www.gnu.org/licenses/>.
~ */
-->
<vector android:autoMirrored="true" android:height="24dp"
android:viewportHeight="24.0" android:viewportWidth="24.0"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<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>

View File

@ -0,0 +1,93 @@
<!--
~ /*
~ * Nextcloud Talk application
~ *
~ * @author Mario Danic
~ * Copyright (C) 2017-2020 Mario Danic <mario@lovelyhq.com>
~ *
~ * This program is free software: you can redistribute it and/or modify
~ * it under the terms of the GNU General Public License as published by
~ * the Free Software Foundation, either version 3 of the License, or
~ * at your option) any later version.
~ *
~ * This program is distributed in the hope that it will be useful,
~ * but WITHOUT ANY WARRANTY; without even the implied warranty of
~ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ * GNU General Public License for more details.
~ *
~ * You should have received a copy of the GNU General Public License
~ * along with this program. If not, see <http://www.gnu.org/licenses/>.
~ */
-->
<vector android:autoMirrored="true" android:height="699dp"
android:viewportHeight="699" android:viewportWidth="1119.6091"
android:width="1119.6091dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#f2f2f2" android:pathData="M292.61,213m-213,0a213,213 0,1 1,426 0a213,213 0,1 1,-426 0"/>
<path android:fillColor="#2f2e41" android:pathData="M0,51.14c0,77.5 48.62,140.21 108.7,140.21"/>
<path android:fillColor="@color/colorPrimary" android:pathData="M108.7,191.35c0,-78.37 54.26,-141.78 121.3,-141.78"/>
<path android:fillColor="@color/colorPrimary" android:pathData="M39.38,58.17c0,73.61 31,133.18 69.32,133.18"/>
<path android:fillColor="#2f2e41" android:pathData="M108.7,191.35c0,-100.14 62.71,-181.17 140.21,-181.17"/>
<path android:fillColor="#a8a8a8" android:pathData="M85.83,192.34s15.42,-0.47 20.06,-3.78 23.71,-7.26 24.87,-1.95 23.17,26.39 5.76,26.53 -40.44,-2.71 -45.08,-5.54S85.83,192.34 85.83,192.34Z"/>
<path android:fillAlpha="0.2" android:fillColor="#FF000000"
android:pathData="M136.83,211.28c-17.4,0.14 -40.44,-2.71 -45.08,-5.54 -3.53,-2.15 -4.94,-9.87 -5.41,-13.43 -0.33,0.01 -0.51,0.02 -0.51,0.02s0.98,12.43 5.61,15.26 27.67,5.68 45.08,5.54c5.02,-0.04 6.76,-1.83 6.66,-4.48C142.49,210.26 140.57,211.25 136.83,211.28Z" android:strokeAlpha="0.2"/>
<path android:fillColor="#3f3d56" android:pathData="M11.61,424.5a187,25.44 0,1 0,374 0a187,25.44 0,1 0,-374 0z"/>
<path android:fillAlpha="0.1" android:fillColor="#FF000000"
android:pathData="M41.61,424.5a157,21.36 0,1 0,314 0a157,21.36 0,1 0,-314 0z" android:strokeAlpha="0.1"/>
<path android:fillColor="#3f3d56" android:pathData="M553.61,660.5a283,38.5 0,1 0,566 0a283,38.5 0,1 0,-566 0z"/>
<path android:fillColor="#3f3d56" android:pathData="M140.61,645.5a170,23.13 0,1 0,340 0a170,23.13 0,1 0,-340 0z"/>
<path android:fillColor="#00000000"
android:pathData="M462.61,626c90,23 263,-30 282,-90"
android:strokeColor="#2f2e41" android:strokeWidth="2"/>
<path android:fillColor="#00000000"
android:pathData="M309.61,259s130,-36 138,80 -107,149 -17,172"
android:strokeColor="#2f2e41" android:strokeWidth="2"/>
<path android:fillColor="#00000000"
android:pathData="M184.01,537.28s39.07,-10.82 41.48,24.04 -32.16,44.78 -5.11,51.7"
android:strokeColor="#2f2e41" android:strokeWidth="2"/>
<path android:fillColor="#2f2e41" android:pathData="M778.7,563.24 L770.83,613.54s-38.78,20.6 -11.51,21.21 155.73,0 155.73,0 24.84,0 -14.54,-21.81l-7.88,-52.72Z"/>
<path android:fillAlpha="0.1" android:fillColor="#FF000000"
android:pathData="M753.83,634.2c6.19,-5.51 17,-11.25 17,-11.25l7.88,-50.3 113.92,0.11 7.88,49.58c9.19,5.09 14.87,8.99 18.2,11.98 5.06,-1.15 10.59,-5.44 -18.2,-21.39l-7.88,-52.72 -113.92,3.03L770.83,613.54S738.24,630.85 753.83,634.2Z" android:strokeAlpha="0.1"/>
<path android:fillColor="#2f2e41" android:pathData="M596.48,212.69L1073.64,212.69A18.05,18.05 0,0 1,1091.69 230.73L1091.69,552.16A18.05,18.05 0,0 1,1073.64 570.21L596.48,570.21A18.05,18.05 0,0 1,578.43 552.16L578.43,230.73A18.05,18.05 0,0 1,596.48 212.69z"/>
<path android:fillColor="#3f3d56" android:pathData="M595.7,231.78h478.71v267.84h-478.71z"/>
<path android:fillColor="#f2f2f2" android:pathData="M835.06,223.29m-3.03,0a3.03,3.03 0,1 1,6.06 0a3.03,3.03 0,1 1,-6.06 0"/>
<path android:fillColor="#2f2e41" android:pathData="M1091.69,520.82L1091.69,552.16a18.04,18.04 0,0 1,-18.05 18.05L596.48,570.21A18.04,18.04 0,0 1,578.43 552.16L578.43,520.82Z"/>
<path android:fillColor="#2f2e41" android:pathData="M968.98,667.47l0,6.06l-326.01,0l0,-4.85l0.45,-1.21l8.04,-21.82l310.86,0l6.67,21.82z"/>
<path android:fillColor="#2f2e41" android:pathData="M1094.44,661.53c-0.59,2.54 -2.84,5.22 -7.9,7.75 -18.18,9.09 -55.14,-2.42 -55.14,-2.42s-28.48,-4.85 -28.48,-17.57a22.72,22.72 0,0 1,2.5 -1.48c7.64,-4.04 32.98,-14.02 77.92,0.42a18.74,18.74 0,0 1,8.54 5.6C1093.69,655.95 1095.12,658.66 1094.44,661.53Z"/>
<path android:fillAlpha="0.1" android:fillColor="#FF000000"
android:pathData="M1094.44,661.53c-22.25,8.53 -42.08,9.16 -62.44,-4.97 -10.27,-7.13 -19.59,-8.89 -26.59,-8.76 7.64,-4.04 32.98,-14.02 77.92,0.42a18.74,18.74 0,0 1,8.54 5.6C1093.69,655.95 1095.12,658.66 1094.44,661.53Z" android:strokeAlpha="0.1"/>
<path android:fillColor="#f2f2f2" android:pathData="M1058.66,654.13a7.88,2.42 0,1 0,15.76 0a7.88,2.42 0,1 0,-15.76 0z"/>
<path android:fillColor="#f2f2f2" android:pathData="M835.06,545.67m-11.51,0a11.51,11.51 0,1 1,23.03 0a11.51,11.51 0,1 1,-23.03 0"/>
<path android:fillAlpha="0.1" android:fillColor="#FF000000"
android:pathData="M968.98,667.47l0,6.06l-326.01,0l0,-4.85l0.45,-1.21l325.56,0z" android:strokeAlpha="0.1"/>
<path android:fillColor="#2f2e41" android:pathData="M108.61,159h208v242h-208z"/>
<path android:fillColor="#3f3d56" android:pathData="M87.61,135h250v86h-250z"/>
<path android:fillColor="#3f3d56" android:pathData="M87.61,237h250v86h-250z"/>
<path android:fillColor="#3f3d56" android:pathData="M87.61,339h250v86h-250z"/>
<path android:fillAlpha="0.4" android:fillColor="@color/colorPrimary"
android:pathData="M271.61,150h16v16h-16z" android:strokeAlpha="0.4"/>
<path android:fillAlpha="0.8" android:fillColor="@color/colorPrimary"
android:pathData="M294.61,150h16v16h-16z" android:strokeAlpha="0.8"/>
<path android:fillColor="@color/colorPrimary" android:pathData="M317.61,150h16v16h-16z"/>
<path android:fillAlpha="0.4" android:fillColor="@color/colorPrimary"
android:pathData="M271.61,251h16v16h-16z" android:strokeAlpha="0.4"/>
<path android:fillAlpha="0.8" android:fillColor="@color/colorPrimary"
android:pathData="M294.61,251h16v16h-16z" android:strokeAlpha="0.8"/>
<path android:fillColor="@color/colorPrimary" android:pathData="M317.61,251h16v16h-16z"/>
<path android:fillAlpha="0.4" android:fillColor="@color/colorPrimary"
android:pathData="M271.61,352h16v16h-16z" android:strokeAlpha="0.4"/>
<path android:fillAlpha="0.8" android:fillColor="@color/colorPrimary"
android:pathData="M294.61,352h16v16h-16z" android:strokeAlpha="0.8"/>
<path android:fillColor="@color/colorPrimary" android:pathData="M317.61,352h16v16h-16z"/>
<path android:fillColor="#2f2e41" android:pathData="M316.61,538m-79,0a79,79 0,1 1,158 0a79,79 0,1 1,-158 0"/>
<path android:fillColor="#2f2e41" android:pathData="M280.61,600h24v43h-24z"/>
<path android:fillColor="#2f2e41" android:pathData="M328.61,600h24v43h-24z"/>
<path android:fillColor="#2f2e41" android:pathData="M280.61,643.5a20,7.5 0,1 0,40 0a20,7.5 0,1 0,-40 0z"/>
<path android:fillColor="#2f2e41" android:pathData="M328.61,642.5a20,7.5 0,1 0,40 0a20,7.5 0,1 0,-40 0z"/>
<path android:fillColor="#fff" android:pathData="M318.61,518m-27,0a27,27 0,1 1,54 0a27,27 0,1 1,-54 0"/>
<path android:fillColor="#3f3d56" android:pathData="M318.61,518m-9,0a9,9 0,1 1,18 0a9,9 0,1 1,-18 0"/>
<path android:fillColor="@color/colorPrimary" android:pathData="M239.98,464.53c-6.38,-28.57 14.01,-57.43 45.54,-64.47s62.27,10.41 68.64,38.98 -14.52,39.1 -46.05,46.14S246.36,493.1 239.98,464.53Z"/>
<path android:fillColor="#2f2e41" android:pathData="M349.51,526.39a12.4,39.5 66.83,1 0,72.63 -31.08a12.4,39.5 66.83,1 0,-72.63 31.08z"/>
<path android:fillColor="#2f2e41" android:pathData="M201.51,579.39a12.4,39.5 66.83,1 0,72.63 -31.08a12.4,39.5 66.83,1 0,-72.63 31.08z"/>
<path android:fillColor="#fff" android:pathData="M362.61,561c0,7.73 -19.91,23 -42,23s-43,-14.27 -43,-22 20.91,-6 43,-6S362.61,553.27 362.61,561Z"/>
</vector>

View File

@ -42,7 +42,7 @@
android:layout_margin="8dp" android:layout_margin="8dp"
android:textAlignment="center" android:textAlignment="center"
android:text="@string/nc_conversations_empty" android:text="@string/nc_conversations_empty"
android:textSize="20sp" android:textSize="16sp"
/> />
</RelativeLayout> </RelativeLayout>

View File

@ -47,7 +47,7 @@
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="match_parent" android:layout_height="match_parent"
android:layout_alignParentStart="true" android:layout_alignParentStart="true"
android:minWidth="48dp" android:minWidth="8dp"
android:layout_centerVertical="true"> android:layout_centerVertical="true">
<ImageButton <ImageButton

View File

@ -325,7 +325,7 @@
<string name="nc_not_defined_error">Unknown error</string> <string name="nc_not_defined_error">Unknown error</string>
<string name="nc_unauthorized_error">Unauthorized</string> <string name="nc_unauthorized_error">Unauthorized</string>
<string name="nc_oops">Ooops, something went wrong.</string> <string name="nc_oops">Ooops, something went wrong!</string>
<string name="nc_general_settings">General</string> <string name="nc_general_settings">General</string>
<string name="nc_allow_guests">Allow guests</string> <string name="nc_allow_guests">Allow guests</string>