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.content.Context
import android.os.Build
import android.os.Bundle
import android.util.Log
import android.view.WindowManager
import android.webkit.SslErrorHandler
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.app.AppCompatDelegate
import com.nextcloud.talk.R
import com.nextcloud.talk.events.CertificateEvent
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.PropertyFactory;
import at.bitfire.dav4jvm.XmlUtils;
import lombok.Getter;
import lombok.Setter;
public class NCEncrypted implements Property {
public static final Name NAME =
@ -43,14 +41,14 @@ public class NCEncrypted implements Property {
private boolean ncEncrypted;
public boolean isNcEncrypted() {
return ncEncrypted;
}
private NCEncrypted(boolean isEncrypted) {
ncEncrypted = isEncrypted;
}
public boolean isNcEncrypted() {
return ncEncrypted;
}
public static class Factory implements PropertyFactory {
@Nullable

View File

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

View File

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

View File

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

View File

@ -34,8 +34,6 @@ import java.io.IOException;
import at.bitfire.dav4jvm.Property;
import at.bitfire.dav4jvm.PropertyFactory;
import at.bitfire.dav4jvm.XmlUtils;
import lombok.Getter;
import lombok.Setter;
public class OCSize implements Property {
public static final Property.Name NAME =
@ -43,14 +41,14 @@ public class OCSize implements Property {
private long ocSize;
public long getOcSize() {
return ocSize;
}
private OCSize(long size) {
ocSize = size;
}
public long getOcSize() {
return ocSize;
}
public static class Factory implements PropertyFactory {
@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,
0, intent, 0)
@ -222,6 +223,7 @@ class MessageNotificationWorker(
NotificationManagerCompat.from(applicationContext).notify(notificationId, notificationBuilder.build())
}
}
private fun getStyle(
decryptedPushMessage: DecryptedPushMessage,
conversationType: Conversation.ConversationType,

View File

@ -211,15 +211,15 @@ class ChatMessage : IMessage, MessageContentType, MessageContentType.Image {
if (!TextUtils.isEmpty(actorDisplayName)) actorDisplayName else sharedApplication
!!.getString(R.string.nc_guest))
}
/*} else if (messageType == MessageType.SINGLE_LINK_MESSAGE) {
return if (actorId.equals(activeUser!!.userId)) {
sharedApplication!!.resources.getString(R.string.nc_sent_a_link_you)
} else {
String.format(sharedApplication
!!.resources
.getString(R.string.nc_sent_a_link),
if (!TextUtils.isEmpty(actorDisplayName)) actorDisplayName else sharedApplication!!.getString(R.string.nc_guest))
}*/
/*} else if (messageType == MessageType.SINGLE_LINK_MESSAGE) {
return if (actorId.equals(activeUser!!.userId)) {
sharedApplication!!.resources.getString(R.string.nc_sent_a_link_you)
} else {
String.format(sharedApplication
!!.resources
.getString(R.string.nc_sent_a_link),
if (!TextUtils.isEmpty(actorDisplayName)) actorDisplayName else sharedApplication!!.getString(R.string.nc_guest))
}*/
} else if (messageType == MessageType.SINGLE_LINK_AUDIO_MESSAGE) {
return if (actorId.equals(activeUser!!.userId)) {
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.signaling.settings.SignalingSettingsOverall
import com.nextcloud.talk.models.json.userprofile.UserProfileOverall
import io.reactivex.Observable
import retrofit2.http.*
interface ApiService {
@ -43,7 +42,7 @@ interface ApiService {
@GET
suspend fun getNotification(@Header("Authorization") authorization: String,
@Url url: String): NotificationOverall
@Url url: String): NotificationOverall
@FormUrlEncoded
@PUT

View File

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

View File

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

View File

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

View File

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

View File

@ -27,6 +27,7 @@ import android.view.ViewGroup
import androidx.core.view.isVisible
import coil.api.load
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.newarch.features.contactsflow.ParticipantElement
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) {
"users" -> {
val conversation = Conversation()
conversation.type = Conversation.ConversationType.ONE_TO_ONE_CONVERSATION
when (participant.type) {
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)) {
user?.getCredentials()?.let { addHeader("Authorization", it) }
fallback(Images().getImageForConversation(context, conversation, true))
}
}
else -> {
holder.itemView.avatarImageView.load(ApiUtils.getUrlForAvatarWithName(user?.baseUrl, participant.userId, R.dimen.avatar_size)) {
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.ext.initRecyclerView
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.utils.bundle.BundleKeys
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.view.*
import org.koin.android.ext.android.inject
class ContactsView(private val bundle: Bundle? = null) : BaseView() {
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)
val view = super.onCreateView(inflater, container)
val contactsViewSource = ContactsViewSource(data = viewModel.contactsLiveData)
val participantsAdapterBuilder = Adapter.builder(this)
.addSource(ContactsViewSource(data = viewModel.contactsLiveData))
.addSource(contactsViewSource)
.addSource(ContactsHeaderSource(activity as Context, ParticipantElementType.PARTICIPANT_HEADER.ordinal))
.addSource(ContactsViewFooterSource(activity as Context, ParticipantElementType.PARTICIPANT_FOOTER.ordinal))
.addPresenter(ContactPresenter(activity as Context, ::onElementClick))
@ -102,9 +103,13 @@ class ContactsView(private val bundle: Bundle? = null) : BaseView() {
view.messageStateImageView.imageTintList = null
})
.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.messageStateImageView.load((activity as Context).getDrawable(R.drawable.ic_announcement_white_24dp))
view.messageStateImageView.imageTintList = resources?.getColor(R.color.colorPrimary)?.let { ColorStateList.valueOf(it) }
view.messageStateImageView.load((activity as Context).getDrawable(R.drawable.ic_undraw_server_down_s4lk))
view.messageStateImageView.imageTintList = null
})
.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
searchLayout?.searchProgressBar?.isVisible = false
}
ContactsViewOperationState.LOADING_FAILED -> {
searchLayout?.searchProgressBar?.isVisible = false
contactsViewSource.postError(Exception(operationState.errorMessage))
}
else -> {
// do nothing, we're waiting
}

View File

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

View File

@ -42,31 +42,31 @@ class ContactsHeaderSource(private val context: Context, private val elementType
headersAlreadyAdded = mutableListOf()
for (participantElement in list) {
if (participantElement.data is Participant) {
val participant = participantElement.data
val header = when (participant.source) {
"users" -> {
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)
}
val participant = participantElement.data
val header = when (participant.source) {
"users" -> {
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)
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

View File

@ -23,7 +23,10 @@
package com.nextcloud.talk.newarch.features.contactsflow.contacts
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.models.json.conversations.Conversation
import com.nextcloud.talk.models.json.conversations.ConversationOverall
@ -167,7 +170,8 @@ class ContactsViewModel constructor(
}
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.Source
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) {
private var currentPage: Page? = null
override fun onPageOpened(page: Page, dependencies: List<Element<*>>) {
super.onPageOpened(page, dependencies)
if (page.previous() == null) {
currentPage = page
postResult(page, data)
}
}
fun postError(exception: Exception){
currentPage?.let { page ->
postResult(page, exception)
}
}
override fun getElementType(data: T): Int {
return data.elementType
}

View File

@ -154,6 +154,7 @@ open class ConversationPresenter(context: Context, onElementClick: ((Page, Holde
{
addHeader("Authorization", user.getCredentials())
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.MaterialDialog
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.autodispose.ControllerScopeProvider
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.mvvm.BaseView
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.DisplayUtils
import com.nextcloud.talk.utils.animations.SharedElementTransition
@ -148,6 +145,7 @@ class ConversationsListView : BaseView() {
override fun onAttach(view: View) {
super.onAttach(view)
floatingActionButton?.isVisible = true
appBar?.isVisible = true
}
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
fun getImageForConversation(context: Context, conversation: Conversation): Drawable? {
fun getImageForConversation(context: Context, conversation: Conversation, fallback: Boolean = false): Drawable? {
conversation.objectType?.let { objectType ->
when (objectType) {
"share:password" -> {
@ -104,6 +104,10 @@ class Images {
when (conversation.type) {
Conversation.ConversationType.ONE_TO_ONE_CONVERSATION -> {
if (fallback) {
return DisplayUtils.getRoundedDrawableFromBitmap(getImageWithBackground(context, R.drawable.ic_baseline_person_24))
}
return null
}
Conversation.ConversationType.GROUP_CONVERSATION -> {

View File

@ -31,7 +31,6 @@ import android.net.Uri
import android.os.Build
import android.service.notification.StatusBarNotification
import android.text.TextUtils
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import com.bluelinelabs.logansquare.LoganSquare
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
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
return if (TextUtils.isEmpty(ringtonePreferencesString)) {
@ -131,6 +130,7 @@ object NotificationUtils {
notificationManagerCompat.createNotificationChannel(channel)
}
}
@TargetApi(Build.VERSION_CODES.O)
fun createNotificationChannelGroup(
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:textAlignment="center"
android:text="@string/nc_conversations_empty"
android:textSize="20sp"
android:textSize="16sp"
/>
</RelativeLayout>

View File

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

View File

@ -325,7 +325,7 @@
<string name="nc_not_defined_error">Unknown error</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_allow_guests">Allow guests</string>