From 44f6391cb42bcb7bb5729dab8dd6d409023d9d91 Mon Sep 17 00:00:00 2001 From: ganfra Date: Tue, 1 Oct 2019 20:11:15 +0200 Subject: [PATCH 1/8] Optimize: use LazyThreeTen --- vector/build.gradle | 4 +++- vector/src/main/java/im/vector/riotx/VectorApplication.kt | 5 +++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/vector/build.gradle b/vector/build.gradle index 16bf70aef0..3073d0f8f7 100644 --- a/vector/build.gradle +++ b/vector/build.gradle @@ -234,7 +234,9 @@ dependencies { implementation 'androidx.constraintlayout:constraintlayout:2.0.0-beta1' implementation 'androidx.core:core-ktx:1.0.2' - implementation 'com.jakewharton.threetenabp:threetenabp:1.1.1' + implementation "org.threeten:threetenbp:1.4.0:no-tzdb" + implementation "com.gabrielittner.threetenbp:lazythreetenbp:0.7.0" + implementation "com.squareup.moshi:moshi-adapters:$moshi_version" kapt "com.squareup.moshi:moshi-kotlin-codegen:$moshi_version" diff --git a/vector/src/main/java/im/vector/riotx/VectorApplication.kt b/vector/src/main/java/im/vector/riotx/VectorApplication.kt index bf56e71915..4884354ef3 100644 --- a/vector/src/main/java/im/vector/riotx/VectorApplication.kt +++ b/vector/src/main/java/im/vector/riotx/VectorApplication.kt @@ -31,9 +31,9 @@ import androidx.multidex.MultiDex import com.airbnb.epoxy.EpoxyAsyncUtil import com.airbnb.epoxy.EpoxyController import com.facebook.stetho.Stetho +import com.gabrielittner.threetenbp.LazyThreeTen import com.github.piasy.biv.BigImageViewer import com.github.piasy.biv.loader.glide.GlideImageLoader -import com.jakewharton.threetenabp.AndroidThreeTen import im.vector.matrix.android.api.Matrix import im.vector.matrix.android.api.MatrixConfiguration import im.vector.matrix.android.api.auth.Authenticator @@ -96,7 +96,8 @@ class VectorApplication : Application(), HasVectorInjector, MatrixConfiguration. Stetho.initializeWithDefaults(this) } logInfo() - AndroidThreeTen.init(this) + LazyThreeTen.init(this) + BigImageViewer.initialize(GlideImageLoader.with(applicationContext)) EpoxyController.defaultDiffingHandler = EpoxyAsyncUtil.getAsyncBackgroundHandler() EpoxyController.defaultModelBuildingHandler = EpoxyAsyncUtil.getAsyncBackgroundHandler() From 275dd20412c4a498293dcef2809bf4ef1dab0390 Mon Sep 17 00:00:00 2001 From: ganfra Date: Tue, 1 Oct 2019 20:12:01 +0200 Subject: [PATCH 2/8] Optimize: don't build OkHttp in Application OnCreate if we don't need it --- .../matrix/android/internal/auth/DefaultAuthenticator.kt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/DefaultAuthenticator.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/DefaultAuthenticator.kt index 949aa6611e..9ae9af8b98 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/DefaultAuthenticator.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/DefaultAuthenticator.kt @@ -39,9 +39,10 @@ import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import okhttp3.OkHttpClient import javax.inject.Inject +import javax.inject.Provider internal class DefaultAuthenticator @Inject constructor(@Unauthenticated - private val okHttpClient: OkHttpClient, + private val okHttpClient: Provider, private val retrofitFactory: RetrofitFactory, private val coroutineDispatchers: MatrixCoroutineDispatchers, private val sessionParamsStore: SessionParamsStore, @@ -119,7 +120,7 @@ internal class DefaultAuthenticator @Inject constructor(@Unauthenticated } private fun buildAuthAPI(homeServerConnectionConfig: HomeServerConnectionConfig): AuthAPI { - val retrofit = retrofitFactory.create(okHttpClient, homeServerConnectionConfig.homeServerUri.toString()) + val retrofit = retrofitFactory.create(okHttpClient.get(), homeServerConnectionConfig.homeServerUri.toString()) return retrofit.create(AuthAPI::class.java) } From 650a151b183f534e649a6a3d2973f9dab27c05fa Mon Sep 17 00:00:00 2001 From: ganfra Date: Tue, 1 Oct 2019 20:12:15 +0200 Subject: [PATCH 3/8] Optimize: remove some epoxy building from main thread --- .../features/home/group/GroupListFragment.kt | 2 +- .../home/group/GroupSummaryController.kt | 18 ++++++-- .../home/room/list/RoomListFragment.kt | 3 +- .../home/room/list/RoomSummaryController.kt | 46 ++++++++++++------- 4 files changed, 48 insertions(+), 21 deletions(-) diff --git a/vector/src/main/java/im/vector/riotx/features/home/group/GroupListFragment.kt b/vector/src/main/java/im/vector/riotx/features/home/group/GroupListFragment.kt index 2615643781..df45bbc9a0 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/group/GroupListFragment.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/group/GroupListFragment.kt @@ -70,7 +70,7 @@ class GroupListFragment : VectorBaseFragment(), GroupSummaryController.Callback is Incomplete -> stateView.state = StateView.State.Loading is Success -> stateView.state = StateView.State.Content } - groupController.setData(state) + groupController.update(state) } override fun onGroupSelected(groupSummary: GroupSummary) { diff --git a/vector/src/main/java/im/vector/riotx/features/home/group/GroupSummaryController.kt b/vector/src/main/java/im/vector/riotx/features/home/group/GroupSummaryController.kt index 785f833077..91fb02a74e 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/group/GroupSummaryController.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/group/GroupSummaryController.kt @@ -16,17 +16,29 @@ package im.vector.riotx.features.home.group +import com.airbnb.epoxy.EpoxyController import com.airbnb.epoxy.TypedEpoxyController import im.vector.matrix.android.api.session.group.model.GroupSummary import im.vector.riotx.features.home.AvatarRenderer import javax.inject.Inject -class GroupSummaryController @Inject constructor(private val avatarRenderer: AvatarRenderer): TypedEpoxyController() { +class GroupSummaryController @Inject constructor(private val avatarRenderer: AvatarRenderer) : EpoxyController() { var callback: Callback? = null + private var viewState: GroupListViewState? = null - override fun buildModels(viewState: GroupListViewState) { - buildGroupModels(viewState.asyncGroups(), viewState.selectedGroup) + init { + requestModelBuild() + } + + fun update(viewState: GroupListViewState) { + this.viewState = viewState + requestModelBuild() + } + + override fun buildModels() { + val nonNullViewState = viewState ?: return + buildGroupModels(nonNullViewState.asyncGroups(), nonNullViewState.selectedGroup) } private fun buildGroupModels(summaries: List?, selected: GroupSummary?) { diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/list/RoomListFragment.kt b/vector/src/main/java/im/vector/riotx/features/home/room/list/RoomListFragment.kt index afe3579d76..cc2224b64a 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/list/RoomListFragment.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/list/RoomListFragment.kt @@ -41,6 +41,7 @@ import im.vector.riotx.features.home.room.list.widget.FabMenuView import im.vector.riotx.features.notifications.NotificationDrawerManager import kotlinx.android.parcel.Parcelize import kotlinx.android.synthetic.main.fragment_room_list.* +import timber.log.Timber import javax.inject.Inject @Parcelize @@ -180,7 +181,7 @@ class RoomListFragment : VectorBaseFragment(), RoomSummaryController.Listener, O is Success -> renderSuccess(state) is Fail -> renderFailure(state.asyncFilteredRooms.error) } - roomController.setData(state) + roomController.update(state) } private fun renderSuccess(state: RoomListViewState) { diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/list/RoomSummaryController.kt b/vector/src/main/java/im/vector/riotx/features/home/room/list/RoomSummaryController.kt index 42e3a3db85..f2e9fbc947 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/list/RoomSummaryController.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/list/RoomSummaryController.kt @@ -17,40 +17,54 @@ package im.vector.riotx.features.home.room.list import androidx.annotation.StringRes +import com.airbnb.epoxy.EpoxyController import com.airbnb.epoxy.TypedEpoxyController import im.vector.matrix.android.api.session.room.model.Membership import im.vector.matrix.android.api.session.room.model.RoomSummary import im.vector.riotx.core.resources.StringProvider import im.vector.riotx.features.home.room.filtered.FilteredRoomFooterItem import im.vector.riotx.features.home.room.filtered.filteredRoomFooterItem +import timber.log.Timber import javax.inject.Inject class RoomSummaryController @Inject constructor(private val stringProvider: StringProvider, private val roomSummaryItemFactory: RoomSummaryItemFactory, private val roomListNameFilter: RoomListNameFilter -) : TypedEpoxyController() { +) : EpoxyController() { var listener: Listener? = null - override fun buildModels(viewState: RoomListViewState) { - if (viewState.displayMode == RoomListFragment.DisplayMode.FILTERED) { - buildFilteredRooms(viewState) + private var viewState: RoomListViewState? = null + + init { + requestModelBuild() + } + + fun update(viewState: RoomListViewState) { + this.viewState = viewState + requestModelBuild() + } + + override fun buildModels() { + val nonNullViewState = viewState ?: return + if (nonNullViewState.displayMode == RoomListFragment.DisplayMode.FILTERED) { + buildFilteredRooms(nonNullViewState) } else { - val roomSummaries = viewState.asyncFilteredRooms() + val roomSummaries = nonNullViewState.asyncFilteredRooms() roomSummaries?.forEach { (category, summaries) -> if (summaries.isEmpty()) { return@forEach } else { - val isExpanded = viewState.isCategoryExpanded(category) - buildRoomCategory(viewState, summaries, category.titleRes, viewState.isCategoryExpanded(category)) { + val isExpanded = nonNullViewState.isCategoryExpanded(category) + buildRoomCategory(nonNullViewState, summaries, category.titleRes, nonNullViewState.isCategoryExpanded(category)) { listener?.onToggleRoomCategory(category) } if (isExpanded) { buildRoomModels(summaries, - viewState.joiningRoomsIds, - viewState.joiningErrorRoomsIds, - viewState.rejectingRoomsIds, - viewState.rejectingErrorRoomsIds) + nonNullViewState.joiningRoomsIds, + nonNullViewState.joiningErrorRoomsIds, + nonNullViewState.rejectingRoomsIds, + nonNullViewState.rejectingErrorRoomsIds) } } } @@ -66,10 +80,10 @@ class RoomSummaryController @Inject constructor(private val stringProvider: Stri .filter { it.membership == Membership.JOIN && roomListNameFilter.test(it) } buildRoomModels(filteredSummaries, - viewState.joiningRoomsIds, - viewState.joiningErrorRoomsIds, - viewState.rejectingRoomsIds, - viewState.rejectingErrorRoomsIds) + viewState.joiningRoomsIds, + viewState.joiningErrorRoomsIds, + viewState.rejectingRoomsIds, + viewState.rejectingErrorRoomsIds) addFilterFooter(viewState) } @@ -105,7 +119,7 @@ class RoomSummaryController @Inject constructor(private val stringProvider: Stri showHighlighted(showHighlighted) listener { mutateExpandedState() - setData(viewState) + update(viewState) } } } From ff7856c535d2ab7013938881f12771a8d7024c0a Mon Sep 17 00:00:00 2001 From: ganfra Date: Wed, 2 Oct 2019 19:30:01 +0200 Subject: [PATCH 4/8] Optimize: start removing some constraint layout from timeline --- .../detail/timeline/item/BaseEventItem.kt | 9 +- .../res/layout/item_timeline_event_base.xml | 141 +++++++++--------- .../item_timeline_event_base_noinfo.xml | 94 ++++++------ ...item_timeline_event_merged_header_stub.xml | 77 +++++----- vector/src/main/res/values/styles_riot.xml | 16 +- 5 files changed, 164 insertions(+), 173 deletions(-) diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/item/BaseEventItem.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/item/BaseEventItem.kt index c6e813e878..8ac8264cad 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/item/BaseEventItem.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/item/BaseEventItem.kt @@ -17,8 +17,11 @@ package im.vector.riotx.features.home.room.detail.timeline.item import android.view.View import android.view.ViewStub +import android.widget.RelativeLayout import androidx.annotation.IdRes import androidx.constraintlayout.widget.Guideline +import androidx.core.view.marginStart +import androidx.core.view.updateLayoutParams import com.airbnb.epoxy.EpoxyAttribute import im.vector.riotx.R import im.vector.riotx.core.epoxy.VectorEpoxyHolder @@ -44,7 +47,9 @@ abstract class BaseEventItem : VectorEpoxyModel override fun bind(holder: H) { super.bind(holder) - holder.leftGuideline.setGuidelineBegin(leftGuideline) + holder.leftGuideline.updateLayoutParams { + this.marginStart = leftGuideline + } holder.checkableBackground.isChecked = highlighted } @@ -55,7 +60,7 @@ abstract class BaseEventItem : VectorEpoxyModel abstract fun getEventIds(): List abstract class BaseHolder(@IdRes val stubId: Int) : VectorEpoxyHolder() { - val leftGuideline by bind(R.id.messageStartGuideline) + val leftGuideline by bind(R.id.messageStartGuideline) val checkableBackground by bind(R.id.messageSelectedBackground) val readReceiptsView by bind(R.id.readReceiptsView) val readMarkerView by bind(R.id.readMarkerView) diff --git a/vector/src/main/res/layout/item_timeline_event_base.xml b/vector/src/main/res/layout/item_timeline_event_base.xml index 4eb9be0b9f..ee5d34bd40 100644 --- a/vector/src/main/res/layout/item_timeline_event_base.xml +++ b/vector/src/main/res/layout/item_timeline_event_base.xml @@ -1,6 +1,5 @@ - + android:layout_width="match_parent" + android:layout_height="match_parent" + android:layout_alignParentTop="true" + android:layout_alignBottom="@+id/readMarkerView" + android:background="?riotx_highlighted_message_background" /> - - - + + + + android:layout="@layout/item_timeline_event_media_message_stub" /> + android:layout_height="wrap_content" + style="@style/TimelineContentStubBaseParams" + android:layout="@layout/item_timeline_event_file_stub" /> + android:layout="@layout/item_timeline_event_redacted_stub" /> + - - + android:layout_below="@+id/viewStubContainer" + android:layout_toEndOf="@+id/messageStartGuideline" + android:orientation="vertical"> - + - + + + + + + android:layout_marginEnd="8dp" + android:layout_marginBottom="2dp" + android:background="?attr/vctr_unread_marker_line_color" + android:visibility="invisible" /> - \ No newline at end of file + \ No newline at end of file diff --git a/vector/src/main/res/layout/item_timeline_event_base_noinfo.xml b/vector/src/main/res/layout/item_timeline_event_base_noinfo.xml index fc4a527d03..99fb052a96 100644 --- a/vector/src/main/res/layout/item_timeline_event_base_noinfo.xml +++ b/vector/src/main/res/layout/item_timeline_event_base_noinfo.xml @@ -1,6 +1,5 @@ - + + + android:layout_marginStart="52dp" + android:orientation="vertical" /> - + + android:layout="@layout/item_timeline_event_default_stub" /> + android:layout="@layout/item_timeline_event_blank_stub" /> + style="@style/TimelineContentStubBaseParams" + android:layout="@layout/item_timeline_event_merged_header_stub" /> - + + + android:layout_below="@id/viewStubContainer" + android:orientation="vertical"> - + + - \ No newline at end of file + + + \ No newline at end of file diff --git a/vector/src/main/res/layout/item_timeline_event_merged_header_stub.xml b/vector/src/main/res/layout/item_timeline_event_merged_header_stub.xml index 46c84aa4e7..ede5b0e749 100644 --- a/vector/src/main/res/layout/item_timeline_event_merged_header_stub.xml +++ b/vector/src/main/res/layout/item_timeline_event_merged_header_stub.xml @@ -1,61 +1,58 @@ - + android:layout_height="wrap_content" + android:orientation="vertical"> - + - + + + + + + android:background="?attr/riotx_header_panel_background"/> + - \ No newline at end of file + \ No newline at end of file diff --git a/vector/src/main/res/values/styles_riot.xml b/vector/src/main/res/values/styles_riot.xml index d1894254cd..1b19c87e08 100644 --- a/vector/src/main/res/values/styles_riot.xml +++ b/vector/src/main/res/values/styles_riot.xml @@ -282,7 +282,7 @@ - - - - -