From 20b80b36b3cd93d93161f5a7cf419cb3438f39d8 Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Fri, 2 Feb 2018 11:40:42 +0100 Subject: [PATCH] Bunch of work on new conversation Signed-off-by: Mario Danic --- app/build.gradle | 3 +- .../talk/adapters/items/AdvancedUserItem.java | 19 +- .../talk/adapters/items/CallItem.java | 18 +- .../talk/adapters/items/EmptyFooterItem.java | 78 ++++ .../talk/adapters/items/UserHeaderItem.java | 103 ++++++ .../talk/adapters/items/UserItem.java | 41 ++- .../application/NextcloudTalkApplication.java | 1 - .../AccountVerificationController.java | 2 +- .../talk/controllers/CallsListController.java | 62 +++- .../talk/controllers/ContactsController.java | 346 ++++++++++++------ .../ServerSelectionController.java | 2 +- .../controllers/SwitchAccountController.java | 22 ++ .../talk/controllers/base/BaseController.java | 1 + .../bottomsheet/CallMenuController.java | 2 +- .../talk/dagger/modules/RestModule.java | 2 +- .../MagicFirebaseMessagingService.java | 2 +- .../nextcloud/talk/utils/MagicFlipView.java | 45 +++ .../talk/utils/bundle/BundleKeys.java | 1 + .../webrtc/MagicPeerConnectionWrapper.java | 4 +- .../talk/webrtc/MagicWebRTCUtils.java | 2 +- .../main/res/drawable/ic_add_white_24px.xml | 25 ++ app/src/main/res/layout/bottom_buttons.xml | 52 +++ .../main/res/layout/controller_call_menu.xml | 8 +- .../main/res/layout/controller_entry_menu.xml | 2 +- .../main/res/layout/controller_generic_rv.xml | 42 ++- app/src/main/res/layout/fast_scroller.xml | 38 ++ app/src/main/res/layout/rv_item_call.xml | 17 +- app/src/main/res/layout/rv_item_contact.xml | 14 +- .../main/res/layout/rv_item_empty_footer.xml | 27 ++ .../main/res/layout/rv_item_title_header.xml | 39 ++ app/src/main/res/layout/surface_renderer.xml | 6 +- ....xml => menu_conversation_plus_filter.xml} | 9 +- app/src/main/res/values/strings.xml | 4 + 33 files changed, 860 insertions(+), 179 deletions(-) create mode 100644 app/src/main/java/com/nextcloud/talk/adapters/items/EmptyFooterItem.java create mode 100644 app/src/main/java/com/nextcloud/talk/adapters/items/UserHeaderItem.java create mode 100644 app/src/main/java/com/nextcloud/talk/utils/MagicFlipView.java create mode 100644 app/src/main/res/drawable/ic_add_white_24px.xml create mode 100644 app/src/main/res/layout/bottom_buttons.xml create mode 100644 app/src/main/res/layout/fast_scroller.xml create mode 100644 app/src/main/res/layout/rv_item_empty_footer.xml create mode 100644 app/src/main/res/layout/rv_item_title_header.xml rename app/src/main/res/menu/{menu_filter.xml => menu_conversation_plus_filter.xml} (85%) diff --git a/app/build.gradle b/app/build.gradle index a4974fdc7..55dffb051 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -111,7 +111,7 @@ dependencies { debugImplementation "javax.transaction:transaction-api:1.1-rev-1" - implementation 'com.github.HITGIF:TextFieldBoxes:1.3.8' + implementation 'com.github.HITGIF:TextFieldBoxes:1.3.9' implementation 'eu.davidea:flexible-adapter:5.0.0-rc4' implementation 'eu.davidea:flexible-adapter-ui:1.0.0-b1' @@ -138,6 +138,7 @@ dependencies { implementation group: 'org.apache.commons', name: 'commons-lang3', version: '3.7' implementation 'com.github.Kennyc1012:BottomSheet:2.4.0' + implementation 'eu.davidea:flipview:1.1.3' testImplementation 'junit:junit:4.12' androidTestImplementation ('com.android.support.test.espresso:espresso-core:3.0.1', { exclude group: 'com.android.support', module: 'support-annotations' diff --git a/app/src/main/java/com/nextcloud/talk/adapters/items/AdvancedUserItem.java b/app/src/main/java/com/nextcloud/talk/adapters/items/AdvancedUserItem.java index cdff7e5c2..d1603a0b3 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/items/AdvancedUserItem.java +++ b/app/src/main/java/com/nextcloud/talk/adapters/items/AdvancedUserItem.java @@ -51,6 +51,7 @@ import eu.davidea.flexibleadapter.FlexibleAdapter; import eu.davidea.flexibleadapter.items.AbstractFlexibleItem; import eu.davidea.flexibleadapter.items.IFilterable; import eu.davidea.flexibleadapter.utils.FlexibleUtils; +import eu.davidea.flipview.FlipView; import eu.davidea.viewholders.FlexibleViewHolder; public class AdvancedUserItem extends AbstractFlexibleItem implements IFilterable { @@ -119,24 +120,23 @@ public class AdvancedUserItem extends AbstractFlexibleItem implements IFilterable { @@ -120,6 +121,9 @@ public class CallItem extends AbstractFlexibleItem holder.passwordProtectedImageView.setVisibility(View.GONE); } + int avatarSize = Math.round(NextcloudTalkApplication + .getSharedApplication().getResources().getDimension(R.dimen.avatar_size)); + switch (room.getType()) { case ROOM_TYPE_ONE_TO_ONE_CALL: holder.avatarImageView.setVisibility(View.VISIBLE); @@ -133,12 +137,12 @@ public class CallItem extends AbstractFlexibleItem GlideApp.with(NextcloudTalkApplication.getSharedApplication().getApplicationContext()) .asBitmap() - .skipMemoryCache(true) .diskCacheStrategy(DiskCacheStrategy.NONE) .load(glideUrl) .centerInside() + .override(avatarSize, avatarSize) .apply(RequestOptions.bitmapTransform(new CircleCrop())) - .into(holder.avatarImageView); + .into(holder.avatarImageView.getFrontImageView()); } else { holder.avatarImageView.setVisibility(View.GONE); @@ -147,23 +151,23 @@ public class CallItem extends AbstractFlexibleItem case ROOM_GROUP_CALL: GlideApp.with(NextcloudTalkApplication.getSharedApplication().getApplicationContext()) .asBitmap() - .skipMemoryCache(true) .diskCacheStrategy(DiskCacheStrategy.NONE) .load(R.drawable.ic_group_white_24px) .centerInside() + .override(avatarSize, avatarSize) .apply(RequestOptions.bitmapTransform(new CircleCrop())) - .into(holder.avatarImageView); + .into(holder.avatarImageView.getFrontImageView()); holder.avatarImageView.setVisibility(View.VISIBLE); break; case ROOM_PUBLIC_CALL: GlideApp.with(NextcloudTalkApplication.getSharedApplication().getApplicationContext()) .asBitmap() - .skipMemoryCache(true) .diskCacheStrategy(DiskCacheStrategy.NONE) .load(R.drawable.ic_link_white_24px) .centerInside() + .override(avatarSize, avatarSize) .apply(RequestOptions.bitmapTransform(new CircleCrop())) - .into(holder.avatarImageView); + .into(holder.avatarImageView.getFrontImageView()); holder.avatarImageView.setVisibility(View.VISIBLE); break; default: @@ -188,7 +192,7 @@ public class CallItem extends AbstractFlexibleItem @BindView(R.id.secondary_text) public TextView roomLastPing; @BindView(R.id.avatar_image) - public ImageView avatarImageView; + public FlipView avatarImageView; @BindView(R.id.more_menu) public ImageButton moreMenuButton; @BindView(R.id.password_protected_image_view) diff --git a/app/src/main/java/com/nextcloud/talk/adapters/items/EmptyFooterItem.java b/app/src/main/java/com/nextcloud/talk/adapters/items/EmptyFooterItem.java new file mode 100644 index 000000000..d69c1f5b0 --- /dev/null +++ b/app/src/main/java/com/nextcloud/talk/adapters/items/EmptyFooterItem.java @@ -0,0 +1,78 @@ +/* + * Nextcloud Talk application + * + * @author Mario Danic + * Copyright (C) 2017-2018 Mario Danic + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.nextcloud.talk.adapters.items; + +import android.view.View; + +import com.nextcloud.talk.R; + +import java.util.List; + +import eu.davidea.flexibleadapter.FlexibleAdapter; +import eu.davidea.flexibleadapter.items.AbstractFlexibleItem; +import eu.davidea.viewholders.FlexibleViewHolder; + +public class EmptyFooterItem extends AbstractFlexibleItem { + int id; + + public EmptyFooterItem(int id) { + this.id = id; + } + + @Override + public boolean equals(Object o) { + if (o instanceof EmptyFooterItem) { + EmptyFooterItem inItem = (EmptyFooterItem) o; + return id == inItem.getModel(); + } + return false; + } + + public int getModel() { + return id; + } + + + @Override + public int getLayoutRes() { + return R.layout.rv_item_empty_footer; + } + + @Override + public EmptyFooterItemViewHolder createViewHolder(View view, FlexibleAdapter adapter) { + return new EmptyFooterItemViewHolder(view, adapter); + } + + @Override + public void bindViewHolder(FlexibleAdapter adapter, EmptyFooterItemViewHolder holder, int position, List payloads) { + + } + + static class EmptyFooterItemViewHolder extends FlexibleViewHolder { + /** + * Default constructor. + */ + EmptyFooterItemViewHolder(View view, FlexibleAdapter adapter) { + super(view, adapter); + } + + } +} diff --git a/app/src/main/java/com/nextcloud/talk/adapters/items/UserHeaderItem.java b/app/src/main/java/com/nextcloud/talk/adapters/items/UserHeaderItem.java new file mode 100644 index 000000000..98b72935d --- /dev/null +++ b/app/src/main/java/com/nextcloud/talk/adapters/items/UserHeaderItem.java @@ -0,0 +1,103 @@ +/* + * Nextcloud Talk application + * + * @author Mario Danic + * Copyright (C) 2017-2018 Mario Danic + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.nextcloud.talk.adapters.items; + +import android.util.Log; +import android.view.View; +import android.widget.TextView; + +import com.nextcloud.talk.R; + +import org.apache.commons.lang3.StringUtils; + +import java.util.List; + +import butterknife.BindView; +import butterknife.ButterKnife; +import eu.davidea.flexibleadapter.FlexibleAdapter; +import eu.davidea.flexibleadapter.items.AbstractHeaderItem; +import eu.davidea.flexibleadapter.items.IFilterable; +import eu.davidea.viewholders.FlexibleViewHolder; + +public class UserHeaderItem extends AbstractHeaderItem implements IFilterable { + private static final String TAG = "UserHeaderItem"; + + private String title; + + public UserHeaderItem(String title) { + super(); + setHidden(false); + setSelectable(false); + this.title = title; + } + + @Override + public boolean filter(String constraint) { + return StringUtils.containsIgnoreCase(title, constraint); + } + + public String getModel() { + return title; + } + + @Override + public boolean equals(Object o) { + if (o instanceof UserHeaderItem) { + UserHeaderItem inItem = (UserHeaderItem) o; + return title.equals(inItem.getModel()); + } + return false; + } + + @Override + public int getLayoutRes() { + return R.layout.rv_item_title_header; + } + + @Override + public HeaderViewHolder createViewHolder(View view, FlexibleAdapter adapter) { + return new HeaderViewHolder(view, adapter); + } + + @Override + public void bindViewHolder(FlexibleAdapter adapter, HeaderViewHolder holder, int position, List payloads) { + if (payloads.size() > 0) { + Log.d(TAG, "We have payloads, so ignoring!"); + } else { + holder.titleTextView.setText(title); + } + } + + static class HeaderViewHolder extends FlexibleViewHolder { + + @BindView(R.id.title_text_view) + public TextView titleTextView; + + /** + * Default constructor. + */ + HeaderViewHolder(View view, FlexibleAdapter adapter) { + super(view, adapter, true); + ButterKnife.bind(this, view); + } + } + +} diff --git a/app/src/main/java/com/nextcloud/talk/adapters/items/UserItem.java b/app/src/main/java/com/nextcloud/talk/adapters/items/UserItem.java index 9a148a506..32713627f 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/items/UserItem.java +++ b/app/src/main/java/com/nextcloud/talk/adapters/items/UserItem.java @@ -21,7 +21,6 @@ package com.nextcloud.talk.adapters.items; import android.view.View; -import android.widget.ImageView; import android.widget.TextView; import com.bumptech.glide.load.engine.DiskCacheStrategy; @@ -45,17 +44,25 @@ import butterknife.ButterKnife; import eu.davidea.flexibleadapter.FlexibleAdapter; import eu.davidea.flexibleadapter.items.AbstractFlexibleItem; import eu.davidea.flexibleadapter.items.IFilterable; +import eu.davidea.flexibleadapter.items.ISectionable; import eu.davidea.flexibleadapter.utils.FlexibleUtils; +import eu.davidea.flipview.FlipView; import eu.davidea.viewholders.FlexibleViewHolder; -public class UserItem extends AbstractFlexibleItem implements IFilterable { +public class UserItem extends AbstractFlexibleItem implements + ISectionable, IFilterable { private Participant participant; private UserEntity userEntity; + private UserHeaderItem header; - public UserItem(Participant participant, UserEntity userEntity) { + private FlipView flipView; + + + public UserItem(Participant participant, UserEntity userEntity, UserHeaderItem userHeaderItem) { this.participant = participant; this.userEntity = userEntity; + this.header = userHeaderItem; } @Override @@ -84,6 +91,10 @@ public class UserItem extends AbstractFlexibleItem return userEntity; } + public void flipItemSelection() { + flipView.flip(!flipView.isFlipped()); + } + @Override public int getLayoutRes() { return R.layout.rv_item_contact; @@ -96,6 +107,9 @@ public class UserItem extends AbstractFlexibleItem @Override public void bindViewHolder(FlexibleAdapter adapter, UserItemViewHolder holder, int position, List payloads) { + + flipView = holder.avatarFlipView; + if (adapter.hasSearchText()) { FlexibleUtils.highlightText(holder.contactDisplayName, participant.getName(), adapter.getSearchText()); } else { @@ -108,14 +122,17 @@ public class UserItem extends AbstractFlexibleItem .setHeader("User-Agent", ApiUtils.getUserAgent()) .build()); + int avatarSize = Math.round(NextcloudTalkApplication + .getSharedApplication().getResources().getDimension(R.dimen.avatar_size)); + GlideApp.with(NextcloudTalkApplication.getSharedApplication().getApplicationContext()) .asBitmap() - .skipMemoryCache(true) .diskCacheStrategy(DiskCacheStrategy.NONE) .load(glideUrl) .centerInside() + .override(avatarSize, avatarSize) .apply(RequestOptions.bitmapTransform(new CircleCrop())) - .into(holder.avatarImageView); + .into(holder.avatarFlipView.getFrontImageView()); } @Override @@ -124,13 +141,23 @@ public class UserItem extends AbstractFlexibleItem StringUtils.containsIgnoreCase(participant.getName().trim(), constraint); } + @Override + public UserHeaderItem getHeader() { + return header; + } + + @Override + public void setHeader(UserHeaderItem header) { + this.header = header; + } + static class UserItemViewHolder extends FlexibleViewHolder { @BindView(R.id.name_text) public TextView contactDisplayName; - @BindView(R.id.avatar_image) - public ImageView avatarImageView; + @BindView(R.id.avatar_flip_view) + public FlipView avatarFlipView; /** * Default constructor. diff --git a/app/src/main/java/com/nextcloud/talk/application/NextcloudTalkApplication.java b/app/src/main/java/com/nextcloud/talk/application/NextcloudTalkApplication.java index 76758750e..9a5711607 100644 --- a/app/src/main/java/com/nextcloud/talk/application/NextcloudTalkApplication.java +++ b/app/src/main/java/com/nextcloud/talk/application/NextcloudTalkApplication.java @@ -117,7 +117,6 @@ public class NextcloudTalkApplication extends MultiDexApplication { initializeWebRtc(); DisplayUtils.useCompatVectorIfNeeded(); - try { buildComponent(); } catch (final GeneralSecurityException exception) { 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 c6d4fc206..21aabafa0 100644 --- a/app/src/main/java/com/nextcloud/talk/controllers/AccountVerificationController.java +++ b/app/src/main/java/com/nextcloud/talk/controllers/AccountVerificationController.java @@ -36,10 +36,10 @@ import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler; import com.evernote.android.job.JobRequest; import com.nextcloud.talk.R; import com.nextcloud.talk.api.NcApi; -import com.nextcloud.talk.utils.ApiUtils; import com.nextcloud.talk.application.NextcloudTalkApplication; import com.nextcloud.talk.controllers.base.BaseController; import com.nextcloud.talk.jobs.PushRegistrationJob; +import com.nextcloud.talk.utils.ApiUtils; import com.nextcloud.talk.utils.ApplicationWideMessageHolder; import com.nextcloud.talk.utils.bundle.BundleKeys; import com.nextcloud.talk.utils.database.user.UserUtils; diff --git a/app/src/main/java/com/nextcloud/talk/controllers/CallsListController.java b/app/src/main/java/com/nextcloud/talk/controllers/CallsListController.java index 9bc16cb5a..9acabf805 100644 --- a/app/src/main/java/com/nextcloud/talk/controllers/CallsListController.java +++ b/app/src/main/java/com/nextcloud/talk/controllers/CallsListController.java @@ -31,7 +31,6 @@ import android.support.design.widget.BottomNavigationView; import android.support.v4.view.MenuItemCompat; import android.support.v4.widget.SwipeRefreshLayout; import android.support.v7.widget.DividerItemDecoration; -import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.support.v7.widget.SearchView; import android.text.InputType; @@ -81,6 +80,7 @@ import javax.inject.Inject; import autodagger.AutoInjector; import butterknife.BindView; +import eu.davidea.fastscroller.FastScroller; import eu.davidea.flexibleadapter.FlexibleAdapter; import eu.davidea.flexibleadapter.common.SmoothScrollLinearLayoutManager; import io.reactivex.android.schedulers.AndroidSchedulers; @@ -90,7 +90,7 @@ import retrofit2.HttpException; @AutoInjector(NextcloudTalkApplication.class) public class CallsListController extends BaseController implements SearchView.OnQueryTextListener, - FlexibleAdapter.OnItemClickListener { + FlexibleAdapter.OnItemClickListener, FastScroller.OnScrollStateChangeListener { public static final String TAG = "CallsListController"; @@ -110,6 +110,11 @@ public class CallsListController extends BaseController implements SearchView.On @BindView(R.id.swipe_refresh_layout) SwipeRefreshLayout swipeRefreshLayout; + @BindView(R.id.fast_scroller) + FastScroller fastScroller; + + private SmoothScrollLinearLayoutManager layoutManager; + private UserEntity userEntity; private Disposable roomsQueryDisposable; private FlexibleAdapter adapter; @@ -117,6 +122,7 @@ public class CallsListController extends BaseController implements SearchView.On private BottomSheet bottomSheet; private MenuItem searchItem; + private Menu menuVariable; private SearchView searchView; private String searchQuery; @@ -158,7 +164,6 @@ public class CallsListController extends BaseController implements SearchView.On adapter.addListener(this); prepareViews(); - } @Override @@ -222,10 +227,32 @@ public class CallsListController extends BaseController implements SearchView.On } + @Override + public boolean onOptionsItemSelected(@NonNull MenuItem item) { + switch (item.getItemId()) { + case R.id.action_new_conversation: + searchItem.setVisible(false); + menuVariable.findItem(R.id.action_new_conversation).setVisible(false); + Bundle bundle = new Bundle(); + bundle.putBoolean(BundleKeys.KEY_NEW_CONVERSATION, true); + if (getParentController() != null) { + getParentController().getRouter().pushController( + (RouterTransaction.with(new ContactsController(bundle)) + .pushChangeHandler(new VerticalChangeHandler()) + .popChangeHandler(new VerticalChangeHandler()))); + } + return true; + default: + return super.onOptionsItemSelected(item); + } + } + @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { super.onCreateOptionsMenu(menu, inflater); - inflater.inflate(R.menu.menu_filter, menu); + + inflater.inflate(R.menu.menu_conversation_plus_filter, menu); + menuVariable = menu; searchItem = menu.findItem(R.id.action_search); initSearchView(); } @@ -312,7 +339,7 @@ public class CallsListController extends BaseController implements SearchView.On } private void prepareViews() { - LinearLayoutManager layoutManager = new SmoothScrollLinearLayoutManager(getActivity()); + layoutManager = new SmoothScrollLinearLayoutManager(getActivity()); recyclerView.setLayoutManager(layoutManager); recyclerView.setHasFixedSize(true); @@ -325,6 +352,16 @@ public class CallsListController extends BaseController implements SearchView.On swipeRefreshLayout.setOnRefreshListener(() -> fetchData(false)); swipeRefreshLayout.setColorSchemeResources(R.color.colorPrimary); + + fastScroller.addOnScrollStateChangeListener(this); + adapter.setFastScroller(fastScroller); + fastScroller.setBubbleTextCreator(position -> { + String displayName = adapter.getItem(position).getModel().getDisplayName(); + if(displayName.length() > 8) { + displayName = displayName.substring(0, 4) + "..."; + } + return displayName; + }); } private void dispose(@Nullable Disposable disposable) { @@ -427,8 +464,14 @@ public class CallsListController extends BaseController implements SearchView.On .pushChangeHandler(new HorizontalChangeHandler())); } - bottomSheet = new BottomSheet.Builder(getActivity()).setView(view).create(); - if (bottomSheet.getWindow() != null) { + boolean isNew = false; + + if (bottomSheet == null) { + bottomSheet = new BottomSheet.Builder(getActivity()).setView(view).create(); + isNew = true; + } + + if (bottomSheet.getWindow() != null && isNew) { bottomSheet.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE); } @@ -465,4 +508,9 @@ public class CallsListController extends BaseController implements SearchView.On protected String getTitle() { return getResources().getString(R.string.nc_app_name); } + + @Override + public void onFastScrollerStateChange(boolean scrolling) { + swipeRefreshLayout.setEnabled(!scrolling); + } } diff --git a/app/src/main/java/com/nextcloud/talk/controllers/ContactsController.java b/app/src/main/java/com/nextcloud/talk/controllers/ContactsController.java index 2a42f047e..200d3bcb7 100644 --- a/app/src/main/java/com/nextcloud/talk/controllers/ContactsController.java +++ b/app/src/main/java/com/nextcloud/talk/controllers/ContactsController.java @@ -31,12 +31,10 @@ import android.support.design.widget.BottomNavigationView; import android.support.v4.view.MenuItemCompat; import android.support.v4.widget.SwipeRefreshLayout; import android.support.v7.widget.DividerItemDecoration; -import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.support.v7.widget.SearchView; import android.text.InputType; import android.text.TextUtils; -import android.view.ActionMode; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; @@ -45,6 +43,8 @@ import android.view.View; import android.view.ViewGroup; import android.view.ViewTreeObserver; import android.view.inputmethod.EditorInfo; +import android.widget.Button; +import android.widget.LinearLayout; import com.bluelinelabs.conductor.RouterTransaction; import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler; @@ -52,6 +52,8 @@ import com.bluelinelabs.conductor.changehandler.VerticalChangeHandler; import com.bluelinelabs.conductor.internal.NoOpControllerChangeHandler; import com.nextcloud.talk.R; import com.nextcloud.talk.activities.CallActivity; +import com.nextcloud.talk.adapters.items.EmptyFooterItem; +import com.nextcloud.talk.adapters.items.UserHeaderItem; import com.nextcloud.talk.adapters.items.UserItem; import com.nextcloud.talk.api.NcApi; import com.nextcloud.talk.application.NextcloudTalkApplication; @@ -61,6 +63,7 @@ import com.nextcloud.talk.models.database.UserEntity; import com.nextcloud.talk.models.json.participants.Participant; import com.nextcloud.talk.models.json.rooms.RoomOverall; import com.nextcloud.talk.models.json.sharees.Sharee; +import com.nextcloud.talk.models.json.sharees.ShareesOverall; import com.nextcloud.talk.utils.ApiUtils; import com.nextcloud.talk.utils.bundle.BundleKeys; import com.nextcloud.talk.utils.database.user.UserUtils; @@ -69,6 +72,7 @@ import org.parceler.Parcels; import java.util.ArrayList; import java.util.Collections; +import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -77,9 +81,15 @@ import javax.inject.Inject; import autodagger.AutoInjector; import butterknife.BindView; +import butterknife.OnClick; +import butterknife.Optional; +import eu.davidea.fastscroller.FastScroller; import eu.davidea.flexibleadapter.FlexibleAdapter; import eu.davidea.flexibleadapter.SelectableAdapter; import eu.davidea.flexibleadapter.common.SmoothScrollLinearLayoutManager; +import eu.davidea.flexibleadapter.items.AbstractFlexibleItem; +import eu.davidea.flexibleadapter.items.IFlexible; +import eu.davidea.flipview.FlipView; import io.reactivex.Observer; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.disposables.Disposable; @@ -88,7 +98,7 @@ import retrofit2.HttpException; @AutoInjector(NextcloudTalkApplication.class) public class ContactsController extends BaseController implements SearchView.OnQueryTextListener, - ActionMode.Callback, FlexibleAdapter.OnItemClickListener { + FlexibleAdapter.OnItemClickListener, FastScroller.OnScrollStateChangeListener { public static final String TAG = "ContactsController"; @@ -105,33 +115,67 @@ public class ContactsController extends BaseController implements SearchView.OnQ @BindView(R.id.swipe_refresh_layout) SwipeRefreshLayout swipeRefreshLayout; + @Nullable + @BindView(R.id.bottom_buttons_layout) + LinearLayout bottomButtonsLinearLayout; + + @BindView(R.id.fast_scroller) + FastScroller fastScroller; + + @Nullable + @BindView(R.id.clear_button) + Button clearButton; + private UserEntity userEntity; private Disposable contactsQueryDisposable; private Disposable cacheQueryDisposable; - private FlexibleAdapter adapter; - private List contactItems = new ArrayList<>(); + private FlexibleAdapter adapter; + private List contactItems = new ArrayList<>(); + + private SmoothScrollLinearLayoutManager layoutManager; private MenuItem searchItem; private SearchView searchView; private String searchQuery; - private ActionMode actionMode; + private boolean isNewConversationView; + + private HashMap userHeaderItems = new HashMap(); public ContactsController() { super(); setHasOptionsMenu(true); } + public ContactsController(Bundle args) { + super(args); + setHasOptionsMenu(true); + if (args.containsKey(BundleKeys.KEY_NEW_CONVERSATION)) { + isNewConversationView = true; + } + } + @Override protected View inflateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup container) { return inflater.inflate(R.layout.controller_generic_rv, container, false); } + @Override + protected void onAttach(@NonNull View view) { + super.onAttach(view); + if (getActionBar() != null && isNewConversationView) { + getActionBar().setDisplayHomeAsUpEnabled(true); + } + } + @Override protected void onViewBound(@NonNull View view) { super.onViewBound(view); NextcloudTalkApplication.getSharedApplication().getComponentApplication().inject(this); + FlipView.resetLayoutAnimationDelay(true, 1000L); + FlipView.stopLayoutAnimation(); + userEntity = userUtils.getCurrentUser(); if (userEntity == null) { @@ -144,15 +188,47 @@ public class ContactsController extends BaseController implements SearchView.OnQ if (adapter == null) { adapter = new FlexibleAdapter<>(contactItems, getActivity(), false); + adapter.setNotifyChangeOfUnfilteredItems(true) + .setMode(SelectableAdapter.Mode.MULTI); + + if (userEntity != null) { fetchData(); } } + adapter.setStickyHeaderElevation(5) + .setUnlinkAllItemsOnRemoveHeaders(true) + .setDisplayHeadersAtStartUp(true) + .setStickyHeaders(true); + adapter.addListener(this); prepareViews(); } + @Optional + @OnClick(R.id.clear_button) + public void onClearButtonClick() { + if (adapter != null) { + List selectedPositions = adapter.getSelectedPositions(); + for (Integer position : selectedPositions) { + UserItem userItem = (UserItem) adapter.getItem(position); + adapter.toggleSelection(position); + if (userItem != null) { + userItem.flipItemSelection(); + } + } + } + + checkAndHandleBottomButtons(); + } + + @Optional + @OnClick(R.id.done_button) + public void onDoneButtonClick() { + + } + private void initSearchView() { if (getActivity() != null) { SearchManager searchManager = (SearchManager) getActivity().getSystemService(Context.SEARCH_SERVICE); @@ -172,10 +248,14 @@ public class ContactsController extends BaseController implements SearchView.OnQ final View mSearchEditFrame = searchView .findViewById(android.support.v7.appcompat.R.id.search_edit_frame); - BottomNavigationView bottomNavigationView = getParentController().getView().findViewById(R.id.navigation); + 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; @@ -186,10 +266,14 @@ public class ContactsController extends BaseController implements SearchView.OnQ if (currentVisibility != oldVisibility) { if (currentVisibility == View.VISIBLE) { - handler.postDelayed(() -> bottomNavigationView.setVisibility(View.GONE), 100); + if (finalBottomNavigationView != null) { + handler.postDelayed(() -> finalBottomNavigationView.setVisibility(View.GONE), 100); + } } else { handler.postDelayed(() -> { - bottomNavigationView.setVisibility(View.VISIBLE); + if (finalBottomNavigationView != null) { + finalBottomNavigationView.setVisibility(View.VISIBLE); + } searchItem.setVisible(contactItems.size() > 0); }, 500); } @@ -202,11 +286,23 @@ public class ContactsController extends BaseController implements SearchView.OnQ } + @Override + public boolean onOptionsItemSelected(@NonNull MenuItem item) { + switch (item.getItemId()) { + case android.R.id.home: + getRouter().popCurrentController(); + return true; + default: + return super.onOptionsItemSelected(item); + } + } + @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { super.onCreateOptionsMenu(menu, inflater); - inflater.inflate(R.menu.menu_filter, menu); + inflater.inflate(R.menu.menu_conversation_plus_filter, menu); searchItem = menu.findItem(R.id.action_search); + menu.findItem(R.id.action_new_conversation).setVisible(false); initSearchView(); } @@ -218,6 +314,7 @@ public class ContactsController extends BaseController implements SearchView.OnQ searchItem.expandActionView(); searchView.setQuery(adapter.getSearchText(), false); } + } private void fetchData() { @@ -226,6 +323,7 @@ public class ContactsController extends BaseController implements SearchView.OnQ Set shareeHashSet = new HashSet<>(); contactItems = new ArrayList<>(); + userHeaderItems = new HashMap<>(); RetrofitBucket retrofitBucket = ApiUtils.getRetrofitBucketForContactsSearch(userEntity.getBaseUrl(), ""); @@ -234,7 +332,7 @@ public class ContactsController extends BaseController implements SearchView.OnQ retrofitBucket.getUrl(), retrofitBucket.getQueryMap()) .subscribeOn(Schedulers.newThread()) .observeOn(AndroidSchedulers.mainThread()) - .subscribe(shareesOverall -> { + .subscribe((ShareesOverall shareesOverall) -> { if (shareesOverall != null) { if (shareesOverall.getOcs().getData().getUsers() != null) { @@ -252,18 +350,52 @@ public class ContactsController extends BaseController implements SearchView.OnQ if (!sharee.getValue().getShareWith().equals(userEntity.getUsername())) { participant = new Participant(); participant.setName(sharee.getLabel()); + String headerTitle; + + headerTitle = sharee.getLabel().substring(0, 1).toUpperCase(); + + UserHeaderItem userHeaderItem; + if (!userHeaderItems.containsKey(headerTitle)) { + userHeaderItem = new UserHeaderItem(headerTitle); + userHeaderItems.put(headerTitle, userHeaderItem); + } + participant.setUserId(sharee.getValue().getShareWith()); - contactItems.add(new UserItem(participant, userEntity)); + contactItems.add(new UserItem(participant, userEntity, + userHeaderItems.get(headerTitle))); } } - Collections.sort(contactItems, (userItem, t1) -> - userItem.getModel().getName().compareToIgnoreCase(t1.getModel().getName())); + + userHeaderItems = new HashMap<>(); + + Collections.sort(contactItems, (o1, o2) -> { + String firstName; + String secondName; + + if (o1 instanceof UserItem) { + firstName = ((UserItem) o1).getModel().getName(); + } else { + firstName = ((UserHeaderItem) o1).getModel(); + } + + if (o2 instanceof UserItem) { + secondName = ((UserItem) o2).getModel().getName(); + } else { + secondName = ((UserHeaderItem) o2).getModel(); + } + + return firstName.compareToIgnoreCase(secondName); + }); adapter.updateDataSet(contactItems, true); searchItem.setVisible(contactItems.size() > 0); swipeRefreshLayout.setRefreshing(false); + + if (isNewConversationView) { + checkAndHandleBottomButtons(); + } } }, throwable -> { @@ -299,7 +431,7 @@ public class ContactsController extends BaseController implements SearchView.OnQ } private void prepareViews() { - LinearLayoutManager layoutManager = new SmoothScrollLinearLayoutManager(getActivity()); + layoutManager = new SmoothScrollLinearLayoutManager(getActivity()); recyclerView.setLayoutManager(layoutManager); recyclerView.setHasFixedSize(true); recyclerView.setAdapter(adapter); @@ -311,6 +443,17 @@ public class ContactsController extends BaseController implements SearchView.OnQ swipeRefreshLayout.setOnRefreshListener(this::fetchData); swipeRefreshLayout.setColorSchemeResources(R.color.colorPrimary); + + fastScroller.addOnScrollStateChangeListener(this); + adapter.setFastScroller(fastScroller); + fastScroller.setBubbleTextCreator(position -> { + IFlexible abstractFlexibleItem = adapter.getItem(position); + if (abstractFlexibleItem instanceof UserItem) { + return ((UserItem)adapter.getItem(position)).getHeader().getModel(); + } else { + return ((UserHeaderItem)adapter.getItem(position)).getModel(); + } + }); } private void dispose(@Nullable Disposable disposable) { @@ -330,8 +473,10 @@ public class ContactsController extends BaseController implements SearchView.OnQ } } + @Override public void onSaveViewState(@NonNull View view, @NonNull Bundle outState) { + adapter.onSaveInstanceState(outState); super.onSaveViewState(view, outState); if (searchView != null && !TextUtils.isEmpty(searchView.getQuery())) { outState.putString(KEY_SEARCH_QUERY, searchView.getQuery().toString()); @@ -342,6 +487,9 @@ public class ContactsController extends BaseController implements SearchView.OnQ public void onRestoreViewState(@NonNull View view, @NonNull Bundle savedViewState) { super.onRestoreViewState(view, savedViewState); searchQuery = savedViewState.getString(KEY_SEARCH_QUERY, ""); + if (adapter != null) { + adapter.onRestoreInstanceState(savedViewState); + } } @Override @@ -377,110 +525,90 @@ public class ContactsController extends BaseController implements SearchView.OnQ } @Override - public boolean onCreateActionMode(ActionMode actionMode, Menu menu) { - adapter.setMode(SelectableAdapter.Mode.MULTI); + public boolean onItemClick(int position) { + if (adapter.getItem(position) instanceof UserItem) { + if (!isNewConversationView) { + UserItem userItem = (UserItem) adapter.getItem(position); + RetrofitBucket retrofitBucket = ApiUtils.getRetrofitBucketForCreateRoom(userEntity.getBaseUrl(), "1", + userItem.getModel().getUserId()); + ncApi.createRoom(ApiUtils.getCredentials(userEntity.getUsername(), userEntity.getToken()), + retrofitBucket.getUrl(), retrofitBucket.getQueryMap()) + .subscribeOn(Schedulers.newThread()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(new Observer() { + @Override + public void onSubscribe(Disposable d) { + + } + + @Override + public void onNext(RoomOverall roomOverall) { + overridePushHandler(new NoOpControllerChangeHandler()); + overridePopHandler(new NoOpControllerChangeHandler()); + Intent callIntent = new Intent(getActivity(), CallActivity.class); + Bundle bundle = new Bundle(); + bundle.putString(BundleKeys.KEY_ROOM_TOKEN, roomOverall.getOcs().getData().getToken()); + bundle.putParcelable(BundleKeys.KEY_USER_ENTITY, Parcels.wrap(userEntity)); + callIntent.putExtras(bundle); + startActivity(callIntent); + } + + @Override + public void onError(Throwable e) { + + } + + @Override + public void onComplete() { + + } + }); + } else { + ((UserItem) adapter.getItem(position)).flipItemSelection(); + adapter.toggleSelection(position); + + checkAndHandleBottomButtons(); + } + } return true; } - @Override - public boolean onPrepareActionMode(ActionMode actionMode, Menu menu) { - return false; - } + private void checkAndHandleBottomButtons() { + if (adapter != null && bottomButtonsLinearLayout != null && clearButton != null) { + if (adapter.getSelectedItemCount() > 0) { + if (bottomButtonsLinearLayout.getVisibility() != View.VISIBLE) { + bottomButtonsLinearLayout.setVisibility(View.VISIBLE); + } + } else { + bottomButtonsLinearLayout.setVisibility(View.GONE); + } + } else if (bottomButtonsLinearLayout != null) { + bottomButtonsLinearLayout.setVisibility(View.GONE); + } - @Override - public boolean onActionItemClicked(ActionMode actionMode, MenuItem menuItem) { - return false; - } - - @Override - public void onDestroyActionMode(ActionMode actionMode) { - adapter.setMode(SelectableAdapter.Mode.IDLE); - actionMode = null; - } - - /*@Override - public boolean onItemClick(int position) { - if (actionMode != null && position != RecyclerView.NO_POSITION) { - // Mark the position selected - toggleSelection(position); - return true; + if (bottomButtonsLinearLayout != null && bottomButtonsLinearLayout.getVisibility() == View.VISIBLE) { + if (adapter.getScrollableFooters().size() == 0) { + adapter.addScrollableFooterWithDelay(new EmptyFooterItem(999), 0, layoutManager + .findLastVisibleItemPosition() == adapter.getItemCount() - 1); + } } else { - // Handle the item click listener - // We don't need to activate anything - return false; + if (adapter != null) { + adapter.removeAllScrollableFooters(); + } } - }*/ - - private void toggleSelection(int position) { - adapter.toggleSelection(position); - - int count = adapter.getSelectedItemCount(); - - if (count == 0) { - actionMode.finish(); - } else { - //setContextTitle(count); - } - } - - @Override - public void onSaveInstanceState(@NonNull Bundle outState) { - adapter.onSaveInstanceState(outState); - super.onSaveInstanceState(outState); - } - - @Override - protected void onRestoreInstanceState(@NonNull Bundle savedInstanceState) { - super.onRestoreInstanceState(savedInstanceState); - if (adapter != null) { - adapter.onRestoreInstanceState(savedInstanceState); - } - } - - @Override - public boolean onItemClick(int position) { - UserItem userItem = adapter.getItem(position); - RetrofitBucket retrofitBucket = ApiUtils.getRetrofitBucketForCreateRoom(userEntity.getBaseUrl(), "1", - userItem.getModel().getUserId()); - ncApi.createRoom(ApiUtils.getCredentials(userEntity.getUsername(), userEntity.getToken()), - retrofitBucket.getUrl(), retrofitBucket.getQueryMap()) - .subscribeOn(Schedulers.newThread()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(new Observer() { - @Override - public void onSubscribe(Disposable d) { - - } - - @Override - public void onNext(RoomOverall roomOverall) { - overridePushHandler(new NoOpControllerChangeHandler()); - overridePopHandler(new NoOpControllerChangeHandler()); - Intent callIntent = new Intent(getActivity(), CallActivity.class); - Bundle bundle = new Bundle(); - bundle.putString(BundleKeys.KEY_ROOM_TOKEN, roomOverall.getOcs().getData().getToken()); - bundle.putParcelable(BundleKeys.KEY_USER_ENTITY, Parcels.wrap(userEntity)); - callIntent.putExtras(bundle); - startActivity(callIntent); - } - - @Override - public void onError(Throwable e) { - - } - - @Override - public void onComplete() { - - } - }); - - return true; } @Override protected String getTitle() { - return getResources().getString(R.string.nc_app_name); + if (!isNewConversationView) { + return getResources().getString(R.string.nc_app_name); + } else { + return getResources().getString(R.string.nc_select_contacts); + } } + @Override + public void onFastScrollerStateChange(boolean scrolling) { + swipeRefreshLayout.setEnabled(!scrolling); + } } diff --git a/app/src/main/java/com/nextcloud/talk/controllers/ServerSelectionController.java b/app/src/main/java/com/nextcloud/talk/controllers/ServerSelectionController.java index e5a058b5e..e0129da33 100644 --- a/app/src/main/java/com/nextcloud/talk/controllers/ServerSelectionController.java +++ b/app/src/main/java/com/nextcloud/talk/controllers/ServerSelectionController.java @@ -39,10 +39,10 @@ import com.bluelinelabs.conductor.RouterTransaction; import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler; import com.nextcloud.talk.R; import com.nextcloud.talk.api.NcApi; -import com.nextcloud.talk.utils.ApiUtils; import com.nextcloud.talk.application.NextcloudTalkApplication; import com.nextcloud.talk.controllers.base.BaseController; import com.nextcloud.talk.utils.AccountUtils; +import com.nextcloud.talk.utils.ApiUtils; import com.nextcloud.talk.utils.ApplicationWideMessageHolder; import com.nextcloud.talk.utils.bundle.BundleKeys; import com.nextcloud.talk.utils.database.user.UserUtils; diff --git a/app/src/main/java/com/nextcloud/talk/controllers/SwitchAccountController.java b/app/src/main/java/com/nextcloud/talk/controllers/SwitchAccountController.java index 843b57619..a7912e8a1 100644 --- a/app/src/main/java/com/nextcloud/talk/controllers/SwitchAccountController.java +++ b/app/src/main/java/com/nextcloud/talk/controllers/SwitchAccountController.java @@ -31,6 +31,7 @@ import android.support.v7.widget.DividerItemDecoration; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; +import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; @@ -129,16 +130,29 @@ public class SwitchAccountController extends BaseController { }; public SwitchAccountController() { + setHasOptionsMenu(true); } public SwitchAccountController(Bundle args) { super(args); + setHasOptionsMenu(true); if (args.containsKey(BundleKeys.KEY_IS_ACCOUNT_IMPORT)) { isAccountImport = true; } } + @Override + public boolean onOptionsItemSelected(@NonNull MenuItem item) { + switch (item.getItemId()) { + case android.R.id.home: + getRouter().popCurrentController(); + return true; + default: + return super.onOptionsItemSelected(item); + } + } + @Override protected View inflateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup container) { return inflater.inflate(R.layout.controller_generic_rv, container, false); @@ -204,6 +218,14 @@ 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()); recyclerView.setLayoutManager(layoutManager); diff --git a/app/src/main/java/com/nextcloud/talk/controllers/base/BaseController.java b/app/src/main/java/com/nextcloud/talk/controllers/base/BaseController.java index ff2b476e2..2ad8e6758 100644 --- a/app/src/main/java/com/nextcloud/talk/controllers/base/BaseController.java +++ b/app/src/main/java/com/nextcloud/talk/controllers/base/BaseController.java @@ -53,6 +53,7 @@ public abstract class BaseController extends RefWatchingController { @Override protected void onAttach(@NonNull View view) { setTitle(); + getActionBar().setDisplayHomeAsUpEnabled(false); super.onAttach(view); } diff --git a/app/src/main/java/com/nextcloud/talk/controllers/bottomsheet/CallMenuController.java b/app/src/main/java/com/nextcloud/talk/controllers/bottomsheet/CallMenuController.java index e99ac1c8c..d0fe90c8d 100644 --- a/app/src/main/java/com/nextcloud/talk/controllers/bottomsheet/CallMenuController.java +++ b/app/src/main/java/com/nextcloud/talk/controllers/bottomsheet/CallMenuController.java @@ -36,10 +36,10 @@ import com.kennyc.bottomsheet.adapters.AppAdapter; import com.nextcloud.talk.R; import com.nextcloud.talk.adapters.items.AppItem; import com.nextcloud.talk.adapters.items.MenuItem; -import com.nextcloud.talk.models.json.rooms.Room; import com.nextcloud.talk.application.NextcloudTalkApplication; import com.nextcloud.talk.controllers.base.BaseController; import com.nextcloud.talk.events.BottomSheetLockEvent; +import com.nextcloud.talk.models.json.rooms.Room; import com.nextcloud.talk.utils.ShareUtils; import com.nextcloud.talk.utils.bundle.BundleKeys; import com.nextcloud.talk.utils.database.user.UserUtils; diff --git a/app/src/main/java/com/nextcloud/talk/dagger/modules/RestModule.java b/app/src/main/java/com/nextcloud/talk/dagger/modules/RestModule.java index 4602d7f79..624a864f2 100644 --- a/app/src/main/java/com/nextcloud/talk/dagger/modules/RestModule.java +++ b/app/src/main/java/com/nextcloud/talk/dagger/modules/RestModule.java @@ -28,8 +28,8 @@ import android.util.Log; import com.github.aurae.retrofit2.LoganSquareConverterFactory; import com.nextcloud.talk.BuildConfig; import com.nextcloud.talk.api.NcApi; -import com.nextcloud.talk.utils.ApiUtils; import com.nextcloud.talk.application.NextcloudTalkApplication; +import com.nextcloud.talk.utils.ApiUtils; import com.nextcloud.talk.utils.preferences.AppPreferences; import com.nextcloud.talk.utils.ssl.MagicTrustManager; import com.nextcloud.talk.utils.ssl.SSLSocketFactoryCompat; diff --git a/app/src/main/java/com/nextcloud/talk/services/firebase/MagicFirebaseMessagingService.java b/app/src/main/java/com/nextcloud/talk/services/firebase/MagicFirebaseMessagingService.java index 02fe573b8..60c4391a0 100644 --- a/app/src/main/java/com/nextcloud/talk/services/firebase/MagicFirebaseMessagingService.java +++ b/app/src/main/java/com/nextcloud/talk/services/firebase/MagicFirebaseMessagingService.java @@ -40,9 +40,9 @@ import com.google.firebase.messaging.FirebaseMessagingService; import com.google.firebase.messaging.RemoteMessage; import com.nextcloud.talk.R; import com.nextcloud.talk.activities.CallActivity; +import com.nextcloud.talk.models.SignatureVerification; import com.nextcloud.talk.models.json.push.DecryptedPushMessage; import com.nextcloud.talk.models.json.push.PushMessage; -import com.nextcloud.talk.models.SignatureVerification; import com.nextcloud.talk.utils.NotificationUtils; import com.nextcloud.talk.utils.PushUtils; import com.nextcloud.talk.utils.bundle.BundleKeys; diff --git a/app/src/main/java/com/nextcloud/talk/utils/MagicFlipView.java b/app/src/main/java/com/nextcloud/talk/utils/MagicFlipView.java new file mode 100644 index 000000000..547c924d5 --- /dev/null +++ b/app/src/main/java/com/nextcloud/talk/utils/MagicFlipView.java @@ -0,0 +1,45 @@ +/* + * Nextcloud Talk application + * + * @author Mario Danic + * Copyright (C) 2017-2018 Mario Danic + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.nextcloud.talk.utils; + +import android.content.Context; +import android.util.AttributeSet; + +import eu.davidea.flipview.FlipView; + +public class MagicFlipView extends FlipView { + public MagicFlipView(Context context) { + super(context); + } + + public MagicFlipView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + @Override + protected void onDetachedFromWindow() { + try { + super.onDetachedFromWindow(); + } catch (IllegalArgumentException e) { + stopFlipping(); + } + } +} diff --git a/app/src/main/java/com/nextcloud/talk/utils/bundle/BundleKeys.java b/app/src/main/java/com/nextcloud/talk/utils/bundle/BundleKeys.java index d52d41f9e..0b3a619b6 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/bundle/BundleKeys.java +++ b/app/src/main/java/com/nextcloud/talk/utils/bundle/BundleKeys.java @@ -36,4 +36,5 @@ public class BundleKeys { public static final String KEY_CALL_SESSION = "KEY_CALL_SESSION"; public static final String KEY_ROOM_TOKEN = "KEY_ROOM_TOKEN"; public static final String KEY_USER_ENTITY = "KEY_USER_ENTITY"; + public static final String KEY_NEW_CONVERSATION = "KEY_NEW_CONVERSATION"; } diff --git a/app/src/main/java/com/nextcloud/talk/webrtc/MagicPeerConnectionWrapper.java b/app/src/main/java/com/nextcloud/talk/webrtc/MagicPeerConnectionWrapper.java index af602709e..d9c11fe18 100644 --- a/app/src/main/java/com/nextcloud/talk/webrtc/MagicPeerConnectionWrapper.java +++ b/app/src/main/java/com/nextcloud/talk/webrtc/MagicPeerConnectionWrapper.java @@ -26,12 +26,12 @@ import android.util.Log; import com.bluelinelabs.logansquare.LoganSquare; import com.nextcloud.talk.R; -import com.nextcloud.talk.models.json.signaling.DataChannelMessage; -import com.nextcloud.talk.models.json.signaling.NCIceCandidate; import com.nextcloud.talk.application.NextcloudTalkApplication; import com.nextcloud.talk.events.MediaStreamEvent; import com.nextcloud.talk.events.PeerConnectionEvent; import com.nextcloud.talk.events.SessionDescriptionSendEvent; +import com.nextcloud.talk.models.json.signaling.DataChannelMessage; +import com.nextcloud.talk.models.json.signaling.NCIceCandidate; import org.greenrobot.eventbus.EventBus; import org.webrtc.DataChannel; diff --git a/app/src/main/java/com/nextcloud/talk/webrtc/MagicWebRTCUtils.java b/app/src/main/java/com/nextcloud/talk/webrtc/MagicWebRTCUtils.java index 578f2c648..17f0514e9 100644 --- a/app/src/main/java/com/nextcloud/talk/webrtc/MagicWebRTCUtils.java +++ b/app/src/main/java/com/nextcloud/talk/webrtc/MagicWebRTCUtils.java @@ -17,7 +17,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * - * Original code: + * Part of the code related to codec handling is originally: * * * Copyright 2016 The WebRTC Project Authors. All rights reserved. diff --git a/app/src/main/res/drawable/ic_add_white_24px.xml b/app/src/main/res/drawable/ic_add_white_24px.xml new file mode 100644 index 000000000..a2c0bf1e4 --- /dev/null +++ b/app/src/main/res/drawable/ic_add_white_24px.xml @@ -0,0 +1,25 @@ + + + + + diff --git a/app/src/main/res/layout/bottom_buttons.xml b/app/src/main/res/layout/bottom_buttons.xml new file mode 100644 index 000000000..ef8d60e0d --- /dev/null +++ b/app/src/main/res/layout/bottom_buttons.xml @@ -0,0 +1,52 @@ + + + + + +