Significant progress on changing the app layout

This commit is contained in:
Mario Danic 2018-11-28 16:18:57 +01:00
parent c450a0c7c4
commit 5ff7316aa5
36 changed files with 109 additions and 683 deletions

View File

@ -74,7 +74,7 @@ public class MagicCallActivity extends BaseActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
NextcloudTalkApplication.getSharedApplication().getComponentApplication().inject (this);
NextcloudTalkApplication.getSharedApplication().getComponentApplication().inject(this);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN |

View File

@ -32,7 +32,7 @@ import com.nextcloud.talk.R;
import com.nextcloud.talk.application.NextcloudTalkApplication;
import com.nextcloud.talk.controllers.CallNotificationController;
import com.nextcloud.talk.controllers.ChatController;
import com.nextcloud.talk.controllers.MagicBottomNavigationController;
import com.nextcloud.talk.controllers.ConversationsListController;
import com.nextcloud.talk.controllers.ServerSelectionController;
import com.nextcloud.talk.controllers.base.providers.ActionBarProvider;
import com.nextcloud.talk.utils.bundle.BundleKeys;
@ -94,7 +94,7 @@ public final class MainActivity extends BaseActivity implements ActionBarProvide
if (getIntent().hasExtra(BundleKeys.KEY_FROM_NOTIFICATION_START_CALL)) {
if (!router.hasRootController()) {
router.setRoot(RouterTransaction.with(new MagicBottomNavigationController())
router.setRoot(RouterTransaction.with(new ConversationsListController())
.pushChangeHandler(new HorizontalChangeHandler())
.popChangeHandler(new HorizontalChangeHandler()));
}
@ -102,7 +102,7 @@ public final class MainActivity extends BaseActivity implements ActionBarProvide
} else if (!router.hasRootController()) {
if (hasDb) {
if (userUtils.anyUserExists()) {
router.setRoot(RouterTransaction.with(new MagicBottomNavigationController())
router.setRoot(RouterTransaction.with(new ConversationsListController())
.pushChangeHandler(new HorizontalChangeHandler())
.popChangeHandler(new HorizontalChangeHandler()));
} else {

View File

@ -106,14 +106,14 @@ public class MagicIncomingTextMessageViewHolder
Resources resources = NextcloudTalkApplication.getSharedApplication().getResources();
if (message.isGrouped()) {
messageUserAvatarView.setVisibility(View.INVISIBLE);
Drawable bubbleDrawable = DisplayUtils.getMessageSelector(resources.getColor(R.color.white_two),
Drawable bubbleDrawable = DisplayUtils.getMessageSelector(resources.getColor(R.color.white_two),
resources.getColor(R.color.transparent),
resources.getColor(R.color.white_two), R.drawable.shape_grouped_incoming_message);
ViewCompat.setBackground(bubble, bubbleDrawable);
messageAuthor.setVisibility(View.GONE);
} else {
messageUserAvatarView.setVisibility(View.VISIBLE);
Drawable bubbleDrawable = DisplayUtils.getMessageSelector(resources.getColor(R.color.white_two),
Drawable bubbleDrawable = DisplayUtils.getMessageSelector(resources.getColor(R.color.white_two),
resources.getColor(R.color.transparent),
resources.getColor(R.color.white_two), R.drawable.shape_incoming_message);
ViewCompat.setBackground(bubble, bubbleDrawable);

View File

@ -116,12 +116,12 @@ public class MagicOutcomingTextMessageViewHolder extends MessageHolders.Outcomin
Resources resources = NextcloudTalkApplication.getSharedApplication().getResources();
if (message.isGrouped) {
Drawable bubbleDrawable = DisplayUtils.getMessageSelector(resources.getColor(R.color.colorPrimary),
Drawable bubbleDrawable = DisplayUtils.getMessageSelector(resources.getColor(R.color.colorPrimary),
resources.getColor(R.color.transparent),
resources.getColor(R.color.colorPrimary), R.drawable.shape_grouped_outcoming_message);
ViewCompat.setBackground(bubble, bubbleDrawable);
} else {
Drawable bubbleDrawable = DisplayUtils.getMessageSelector(resources.getColor(R.color.colorPrimary),
Drawable bubbleDrawable = DisplayUtils.getMessageSelector(resources.getColor(R.color.colorPrimary),
resources.getColor(R.color.transparent),
resources.getColor(R.color.colorPrimary), R.drawable.shape_outcoming_message);
ViewCompat.setBackground(bubble, bubbleDrawable);

View File

@ -407,7 +407,7 @@ public class AccountVerificationController extends BaseController {
getActivity().runOnUiThread(() -> {
if (userUtils.getUsers().size() == 1) {
getRouter().setRoot(RouterTransaction.with(new
MagicBottomNavigationController())
ConversationsListController())
.pushChangeHandler(new HorizontalChangeHandler())
.popChangeHandler(new HorizontalChangeHandler()));
} else {
@ -488,7 +488,7 @@ public class AccountVerificationController extends BaseController {
} else {
if (userUtils.anyUserExists()) {
getRouter().setRoot(RouterTransaction.with(new MagicBottomNavigationController())
getRouter().setRoot(RouterTransaction.with(new ConversationsListController())
.pushChangeHandler(new HorizontalChangeHandler())
.popChangeHandler(new HorizontalChangeHandler()));
} else {

View File

@ -1890,7 +1890,7 @@ public class CallController extends BaseController {
private void gotNick(String sessionOrUserId, String nick, boolean isFromAnEvent) {
if (isFromAnEvent && hasExternalSignalingServer) {
// get session based on userId
sessionOrUserId = webSocketClient.getSessionForUserId(sessionOrUserId);
sessionOrUserId = webSocketClient.getSessionForUserId(sessionOrUserId);
}
if (relativeLayout != null) {

View File

@ -476,9 +476,6 @@ public class ChatController extends BaseController implements MessagesListAdapte
@Override
protected void onAttach(@NonNull View view) {
super.onAttach(view);
if (getActionBar() != null) {
getActionBar().setDisplayHomeAsUpEnabled(true);
}
ApplicationWideCurrentRoomHolder.getInstance().setCurrentRoomId(roomId);
ApplicationWideCurrentRoomHolder.getInstance().setCurrentRoomToken(roomId);

View File

@ -198,10 +198,6 @@ public class ContactsController extends BaseController implements SearchView.OnQ
toggleNewCallHeaderVisibility(!isPublicCall);
checkAndHandleDoneMenuItem();
if (getActionBar() != null) {
getActionBar().setDisplayHomeAsUpEnabled(true);
}
}
}
@ -352,46 +348,6 @@ public class ContactsController extends BaseController implements SearchView.OnQ
searchView.setOnQueryTextListener(this);
}
}
final View mSearchEditFrame = searchView
.findViewById(androidx.appcompat.R.id.search_edit_frame);
BottomNavigationView bottomNavigationView = null;
if (getParentController() != null && getParentController().getView() != null) {
bottomNavigationView = getParentController().getView().findViewById(R.id.navigation);
}
Handler handler = new Handler();
ViewTreeObserver vto = mSearchEditFrame.getViewTreeObserver();
BottomNavigationView finalBottomNavigationView = bottomNavigationView;
vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
int oldVisibility = -1;
@Override
public void onGlobalLayout() {
int currentVisibility = mSearchEditFrame.getVisibility();
if (currentVisibility != oldVisibility) {
if (currentVisibility == View.VISIBLE) {
if (finalBottomNavigationView != null) {
handler.postDelayed(() -> finalBottomNavigationView.setVisibility(View.GONE), 100);
}
} else {
handler.postDelayed(() -> {
if (finalBottomNavigationView != null) {
finalBottomNavigationView.setVisibility(View.VISIBLE);
}
searchItem.setVisible(contactItems.size() > 0);
}, 500);
}
oldVisibility = currentVisibility;
}
}
});
}
@Override
@ -414,7 +370,7 @@ public class ContactsController extends BaseController implements SearchView.OnQ
inflater.inflate(R.menu.menu_conversation_plus_filter, menu);
searchItem = menu.findItem(R.id.action_search);
doneMenuItem = menu.findItem(R.id.contacts_selection_done);
menu.findItem(R.id.action_new_conversation).setVisible(false);
menu.findItem(R.id.action_settings).setVisible(false);
initSearchView();
}
@ -621,7 +577,7 @@ public class ContactsController extends BaseController implements SearchView.OnQ
secondName = ((GenericTextHeaderItem) o2).getModel();
}
if (o1 instanceof UserItem && o2 instanceof UserItem) {
if (o1 instanceof UserItem && o2 instanceof UserItem) {
if ("groups".equals(((UserItem) o1).getModel().getSource()) && "groups".equals(((UserItem) o2).getModel().getSource())) {
return firstName.compareToIgnoreCase(secondName);
} else if ("groups".equals(((UserItem) o1).getModel().getSource())) {
@ -848,12 +804,6 @@ public class ContactsController extends BaseController implements SearchView.OnQ
bottomSheet = new BottomSheet.Builder(getActivity()).setView(view).create();
}
bottomSheet.setOnCancelListener(dialog -> {
if (getActionBar() != null) {
getActionBar().setDisplayHomeAsUpEnabled(true);
}
});
bottomSheet.setOnShowListener(dialog -> eventBus.post(new BottomSheetLockEvent(false, 0,
false, false)));

View File

@ -208,14 +208,6 @@ public class ConversationInfoController extends BaseController {
adapter.notifyDataSetChanged();
}
@Override
protected void onAttach(@NonNull View view) {
super.onAttach(view);
if (getActionBar() != null) {
getActionBar().setDisplayHomeAsUpEnabled(true);
}
}
@Override
protected String getTitle() {
return getResources().getString(R.string.nc_conversation_menu_conversation_info);
@ -248,6 +240,7 @@ public class ConversationInfoController extends BaseController {
});
}
private void fetchRoomInfo() {
ncApi.getRoom(credentials, ApiUtils.getRoom(conversationUser.getBaseUrl(), conversationToken))
.subscribeOn(Schedulers.newThread())

View File

@ -176,9 +176,6 @@ public class ConversationsListController extends BaseController implements Searc
protected void onAttach(@NonNull View view) {
super.onAttach(view);
eventBus.register(this);
if (getActionBar() != null) {
getActionBar().setDisplayHomeAsUpEnabled(false);
}
currentUser = userUtils.getCurrentUser();
@ -214,47 +211,20 @@ public class ConversationsListController extends BaseController implements Searc
searchView.setOnQueryTextListener(this);
}
}
final View mSearchEditFrame = searchView
.findViewById(androidx.appcompat.R.id.search_edit_frame);
BottomNavigationView bottomNavigationView = getParentController().getView().findViewById(R.id.navigation);
Handler handler = new Handler();
ViewTreeObserver vto = mSearchEditFrame.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
int oldVisibility = -1;
@Override
public void onGlobalLayout() {
int currentVisibility = mSearchEditFrame.getVisibility();
if (currentVisibility != oldVisibility) {
if (currentVisibility == View.VISIBLE) {
handler.postDelayed(() -> bottomNavigationView.setVisibility(View.GONE), 100);
} else {
handler.postDelayed(() -> {
bottomNavigationView.setVisibility(View.VISIBLE);
searchItem.setVisible(callItems.size() > 0);
}, 500);
}
oldVisibility = currentVisibility;
}
}
});
}
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
switch (item.getItemId()) {
case R.id.action_new_conversation:
/*case R.id.action_new_conversation:
Bundle bundle = new Bundle();
bundle.putParcelable(BundleKeys.KEY_MENU_TYPE, Parcels.wrap(CallMenuController.MenuType.NEW_CONVERSATION));
prepareAndShowBottomSheetWithBundle(bundle, true);
return true;*/
case R.id.action_settings:
getRouter().pushController((RouterTransaction.with(new SettingsController())
.pushChangeHandler(new VerticalChangeHandler())
.popChangeHandler(new VerticalChangeHandler())));
return true;
default:
return super.onOptionsItemSelected(item);
@ -412,10 +382,7 @@ public class ConversationsListController extends BaseController implements Searc
emptyLayoutView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (getParentController() != null && getParentController().getView() != null) {
((BottomNavigationView) getParentController().getView().findViewById(R.id.navigation))
.setSelectedItemId(R.id.navigation_contacts);
}
// TODO: show new conversation screen
}
});
@ -583,7 +550,7 @@ public class ConversationsListController extends BaseController implements Searc
if (currentUser.hasSpreedCapabilityWithName("chat-v2")) {
bundle.putString(BundleKeys.KEY_CONVERSATION_NAME, conversation.getDisplayName());
getParentController().getRouter().pushController((RouterTransaction.with(new ChatController(bundle))
getRouter().pushController((RouterTransaction.with(new ChatController(bundle))
.pushChangeHandler(new HorizontalChangeHandler())
.popChangeHandler(new HorizontalChangeHandler())));
} else {

View File

@ -1,76 +0,0 @@
/*
* Nextcloud Talk application
*
* @author Mario Danic
* Copyright (C) 2017 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/>.
*
* The bottom navigation was taken from a PR to Conductor by Chris6647@gmail.com
* https://github.com/bluelinelabs/Conductor/pull/316 and https://github.com/chris6647/Conductor/pull/1/files
* and of course modified by yours truly.
*/
package com.nextcloud.talk.controllers;
import com.bluelinelabs.conductor.Controller;
import com.nextcloud.talk.R;
import com.nextcloud.talk.controllers.base.bottomnavigation.BottomNavigationController;
import com.nextcloud.talk.controllers.base.bottomnavigation.BottomNavigationMenuItem;
import java.lang.reflect.Constructor;
import androidx.annotation.IdRes;
public class MagicBottomNavigationController extends BottomNavigationController {
public MagicBottomNavigationController() {
super(R.menu.menu_navigation);
}
/**
* Supplied MenuItemId must match a {@link Controller} as defined in {@link
* BottomNavigationMenuItem} or an {@link IllegalArgumentException} will be thrown.
*
* @param itemId
*/
@Override
protected Controller getControllerFor(@IdRes int itemId) {
Constructor[] constructors =
BottomNavigationMenuItem.getEnum(itemId).getControllerClass().getConstructors();
Controller controller = null;
try {
/* Determine default or Bundle constructor */
for (Constructor constructor : constructors) {
if (constructor.getParameterTypes().length == 0) {
controller = (Controller) constructor.newInstance();
}
}
} catch (Exception e) {
throw new RuntimeException(
"An exception occurred while creating a new instance for mapping of "
+ itemId
+ ". "
+ e.getMessage(),
e);
}
if (controller == null) {
throw new RuntimeException(
"Controller must have a public empty constructor. "
+ itemId);
}
return controller;
}
}

View File

@ -112,15 +112,6 @@ public class RingtoneSelectionController extends BaseController implements Flexi
prepareViews();
}
@Override
protected void onAttach(@NonNull View view) {
super.onAttach(view);
if (getActionBar() != null) {
getActionBar().setDisplayHomeAsUpEnabled(true);
}
}
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
switch (item.getItemId()) {

View File

@ -188,6 +188,7 @@ public class SettingsController extends BaseController {
@Override
protected void onViewBound(@NonNull View view) {
super.onViewBound(view);
setHasOptionsMenu(true);
NextcloudTalkApplication.getSharedApplication().getComponentApplication().inject(this);
@ -258,13 +259,13 @@ public class SettingsController extends BaseController {
});
addAccountButton.addPreferenceClickListener(view15 -> {
getParentController().getRouter().pushController(RouterTransaction.with(new
getRouter().pushController(RouterTransaction.with(new
ServerSelectionController()).pushChangeHandler(new VerticalChangeHandler())
.popChangeHandler(new VerticalChangeHandler()));
});
switchAccountButton.addPreferenceClickListener(view16 -> {
getParentController().getRouter().pushController(RouterTransaction.with(new
getRouter().pushController(RouterTransaction.with(new
SwitchAccountController()).pushChangeHandler(new VerticalChangeHandler())
.popChangeHandler(new VerticalChangeHandler()));
});
@ -371,7 +372,7 @@ public class SettingsController extends BaseController {
baseUrlTextView.setText(currentUser.getBaseUrl());
reauthorizeButton.addPreferenceClickListener(view14 -> {
getParentController().getRouter().pushController(RouterTransaction.with(
getRouter().pushController(RouterTransaction.with(
new WebViewLoginController(currentUser.getBaseUrl(), true))
.pushChangeHandler(new VerticalChangeHandler())
.popChangeHandler(new VerticalChangeHandler()));

View File

@ -222,13 +222,6 @@ public class SwitchAccountController extends BaseController {
prepareViews();
}
@Override
protected void onAttach(@NonNull View view) {
super.onAttach(view);
if (getActionBar() != null) {
getActionBar().setDisplayHomeAsUpEnabled(true);
}
}
private void prepareViews() {
LinearLayoutManager layoutManager = new SmoothScrollLinearLayoutManager(getActivity());

View File

@ -3,13 +3,13 @@
*
* @author BlueLine Labs, Inc.
* Copyright (C) 2016 BlueLine Labs, Inc.
*
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
*
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -20,12 +20,13 @@ package com.nextcloud.talk.controllers.base;
import android.os.Bundle;
import android.util.Log;
import android.view.MenuItem;
import android.view.View;
import com.bluelinelabs.conductor.Controller;
import com.nextcloud.talk.application.NextcloudTalkApplication;
import com.nextcloud.talk.controllers.AccountVerificationController;
import com.nextcloud.talk.controllers.MagicBottomNavigationController;
import com.nextcloud.talk.controllers.ConversationsListController;
import com.nextcloud.talk.controllers.ServerSelectionController;
import com.nextcloud.talk.controllers.SwitchAccountController;
import com.nextcloud.talk.controllers.WebViewLoginController;
@ -57,6 +58,17 @@ public abstract class BaseController extends ButterKnifeController {
cleanTempCertPreference();
}
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
getRouter().popCurrentController();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
private void cleanTempCertPreference() {
NextcloudTalkApplication.getSharedApplication().getComponentApplication().inject(this);
@ -92,10 +104,9 @@ public abstract class BaseController extends ButterKnifeController {
@Override
protected void onAttach(@NonNull View view) {
setTitle();
if (!MagicBottomNavigationController.class.getName().equals(getClass().getName()) && getActionBar() != null) {
getActionBar().setDisplayHomeAsUpEnabled(false);
if (getActionBar() != null) {
getActionBar().setDisplayHomeAsUpEnabled(getRouter().getBackstackSize() > 1);
}
super.onAttach(view);
}

View File

@ -3,13 +3,13 @@
*
* @author BlueLine Labs, Inc.
* Copyright (C) 2016 BlueLine Labs, Inc.
*
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
*
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

View File

@ -1,320 +0,0 @@
/*
* Nextcloud Talk application
*
* @author Mario Danic
* Copyright (C) 2017-2018 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/>.
*
* The bottom navigation was taken from a PR to Conductor by Chris6647@gmail.com
* https://github.com/bluelinelabs/Conductor/pull/316 and https://github.com/chris6647/Conductor/pull/1/files
* and of course modified by yours truly.
*/
package com.nextcloud.talk.controllers.base.bottomnavigation;
import android.os.Bundle;
import android.util.Log;
import android.util.SparseArray;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import com.bluelinelabs.conductor.ChangeHandlerFrameLayout;
import com.bluelinelabs.conductor.Controller;
import com.bluelinelabs.conductor.Router;
import com.bluelinelabs.conductor.RouterTransaction;
import com.bluelinelabs.conductor.changehandler.FadeChangeHandler;
import com.google.android.material.bottomnavigation.BottomNavigationView;
import com.nextcloud.talk.R;
import com.nextcloud.talk.controllers.base.BaseController;
import com.nextcloud.talk.utils.animations.ViewHidingBehaviourAnimation;
import com.nextcloud.talk.utils.bundle.BundleBuilder;
import androidx.annotation.MenuRes;
import androidx.annotation.NonNull;
import androidx.coordinatorlayout.widget.CoordinatorLayout;
import butterknife.BindView;
/**
* The {@link Controller} for the Bottom Navigation View. Populates a {@link BottomNavigationView}
* with the supplied {@link Menu} resource. The first item set as checked will be shown by default.
* The backstack of each {@link MenuItem} is switched out, in order to maintain a separate backstack
* for each {@link MenuItem} - even though that is against the Google Design Guidelines:
*
* @author chris6647@gmail.com
* @see <a
* href="https://material.io/guidelines/components/bottom-navigation.html#bottom-navigation-behavior">Material
* Design Guidelines</a>
*
* Internally works similarly to {@link com.bluelinelabs.conductor.support.RouterPagerAdapter},
* in the sense that it keeps track of the currently active {@link MenuItem} and the paired
* Child {@link Router}. Everytime we navigate from one to another,
* or {@link Controller#onSaveInstanceState(Bundle)} is called, we save the entire instance state
* of the Child {@link Router}, and cache it, so we have it available when we navigate to
* another {@link MenuItem} and can then restore the correct Child {@link Router}
* (and thus the entire backstack)
*/
public abstract class BottomNavigationController extends BaseController {
public static final String TAG = "BottomNavigationContr";
public static final int INVALID_INT = -1;
private static final String KEY_MENU_RESOURCE = "key_menu_resource";
private static final String KEY_STATE_ROUTER_BUNDLES = "key_state_router_bundles";
private static final String KEY_STATE_CURRENTLY_SELECTED_ID = "key_state_currently_selected_id";
@BindView(R.id.navigation)
BottomNavigationView bottomNavigationView;
@BindView(R.id.bottom_navigation_controller_container)
ChangeHandlerFrameLayout controllerContainer;
private int currentlySelectedItemId = BottomNavigationController.INVALID_INT;
private SparseArray<Bundle> routerSavedStateBundles;
public BottomNavigationController(@MenuRes int menu) {
this(new BundleBuilder(new Bundle()).putInt(KEY_MENU_RESOURCE, menu).build());
}
public BottomNavigationController(Bundle args) {
super(args);
}
@NonNull
@Override
protected View inflateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup container) {
return inflater.inflate(R.layout.controller_bottom_navigation, container, false);
}
@Override
protected void onViewBound(@NonNull View view) {
super.onViewBound(view);
/* Setup the BottomNavigationView with the constructor supplied Menu resource */
bottomNavigationView.inflateMenu(getMenuResource());
bottomNavigationView.setOnNavigationItemSelectedListener(item -> {
int nextItemId = item.getItemId();
if (currentlySelectedItemId != nextItemId) {
Router oldChildRouter = getChildRouter(currentlySelectedItemId);
save(oldChildRouter, currentlySelectedItemId);
destroyChildRouter(oldChildRouter);
configureRouter(getChildRouter(nextItemId), nextItemId);
currentlySelectedItemId = nextItemId;
} else {
resetCurrentBackstack();
}
return true;
});
CoordinatorLayout.LayoutParams layoutParams = (CoordinatorLayout.LayoutParams) bottomNavigationView.getLayoutParams();
layoutParams.setBehavior(new ViewHidingBehaviourAnimation());
}
@Override
protected void onAttach(@NonNull View view) {
super.onAttach(view);
/*
* Fresh start, setup everything.
* Must be done in onAttach to avoid artifacts if using multiple Activities,
* and in case of resuming the app (i.e. when the view is not created again)
*/
if (routerSavedStateBundles == null) {
Menu menu = bottomNavigationView.getMenu();
int menuSize = menu.size();
routerSavedStateBundles = new SparseArray<>(menuSize);
for (int i = 0; i < menuSize; i++) {
MenuItem menuItem = menu.getItem(i);
/* Ensure the first checked item is shown */
if (menuItem.isChecked()) {
/*
* Seems like the BottomNavigationView always initializes index 0 as isChecked / Selected,
* regardless of what was set in the menu xml originally.
* So basically all we're doing here is always setting up menuItem index 0.
*/
int itemId = menuItem.getItemId();
configureRouter(getChildRouter(itemId), itemId);
bottomNavigationView.setSelectedItemId(itemId);
currentlySelectedItemId = bottomNavigationView.getSelectedItemId();
break;
}
}
} else {
/*
* Since we are restoring our state,
* and onRestoreInstanceState is called before onViewBound,
* all we need to do is rebind.
*/
getChildRouter(currentlySelectedItemId).rebindIfNeeded();
}
}
/**
* Get the Child {@link Router} matching the supplied ItemId.
*
* @param itemId MenuItem ID
* @return
*/
protected Router getChildRouter(int itemId) {
return getChildRouter(controllerContainer, "itemId:" + itemId);
}
/**
* Correctly configure the {@link Router} given the cached routerSavedState.
*
* @param itemId {@link MenuItem} ID
* @return true if {@link Router} was restored
*/
private void configureRouter(@NonNull Router childRouter, int itemId) {
if (!childRouter.hasRootController()) {
Bundle routerSavedState = routerSavedStateBundles.get(itemId);
if (routerSavedState != null && !routerSavedState.isEmpty()) {
childRouter.restoreInstanceState(routerSavedState);
routerSavedStateBundles.remove(itemId);
} else {
childRouter.setRoot(RouterTransaction.with(getControllerFor(itemId)));
}
}
childRouter.rebindIfNeeded();
}
/**
* Remove the supplied {@link Router} as a child of this Controller.
*
* @param childRouter
*/
protected void destroyChildRouter(@NonNull Router childRouter) {
removeChildRouter(childRouter);
}
/**
* Resets the current backstack to the {@link Controller}, supplied by {@link
* BottomNavigationController#getControllerFor(int)}, using a {@link FadeChangeHandler}.
*/
protected void resetCurrentBackstack() {
if (currentlySelectedItemId != BottomNavigationController.INVALID_INT) {
destroyChildRouter(getChildRouter(currentlySelectedItemId));
routerSavedStateBundles.remove(currentlySelectedItemId);
/* Must get reference to newly recreated childRouter to avoid old view not being removed */
getChildRouter(currentlySelectedItemId).setRoot(
RouterTransaction.with(getControllerFor(currentlySelectedItemId))
.pushChangeHandler(new FadeChangeHandler(true)));
} else {
Log.w(TAG,
"Attempted to reset backstack on BottomNavigationController with currentlySelectedItemId=" +
currentlySelectedItemId);
}
}
/**
* Navigate to the supplied {@link Controller}, while setting the menuItemId as selected on the
* {@link BottomNavigationView}.
*
* @param itemId {@link MenuItem} ID
*/
protected void navigateTo(int itemId) {
if (currentlySelectedItemId != itemId) {
destroyChildRouter(getChildRouter(currentlySelectedItemId));
routerSavedStateBundles.remove(currentlySelectedItemId);
/* Ensure correct Checked state based on new selection */
Menu menu = bottomNavigationView.getMenu();
for (int i = 0; i < menu.size(); i++) {
MenuItem menuItem = menu.getItem(i);
if (menuItem.isChecked() && menuItem.getItemId() != itemId) {
menuItem.setChecked(false);
} else if (menuItem.getItemId() == itemId) {
menuItem.setChecked(true);
}
}
configureRouter(getChildRouter(itemId), itemId);
currentlySelectedItemId = itemId;
} else {
resetCurrentBackstack();
}
}
/**
* Saves the Child {@link Router} into a {@link Bundle} and caches that {@link Bundle}.
* <p>
* Be cautious as this call causes the controller flag it needs reattach,
* so it should only be called just prior to destroying the router
*
* @param itemId {@link MenuItem} ID
*/
private void save(Router childRouter, int itemId) {
Bundle routerBundle = new Bundle();
childRouter.saveInstanceState(routerBundle);
routerSavedStateBundles.put(itemId, routerBundle);
}
@Override
protected void onRestoreInstanceState(@NonNull Bundle savedInstanceState) {
routerSavedStateBundles = savedInstanceState.getSparseParcelableArray(KEY_STATE_ROUTER_BUNDLES);
currentlySelectedItemId =
savedInstanceState.getInt(KEY_STATE_CURRENTLY_SELECTED_ID, BottomNavigationController.INVALID_INT);
}
@Override
protected void onSaveInstanceState(@NonNull Bundle outState) {
outState.putSparseParcelableArray(KEY_STATE_ROUTER_BUNDLES, routerSavedStateBundles);
/*
* For some reason the BottomNavigationView does not seem to correctly restore its
* selectedId, even though the view appears with the correct state.
* So we keep track of it manually
*/
outState.putInt(KEY_STATE_CURRENTLY_SELECTED_ID, currentlySelectedItemId);
}
@Override
public boolean handleBack() {
/*
* The childRouter should handleBack,
* as this BottomNavigationController doesn't have a back step sensible to the user.
*/
Router childRouter = getChildRouter(currentlySelectedItemId);
if (childRouter != null) {
if (childRouter.getBackstackSize() > 1) {
return childRouter.handleBack();
} else if (currentlySelectedItemId != R.id.navigation_calls) {
navigateTo(R.id.navigation_calls);
return true;
} else {
return false;
}
} else {
Log.d(TAG, "handleBack called with getChildRouter(currentlySelectedItemId) == null.");
return false;
}
}
/**
* Get the {@link Menu} Resource ID from {@link Controller#getArgs()}
*
* @return the {@link Menu} Resource ID
*/
private int getMenuResource() {
return getArgs().getInt(KEY_MENU_RESOURCE);
}
/**
* Return a target instance of {@link Controller} for given menu item ID
*
* @param itemId the ID tapped by the user
* @return the {@link Controller} instance to navigate to
*/
protected abstract Controller getControllerFor(int itemId);
}

View File

@ -1,87 +0,0 @@
/*
* Nextcloud Talk application
*
* @author Mario Danic
* Copyright (C) 2017 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/>.
*
* The bottom navigation was taken from a PR to Conductor by Chris6647@gmail.com
* https://github.com/bluelinelabs/Conductor/pull/316 and https://github.com/chris6647/Conductor/pull/1/files
* and of course modified by yours truly.
*/
package com.nextcloud.talk.controllers.base.bottomnavigation;
import com.bluelinelabs.conductor.Controller;
import com.nextcloud.talk.R;
import com.nextcloud.talk.controllers.ContactsController;
import com.nextcloud.talk.controllers.ConversationsListController;
import com.nextcloud.talk.controllers.SettingsController;
import com.nextcloud.talk.utils.BottomNavigationUtils;
import androidx.annotation.IdRes;
/**
* Enum representation of valid Bottom Navigation Menu Items
*/
public enum BottomNavigationMenuItem {
CALLS(R.id.navigation_calls, ConversationsListController.class),
CONTACTS(R.id.navigation_contacts, ContactsController.class),
SETTINGS(R.id.navigation_settings, SettingsController.class);
private int menuResId;
private Class<? extends Controller> controllerClass;
BottomNavigationMenuItem(@IdRes int menuResId, Class<? extends Controller> controllerClass) {
this.menuResId = menuResId;
this.controllerClass = controllerClass;
}
public static BottomNavigationMenuItem getEnum(@IdRes int menuResId) {
for (BottomNavigationMenuItem type : BottomNavigationMenuItem.values()) {
if (menuResId == type.getMenuResId()) {
return type;
}
}
throw new IllegalArgumentException("Unable to map " + menuResId);
}
public static BottomNavigationMenuItem getEnum(Class<? extends Controller> controllerClass) {
for (BottomNavigationMenuItem type : BottomNavigationMenuItem.values()) {
if (BottomNavigationUtils.equals(controllerClass, type.getControllerClass())) {
return type;
}
}
throw new IllegalArgumentException("Unable to map " + controllerClass);
}
public int getMenuResId() {
return menuResId;
}
public Class<? extends Controller> getControllerClass() {
return controllerClass;
}
@Override
public String toString() {
return "BottomNavigationMenuItem{"
+ "menuResId="
+ menuResId
+ ", controllerClass="
+ controllerClass
+ '}';
}
}

View File

@ -139,7 +139,7 @@ public class CallMenuController extends BaseController implements FlexibleAdapte
menuItems.add(new MenuItem(getResources().getString(R.string.nc_remove_from_favorites), 97, getResources()
.getDrawable(R.drawable.ic_star_border_grey600_24dp)));
} else if ((currentUser = userUtils.getCurrentUser()) != null &&
currentUser.hasSpreedCapabilityWithName("favorites")){
currentUser.hasSpreedCapabilityWithName("favorites")) {
menuItems.add(new MenuItem(getResources().getString(R.string.nc_add_to_favorites), 98, getResources()
.getDrawable(R.drawable.ic_star_grey600_24dp)));
}

View File

@ -131,7 +131,7 @@ public class EntryMenuController extends BaseController {
bundle.putString(BundleKeys.KEY_CALL_URL, callUrl);
bundle.putString(BundleKeys.KEY_CONVERSATION_PASSWORD, editText.getText().toString());
bundle.putInt(BundleKeys.KEY_OPERATION_CODE, operationCode);
if(originalBundle.containsKey(BundleKeys.KEY_SPREED_CAPABILITIES)) {
if (originalBundle.containsKey(BundleKeys.KEY_SPREED_CAPABILITIES)) {
bundle.putParcelable(BundleKeys.KEY_SPREED_CAPABILITIES, originalBundle.getParcelable(BundleKeys.KEY_SPREED_CAPABILITIES));
}
getRouter().pushController(RouterTransaction.with(new OperationsMenuController(bundle))

View File

@ -141,7 +141,7 @@ public class OperationsMenuController extends BaseController {
if (args.containsKey(BundleKeys.KEY_INVITED_GROUP)) {
this.invitedGroups = args.getStringArrayList(BundleKeys.KEY_INVITED_GROUP);
}
if (args.containsKey(BundleKeys.KEY_CONVERSATION_TYPE)) {
this.conversationType = Parcels.unwrap(args.getParcelable(BundleKeys.KEY_CONVERSATION_TYPE));
}
@ -168,7 +168,7 @@ public class OperationsMenuController extends BaseController {
currentUser = userUtils.getCurrentUser();
OperationsObserver operationsObserver = new OperationsObserver();
if (!TextUtils.isEmpty(callUrl) ) {
if (!TextUtils.isEmpty(callUrl)) {
conversationToken = callUrl.substring(callUrl.lastIndexOf("/") + 1, callUrl.length());
if (callUrl.contains("/index.php")) {
baseUrl = callUrl.substring(0, callUrl.indexOf("/index.php"));
@ -274,7 +274,7 @@ public class OperationsMenuController extends BaseController {
RetrofitBucket retrofitBucket;
boolean isGroupCallWorkaround = false;
String invite = null;
if (invitedGroups.size() > 0) {
invite = invitedGroups.get(0);
}
@ -289,7 +289,7 @@ public class OperationsMenuController extends BaseController {
isGroupCallWorkaround = true;
roomType = "3";
}
retrofitBucket = ApiUtils.getRetrofitBucketForCreateRoom(currentUser.getBaseUrl(),
roomType, invite, null);
}

View File

@ -22,5 +22,6 @@ package com.nextcloud.talk.interfaces;
public interface ClosedInterface {
void providerInstallerInstallIfNeededAsync();
boolean isGooglePlayServicesAvailable();
}

View File

@ -265,7 +265,7 @@ public class NotificationWorker extends Worker {
PendingIntent pendingIntent = PendingIntent.getActivity(context,
0, intent, PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT);
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context);
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context);
CRC32 crc32 = new CRC32();

View File

@ -36,7 +36,8 @@ import lombok.Data;
@Data
public class RingtoneSettings {
@JsonField(name = "ringtoneUri", typeConverter = UriTypeConverter.class)
@Nullable Uri ringtoneUri;
@Nullable
Uri ringtoneUri;
@JsonField(name = "ringtoneName")
String ringtoneName;
}

View File

@ -73,7 +73,7 @@ public class Conversation {
public int unreadMessages;
@JsonField(name = "unreadMention")
public boolean unreadMention;
@JsonField(name = "lastMessage")
@JsonField(name = "lastMessage")
public ChatMessage lastMessage;
@JsonField(name = "objectType")
String objectType;

View File

@ -30,7 +30,7 @@ import lombok.Data;
@Data
@JsonObject
@Parcel
public class BaseWebSocketMessage{
public class BaseWebSocketMessage {
@JsonField(name = "type")
String type;
}

View File

@ -197,7 +197,7 @@ public class ApiUtils {
public static String getUrlForAvatarWithName(String baseUrl, String name, @DimenRes int avatarSize) {
avatarSize = Math.round(NextcloudTalkApplication
.getSharedApplication().getResources().getDimension(avatarSize));
.getSharedApplication().getResources().getDimension(avatarSize));
return baseUrl + "/index.php/avatar/" + Uri.encode(name) + "/" + avatarSize;
}

View File

@ -110,17 +110,17 @@ public class DisplayUtils {
int end = text.indexOf(m.group()) + m.group().length();
spannable.setSpan(new ForegroundColorSpan(color), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
spannable.setSpan(new StyleSpan(Typeface.BOLD), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
spannable.setSpan(new AbsoluteSizeSpan(textSize) , start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
spannable.setSpan(new AbsoluteSizeSpan(textSize), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
return spannable;
}
public static Drawable getMessageSelector(@ColorInt int normalColor, @ColorInt int selectedColor,
@ColorInt int pressedColor, @DrawableRes int shape) {
@ColorInt int pressedColor, @DrawableRes int shape) {
Drawable vectorDrawable = ContextCompat.getDrawable(NextcloudTalkApplication.getSharedApplication()
.getApplicationContext(),
.getApplicationContext(),
shape);
Drawable drawable = DrawableCompat.wrap(vectorDrawable).mutate();
DrawableCompat.setTintList(

View File

@ -50,11 +50,11 @@ public class KeyboardUtils {
if (shouldSetBottomPadding) {
if (contentView.getPaddingBottom() != diff) {
//set the padding of the contentView for the keyboard
contentView.setPadding(0, 0, 0, diff);
contentView.setPadding(0, 0, 0, diff);
}
} else {
//check if the padding is != initialBottomPadding (if yes reset the padding)
if (contentView.getPaddingBottom() != 0) {
if (contentView.getPaddingBottom() != 0) {
//reset the padding of the contentView
contentView.setPadding(0, 0, 0, 0);
}

View File

@ -109,8 +109,11 @@ class SSLSocketFactoryCompat(keyManager: KeyManager?,
}
}
override fun getDefaultCipherSuites(): Array<String>? = cipherSuites ?: delegate.defaultCipherSuites
override fun getSupportedCipherSuites(): Array<String>? = cipherSuites ?: delegate.supportedCipherSuites
override fun getDefaultCipherSuites(): Array<String>? = cipherSuites
?: delegate.defaultCipherSuites
override fun getSupportedCipherSuites(): Array<String>? = cipherSuites
?: delegate.supportedCipherSuites
override fun createSocket(s: Socket, host: String, port: Int, autoClose: Boolean): Socket {
val ssl = delegate.createSocket(s, host, port, autoClose)

View File

@ -166,11 +166,11 @@ public class MagicProximitySensor implements SensorEventListener {
}
StringBuilder info = new StringBuilder("Proximity sensor: ");
info.append("name=").append(proximitySensor.getName())
.append(", vendor: ").append(proximitySensor.getVendor())
.append(", power: ").append(proximitySensor.getPower())
.append(", resolution: ").append(proximitySensor.getResolution())
.append(", max range: ").append(proximitySensor.getMaximumRange())
.append(", min delay: ").append(proximitySensor.getMinDelay());
.append(", vendor: ").append(proximitySensor.getVendor())
.append(", power: ").append(proximitySensor.getPower())
.append(", resolution: ").append(proximitySensor.getResolution())
.append(", max range: ").append(proximitySensor.getMaximumRange())
.append(", min delay: ").append(proximitySensor.getMinDelay());
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH) {
// Added in API level 20.
info.append(", type: ").append(proximitySensor.getStringType());
@ -178,8 +178,8 @@ public class MagicProximitySensor implements SensorEventListener {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
// Added in API level 21.
info.append(", max delay: ").append(proximitySensor.getMaxDelay())
.append(", reporting mode: ").append(proximitySensor.getReportingMode())
.append(", isWakeUpSensor: ").append(proximitySensor.isWakeUpSensor());
.append(", reporting mode: ").append(proximitySensor.getReportingMode())
.append(", isWakeUpSensor: ").append(proximitySensor.isWakeUpSensor());
}
Log.d(TAG, info.toString());
}

View File

@ -67,7 +67,7 @@ public class WebSocketConnectionHelper {
}
MagicWebSocketInstance magicWebSocketInstance;
if (magicWebSocketInstanceMap.containsKey(userEntity.getId()) && (magicWebSocketInstance = magicWebSocketInstanceMap.get(userEntity.getId())) != null && !magicWebSocketInstance.isPermanentlyClosed()) {
if (magicWebSocketInstanceMap.containsKey(userEntity.getId()) && (magicWebSocketInstance = magicWebSocketInstanceMap.get(userEntity.getId())) != null && !magicWebSocketInstance.isPermanentlyClosed()) {
return magicWebSocketInstance;
} else {
magicWebSocketInstance = new MagicWebSocketInstance(userEntity, generatedURL, webSocketTicket);
@ -85,6 +85,7 @@ public class WebSocketConnectionHelper {
}
}
}
HelloOverallWebSocketMessage getAssembledHelloModel(UserEntity userEntity, String ticket) {
HelloOverallWebSocketMessage helloOverallWebSocketMessage = new HelloOverallWebSocketMessage();
helloOverallWebSocketMessage.setType("hello");

View File

@ -0,0 +1,25 @@
<!--
~ Nextcloud Talk application
~
~ @author Mario Danic
~ Copyright (C) 2017-2018 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="#FFFFFF" android:pathData="M19.43,12.98c0.04,-0.32 0.07,-0.64 0.07,-0.98s-0.03,-0.66 -0.07,-0.98l2.11,-1.65c0.19,-0.15 0.24,-0.42 0.12,-0.64l-2,-3.46c-0.12,-0.22 -0.39,-0.3 -0.61,-0.22l-2.49,1c-0.52,-0.4 -1.08,-0.73 -1.69,-0.98l-0.38,-2.65C14.46,2.18 14.25,2 14,2h-4c-0.25,0 -0.46,0.18 -0.49,0.42l-0.38,2.65c-0.61,0.25 -1.17,0.59 -1.69,0.98l-2.49,-1c-0.23,-0.09 -0.49,0 -0.61,0.22l-2,3.46c-0.13,0.22 -0.07,0.49 0.12,0.64l2.11,1.65c-0.04,0.32 -0.07,0.65 -0.07,0.98s0.03,0.66 0.07,0.98l-2.11,1.65c-0.19,0.15 -0.24,0.42 -0.12,0.64l2,3.46c0.12,0.22 0.39,0.3 0.61,0.22l2.49,-1c0.52,0.4 1.08,0.73 1.69,0.98l0.38,2.65c0.03,0.24 0.24,0.42 0.49,0.42h4c0.25,0 0.46,-0.18 0.49,-0.42l0.38,-2.65c0.61,-0.25 1.17,-0.59 1.69,-0.98l2.49,1c0.23,0.09 0.49,0 0.61,-0.22l2,-3.46c0.12,-0.22 0.07,-0.49 -0.12,-0.64l-2.11,-1.65zM12,15.5c-1.93,0 -3.5,-1.57 -3.5,-3.5s1.57,-3.5 3.5,-3.5 3.5,1.57 3.5,3.5 -1.57,3.5 -3.5,3.5z"/>
</vector>

View File

@ -1,24 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/bottom_navigation_root"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.bluelinelabs.conductor.ChangeHandlerFrameLayout
android:id="@+id/bottom_navigation_controller_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="top"
app:layout_behavior="@string/appbar_scrolling_view_behavior"/>
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="@+id/navigation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:animateLayoutChanges="true"
android:background="@color/white"/>
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View File

@ -23,8 +23,7 @@
xmlns:apc="http://schemas.android.com/apk/res-auto"
android:id="@+id/settings_screen"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="48dp">
android:layout_height="match_parent">
<com.yarolegovich.mp.MaterialPreferenceCategory
android:id="@+id/message_view"

View File

@ -31,10 +31,10 @@
app:actionViewClass="androidx.appcompat.widget.SearchView"
/>
<item android:id="@+id/action_new_conversation"
android:title="@string/nc_new_conversation"
android:icon="@drawable/ic_add_white_24px"
app:showAsAction="ifRoom"/>
<item android:id="@+id/action_settings"
android:title="@string/nc_bottom_navigation_title_settings"
android:icon="@drawable/ic_settings_white_24dp"
app:showAsAction="ifRoom"/>
<item
android:id="@+id/contacts_selection_done"