Lots of progress on layouts

Signed-off-by: Mario Danic <mario@lovelyhq.com>
This commit is contained in:
Mario Danic 2020-01-20 21:55:12 +01:00
parent cc24c81b0d
commit 419830d2bd
No known key found for this signature in database
GPG Key ID: CDE0BBD2738C4CC0
17 changed files with 132 additions and 111 deletions

View File

@ -107,17 +107,6 @@ class MainActivity : BaseActivity(), ActionBarProvider {
}
}
@OnClick(R.id.floatingActionButton)
fun onFloatingActionButtonClick() {
val bundle = Bundle()
bundle.putBoolean(BundleKeys.KEY_NEW_CONVERSATION, true)
router?.pushController(
RouterTransaction.with(ContactsController(bundle))
.pushChangeHandler(HorizontalChangeHandler())
.popChangeHandler(HorizontalChangeHandler()))
}
@RequiresApi(api = Build.VERSION_CODES.M)
fun checkIfWeAreSecure() {
val keyguardManager = getSystemService(Context.KEYGUARD_SERVICE) as KeyguardManager

View File

@ -30,11 +30,13 @@ import android.text.InputType
import android.util.Log
import android.view.*
import android.view.inputmethod.EditorInfo
import android.widget.FrameLayout
import android.widget.ProgressBar
import android.widget.RelativeLayout
import androidx.appcompat.widget.SearchView
import androidx.coordinatorlayout.widget.CoordinatorLayout
import androidx.core.view.MenuItemCompat
import androidx.core.widget.NestedScrollView
import androidx.recyclerview.widget.RecyclerView
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
import androidx.work.Data
@ -132,7 +134,7 @@ class ContactsController : BaseController,
@JvmField
@BindView(R.id.generic_rv_layout)
var genericRvLayout: CoordinatorLayout? = null
var genericRvLayout: FrameLayout? = null
private var credentials: String? = null
private var currentUser: UserNgEntity? = null

View File

@ -33,7 +33,6 @@ import android.view.inputmethod.InputMethodManager
import android.widget.EditText
import androidx.annotation.RequiresApi
import androidx.appcompat.app.ActionBar
import androidx.coordinatorlayout.widget.CoordinatorLayout
import androidx.core.view.isVisible
import com.bluelinelabs.conductor.ControllerChangeHandler
import com.bluelinelabs.conductor.ControllerChangeType
@ -44,11 +43,11 @@ import com.nextcloud.talk.R
import com.nextcloud.talk.activities.MainActivity
import com.nextcloud.talk.controllers.SwitchAccountController
import com.nextcloud.talk.controllers.base.providers.ActionBarProvider
import com.nextcloud.talk.utils.FABAwareScrollingViewBehavior
import com.nextcloud.talk.utils.preferences.AppPreferences
import com.uber.autodispose.lifecycle.LifecycleScopeProvider
import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.android.synthetic.main.search_layout.*
import kotlinx.android.synthetic.main.search_layout.view.*
import org.greenrobot.eventbus.EventBus
import org.koin.android.ext.android.inject
import java.util.*
@ -73,18 +72,6 @@ abstract class BaseController : ButterKnifeController(), ComponentCallbacks {
return actionBarProvider?.supportActionBar
}
protected val floatingActionButton: FloatingActionButton?
get() {
var floatingActionButton: FloatingActionButton? = null
activity?.let {
if (it is MainActivity) {
floatingActionButton = it.floatingActionButton
}
}
return floatingActionButton
}
protected val appBar: AppBarLayout?
get() {
var appBarLayout: AppBarLayout? = null
@ -124,22 +111,12 @@ abstract class BaseController : ButterKnifeController(), ComponentCallbacks {
activity?.let {
if (it is MainActivity) {
it.searchCardView.isVisible = value
it.floatingActionButton.isVisible = value
it.inputEditText.hint = getSearchHint()
val layoutParamsForContainer = it.container.layoutParams as CoordinatorLayout.LayoutParams
val layoutParams = it.toolbar.layoutParams as AppBarLayout.LayoutParams
if (value) {
layoutParamsForContainer.behavior = FABAwareScrollingViewBehavior()
layoutParams.scrollFlags = AppBarLayout.LayoutParams.SCROLL_FLAG_SCROLL or AppBarLayout.LayoutParams.SCROLL_FLAG_SNAP or AppBarLayout.LayoutParams.SCROLL_FLAG_ENTER_ALWAYS
it.appBar.setBackgroundResource(R.color.transparent)
} else {
layoutParamsForContainer.behavior = AppBarLayout.ScrollingViewBehavior()
layoutParams.scrollFlags = 0
it.appBar.setBackgroundResource(R.color.colorPrimary)
}
it.container.layoutParams = layoutParamsForContainer
it.toolbar.layoutParams = layoutParams
}
}

View File

@ -27,11 +27,11 @@ import com.nextcloud.talk.newarch.local.dao.UsersDao
import com.nextcloud.talk.newarch.local.models.UserNgEntity
class UsersRepositoryImpl(private val usersDao: UsersDao) : UsersRepository {
override fun getActiveUserLiveData(): LiveData<UserNgEntity> {
override fun getActiveUserLiveData(): LiveData<UserNgEntity?> {
return usersDao.getActiveUserLiveData().distinctUntilChanged()
}
override fun getActiveUser(): UserNgEntity {
override fun getActiveUser(): UserNgEntity? {
return usersDao.getActiveUser()
}

View File

@ -108,9 +108,9 @@ fun createOkHttpClient(
val httpClient = OkHttpClient.Builder()
httpClient.retryOnConnectionFailure(true)
httpClient.connectTimeout(45, TimeUnit.SECONDS)
httpClient.readTimeout(45, TimeUnit.SECONDS)
httpClient.writeTimeout(45, TimeUnit.SECONDS)
httpClient.connectTimeout(300, TimeUnit.SECONDS)
httpClient.readTimeout(300, TimeUnit.SECONDS)
httpClient.writeTimeout(300, TimeUnit.SECONDS)
httpClient.cookieJar(JavaNetCookieJar(cookieManager))
httpClient.cache(cache)

View File

@ -24,7 +24,7 @@ import androidx.lifecycle.LiveData
import com.nextcloud.talk.newarch.local.models.UserNgEntity
interface UsersRepository {
fun getActiveUserLiveData(): LiveData<UserNgEntity>
fun getActiveUserLiveData(): LiveData<UserNgEntity?>
fun getActiveUser(): UserNgEntity?
fun getUsers(): List<UserNgEntity>
fun getUserWithId(id: Long): UserNgEntity

View File

@ -146,15 +146,18 @@ class LoginEntryViewModel constructor(
private suspend fun getSignalingSettings() {
getSignalingSettingsUseCase.invoke(ioScope, parametersOf(user), object : UseCaseResponse<SignalingSettingsOverall> {
override suspend fun onSuccess(result: SignalingSettingsOverall) {
user.signalingSettings = result.ocs.signalingSettings
val pushConfiguration = PushConfiguration()
val pushConfigurationStateWrapper = PushConfigurationStateWrapper(PushConfigurationState.PENDING, 0)
pushConfiguration.pushConfigurationStateWrapper = pushConfigurationStateWrapper
usersRepository.insertUser(user)
setAdjustedUserAsActive()
registerForPush()
withContext(Dispatchers.IO) {
user.signalingSettings = result.ocs.signalingSettings
val pushConfiguration = PushConfiguration()
val pushConfigurationStateWrapper = PushConfigurationStateWrapper(PushConfigurationState.PENDING, 0)
pushConfiguration.pushConfigurationStateWrapper = pushConfigurationStateWrapper
usersRepository.insertUser(user)
setAdjustedUserAsActive()
registerForPush()
}
}
override suspend fun onError(errorModel: ErrorModel?) {
state.postValue(LoginEntryStateWrapper(LoginEntryState.FAILED, LoginEntryStateClarification.SIGNALING_SETTINGS_FETCH_FAILED))
}
@ -176,19 +179,23 @@ class LoginEntryViewModel constructor(
val options = PushUtils(usersRepository).getMapForPushRegistrationWithServer(context, token)
registerPushWithServerUseCase.invoke(ioScope, parametersOf(user, options), object : UseCaseResponse<PushRegistrationOverall> {
override suspend fun onSuccess(result: PushRegistrationOverall) {
user.pushConfiguration?.deviceIdentifier = result.ocs.data.deviceIdentifier
user.pushConfiguration?.deviceIdentifierSignature = result.ocs.data.signature
user.pushConfiguration?.userPublicKey = result.ocs.data.publicKey
user.pushConfiguration?.pushConfigurationStateWrapper = PushConfigurationStateWrapper(PushConfigurationState.SERVER_REGISTRATION_DONE, null)
usersRepository.updateUser(user)
registerForPushWithProxy()
withContext(Dispatchers.IO) {
user.pushConfiguration?.deviceIdentifier = result.ocs.data.deviceIdentifier
user.pushConfiguration?.deviceIdentifierSignature = result.ocs.data.signature
user.pushConfiguration?.userPublicKey = result.ocs.data.publicKey
user.pushConfiguration?.pushConfigurationStateWrapper = PushConfigurationStateWrapper(PushConfigurationState.SERVER_REGISTRATION_DONE, null)
usersRepository.updateUser(user)
registerForPushWithProxy()
}
}
override suspend fun onError(errorModel: ErrorModel?) {
user.pushConfiguration?.pushConfigurationStateWrapper?.pushConfigurationState = PushConfigurationState.FAILED_WITH_SERVER_REGISTRATION
user.pushConfiguration?.pushConfigurationStateWrapper?.reason = errorModel?.code
usersRepository.updateUser(user)
state.postValue(LoginEntryStateWrapper(LoginEntryState.OK, LoginEntryStateClarification.PUSH_REGISTRATION_WITH_SERVER_FAILED))
withContext(Dispatchers.IO) {
user.pushConfiguration?.pushConfigurationStateWrapper?.pushConfigurationState = PushConfigurationState.FAILED_WITH_SERVER_REGISTRATION
user.pushConfiguration?.pushConfigurationStateWrapper?.reason = errorModel?.code
usersRepository.updateUser(user)
state.postValue(LoginEntryStateWrapper(LoginEntryState.OK, LoginEntryStateClarification.PUSH_REGISTRATION_WITH_SERVER_FAILED))
}
}
})
}
@ -199,9 +206,11 @@ class LoginEntryViewModel constructor(
if (options != null) {
registerPushWithProxyUseCase.invoke(ioScope, parametersOf(user, options), object : UseCaseResponse<Any> {
override suspend fun onSuccess(result: Any) {
user.pushConfiguration?.pushConfigurationStateWrapper = PushConfigurationStateWrapper(PushConfigurationState.PROXY_REGISTRATION_DONE, null)
usersRepository.updateUser(user)
state.postValue(LoginEntryStateWrapper(LoginEntryState.OK, if (!updatingUser) LoginEntryStateClarification.ACCOUNT_CREATED else LoginEntryStateClarification.ACCOUNT_UPDATED))
withContext(Dispatchers.IO) {
user.pushConfiguration?.pushConfigurationStateWrapper = PushConfigurationStateWrapper(PushConfigurationState.PROXY_REGISTRATION_DONE, null)
usersRepository.updateUser(user)
state.postValue(LoginEntryStateWrapper(LoginEntryState.OK, if (!updatingUser) LoginEntryStateClarification.ACCOUNT_CREATED else LoginEntryStateClarification.ACCOUNT_UPDATED))
}
}
override suspend fun onError(errorModel: ErrorModel?) {
@ -215,9 +224,11 @@ class LoginEntryViewModel constructor(
}
})
} else {
user.pushConfiguration?.pushConfigurationStateWrapper?.pushConfigurationState = PushConfigurationState.FAILED_WITH_PROXY_REGISTRATION
usersRepository.updateUser(user)
state.postValue(LoginEntryStateWrapper(LoginEntryState.OK, LoginEntryStateClarification.PUSH_REGISTRATION_WITH_PUSH_PROXY_FAILED))
withContext(Dispatchers.IO) {
user.pushConfiguration?.pushConfigurationStateWrapper?.pushConfigurationState = PushConfigurationState.FAILED_WITH_PROXY_REGISTRATION
usersRepository.updateUser(user)
state.postValue(LoginEntryStateWrapper(LoginEntryState.OK, LoginEntryStateClarification.PUSH_REGISTRATION_WITH_PUSH_PROXY_FAILED))
}
}
}

View File

@ -27,6 +27,7 @@ import android.view.View
import android.view.ViewGroup
import androidx.core.view.isVisible
import androidx.lifecycle.observe
import butterknife.OnClick
import com.afollestad.materialdialogs.LayoutMode
import com.afollestad.materialdialogs.MaterialDialog
import com.afollestad.materialdialogs.bottomsheets.BottomSheet
@ -94,12 +95,12 @@ class ConversationsListView : BaseView() {
view.apply {
recyclerView.initRecyclerView(SmoothScrollLinearLayoutManager(activity), adapter, false)
swipeRefreshLayoutView.setOnRefreshListener {
/*swipeRefreshLayoutView.setOnRefreshListener {
view.swipeRefreshLayoutView.isRefreshing = false
viewModel.loadConversations()
}
swipeRefreshLayoutView.setColorSchemeResources(R.color.colorPrimary)
swipeRefreshLayoutView.setColorSchemeResources(R.color.colorPrimary)*/
}
activity?.inputEditText?.addTextChangedListener(DebouncingTextWatcher(lifecycle, ::setSearchQuery))
@ -137,6 +138,16 @@ class ConversationsListView : BaseView() {
return view
}
@OnClick(R.id.floatingActionButton)
fun onFloatingActionButtonClick() {
val bundle = Bundle()
bundle.putBoolean(BundleKeys.KEY_NEW_CONVERSATION, true)
router?.pushController(
RouterTransaction.with(ContactsController(bundle))
.pushChangeHandler(HorizontalChangeHandler())
.popChangeHandler(HorizontalChangeHandler()))
}
override fun onChangeStarted(changeHandler: ControllerChangeHandler, changeType: ControllerChangeType) {
actionBar?.setIcon(null)
super.onChangeStarted(changeHandler, changeType)

View File

@ -22,9 +22,7 @@ package com.nextcloud.talk.newarch.features.conversationslist
import android.app.Application
import android.graphics.drawable.Drawable
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.Transformations
import androidx.lifecycle.viewModelScope
import androidx.lifecycle.*
import coil.Coil
import coil.api.get
import coil.transform.CircleCropTransformation
@ -68,12 +66,21 @@ class ConversationsListViewModel constructor(
if (networkStateLiveData.value != ConversationsListViewNetworkState.LOADING) {
networkStateLiveData.postValue(ConversationsListViewNetworkState.LOADING)
}
loadConversations()
loadAvatar()
if (user != null) {
loadConversations()
loadAvatar()
}
filterLiveData.value = null
Transformations.switchMap(filterLiveData) { filter ->
conversationsRepository.getConversationsForUser(user.id!!, filter)
if (user != null) {
conversationsRepository.getConversationsForUser(user.id!!, filter)
} else {
liveData {
listOf<Conversation>()
}
}
}
}

View File

@ -29,10 +29,10 @@ import com.nextcloud.talk.newarch.local.models.other.UserStatus
abstract class UsersDao {
// get active user
@Query("SELECT * FROM users where status = 1")
abstract fun getActiveUser(): UserNgEntity
abstract fun getActiveUser(): UserNgEntity?
@Query("SELECT * FROM users WHERE status = 1")
abstract fun getActiveUserLiveData(): LiveData<UserNgEntity>
abstract fun getActiveUserLiveData(): LiveData<UserNgEntity?>
@Query("DELETE FROM users WHERE id = :id")
abstract suspend fun deleteUserWithId(id: Long)

View File

@ -47,7 +47,7 @@ class GlobalService constructor(usersRepository: UsersRepository,
private val getConversationUseCase: GetConversationUseCase) : KoinComponent {
private val applicationScope = CoroutineScope(Dispatchers.Default)
private val previousUser: UserNgEntity? = null
val currentUserLiveData: LiveData<UserNgEntity> = usersRepository.getActiveUserLiveData()
val currentUserLiveData: LiveData<UserNgEntity?> = usersRepository.getActiveUserLiveData()
private var currentConversation: Conversation? = null
init {

View File

@ -13,22 +13,28 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.nextcloud.talk.utils;
package com.nextcloud.talk.utils.animations;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.cardview.widget.CardView;
import androidx.coordinatorlayout.widget.CoordinatorLayout;
import androidx.core.view.ViewCompat;
import com.google.android.material.appbar.AppBarLayout;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.nextcloud.talk.R;
import java.util.List;
public class FABAwareScrollingViewBehavior extends AppBarLayout.ScrollingViewBehavior {
private boolean slidingDown = false;
private int searchBarHeight;
public FABAwareScrollingViewBehavior() {
}
@ -36,6 +42,14 @@ public class FABAwareScrollingViewBehavior extends AppBarLayout.ScrollingViewBeh
super(context, attrs);
}
@Override
protected void layoutChild(@NonNull CoordinatorLayout parent, @NonNull View child, int layoutDirection) {
if (child.getId() == R.id.searchCardView) {
searchBarHeight = child.getHeight();
}
super.layoutChild(parent, child, layoutDirection);
}
@Override
public boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) {
return super.layoutDependsOn(parent, child, dependency) ||
@ -55,14 +69,16 @@ public class FABAwareScrollingViewBehavior extends AppBarLayout.ScrollingViewBeh
public void onNestedScroll(final CoordinatorLayout coordinatorLayout, final View child,
final View target, final int dxConsumed, final int dyConsumed,
final int dxUnconsumed, final int dyUnconsumed) {
super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed, dxUnconsumed,
dyUnconsumed);
//super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed, dxUnconsumed,
// dyUnconsumed);
if (dyConsumed > 0) {
// User scrolled down -> hide the FAB
List<View> dependencies = coordinatorLayout.getDependencies(child);
for (View view : dependencies) {
if (view instanceof FloatingActionButton) {
((FloatingActionButton) view).hide();
} else if (view.getId() == R.id.searchCardView) {
//slideUp(child);
}
}
} else if (dyConsumed < 0) {
@ -71,8 +87,26 @@ public class FABAwareScrollingViewBehavior extends AppBarLayout.ScrollingViewBeh
for (View view : dependencies) {
if (view instanceof FloatingActionButton) {
((FloatingActionButton) view).show();
} else if (view.getId() == R.id.searchCardView) {
//slideDown(view);
}
}
}
}
private void slideUp(View child) {
if (slidingDown) {
slidingDown = false;
child.clearAnimation();
child.animate().translationY(0).setDuration(200);
}
}
private void slideDown(View child) {
if (!slidingDown) {
slidingDown = true;
child.clearAnimation();
child.animate().translationY(searchBarHeight).setDuration(200);
}
}
}

View File

@ -30,7 +30,9 @@ import androidx.annotation.NonNull;
import androidx.coordinatorlayout.widget.CoordinatorLayout;
import androidx.core.view.ViewCompat;
public class ViewHidingBehaviourAnimation extends CoordinatorLayout.Behavior<View> {
import com.google.android.material.appbar.AppBarLayout;
public class ViewHidingBehaviourAnimation extends AppBarLayout.ScrollingViewBehavior {
private int height;
private boolean slidingDown = false;

View File

@ -26,7 +26,7 @@
android:layout_height="match_parent"
tools:context=".activities.MainActivity"
android:animateLayoutChanges="true"
android:background="@color/transparent">
android:fitsSystemWindows="true">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appBar"
@ -45,25 +45,13 @@
app:layout_scrollFlags="scroll|enterAlways|snap"
app:popupTheme="@style/appActionBarPopupMenu">
<include layout="@layout/search_layout"/>
<include layout="@layout/search_layout" />
</com.google.android.material.appbar.MaterialToolbar>
</com.google.android.material.appbar.AppBarLayout>
<com.nextcloud.talk.newarch.utils.ChangeHandlerCoordinatorLayout
<com.bluelinelabs.conductor.ChangeHandlerFrameLayout
android:id="@+id/controller_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="com.nextcloud.talk.utils.FABAwareScrollingViewBehavior"
/>
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/floatingActionButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="16dp"
app:backgroundTint="@color/colorPrimary"
app:srcCompat="@drawable/ic_add_white_24px"
app:tint="@color/white" />
android:layout_height="match_parent" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View File

@ -18,7 +18,7 @@
~ along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/generic_rv_layout"
@ -26,20 +26,22 @@
android:layout_height="match_parent"
android:animateLayoutChanges="true">
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:id="@+id/swipeRefreshLayoutView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="visible"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:listitem="@layout/rv_item_conversation_with_last_message" />
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/floatingActionButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="16dp"
android:nestedScrollingEnabled="true"
android:paddingBottom="16dp"
app:backgroundTint="@color/colorPrimary"
app:srcCompat="@drawable/ic_add_white_24px"
app:tint="@color/white" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
</FrameLayout>

View File

@ -37,8 +37,8 @@
app:contentPaddingRight="16dp"
android:background="@color/transparent"
app:cardBackgroundColor="@color/transparent"
android:elevation="4dp"
app:cardElevation="4dp"
android:elevation="2dp"
app:cardElevation="2dp"
android:visibility="gone">
<RelativeLayout

View File

@ -31,8 +31,6 @@
<item name="android:textColor">@color/nc_incoming_text_default</item>
<item name="android:popupMenuStyle">@style/appActionBarPopupMenu</item>
<item name="actionOverflowMenuStyle">@style/appActionBarPopupMenu</item>
<item name="android:statusBarColor">@color/colorPrimary</item>
<item name="actionBarStyle">@style/appActionBarStyle</item>
</style>
<style name="ErrorAppearance" parent="@android:style/TextAppearance">