diff --git a/app/build.gradle b/app/build.gradle index a879b743a..ae6bd7f8a 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -143,6 +143,7 @@ ext { work_version = "1.0.1" koin_version = "2.1.0-alpha-1" lifecycle_version = "2.1.0" + coil_version = "0.7.0" } @@ -269,6 +270,10 @@ dependencies { implementation 'com.github.mario.fresco:animated-gif:111' implementation 'com.github.mario.fresco:imagepipeline-okhttp3:111' + implementation "io.coil-kt:coil:${coil_version}" + implementation "io.coil-kt:coil-gif:${coil_version}" + implementation "io.coil-kt:coil-svg:${coil_version}" + implementation 'com.github.natario1:Autocomplete:v1.1.0' implementation 'com.github.cotechde.hwsecurity:hwsecurity-fido:2.4.5' diff --git a/app/src/main/java/com/nextcloud/talk/application/NextcloudTalkApplication.kt b/app/src/main/java/com/nextcloud/talk/application/NextcloudTalkApplication.kt index 9ab60366a..0adfabe85 100644 --- a/app/src/main/java/com/nextcloud/talk/application/NextcloudTalkApplication.kt +++ b/app/src/main/java/com/nextcloud/talk/application/NextcloudTalkApplication.kt @@ -151,7 +151,6 @@ class NextcloudTalkApplication : Application(), LifecycleObserver { Security.insertProviderAt(Conscrypt.newProvider(), 1) ClosedInterfaceImpl().providerInstallerInstallIfNeededAsync() - DeviceUtils.ignoreSpecialBatteryFeatures() val pushRegistrationWork = OneTimeWorkRequest.Builder(PushRegistrationWorker::class.java).build() val accountRemovalWork = OneTimeWorkRequest.Builder(AccountRemovalWorker::class.java).build() diff --git a/app/src/main/java/com/nextcloud/talk/controllers/AccountVerificationController.java b/app/src/main/java/com/nextcloud/talk/controllers/AccountVerificationController.java index 92addccf7..3193ea899 100644 --- a/app/src/main/java/com/nextcloud/talk/controllers/AccountVerificationController.java +++ b/app/src/main/java/com/nextcloud/talk/controllers/AccountVerificationController.java @@ -48,6 +48,7 @@ import com.nextcloud.talk.jobs.CapabilitiesWorker; import com.nextcloud.talk.jobs.PushRegistrationWorker; import com.nextcloud.talk.jobs.SignalingSettingsWorker; import com.nextcloud.talk.models.database.UserEntity; +import com.nextcloud.talk.newarch.features.conversationsList.ConversationsListView; import com.nextcloud.talk.utils.ApiUtils; import com.nextcloud.talk.utils.ClosedInterfaceImpl; import com.nextcloud.talk.utils.bundle.BundleKeys; @@ -407,7 +408,7 @@ public class AccountVerificationController extends BaseController { getActivity().runOnUiThread(() -> { if (userUtils.getUsers().size() == 1) { getRouter().setRoot(RouterTransaction.with(new - ConversationsListController()) + ConversationsListView()) .pushChangeHandler(new HorizontalChangeHandler()) .popChangeHandler(new HorizontalChangeHandler())); } else { @@ -474,7 +475,7 @@ public class AccountVerificationController extends BaseController { } else { if (userUtils.anyUserExists()) { - getRouter().setRoot(RouterTransaction.with(new ConversationsListController()) + getRouter().setRoot(RouterTransaction.with(new ConversationsListView()) .pushChangeHandler(new HorizontalChangeHandler()) .popChangeHandler(new HorizontalChangeHandler())); } else { diff --git a/app/src/main/java/com/nextcloud/talk/controllers/ConversationsListController.java b/app/src/main/java/com/nextcloud/talk/controllers/ConversationsListController.java index 11537d5d2..51ef1fdc3 100644 --- a/app/src/main/java/com/nextcloud/talk/controllers/ConversationsListController.java +++ b/app/src/main/java/com/nextcloud/talk/controllers/ConversationsListController.java @@ -142,9 +142,6 @@ public class ConversationsListController extends BaseController implements Searc @BindView(R.id.progressBar) ProgressBar progressBarView; - @BindView(R.id.emptyLayout) - RelativeLayout emptyLayoutView; - @BindView(R.id.fast_scroller) FastScroller fastScroller; @@ -319,7 +316,7 @@ public class ConversationsListController extends BaseController implements Searc progressBarView.setVisibility(View.GONE); } - if (roomsOverall.getOcs().getData().size() > 0) { + /*if (roomsOverall.getOcs().getData().size() > 0) { if (emptyLayoutView.getVisibility() != View.GONE) { emptyLayoutView.setVisibility(View.GONE); } @@ -335,7 +332,7 @@ public class ConversationsListController extends BaseController implements Searc if (swipeRefreshLayout.getVisibility() != View.GONE) { swipeRefreshLayout.setVisibility(View.GONE); } - } + }*/ Conversation conversation; for (int i = 0; i < roomsOverall.getOcs().getData().size(); i++) { @@ -386,14 +383,14 @@ public class ConversationsListController extends BaseController implements Searc HttpException exception = (HttpException) throwable; switch (exception.code()) { case 401: - if (getParentController() != null && + /*if (getParentController() != null && getParentController().getRouter() != null) { getParentController().getRouter().pushController((RouterTransaction.with (new WebViewLoginController(currentUser.getBaseUrl(), true)) .pushChangeHandler(new VerticalChangeHandler()) .popChangeHandler(new VerticalChangeHandler()))); - } + }*/ break; default: break; @@ -432,7 +429,7 @@ public class ConversationsListController extends BaseController implements Searc swipeRefreshLayout.setOnRefreshListener(() -> fetchData(false)); swipeRefreshLayout.setColorSchemeResources(R.color.colorPrimary); - emptyLayoutView.setOnClickListener(v -> showNewConversationsScreen()); + //emptyLayoutView.setOnClickListener(v -> showNewConversationsScreen()); floatingActionButton.setOnClickListener(v -> { showNewConversationsScreen(); }); diff --git a/app/src/main/java/com/nextcloud/talk/newarch/di/module/NetworkModule.kt b/app/src/main/java/com/nextcloud/talk/newarch/di/module/NetworkModule.kt index 0f2a6891f..907b80b7f 100644 --- a/app/src/main/java/com/nextcloud/talk/newarch/di/module/NetworkModule.kt +++ b/app/src/main/java/com/nextcloud/talk/newarch/di/module/NetworkModule.kt @@ -251,3 +251,9 @@ fun createNextcloudTalkRepository(apiService: ApiService): NextcloudTalkReposito return NextcloudTalkRepositoryImpl(apiService) } +fun createGetConversationsUseCase( + nextcloudTalkRepository: NextcloudTalkRepository, + apiErrorHandler: ApiErrorHandler +): GetConversationsUseCase { + return GetConversationsUseCase(nextcloudTalkRepository, apiErrorHandler) +} 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 d1fafa2f7..12ff092de 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,6 +22,7 @@ package com.nextcloud.talk.newarch.features.conversationsList import android.app.SearchManager import android.content.Context +import android.content.res.Resources import android.graphics.Bitmap import android.os.Build import android.os.Bundle @@ -60,6 +61,7 @@ import com.nextcloud.talk.models.json.conversations.Conversation import com.nextcloud.talk.newarch.conversationsList.mvp.BaseView import com.nextcloud.talk.newarch.mvvm.ViewState.FAILED import com.nextcloud.talk.newarch.mvvm.ViewState.LOADED +import com.nextcloud.talk.newarch.mvvm.ViewState.LOADED_EMPTY import com.nextcloud.talk.newarch.mvvm.ViewState.LOADING import com.nextcloud.talk.newarch.mvvm.ext.initRecyclerView import com.nextcloud.talk.utils.ApiUtils @@ -72,12 +74,14 @@ import eu.davidea.flexibleadapter.FlexibleAdapter.OnItemClickListener import eu.davidea.flexibleadapter.FlexibleAdapter.OnItemLongClickListener import eu.davidea.flexibleadapter.common.SmoothScrollLinearLayoutManager import eu.davidea.flexibleadapter.items.IFlexible -import kotlinx.android.synthetic.main.controller_conversations_rv.view.emptyLayout +import kotlinx.android.synthetic.main.controller_conversations_rv.view.dataStateView import kotlinx.android.synthetic.main.controller_conversations_rv.view.floatingActionButton -import kotlinx.android.synthetic.main.controller_conversations_rv.view.progressBar import kotlinx.android.synthetic.main.controller_conversations_rv.view.recyclerView -import kotlinx.android.synthetic.main.controller_conversations_rv.view.swipeRefreshLayoutView import kotlinx.android.synthetic.main.fast_scroller.view.fast_scroller +import kotlinx.android.synthetic.main.view_states.view.errorStateImageView +import kotlinx.android.synthetic.main.view_states.view.errorStateTextView +import kotlinx.android.synthetic.main.view_states.view.loadingStateView +import kotlinx.android.synthetic.main.view_states.view.stateWithMessageView import org.koin.android.ext.android.inject import org.parceler.Parcels import java.util.ArrayList @@ -178,18 +182,36 @@ class ConversationsListView() : BaseView(), OnQueryTextListener, viewState.observe(this@ConversationsListView, Observer { value -> when (value) { LOADING -> { - view?.recyclerView?.visibility = View.GONE - view?.emptyLayout?.visibility = View.GONE - view?.swipeRefreshLayoutView?.visibility = View.GONE - view?.progressBar?.visibility = View.VISIBLE + view?.loadingStateView?.visibility = View.VISIBLE + view?.stateWithMessageView?.visibility = View.GONE + view?.dataStateView?.visibility = View.GONE view?.floatingActionButton?.visibility = View.GONE - searchItem?.setVisible(false) + searchItem?.isVisible = false } - LOADED, FAILED -> { - view?.recyclerView?.visibility = View.VISIBLE - // The rest is handled in an actual network call - view?.progressBar?.visibility = View.GONE - view?.floatingActionButton?.visibility = View.VISIBLE + LOADED -> { + view?.loadingStateView?.visibility = View.GONE + view?.stateWithMessageView?.visibility = View.GONE + view!!.dataStateView.visibility = View.VISIBLE + view?.floatingActionButton?.visibility = View.GONE + searchItem?.isVisible = true + } + LOADED_EMPTY, FAILED -> { + view?.loadingStateView?.visibility = View.GONE + view?.dataStateView?.visibility = View.VISIBLE + view?.floatingActionButton?.visibility = View.GONE + searchItem?.isVisible = false + + if (value.equals(FAILED)) { + view?.stateWithMessageView?.errorStateTextView?.text = messageData + view?.stateWithMessageView?.errorStateImageView?.setImageResource( + R.drawable.ic_announcement_white_24dp + ) + } else { + view?.stateWithMessageView?.errorStateTextView?.text = resources?.getText(R.string.nc_conversations_empty) + view?.stateWithMessageView?.errorStateImageView?.setImageResource(R.drawable.ic_logo) + } + + view?.stateWithMessageView?.visibility = View.VISIBLE } else -> { // We should not be here @@ -208,16 +230,6 @@ class ConversationsListView() : BaseView(), OnQueryTextListener, } recyclerViewAdapter.updateDataSet(newConversations as List>?) - - if (it.isNotEmpty()) { - view?.emptyLayout?.visibility = View.GONE - view?.swipeRefreshLayoutView?.visibility = View.VISIBLE - searchItem?.setVisible(true) - } else { - view?.emptyLayout?.visibility = View.VISIBLE - view?.swipeRefreshLayoutView?.visibility = View.GONE - searchItem?.setVisible(false) - } }) }) @@ -243,7 +255,8 @@ class ConversationsListView() : BaseView(), OnQueryTextListener, dataSource.subscribe(object : BaseBitmapDataSubscriber() { override fun onNewResultImpl(bitmap: Bitmap?) { if (bitmap != null && resources != null) { - val roundedBitmapDrawable = RoundedBitmapDrawableFactory.create(resources!!, bitmap) + val roundedBitmapDrawable = RoundedBitmapDrawableFactory.create(resources as Resources, + bitmap) roundedBitmapDrawable.isCircular = true roundedBitmapDrawable.setAntiAlias(true) menuItem.icon = roundedBitmapDrawable @@ -261,8 +274,19 @@ class ConversationsListView() : BaseView(), OnQueryTextListener, return R.layout.controller_conversations_rv } - @OnClick(R.id.floatingActionButton, R.id.emptyLayout) + @OnClick(R.id.floatingActionButton) fun onFloatingActionButtonClick() { + openNewConversationScreen() + } + + @OnClick(R.id.stateWithMessageView) + fun onStateWithMessageViewClick() { + if (viewModel.viewState.equals(LOADED_EMPTY)) { + openNewConversationScreen() + } + } + + private fun openNewConversationScreen() { val bundle = Bundle() bundle.putBoolean(BundleKeys.KEY_NEW_CONVERSATION, true) router.pushController( @@ -273,7 +297,7 @@ class ConversationsListView() : BaseView(), OnQueryTextListener, } override fun getTitle(): String? { - return resources!!.getString(R.string.nc_app_name) + return resources?.getString(R.string.nc_app_name) } override fun onAttach(view: View) { 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 11e07106c..3d951f8c5 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 @@ -30,6 +30,7 @@ import com.nextcloud.talk.newarch.domain.usecases.base.UseCaseResponse import com.nextcloud.talk.newarch.mvvm.ViewState import com.nextcloud.talk.newarch.mvvm.ViewState.FAILED import com.nextcloud.talk.newarch.mvvm.ViewState.LOADED +import com.nextcloud.talk.newarch.mvvm.ViewState.LOADED_EMPTY import com.nextcloud.talk.newarch.mvvm.ViewState.LOADING import com.nextcloud.talk.utils.database.user.UserUtils import org.apache.commons.lang3.builder.CompareToBuilder @@ -41,7 +42,7 @@ class ConversationsListViewModel constructor( val conversationsListData = MutableLiveData>() val viewState = MutableLiveData(LOADING) - val messageData = MutableLiveData() + var messageData : String? = null val searchQuery = MutableLiveData() lateinit var currentUser: UserEntity @@ -66,11 +67,12 @@ class ConversationsListViewModel constructor( }) conversationsListData.value = newConversations - viewState.value = LOADED + viewState.value = if (newConversations.isNotEmpty()) LOADED else LOADED_EMPTY + } override fun onError(errorModel: ErrorModel?) { - messageData.value = errorModel?.message + messageData = errorModel?.message viewState.value = FAILED } diff --git a/app/src/main/java/com/nextcloud/talk/newarch/mvvm/ViewState.kt b/app/src/main/java/com/nextcloud/talk/newarch/mvvm/ViewState.kt index f79a946b2..a45011ce5 100644 --- a/app/src/main/java/com/nextcloud/talk/newarch/mvvm/ViewState.kt +++ b/app/src/main/java/com/nextcloud/talk/newarch/mvvm/ViewState.kt @@ -22,6 +22,7 @@ package com.nextcloud.talk.newarch.mvvm enum class ViewState { LOADING, + LOADED_EMPTY, LOADED, FAILED } \ No newline at end of file diff --git a/app/src/main/java/com/nextcloud/talk/newarch/utils/NetworkUtils.kt b/app/src/main/java/com/nextcloud/talk/newarch/utils/NetworkUtils.kt index 5bef4296f..fa820cb89 100644 --- a/app/src/main/java/com/nextcloud/talk/newarch/utils/NetworkUtils.kt +++ b/app/src/main/java/com/nextcloud/talk/newarch/utils/NetworkUtils.kt @@ -47,7 +47,7 @@ class NetworkUtils { .header("OCS-APIRequest", "true") .method(original.method, original.body) .build() - + val response = chain.proceed(request) if (request.url.encodedPath.contains("/avatar/")) { diff --git a/app/src/main/res/drawable/ic_announcement_white_24dp.xml b/app/src/main/res/drawable/ic_announcement_white_24dp.xml new file mode 100644 index 000000000..bec379dc1 --- /dev/null +++ b/app/src/main/res/drawable/ic_announcement_white_24dp.xml @@ -0,0 +1,25 @@ + + + + + diff --git a/app/src/main/res/layout/controller_conversations_rv.xml b/app/src/main/res/layout/controller_conversations_rv.xml index 7e9ab6795..50111a510 100644 --- a/app/src/main/res/layout/controller_conversations_rv.xml +++ b/app/src/main/res/layout/controller_conversations_rv.xml @@ -25,54 +25,20 @@ android:layout_width="match_parent" android:layout_height="match_parent"> - - - - - - - - + + android:layout_height="match_parent" + android:id="@+id/dataStateView" + android:visibility="invisible"> + + + + + + + + + + + + + \ No newline at end of file