diff --git a/app/build.gradle b/app/build.gradle index 98ab86851..3e9ff0fcb 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -154,9 +154,9 @@ android { } ext { - work_version = "2.3.0-alpha02" + work_version = '2.3.0-beta02' koin_version = "2.1.0-alpha-1" - lifecycle_version = "2.2.0-rc01" + lifecycle_version = '2.2.0-rc03' coil_version = "0.9.1" room_version = "2.2.3" } @@ -257,12 +257,12 @@ dependencies { implementation 'com.squareup.okhttp3:okhttp-urlconnection:3.14.3' implementation 'com.squareup.okhttp3:logging-interceptor:3.14.3' - implementation 'com.squareup.retrofit2:retrofit:2.6.2' - implementation 'com.squareup.retrofit2:adapter-rxjava2:2.6.2' + implementation 'com.squareup.retrofit2:retrofit:2.7.1' + implementation 'com.squareup.retrofit2:adapter-rxjava2:2.7.1' implementation 'com.github.aurae.retrofit2:converter-logansquare:1.4.1' implementation group: 'joda-time', name: 'joda-time', version: '2.10.3' implementation 'com.bluelinelabs:logansquare:1.3.7' - implementation group: 'com.fasterxml.jackson.core', name: 'jackson-core', version: '2.10.0.pr1' + implementation group: 'com.fasterxml.jackson.core', name: 'jackson-core', version: '2.10.1' kapt 'com.bluelinelabs:logansquare-compiler:1.3.7' compileOnly 'javax.annotation:jsr250-api:1.0' @@ -277,8 +277,8 @@ dependencies { annotationProcessor "org.projectlombok:lombok:1.18.10" kapt "org.projectlombok:lombok:1.18.10" - implementation 'com.jakewharton:butterknife:10.2.0' - kapt 'com.jakewharton:butterknife-compiler:10.2.0' + implementation 'com.jakewharton:butterknife:10.2.1' + kapt 'com.jakewharton:butterknife-compiler:10.2.1' implementation 'com.github.HITGIF:TextFieldBoxes:1.4.5' implementation 'eu.davidea:flexible-adapter:5.1.0' implementation 'eu.davidea:flexible-adapter-ui:1.0.0' @@ -315,13 +315,13 @@ dependencies { implementation 'org.parceler:parceler-api:1.1.12' kapt 'org.parceler:parceler:1.1.12' - testImplementation 'junit:junit:4.12' + testImplementation 'junit:junit:4.13' testImplementation 'org.mockito:mockito-core:3.0.0' testImplementation 'org.powermock:powermock-core:2.0.2' testImplementation 'org.powermock:powermock-module-junit4:2.0.2' testImplementation 'org.powermock:powermock-api-mockito2:2.0.2' - androidTestImplementation('androidx.test.espresso:espresso-core:3.3.0-alpha02', { + androidTestImplementation('androidx.test.espresso:espresso-core:3.3.0-alpha03', { exclude group: 'com.android.support', module: 'support-annotations' }) implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.0.0' diff --git a/app/src/main/java/com/nextcloud/talk/models/json/conversations/Conversation.kt b/app/src/main/java/com/nextcloud/talk/models/json/conversations/Conversation.kt index ae51873a6..c160fb3fd 100644 --- a/app/src/main/java/com/nextcloud/talk/models/json/conversations/Conversation.kt +++ b/app/src/main/java/com/nextcloud/talk/models/json/conversations/Conversation.kt @@ -39,9 +39,11 @@ import java.util.* @Data @JsonObject(serializeNullCollectionElements = true, serializeNullObjects = true) class Conversation { + @JsonIgnore + var databaseId: String? = null @JsonIgnore @NonNull - var internalUserId: Long? = null + var databaseUserId: Long? = null @JsonField(name = ["id"]) var conversationId: String? = null @JsonField(name = ["token"]) diff --git a/app/src/main/java/com/nextcloud/talk/newarch/data/presenters/AdvancedEmptyPresenter.kt b/app/src/main/java/com/nextcloud/talk/newarch/data/presenters/AdvancedEmptyPresenter.kt new file mode 100644 index 000000000..42ff0b7d2 --- /dev/null +++ b/app/src/main/java/com/nextcloud/talk/newarch/data/presenters/AdvancedEmptyPresenter.kt @@ -0,0 +1,37 @@ +/* + * + * * Nextcloud Talk application + * * + * * @author Mario Danic + * * Copyright (C) 2017-2020 Mario Danic + * * + * * 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 . + * + */ + +package com.nextcloud.talk.newarch.data.presenters + +import android.content.Context +import com.otaliastudios.elements.Element +import com.otaliastudios.elements.Page +import com.otaliastudios.elements.extensions.EmptyPresenter + +class AdvancedEmptyPresenter(context: Context, layout: Int, private val onViewClick: (() -> Unit)? = null) : EmptyPresenter(context, layout) { + override fun onBind(page: Page, holder: Holder, element: Element, payloads: List) { + super.onBind(page, holder, element, payloads) + holder.itemView.setOnClickListener { + onViewClick?.invoke() + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/nextcloud/talk/adapters/ConversationPresenter.kt b/app/src/main/java/com/nextcloud/talk/newarch/features/conversationsList/ConversationPresenter.kt similarity index 99% rename from app/src/main/java/com/nextcloud/talk/adapters/ConversationPresenter.kt rename to app/src/main/java/com/nextcloud/talk/newarch/features/conversationsList/ConversationPresenter.kt index 135cdaab8..6d0b0b297 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/ConversationPresenter.kt +++ b/app/src/main/java/com/nextcloud/talk/newarch/features/conversationsList/ConversationPresenter.kt @@ -20,7 +20,7 @@ * */ -package com.nextcloud.talk.adapters +package com.nextcloud.talk.newarch.features.conversationsList import android.content.Context import android.graphics.drawable.Drawable diff --git a/app/src/main/java/com/nextcloud/talk/newarch/features/conversationsList/ConversationsListSource.kt b/app/src/main/java/com/nextcloud/talk/newarch/features/conversationsList/ConversationsListSource.kt new file mode 100644 index 000000000..cb81efd7b --- /dev/null +++ b/app/src/main/java/com/nextcloud/talk/newarch/features/conversationsList/ConversationsListSource.kt @@ -0,0 +1,49 @@ +/* + * + * * Nextcloud Talk application + * * + * * @author Mario Danic + * * Copyright (C) 2017-2020 Mario Danic + * * + * * 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 . + * + */ + +package com.nextcloud.talk.newarch.features.conversationsList + +import androidx.lifecycle.LiveData +import com.nextcloud.talk.models.json.conversations.Conversation +import com.otaliastudios.elements.Element +import com.otaliastudios.elements.Page +import com.otaliastudios.elements.Source +import com.otaliastudios.elements.extensions.MainSource + +class ConversationsListSource(private val data: LiveData>, private val elementType: Int = 0, loadingIndicatorsEnabled: Boolean = true, errorIndicatorEnabled: Boolean = true, emptyIndicatorEnabled: Boolean = true) : MainSource(loadingIndicatorsEnabled, errorIndicatorEnabled, emptyIndicatorEnabled) { + + override fun onPageOpened(page: Page, dependencies: List>) { + super.onPageOpened(page, dependencies) + if (page.previous() == null) { + postResult(page, data) + } + } + + override fun dependsOn(source: Source<*>): Boolean { + return false + } + + override fun areItemsTheSame(first: T, second: T): Boolean { + return first.databaseId == second.databaseId + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/nextcloud/talk/newarch/features/conversationsList/ConversationsListView.kt b/app/src/main/java/com/nextcloud/talk/newarch/features/conversationsList/ConversationsListView.kt index d5af2818d..91599ee0d 100644 --- a/app/src/main/java/com/nextcloud/talk/newarch/features/conversationsList/ConversationsListView.kt +++ b/app/src/main/java/com/nextcloud/talk/newarch/features/conversationsList/ConversationsListView.kt @@ -22,7 +22,6 @@ package com.nextcloud.talk.newarch.features.conversationsList import android.os.Bundle import android.view.* -import android.view.ViewGroup.LayoutParams.WRAP_CONTENT import androidx.appcompat.widget.SearchView import androidx.lifecycle.observe import butterknife.OnClick @@ -36,13 +35,13 @@ import com.bluelinelabs.conductor.changehandler.TransitionChangeHandlerCompat import com.bluelinelabs.conductor.changehandler.VerticalChangeHandler import com.nextcloud.talk.R import com.nextcloud.talk.R.drawable -import com.nextcloud.talk.adapters.ConversationsPresenter import com.nextcloud.talk.controllers.ContactsController import com.nextcloud.talk.controllers.SettingsController import com.nextcloud.talk.controllers.bottomsheet.items.BasicListItemWithImage import com.nextcloud.talk.controllers.bottomsheet.items.listItemsWithImage import com.nextcloud.talk.models.json.conversations.Conversation import com.nextcloud.talk.newarch.conversationsList.mvp.BaseView +import com.nextcloud.talk.newarch.data.presenters.AdvancedEmptyPresenter import com.nextcloud.talk.newarch.mvvm.ext.initRecyclerView import com.nextcloud.talk.utils.ConductorRemapping import com.nextcloud.talk.utils.DisplayUtils @@ -147,19 +146,19 @@ class ConversationsListView : BaseView() { val view = super.onCreateView(inflater, container) val adapter = Adapter.builder(this) - .addSource(Source.fromLiveData(viewModel.conversationsLiveData)) + .addSource(ConversationsListSource(viewModel.conversationsLiveData)) .addPresenter(ConversationsPresenter(context, ::onElementClick, ::onElementLongClick)) .addPresenter(Presenter.forLoadingIndicator(context, R.layout.loading_state)) - .addPresenter(Presenter.forEmptyIndicator(context, R.layout.message_state)) + .addPresenter(AdvancedEmptyPresenter(context, R.layout.message_state, ::openNewConversationScreen)) .addPresenter(Presenter.forErrorIndicator(context, R.layout.message_state) { view, throwable -> view.messageStateTextView.setText(R.string.nc_oops) view.messageStateImageView.setImageDrawable(context.getDrawable(drawable.ic_announcement_white_24dp)) }) .into(view.recyclerView) + view.apply { recyclerView.initRecyclerView(SmoothScrollLinearLayoutManager(activity), adapter, false) - swipeRefreshLayoutView.setOnRefreshListener { view.swipeRefreshLayoutView.isRefreshing = false viewModel.loadConversations() diff --git a/app/src/main/java/com/nextcloud/talk/newarch/features/conversationsList/ConversationsListViewModel.kt b/app/src/main/java/com/nextcloud/talk/newarch/features/conversationsList/ConversationsListViewModel.kt index d55d6af38..50dab2925 100644 --- a/app/src/main/java/com/nextcloud/talk/newarch/features/conversationsList/ConversationsListViewModel.kt +++ b/app/src/main/java/com/nextcloud/talk/newarch/features/conversationsList/ConversationsListViewModel.kt @@ -182,7 +182,7 @@ class ConversationsListViewModel constructor( val mutableList = result.toMutableList() val internalUserId = globalService.currentUserLiveData.value!!.id mutableList.forEach { - it.internalUserId = internalUserId + it.databaseUserId = internalUserId } conversationsRepository.saveConversationsForUser( diff --git a/app/src/main/java/com/nextcloud/talk/newarch/local/converters/ParticipantMapConverter.kt b/app/src/main/java/com/nextcloud/talk/newarch/local/converters/ParticipantMapConverter.kt index 2e623c073..f5d0e9aa8 100644 --- a/app/src/main/java/com/nextcloud/talk/newarch/local/converters/ParticipantMapConverter.kt +++ b/app/src/main/java/com/nextcloud/talk/newarch/local/converters/ParticipantMapConverter.kt @@ -42,7 +42,7 @@ class ParticipantMapConverter { return null } - return LoganSquare.parse(value, HashMap::class.java) as java.util.HashMap? + return LoganSquare.parseMap(value, Participant::class.java) as HashMap? } } \ No newline at end of file diff --git a/app/src/main/java/com/nextcloud/talk/newarch/local/models/ConversationEntity.kt b/app/src/main/java/com/nextcloud/talk/newarch/local/models/ConversationEntity.kt index f1603a746..73eed3fce 100644 --- a/app/src/main/java/com/nextcloud/talk/newarch/local/models/ConversationEntity.kt +++ b/app/src/main/java/com/nextcloud/talk/newarch/local/models/ConversationEntity.kt @@ -118,7 +118,8 @@ data class ConversationEntity( fun ConversationEntity.toConversation(): Conversation { val conversation = Conversation() - conversation.internalUserId = this.userId + conversation.databaseId = this.id + conversation.databaseUserId = this.userId conversation.conversationId = this.conversationId conversation.type = this.type conversation.token = this.token @@ -148,8 +149,8 @@ fun ConversationEntity.toConversation(): Conversation { } fun Conversation.toConversationEntity(): ConversationEntity { - val conversationEntity = ConversationEntity(this.internalUserId.toString() + "@" + this.token) - conversationEntity.userId = this.internalUserId + val conversationEntity = ConversationEntity(this.databaseUserId.toString() + "@" + this.token) + conversationEntity.userId = this.databaseUserId conversationEntity.conversationId = this.conversationId conversationEntity.token = this.token conversationEntity.name = this.name diff --git a/app/src/main/java/com/nextcloud/talk/newarch/services/shortcuts/ShortcutService.kt b/app/src/main/java/com/nextcloud/talk/newarch/services/shortcuts/ShortcutService.kt index 15e963f3e..a452602bd 100644 --- a/app/src/main/java/com/nextcloud/talk/newarch/services/shortcuts/ShortcutService.kt +++ b/app/src/main/java/com/nextcloud/talk/newarch/services/shortcuts/ShortcutService.kt @@ -25,6 +25,7 @@ package com.nextcloud.talk.newarch.services.shortcuts import android.content.Context import android.content.Intent import android.graphics.drawable.BitmapDrawable +import android.graphics.drawable.Drawable import androidx.core.app.Person import androidx.core.content.pm.ShortcutInfoCompat import androidx.core.content.pm.ShortcutManagerCompat @@ -38,6 +39,7 @@ import coil.transform.CircleCropTransformation import com.nextcloud.talk.R import com.nextcloud.talk.activities.MainActivity import com.nextcloud.talk.models.json.conversations.Conversation +import com.nextcloud.talk.models.json.participants.Participant import com.nextcloud.talk.newarch.domain.repository.offline.ConversationsRepository import com.nextcloud.talk.newarch.local.models.UserNgEntity import com.nextcloud.talk.newarch.local.models.getCredentials @@ -47,6 +49,7 @@ import com.nextcloud.talk.utils.ApiUtils import com.nextcloud.talk.utils.bundle.BundleKeys import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.launch +import java.lang.Exception import kotlin.math.abs @@ -91,6 +94,7 @@ class ShortcutService constructor(private var context: Context, .setAlwaysBadged() .build()) + var iconImage: Drawable? = null for ((index, conversation) in conversations.withIndex()) { val intent = Intent(context, MainActivity::class.java) intent.action = BundleKeys.KEY_OPEN_CONVERSATION @@ -99,28 +103,31 @@ class ShortcutService constructor(private var context: Context, val persons = mutableListOf() conversation.participants?.forEach { - val hashMap = it.value as HashMap<*, *> + val key = it.key + val participant = it.value val personBuilder = Person.Builder() - personBuilder.setName(hashMap["name"].toString()) + personBuilder.setName(participant.name.toString()) personBuilder.setBot(false) // we need a key for each of the users - /*val isGuest = hashMap["type"]?.equals(Participant.ParticipantType.GUEST) == true - || hashMap["type"]?.equals(Participant.ParticipantType.GUEST_AS_MODERATOR) == true - || hashMap["type"]?.equals(Participant.ParticipantType.USER_FOLLOWING_LINK) == true + val isGuest = participant.type == Participant.ParticipantType.GUEST || participant.type == Participant.ParticipantType.GUEST_AS_MODERATOR || participant.type == Participant.ParticipantType.USER_FOLLOWING_LINK - val avatarUrl = if (isGuest) ApiUtils.getUrlForAvatarWithNameForGuests(user.baseUrl, hashMap["name"].toString(), R.dimen.avatar_size_big) - else ApiUtils.getUrlForAvatarWithName(user.baseUrl, hashMap["userId"].toString(), R.dimen.avatar_size_big) + val avatarUrl = if (isGuest) ApiUtils.getUrlForAvatarWithNameForGuests(user.baseUrl, participant.name, R.dimen.avatar_size_big) + else ApiUtils.getUrlForAvatarWithName(user.baseUrl, it.key, R.dimen.avatar_size_big) - iconImage = Coil.get(avatarUrl) { - addHeader("Authorization", user.getCredentials()) - transformations(CircleCropTransformation()) + try { + iconImage = Coil.get(avatarUrl) { + addHeader("Authorization", user.getCredentials()) + transformations(CircleCropTransformation()) + } + personBuilder.setIcon(IconCompat.createWithBitmap((iconImage as BitmapDrawable).bitmap)) + } catch (e: Exception) { + // No icon, that's fine for now } - personBuilder.setIcon(IconCompat.createWithBitmap((iconImage as BitmapDrawable).bitmap))*/ persons.add(personBuilder.build()) } - var iconImage = images.getImageForConversation(context, conversation) + iconImage = images.getImageForConversation(context, conversation) if (iconImage == null) { iconImage = Coil.get(ApiUtils.getUrlForAvatarWithName(user.baseUrl, conversation.name, R.dimen.avatar_size_big)) { diff --git a/app/src/main/res/layout/controller_conversations_rv.xml b/app/src/main/res/layout/controller_conversations_rv.xml index 1875d6e40..24d3206c6 100644 --- a/app/src/main/res/layout/controller_conversations_rv.xml +++ b/app/src/main/res/layout/controller_conversations_rv.xml @@ -49,8 +49,6 @@ android:layout_height="wrap_content" android:layout_gravity="bottom|end" android:layout_margin="16dp" - app:layout_anchor="@id/recyclerView" - app:layout_anchorGravity="bottom|end" app:backgroundTint="@color/colorPrimary" app:srcCompat="@drawable/ic_add_white_24px" app:tint="@color/white" /> diff --git a/app/src/main/res/menu/menu_conversation_plus_filter.xml b/app/src/main/res/menu/menu_conversation_plus_filter.xml index 637af70be..81cc62c16 100644 --- a/app/src/main/res/menu/menu_conversation_plus_filter.xml +++ b/app/src/main/res/menu/menu_conversation_plus_filter.xml @@ -33,8 +33,7 @@