Bunch of work on new conversation

Signed-off-by: Mario Danic <mario@lovelyhq.com>
This commit is contained in:
Mario Danic 2018-02-02 11:40:42 +01:00
parent 9f11964fc5
commit 20b80b36b3
33 changed files with 860 additions and 179 deletions

View File

@ -111,7 +111,7 @@ dependencies {
debugImplementation "javax.transaction:transaction-api:1.1-rev-1" 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:5.0.0-rc4'
implementation 'eu.davidea:flexible-adapter-ui:1.0.0-b1' 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 group: 'org.apache.commons', name: 'commons-lang3', version: '3.7'
implementation 'com.github.Kennyc1012:BottomSheet:2.4.0' implementation 'com.github.Kennyc1012:BottomSheet:2.4.0'
implementation 'eu.davidea:flipview:1.1.3'
testImplementation 'junit:junit:4.12' testImplementation 'junit:junit:4.12'
androidTestImplementation ('com.android.support.test.espresso:espresso-core:3.0.1', { androidTestImplementation ('com.android.support.test.espresso:espresso-core:3.0.1', {
exclude group: 'com.android.support', module: 'support-annotations' exclude group: 'com.android.support', module: 'support-annotations'

View File

@ -51,6 +51,7 @@ import eu.davidea.flexibleadapter.FlexibleAdapter;
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem; import eu.davidea.flexibleadapter.items.AbstractFlexibleItem;
import eu.davidea.flexibleadapter.items.IFilterable; import eu.davidea.flexibleadapter.items.IFilterable;
import eu.davidea.flexibleadapter.utils.FlexibleUtils; import eu.davidea.flexibleadapter.utils.FlexibleUtils;
import eu.davidea.flipview.FlipView;
import eu.davidea.viewholders.FlexibleViewHolder; import eu.davidea.viewholders.FlexibleViewHolder;
public class AdvancedUserItem extends AbstractFlexibleItem<AdvancedUserItem.UserItemViewHolder> implements IFilterable { public class AdvancedUserItem extends AbstractFlexibleItem<AdvancedUserItem.UserItemViewHolder> implements IFilterable {
@ -119,24 +120,23 @@ public class AdvancedUserItem extends AbstractFlexibleItem<AdvancedUserItem.User
if (userEntity.getBaseUrl().startsWith("http://") || userEntity.getBaseUrl().startsWith("https://")) { if (userEntity.getBaseUrl().startsWith("http://") || userEntity.getBaseUrl().startsWith("https://")) {
holder.avatarImageView.setVisibility(View.VISIBLE); holder.avatarImageView.setVisibility(View.VISIBLE);
RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) holder.linearLayout.getLayoutParams();
layoutParams.setMarginStart(0);
layoutParams.removeRule(RelativeLayout.ALIGN_PARENT_START);
holder.linearLayout.setLayoutParams(layoutParams);
GlideUrl glideUrl = new GlideUrl(ApiUtils.getUrlForAvatarWithName(userEntity.getBaseUrl(), GlideUrl glideUrl = new GlideUrl(ApiUtils.getUrlForAvatarWithName(userEntity.getBaseUrl(),
participant.getUserId(), false), new LazyHeaders.Builder() participant.getUserId(), false), new LazyHeaders.Builder()
.setHeader("Accept", "image/*") .setHeader("Accept", "image/*")
.setHeader("User-Agent", ApiUtils.getUserAgent()) .setHeader("User-Agent", ApiUtils.getUserAgent())
.build()); .build());
int avatarSize = Math.round(NextcloudTalkApplication
.getSharedApplication().getResources().getDimension(R.dimen.avatar_size));
GlideApp.with(NextcloudTalkApplication.getSharedApplication().getApplicationContext()) GlideApp.with(NextcloudTalkApplication.getSharedApplication().getApplicationContext())
.asBitmap() .asBitmap()
.skipMemoryCache(true)
.diskCacheStrategy(DiskCacheStrategy.NONE) .diskCacheStrategy(DiskCacheStrategy.NONE)
.load(glideUrl) .load(glideUrl)
.centerInside() .centerInside()
.override(avatarSize, avatarSize)
.apply(RequestOptions.bitmapTransform(new CircleCrop())) .apply(RequestOptions.bitmapTransform(new CircleCrop()))
.into(holder.avatarImageView); .into(holder.avatarImageView.getFrontImageView());
} else { } else {
holder.avatarImageView.setVisibility(View.GONE); holder.avatarImageView.setVisibility(View.GONE);
RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) holder.linearLayout.getLayoutParams(); RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) holder.linearLayout.getLayoutParams();
@ -161,11 +161,13 @@ public class AdvancedUserItem extends AbstractFlexibleItem<AdvancedUserItem.User
@BindView(R.id.secondary_text) @BindView(R.id.secondary_text)
public TextView serverUrl; public TextView serverUrl;
@BindView(R.id.avatar_image) @BindView(R.id.avatar_image)
public ImageView avatarImageView; public FlipView avatarImageView;
@BindView(R.id.linear_layout) @BindView(R.id.linear_layout)
LinearLayout linearLayout; LinearLayout linearLayout;
@BindView(R.id.more_menu) @BindView(R.id.more_menu)
ImageButton moreMenuButton; ImageButton moreMenuButton;
@BindView(R.id.password_protected_image_view)
ImageView passwordProtectedImageView;
/** /**
* Default constructor. * Default constructor.
@ -174,8 +176,7 @@ public class AdvancedUserItem extends AbstractFlexibleItem<AdvancedUserItem.User
super(view, adapter); super(view, adapter);
ButterKnife.bind(this, view); ButterKnife.bind(this, view);
moreMenuButton.setVisibility(View.GONE); moreMenuButton.setVisibility(View.GONE);
passwordProtectedImageView.setVisibility(View.GONE);
} }
} }
} }

View File

@ -51,6 +51,7 @@ import eu.davidea.flexibleadapter.FlexibleAdapter;
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem; import eu.davidea.flexibleadapter.items.AbstractFlexibleItem;
import eu.davidea.flexibleadapter.items.IFilterable; import eu.davidea.flexibleadapter.items.IFilterable;
import eu.davidea.flexibleadapter.utils.FlexibleUtils; import eu.davidea.flexibleadapter.utils.FlexibleUtils;
import eu.davidea.flipview.FlipView;
import eu.davidea.viewholders.FlexibleViewHolder; import eu.davidea.viewholders.FlexibleViewHolder;
public class CallItem extends AbstractFlexibleItem<CallItem.RoomItemViewHolder> implements IFilterable { public class CallItem extends AbstractFlexibleItem<CallItem.RoomItemViewHolder> implements IFilterable {
@ -120,6 +121,9 @@ public class CallItem extends AbstractFlexibleItem<CallItem.RoomItemViewHolder>
holder.passwordProtectedImageView.setVisibility(View.GONE); holder.passwordProtectedImageView.setVisibility(View.GONE);
} }
int avatarSize = Math.round(NextcloudTalkApplication
.getSharedApplication().getResources().getDimension(R.dimen.avatar_size));
switch (room.getType()) { switch (room.getType()) {
case ROOM_TYPE_ONE_TO_ONE_CALL: case ROOM_TYPE_ONE_TO_ONE_CALL:
holder.avatarImageView.setVisibility(View.VISIBLE); holder.avatarImageView.setVisibility(View.VISIBLE);
@ -133,12 +137,12 @@ public class CallItem extends AbstractFlexibleItem<CallItem.RoomItemViewHolder>
GlideApp.with(NextcloudTalkApplication.getSharedApplication().getApplicationContext()) GlideApp.with(NextcloudTalkApplication.getSharedApplication().getApplicationContext())
.asBitmap() .asBitmap()
.skipMemoryCache(true)
.diskCacheStrategy(DiskCacheStrategy.NONE) .diskCacheStrategy(DiskCacheStrategy.NONE)
.load(glideUrl) .load(glideUrl)
.centerInside() .centerInside()
.override(avatarSize, avatarSize)
.apply(RequestOptions.bitmapTransform(new CircleCrop())) .apply(RequestOptions.bitmapTransform(new CircleCrop()))
.into(holder.avatarImageView); .into(holder.avatarImageView.getFrontImageView());
} else { } else {
holder.avatarImageView.setVisibility(View.GONE); holder.avatarImageView.setVisibility(View.GONE);
@ -147,23 +151,23 @@ public class CallItem extends AbstractFlexibleItem<CallItem.RoomItemViewHolder>
case ROOM_GROUP_CALL: case ROOM_GROUP_CALL:
GlideApp.with(NextcloudTalkApplication.getSharedApplication().getApplicationContext()) GlideApp.with(NextcloudTalkApplication.getSharedApplication().getApplicationContext())
.asBitmap() .asBitmap()
.skipMemoryCache(true)
.diskCacheStrategy(DiskCacheStrategy.NONE) .diskCacheStrategy(DiskCacheStrategy.NONE)
.load(R.drawable.ic_group_white_24px) .load(R.drawable.ic_group_white_24px)
.centerInside() .centerInside()
.override(avatarSize, avatarSize)
.apply(RequestOptions.bitmapTransform(new CircleCrop())) .apply(RequestOptions.bitmapTransform(new CircleCrop()))
.into(holder.avatarImageView); .into(holder.avatarImageView.getFrontImageView());
holder.avatarImageView.setVisibility(View.VISIBLE); holder.avatarImageView.setVisibility(View.VISIBLE);
break; break;
case ROOM_PUBLIC_CALL: case ROOM_PUBLIC_CALL:
GlideApp.with(NextcloudTalkApplication.getSharedApplication().getApplicationContext()) GlideApp.with(NextcloudTalkApplication.getSharedApplication().getApplicationContext())
.asBitmap() .asBitmap()
.skipMemoryCache(true)
.diskCacheStrategy(DiskCacheStrategy.NONE) .diskCacheStrategy(DiskCacheStrategy.NONE)
.load(R.drawable.ic_link_white_24px) .load(R.drawable.ic_link_white_24px)
.centerInside() .centerInside()
.override(avatarSize, avatarSize)
.apply(RequestOptions.bitmapTransform(new CircleCrop())) .apply(RequestOptions.bitmapTransform(new CircleCrop()))
.into(holder.avatarImageView); .into(holder.avatarImageView.getFrontImageView());
holder.avatarImageView.setVisibility(View.VISIBLE); holder.avatarImageView.setVisibility(View.VISIBLE);
break; break;
default: default:
@ -188,7 +192,7 @@ public class CallItem extends AbstractFlexibleItem<CallItem.RoomItemViewHolder>
@BindView(R.id.secondary_text) @BindView(R.id.secondary_text)
public TextView roomLastPing; public TextView roomLastPing;
@BindView(R.id.avatar_image) @BindView(R.id.avatar_image)
public ImageView avatarImageView; public FlipView avatarImageView;
@BindView(R.id.more_menu) @BindView(R.id.more_menu)
public ImageButton moreMenuButton; public ImageButton moreMenuButton;
@BindView(R.id.password_protected_image_view) @BindView(R.id.password_protected_image_view)

View File

@ -0,0 +1,78 @@
/*
* 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/>.
*/
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<EmptyFooterItem.EmptyFooterItemViewHolder> {
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<Object> payloads) {
}
static class EmptyFooterItemViewHolder extends FlexibleViewHolder {
/**
* Default constructor.
*/
EmptyFooterItemViewHolder(View view, FlexibleAdapter adapter) {
super(view, adapter);
}
}
}

View File

@ -0,0 +1,103 @@
/*
* 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/>.
*/
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<UserHeaderItem.HeaderViewHolder> 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<Object> 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);
}
}
}

View File

@ -21,7 +21,6 @@
package com.nextcloud.talk.adapters.items; package com.nextcloud.talk.adapters.items;
import android.view.View; import android.view.View;
import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import com.bumptech.glide.load.engine.DiskCacheStrategy; import com.bumptech.glide.load.engine.DiskCacheStrategy;
@ -45,17 +44,25 @@ import butterknife.ButterKnife;
import eu.davidea.flexibleadapter.FlexibleAdapter; import eu.davidea.flexibleadapter.FlexibleAdapter;
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem; import eu.davidea.flexibleadapter.items.AbstractFlexibleItem;
import eu.davidea.flexibleadapter.items.IFilterable; import eu.davidea.flexibleadapter.items.IFilterable;
import eu.davidea.flexibleadapter.items.ISectionable;
import eu.davidea.flexibleadapter.utils.FlexibleUtils; import eu.davidea.flexibleadapter.utils.FlexibleUtils;
import eu.davidea.flipview.FlipView;
import eu.davidea.viewholders.FlexibleViewHolder; import eu.davidea.viewholders.FlexibleViewHolder;
public class UserItem extends AbstractFlexibleItem<UserItem.UserItemViewHolder> implements IFilterable { public class UserItem extends AbstractFlexibleItem<UserItem.UserItemViewHolder> implements
ISectionable<UserItem.UserItemViewHolder, UserHeaderItem>, IFilterable {
private Participant participant; private Participant participant;
private UserEntity userEntity; 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.participant = participant;
this.userEntity = userEntity; this.userEntity = userEntity;
this.header = userHeaderItem;
} }
@Override @Override
@ -84,6 +91,10 @@ public class UserItem extends AbstractFlexibleItem<UserItem.UserItemViewHolder>
return userEntity; return userEntity;
} }
public void flipItemSelection() {
flipView.flip(!flipView.isFlipped());
}
@Override @Override
public int getLayoutRes() { public int getLayoutRes() {
return R.layout.rv_item_contact; return R.layout.rv_item_contact;
@ -96,6 +107,9 @@ public class UserItem extends AbstractFlexibleItem<UserItem.UserItemViewHolder>
@Override @Override
public void bindViewHolder(FlexibleAdapter adapter, UserItemViewHolder holder, int position, List payloads) { public void bindViewHolder(FlexibleAdapter adapter, UserItemViewHolder holder, int position, List payloads) {
flipView = holder.avatarFlipView;
if (adapter.hasSearchText()) { if (adapter.hasSearchText()) {
FlexibleUtils.highlightText(holder.contactDisplayName, participant.getName(), adapter.getSearchText()); FlexibleUtils.highlightText(holder.contactDisplayName, participant.getName(), adapter.getSearchText());
} else { } else {
@ -108,14 +122,17 @@ public class UserItem extends AbstractFlexibleItem<UserItem.UserItemViewHolder>
.setHeader("User-Agent", ApiUtils.getUserAgent()) .setHeader("User-Agent", ApiUtils.getUserAgent())
.build()); .build());
int avatarSize = Math.round(NextcloudTalkApplication
.getSharedApplication().getResources().getDimension(R.dimen.avatar_size));
GlideApp.with(NextcloudTalkApplication.getSharedApplication().getApplicationContext()) GlideApp.with(NextcloudTalkApplication.getSharedApplication().getApplicationContext())
.asBitmap() .asBitmap()
.skipMemoryCache(true)
.diskCacheStrategy(DiskCacheStrategy.NONE) .diskCacheStrategy(DiskCacheStrategy.NONE)
.load(glideUrl) .load(glideUrl)
.centerInside() .centerInside()
.override(avatarSize, avatarSize)
.apply(RequestOptions.bitmapTransform(new CircleCrop())) .apply(RequestOptions.bitmapTransform(new CircleCrop()))
.into(holder.avatarImageView); .into(holder.avatarFlipView.getFrontImageView());
} }
@Override @Override
@ -124,13 +141,23 @@ public class UserItem extends AbstractFlexibleItem<UserItem.UserItemViewHolder>
StringUtils.containsIgnoreCase(participant.getName().trim(), constraint); 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 { static class UserItemViewHolder extends FlexibleViewHolder {
@BindView(R.id.name_text) @BindView(R.id.name_text)
public TextView contactDisplayName; public TextView contactDisplayName;
@BindView(R.id.avatar_image) @BindView(R.id.avatar_flip_view)
public ImageView avatarImageView; public FlipView avatarFlipView;
/** /**
* Default constructor. * Default constructor.

View File

@ -117,7 +117,6 @@ public class NextcloudTalkApplication extends MultiDexApplication {
initializeWebRtc(); initializeWebRtc();
DisplayUtils.useCompatVectorIfNeeded(); DisplayUtils.useCompatVectorIfNeeded();
try { try {
buildComponent(); buildComponent();
} catch (final GeneralSecurityException exception) { } catch (final GeneralSecurityException exception) {

View File

@ -36,10 +36,10 @@ import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler;
import com.evernote.android.job.JobRequest; import com.evernote.android.job.JobRequest;
import com.nextcloud.talk.R; import com.nextcloud.talk.R;
import com.nextcloud.talk.api.NcApi; import com.nextcloud.talk.api.NcApi;
import com.nextcloud.talk.utils.ApiUtils;
import com.nextcloud.talk.application.NextcloudTalkApplication; import com.nextcloud.talk.application.NextcloudTalkApplication;
import com.nextcloud.talk.controllers.base.BaseController; import com.nextcloud.talk.controllers.base.BaseController;
import com.nextcloud.talk.jobs.PushRegistrationJob; import com.nextcloud.talk.jobs.PushRegistrationJob;
import com.nextcloud.talk.utils.ApiUtils;
import com.nextcloud.talk.utils.ApplicationWideMessageHolder; import com.nextcloud.talk.utils.ApplicationWideMessageHolder;
import com.nextcloud.talk.utils.bundle.BundleKeys; import com.nextcloud.talk.utils.bundle.BundleKeys;
import com.nextcloud.talk.utils.database.user.UserUtils; import com.nextcloud.talk.utils.database.user.UserUtils;

View File

@ -31,7 +31,6 @@ import android.support.design.widget.BottomNavigationView;
import android.support.v4.view.MenuItemCompat; import android.support.v4.view.MenuItemCompat;
import android.support.v4.widget.SwipeRefreshLayout; import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.widget.DividerItemDecoration; import android.support.v7.widget.DividerItemDecoration;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView; import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.SearchView; import android.support.v7.widget.SearchView;
import android.text.InputType; import android.text.InputType;
@ -81,6 +80,7 @@ import javax.inject.Inject;
import autodagger.AutoInjector; import autodagger.AutoInjector;
import butterknife.BindView; import butterknife.BindView;
import eu.davidea.fastscroller.FastScroller;
import eu.davidea.flexibleadapter.FlexibleAdapter; import eu.davidea.flexibleadapter.FlexibleAdapter;
import eu.davidea.flexibleadapter.common.SmoothScrollLinearLayoutManager; import eu.davidea.flexibleadapter.common.SmoothScrollLinearLayoutManager;
import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.android.schedulers.AndroidSchedulers;
@ -90,7 +90,7 @@ import retrofit2.HttpException;
@AutoInjector(NextcloudTalkApplication.class) @AutoInjector(NextcloudTalkApplication.class)
public class CallsListController extends BaseController implements SearchView.OnQueryTextListener, public class CallsListController extends BaseController implements SearchView.OnQueryTextListener,
FlexibleAdapter.OnItemClickListener { FlexibleAdapter.OnItemClickListener, FastScroller.OnScrollStateChangeListener {
public static final String TAG = "CallsListController"; public static final String TAG = "CallsListController";
@ -110,6 +110,11 @@ public class CallsListController extends BaseController implements SearchView.On
@BindView(R.id.swipe_refresh_layout) @BindView(R.id.swipe_refresh_layout)
SwipeRefreshLayout swipeRefreshLayout; SwipeRefreshLayout swipeRefreshLayout;
@BindView(R.id.fast_scroller)
FastScroller fastScroller;
private SmoothScrollLinearLayoutManager layoutManager;
private UserEntity userEntity; private UserEntity userEntity;
private Disposable roomsQueryDisposable; private Disposable roomsQueryDisposable;
private FlexibleAdapter<CallItem> adapter; private FlexibleAdapter<CallItem> adapter;
@ -117,6 +122,7 @@ public class CallsListController extends BaseController implements SearchView.On
private BottomSheet bottomSheet; private BottomSheet bottomSheet;
private MenuItem searchItem; private MenuItem searchItem;
private Menu menuVariable;
private SearchView searchView; private SearchView searchView;
private String searchQuery; private String searchQuery;
@ -158,7 +164,6 @@ public class CallsListController extends BaseController implements SearchView.On
adapter.addListener(this); adapter.addListener(this);
prepareViews(); prepareViews();
} }
@Override @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 @Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, 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); searchItem = menu.findItem(R.id.action_search);
initSearchView(); initSearchView();
} }
@ -312,7 +339,7 @@ public class CallsListController extends BaseController implements SearchView.On
} }
private void prepareViews() { private void prepareViews() {
LinearLayoutManager layoutManager = new SmoothScrollLinearLayoutManager(getActivity()); layoutManager = new SmoothScrollLinearLayoutManager(getActivity());
recyclerView.setLayoutManager(layoutManager); recyclerView.setLayoutManager(layoutManager);
recyclerView.setHasFixedSize(true); recyclerView.setHasFixedSize(true);
@ -325,6 +352,16 @@ public class CallsListController extends BaseController implements SearchView.On
swipeRefreshLayout.setOnRefreshListener(() -> fetchData(false)); swipeRefreshLayout.setOnRefreshListener(() -> fetchData(false));
swipeRefreshLayout.setColorSchemeResources(R.color.colorPrimary); 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) { private void dispose(@Nullable Disposable disposable) {
@ -427,8 +464,14 @@ public class CallsListController extends BaseController implements SearchView.On
.pushChangeHandler(new HorizontalChangeHandler())); .pushChangeHandler(new HorizontalChangeHandler()));
} }
boolean isNew = false;
if (bottomSheet == null) {
bottomSheet = new BottomSheet.Builder(getActivity()).setView(view).create(); bottomSheet = new BottomSheet.Builder(getActivity()).setView(view).create();
if (bottomSheet.getWindow() != null) { isNew = true;
}
if (bottomSheet.getWindow() != null && isNew) {
bottomSheet.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE); bottomSheet.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
} }
@ -465,4 +508,9 @@ public class CallsListController extends BaseController implements SearchView.On
protected String getTitle() { protected String getTitle() {
return getResources().getString(R.string.nc_app_name); return getResources().getString(R.string.nc_app_name);
} }
@Override
public void onFastScrollerStateChange(boolean scrolling) {
swipeRefreshLayout.setEnabled(!scrolling);
}
} }

View File

@ -31,12 +31,10 @@ import android.support.design.widget.BottomNavigationView;
import android.support.v4.view.MenuItemCompat; import android.support.v4.view.MenuItemCompat;
import android.support.v4.widget.SwipeRefreshLayout; import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.widget.DividerItemDecoration; import android.support.v7.widget.DividerItemDecoration;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView; import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.SearchView; import android.support.v7.widget.SearchView;
import android.text.InputType; import android.text.InputType;
import android.text.TextUtils; import android.text.TextUtils;
import android.view.ActionMode;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.Menu; import android.view.Menu;
import android.view.MenuInflater; import android.view.MenuInflater;
@ -45,6 +43,8 @@ import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.view.ViewTreeObserver; import android.view.ViewTreeObserver;
import android.view.inputmethod.EditorInfo; import android.view.inputmethod.EditorInfo;
import android.widget.Button;
import android.widget.LinearLayout;
import com.bluelinelabs.conductor.RouterTransaction; import com.bluelinelabs.conductor.RouterTransaction;
import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler; import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler;
@ -52,6 +52,8 @@ import com.bluelinelabs.conductor.changehandler.VerticalChangeHandler;
import com.bluelinelabs.conductor.internal.NoOpControllerChangeHandler; import com.bluelinelabs.conductor.internal.NoOpControllerChangeHandler;
import com.nextcloud.talk.R; import com.nextcloud.talk.R;
import com.nextcloud.talk.activities.CallActivity; 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.adapters.items.UserItem;
import com.nextcloud.talk.api.NcApi; import com.nextcloud.talk.api.NcApi;
import com.nextcloud.talk.application.NextcloudTalkApplication; 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.participants.Participant;
import com.nextcloud.talk.models.json.rooms.RoomOverall; import com.nextcloud.talk.models.json.rooms.RoomOverall;
import com.nextcloud.talk.models.json.sharees.Sharee; 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.ApiUtils;
import com.nextcloud.talk.utils.bundle.BundleKeys; import com.nextcloud.talk.utils.bundle.BundleKeys;
import com.nextcloud.talk.utils.database.user.UserUtils; import com.nextcloud.talk.utils.database.user.UserUtils;
@ -69,6 +72,7 @@ import org.parceler.Parcels;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
@ -77,9 +81,15 @@ import javax.inject.Inject;
import autodagger.AutoInjector; import autodagger.AutoInjector;
import butterknife.BindView; import butterknife.BindView;
import butterknife.OnClick;
import butterknife.Optional;
import eu.davidea.fastscroller.FastScroller;
import eu.davidea.flexibleadapter.FlexibleAdapter; import eu.davidea.flexibleadapter.FlexibleAdapter;
import eu.davidea.flexibleadapter.SelectableAdapter; import eu.davidea.flexibleadapter.SelectableAdapter;
import eu.davidea.flexibleadapter.common.SmoothScrollLinearLayoutManager; 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.Observer;
import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable; import io.reactivex.disposables.Disposable;
@ -88,7 +98,7 @@ import retrofit2.HttpException;
@AutoInjector(NextcloudTalkApplication.class) @AutoInjector(NextcloudTalkApplication.class)
public class ContactsController extends BaseController implements SearchView.OnQueryTextListener, public class ContactsController extends BaseController implements SearchView.OnQueryTextListener,
ActionMode.Callback, FlexibleAdapter.OnItemClickListener { FlexibleAdapter.OnItemClickListener, FastScroller.OnScrollStateChangeListener {
public static final String TAG = "ContactsController"; public static final String TAG = "ContactsController";
@ -105,33 +115,67 @@ public class ContactsController extends BaseController implements SearchView.OnQ
@BindView(R.id.swipe_refresh_layout) @BindView(R.id.swipe_refresh_layout)
SwipeRefreshLayout swipeRefreshLayout; 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 UserEntity userEntity;
private Disposable contactsQueryDisposable; private Disposable contactsQueryDisposable;
private Disposable cacheQueryDisposable; private Disposable cacheQueryDisposable;
private FlexibleAdapter<UserItem> adapter; private FlexibleAdapter adapter;
private List<UserItem> contactItems = new ArrayList<>(); private List<AbstractFlexibleItem> contactItems = new ArrayList<>();
private SmoothScrollLinearLayoutManager layoutManager;
private MenuItem searchItem; private MenuItem searchItem;
private SearchView searchView; private SearchView searchView;
private String searchQuery; private String searchQuery;
private ActionMode actionMode; private boolean isNewConversationView;
private HashMap<String, UserHeaderItem> userHeaderItems = new HashMap<String, UserHeaderItem>();
public ContactsController() { public ContactsController() {
super(); super();
setHasOptionsMenu(true); setHasOptionsMenu(true);
} }
public ContactsController(Bundle args) {
super(args);
setHasOptionsMenu(true);
if (args.containsKey(BundleKeys.KEY_NEW_CONVERSATION)) {
isNewConversationView = true;
}
}
@Override @Override
protected View inflateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup container) { protected View inflateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup container) {
return inflater.inflate(R.layout.controller_generic_rv, container, false); 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 @Override
protected void onViewBound(@NonNull View view) { protected void onViewBound(@NonNull View view) {
super.onViewBound(view); super.onViewBound(view);
NextcloudTalkApplication.getSharedApplication().getComponentApplication().inject(this); NextcloudTalkApplication.getSharedApplication().getComponentApplication().inject(this);
FlipView.resetLayoutAnimationDelay(true, 1000L);
FlipView.stopLayoutAnimation();
userEntity = userUtils.getCurrentUser(); userEntity = userUtils.getCurrentUser();
if (userEntity == null) { if (userEntity == null) {
@ -144,15 +188,47 @@ public class ContactsController extends BaseController implements SearchView.OnQ
if (adapter == null) { if (adapter == null) {
adapter = new FlexibleAdapter<>(contactItems, getActivity(), false); adapter = new FlexibleAdapter<>(contactItems, getActivity(), false);
adapter.setNotifyChangeOfUnfilteredItems(true)
.setMode(SelectableAdapter.Mode.MULTI);
if (userEntity != null) { if (userEntity != null) {
fetchData(); fetchData();
} }
} }
adapter.setStickyHeaderElevation(5)
.setUnlinkAllItemsOnRemoveHeaders(true)
.setDisplayHeadersAtStartUp(true)
.setStickyHeaders(true);
adapter.addListener(this); adapter.addListener(this);
prepareViews(); prepareViews();
} }
@Optional
@OnClick(R.id.clear_button)
public void onClearButtonClick() {
if (adapter != null) {
List<Integer> 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() { private void initSearchView() {
if (getActivity() != null) { if (getActivity() != null) {
SearchManager searchManager = (SearchManager) getActivity().getSystemService(Context.SEARCH_SERVICE); SearchManager searchManager = (SearchManager) getActivity().getSystemService(Context.SEARCH_SERVICE);
@ -172,10 +248,14 @@ public class ContactsController extends BaseController implements SearchView.OnQ
final View mSearchEditFrame = searchView final View mSearchEditFrame = searchView
.findViewById(android.support.v7.appcompat.R.id.search_edit_frame); .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(); Handler handler = new Handler();
ViewTreeObserver vto = mSearchEditFrame.getViewTreeObserver(); ViewTreeObserver vto = mSearchEditFrame.getViewTreeObserver();
BottomNavigationView finalBottomNavigationView = bottomNavigationView;
vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
int oldVisibility = -1; int oldVisibility = -1;
@ -186,10 +266,14 @@ public class ContactsController extends BaseController implements SearchView.OnQ
if (currentVisibility != oldVisibility) { if (currentVisibility != oldVisibility) {
if (currentVisibility == View.VISIBLE) { if (currentVisibility == View.VISIBLE) {
handler.postDelayed(() -> bottomNavigationView.setVisibility(View.GONE), 100); if (finalBottomNavigationView != null) {
handler.postDelayed(() -> finalBottomNavigationView.setVisibility(View.GONE), 100);
}
} else { } else {
handler.postDelayed(() -> { handler.postDelayed(() -> {
bottomNavigationView.setVisibility(View.VISIBLE); if (finalBottomNavigationView != null) {
finalBottomNavigationView.setVisibility(View.VISIBLE);
}
searchItem.setVisible(contactItems.size() > 0); searchItem.setVisible(contactItems.size() > 0);
}, 500); }, 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 @Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, 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); searchItem = menu.findItem(R.id.action_search);
menu.findItem(R.id.action_new_conversation).setVisible(false);
initSearchView(); initSearchView();
} }
@ -218,6 +314,7 @@ public class ContactsController extends BaseController implements SearchView.OnQ
searchItem.expandActionView(); searchItem.expandActionView();
searchView.setQuery(adapter.getSearchText(), false); searchView.setQuery(adapter.getSearchText(), false);
} }
} }
private void fetchData() { private void fetchData() {
@ -226,6 +323,7 @@ public class ContactsController extends BaseController implements SearchView.OnQ
Set<Sharee> shareeHashSet = new HashSet<>(); Set<Sharee> shareeHashSet = new HashSet<>();
contactItems = new ArrayList<>(); contactItems = new ArrayList<>();
userHeaderItems = new HashMap<>();
RetrofitBucket retrofitBucket = ApiUtils.getRetrofitBucketForContactsSearch(userEntity.getBaseUrl(), RetrofitBucket retrofitBucket = ApiUtils.getRetrofitBucketForContactsSearch(userEntity.getBaseUrl(),
""); "");
@ -234,7 +332,7 @@ public class ContactsController extends BaseController implements SearchView.OnQ
retrofitBucket.getUrl(), retrofitBucket.getQueryMap()) retrofitBucket.getUrl(), retrofitBucket.getQueryMap())
.subscribeOn(Schedulers.newThread()) .subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribe(shareesOverall -> { .subscribe((ShareesOverall shareesOverall) -> {
if (shareesOverall != null) { if (shareesOverall != null) {
if (shareesOverall.getOcs().getData().getUsers() != 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())) { if (!sharee.getValue().getShareWith().equals(userEntity.getUsername())) {
participant = new Participant(); participant = new Participant();
participant.setName(sharee.getLabel()); 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()); 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); adapter.updateDataSet(contactItems, true);
searchItem.setVisible(contactItems.size() > 0); searchItem.setVisible(contactItems.size() > 0);
swipeRefreshLayout.setRefreshing(false); swipeRefreshLayout.setRefreshing(false);
if (isNewConversationView) {
checkAndHandleBottomButtons();
}
} }
}, throwable -> { }, throwable -> {
@ -299,7 +431,7 @@ public class ContactsController extends BaseController implements SearchView.OnQ
} }
private void prepareViews() { private void prepareViews() {
LinearLayoutManager layoutManager = new SmoothScrollLinearLayoutManager(getActivity()); layoutManager = new SmoothScrollLinearLayoutManager(getActivity());
recyclerView.setLayoutManager(layoutManager); recyclerView.setLayoutManager(layoutManager);
recyclerView.setHasFixedSize(true); recyclerView.setHasFixedSize(true);
recyclerView.setAdapter(adapter); recyclerView.setAdapter(adapter);
@ -311,6 +443,17 @@ public class ContactsController extends BaseController implements SearchView.OnQ
swipeRefreshLayout.setOnRefreshListener(this::fetchData); swipeRefreshLayout.setOnRefreshListener(this::fetchData);
swipeRefreshLayout.setColorSchemeResources(R.color.colorPrimary); 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) { private void dispose(@Nullable Disposable disposable) {
@ -330,8 +473,10 @@ public class ContactsController extends BaseController implements SearchView.OnQ
} }
} }
@Override @Override
public void onSaveViewState(@NonNull View view, @NonNull Bundle outState) { public void onSaveViewState(@NonNull View view, @NonNull Bundle outState) {
adapter.onSaveInstanceState(outState);
super.onSaveViewState(view, outState); super.onSaveViewState(view, outState);
if (searchView != null && !TextUtils.isEmpty(searchView.getQuery())) { if (searchView != null && !TextUtils.isEmpty(searchView.getQuery())) {
outState.putString(KEY_SEARCH_QUERY, searchView.getQuery().toString()); 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) { public void onRestoreViewState(@NonNull View view, @NonNull Bundle savedViewState) {
super.onRestoreViewState(view, savedViewState); super.onRestoreViewState(view, savedViewState);
searchQuery = savedViewState.getString(KEY_SEARCH_QUERY, ""); searchQuery = savedViewState.getString(KEY_SEARCH_QUERY, "");
if (adapter != null) {
adapter.onRestoreInstanceState(savedViewState);
}
} }
@Override @Override
@ -377,69 +525,10 @@ public class ContactsController extends BaseController implements SearchView.OnQ
} }
@Override @Override
public boolean onCreateActionMode(ActionMode actionMode, Menu menu) {
adapter.setMode(SelectableAdapter.Mode.MULTI);
return true;
}
@Override
public boolean onPrepareActionMode(ActionMode actionMode, Menu menu) {
return false;
}
@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) { public boolean onItemClick(int position) {
if (actionMode != null && position != RecyclerView.NO_POSITION) { if (adapter.getItem(position) instanceof UserItem) {
// Mark the position selected if (!isNewConversationView) {
toggleSelection(position); UserItem userItem = (UserItem) adapter.getItem(position);
return true;
} else {
// Handle the item click listener
// We don't need to activate anything
return false;
}
}*/
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", RetrofitBucket retrofitBucket = ApiUtils.getRetrofitBucketForCreateRoom(userEntity.getBaseUrl(), "1",
userItem.getModel().getUserId()); userItem.getModel().getUserId());
ncApi.createRoom(ApiUtils.getCredentials(userEntity.getUsername(), userEntity.getToken()), ncApi.createRoom(ApiUtils.getCredentials(userEntity.getUsername(), userEntity.getToken()),
@ -474,13 +563,52 @@ public class ContactsController extends BaseController implements SearchView.OnQ
} }
}); });
} else {
((UserItem) adapter.getItem(position)).flipItemSelection();
adapter.toggleSelection(position);
checkAndHandleBottomButtons();
}
}
return true; return true;
} }
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);
}
if (bottomButtonsLinearLayout != null && bottomButtonsLinearLayout.getVisibility() == View.VISIBLE) {
if (adapter.getScrollableFooters().size() == 0) {
adapter.addScrollableFooterWithDelay(new EmptyFooterItem(999), 0, layoutManager
.findLastVisibleItemPosition() == adapter.getItemCount() - 1);
}
} else {
if (adapter != null) {
adapter.removeAllScrollableFooters();
}
}
}
@Override @Override
protected String getTitle() { protected String getTitle() {
if (!isNewConversationView) {
return getResources().getString(R.string.nc_app_name); 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);
}
} }

View File

@ -39,10 +39,10 @@ import com.bluelinelabs.conductor.RouterTransaction;
import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler; import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler;
import com.nextcloud.talk.R; import com.nextcloud.talk.R;
import com.nextcloud.talk.api.NcApi; import com.nextcloud.talk.api.NcApi;
import com.nextcloud.talk.utils.ApiUtils;
import com.nextcloud.talk.application.NextcloudTalkApplication; import com.nextcloud.talk.application.NextcloudTalkApplication;
import com.nextcloud.talk.controllers.base.BaseController; import com.nextcloud.talk.controllers.base.BaseController;
import com.nextcloud.talk.utils.AccountUtils; import com.nextcloud.talk.utils.AccountUtils;
import com.nextcloud.talk.utils.ApiUtils;
import com.nextcloud.talk.utils.ApplicationWideMessageHolder; import com.nextcloud.talk.utils.ApplicationWideMessageHolder;
import com.nextcloud.talk.utils.bundle.BundleKeys; import com.nextcloud.talk.utils.bundle.BundleKeys;
import com.nextcloud.talk.utils.database.user.UserUtils; import com.nextcloud.talk.utils.database.user.UserUtils;

View File

@ -31,6 +31,7 @@ import android.support.v7.widget.DividerItemDecoration;
import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView; import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
@ -129,16 +130,29 @@ public class SwitchAccountController extends BaseController {
}; };
public SwitchAccountController() { public SwitchAccountController() {
setHasOptionsMenu(true);
} }
public SwitchAccountController(Bundle args) { public SwitchAccountController(Bundle args) {
super(args); super(args);
setHasOptionsMenu(true);
if (args.containsKey(BundleKeys.KEY_IS_ACCOUNT_IMPORT)) { if (args.containsKey(BundleKeys.KEY_IS_ACCOUNT_IMPORT)) {
isAccountImport = true; 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 @Override
protected View inflateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup container) { protected View inflateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup container) {
return inflater.inflate(R.layout.controller_generic_rv, container, false); return inflater.inflate(R.layout.controller_generic_rv, container, false);
@ -204,6 +218,14 @@ public class SwitchAccountController extends BaseController {
prepareViews(); prepareViews();
} }
@Override
protected void onAttach(@NonNull View view) {
super.onAttach(view);
if (getActionBar() != null) {
getActionBar().setDisplayHomeAsUpEnabled(true);
}
}
private void prepareViews() { private void prepareViews() {
LinearLayoutManager layoutManager = new SmoothScrollLinearLayoutManager(getActivity()); LinearLayoutManager layoutManager = new SmoothScrollLinearLayoutManager(getActivity());
recyclerView.setLayoutManager(layoutManager); recyclerView.setLayoutManager(layoutManager);

View File

@ -53,6 +53,7 @@ public abstract class BaseController extends RefWatchingController {
@Override @Override
protected void onAttach(@NonNull View view) { protected void onAttach(@NonNull View view) {
setTitle(); setTitle();
getActionBar().setDisplayHomeAsUpEnabled(false);
super.onAttach(view); super.onAttach(view);
} }

View File

@ -36,10 +36,10 @@ import com.kennyc.bottomsheet.adapters.AppAdapter;
import com.nextcloud.talk.R; import com.nextcloud.talk.R;
import com.nextcloud.talk.adapters.items.AppItem; import com.nextcloud.talk.adapters.items.AppItem;
import com.nextcloud.talk.adapters.items.MenuItem; 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.application.NextcloudTalkApplication;
import com.nextcloud.talk.controllers.base.BaseController; import com.nextcloud.talk.controllers.base.BaseController;
import com.nextcloud.talk.events.BottomSheetLockEvent; 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.ShareUtils;
import com.nextcloud.talk.utils.bundle.BundleKeys; import com.nextcloud.talk.utils.bundle.BundleKeys;
import com.nextcloud.talk.utils.database.user.UserUtils; import com.nextcloud.talk.utils.database.user.UserUtils;

View File

@ -28,8 +28,8 @@ import android.util.Log;
import com.github.aurae.retrofit2.LoganSquareConverterFactory; import com.github.aurae.retrofit2.LoganSquareConverterFactory;
import com.nextcloud.talk.BuildConfig; import com.nextcloud.talk.BuildConfig;
import com.nextcloud.talk.api.NcApi; import com.nextcloud.talk.api.NcApi;
import com.nextcloud.talk.utils.ApiUtils;
import com.nextcloud.talk.application.NextcloudTalkApplication; import com.nextcloud.talk.application.NextcloudTalkApplication;
import com.nextcloud.talk.utils.ApiUtils;
import com.nextcloud.talk.utils.preferences.AppPreferences; import com.nextcloud.talk.utils.preferences.AppPreferences;
import com.nextcloud.talk.utils.ssl.MagicTrustManager; import com.nextcloud.talk.utils.ssl.MagicTrustManager;
import com.nextcloud.talk.utils.ssl.SSLSocketFactoryCompat; import com.nextcloud.talk.utils.ssl.SSLSocketFactoryCompat;

View File

@ -40,9 +40,9 @@ import com.google.firebase.messaging.FirebaseMessagingService;
import com.google.firebase.messaging.RemoteMessage; import com.google.firebase.messaging.RemoteMessage;
import com.nextcloud.talk.R; import com.nextcloud.talk.R;
import com.nextcloud.talk.activities.CallActivity; 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.DecryptedPushMessage;
import com.nextcloud.talk.models.json.push.PushMessage; 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.NotificationUtils;
import com.nextcloud.talk.utils.PushUtils; import com.nextcloud.talk.utils.PushUtils;
import com.nextcloud.talk.utils.bundle.BundleKeys; import com.nextcloud.talk.utils.bundle.BundleKeys;

View File

@ -0,0 +1,45 @@
/*
* 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/>.
*/
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();
}
}
}

View File

@ -36,4 +36,5 @@ public class BundleKeys {
public static final String KEY_CALL_SESSION = "KEY_CALL_SESSION"; 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_ROOM_TOKEN = "KEY_ROOM_TOKEN";
public static final String KEY_USER_ENTITY = "KEY_USER_ENTITY"; public static final String KEY_USER_ENTITY = "KEY_USER_ENTITY";
public static final String KEY_NEW_CONVERSATION = "KEY_NEW_CONVERSATION";
} }

View File

@ -26,12 +26,12 @@ import android.util.Log;
import com.bluelinelabs.logansquare.LoganSquare; import com.bluelinelabs.logansquare.LoganSquare;
import com.nextcloud.talk.R; 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.application.NextcloudTalkApplication;
import com.nextcloud.talk.events.MediaStreamEvent; import com.nextcloud.talk.events.MediaStreamEvent;
import com.nextcloud.talk.events.PeerConnectionEvent; import com.nextcloud.talk.events.PeerConnectionEvent;
import com.nextcloud.talk.events.SessionDescriptionSendEvent; 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.greenrobot.eventbus.EventBus;
import org.webrtc.DataChannel; import org.webrtc.DataChannel;

View File

@ -17,7 +17,7 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
* *
* Original code: * Part of the code related to codec handling is originally:
* *
* *
* Copyright 2016 The WebRTC Project Authors. All rights reserved. * Copyright 2016 The WebRTC Project Authors. All rights reserved.

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,13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/>
</vector>

View File

@ -0,0 +1,52 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ 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/>.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/bottom_buttons_layout"
android:layout_width="match_parent"
android:layout_height="32dp"
android:alpha="0.7"
android:animateLayoutChanges="true"
android:gravity="bottom"
android:orientation="horizontal"
android:visibility="gone">
<Button
android:id="@+id/clear_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="0.6"
android:background="@color/nc_darkRed"
android:text="@string/nc_contacts_clear"
android:textAlignment="center"
android:textColor="@color/nc_white_color_complete"/>
<Button
android:id="@+id/done_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="0.4"
android:background="@color/nc_darkGreen"
android:text="@string/nc_contacts_done"
android:textAlignment="center"
android:textColor="@color/nc_white_color_complete"/>
</LinearLayout>

View File

@ -57,9 +57,9 @@
android:layout_marginBottom="12dp" android:layout_marginBottom="12dp"
android:layout_marginEnd="8dp" android:layout_marginEnd="8dp"
android:layout_marginTop="8dp" android:layout_marginTop="8dp"
android:alpha="0.7"
android:background="#0000" android:background="#0000"
android:enabled="false" android:enabled="false"
android:alpha="0.7"
android:text="@string/nc_proceed" android:text="@string/nc_proceed"
android:textColor="@color/colorPrimary"/> android:textColor="@color/colorPrimary"/>

View File

@ -19,17 +19,37 @@
~ along with this program. If not, see <http://www.gnu.org/licenses/>. ~ along with this program. If not, see <http://www.gnu.org/licenses/>.
--> -->
<android.support.v4.widget.SwipeRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android" <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/swipe_refresh_layout"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:background="@color/nc_white_color"> android:background="@color/nc_white_color">
<android.support.v4.widget.SwipeRefreshLayout
android:id="@+id/swipe_refresh_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView <android.support.v7.widget.RecyclerView
android:id="@+id/recycler_view" android:id="@+id/recycler_view"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
tools:listitem="@layout/rv_item_call"/> tools:listitem="@layout/rv_item_call"/>
</android.support.v4.widget.SwipeRefreshLayout> </FrameLayout>
</android.support.v4.widget.SwipeRefreshLayout>
<include
layout="@layout/bottom_buttons"
android:layout_width="match_parent"
android:layout_height="32dp"
android:layout_gravity="bottom"
android:visibility="gone"/>
<include layout="@layout/fast_scroller"/>
</FrameLayout>

View File

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ 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/>.
-->
<eu.davidea.fastscroller.FastScroller xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/fast_scroller"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_alignBottom="@+id/swipe_refresh_layout"
android:layout_alignParentEnd="true"
android:layout_alignTop="@+id/swipe_refresh_layout"
android:layout_centerHorizontal="true"
app:fastScrollerAutoHideDelayInMillis="1000"
app:fastScrollerAutoHideEnabled="true"
app:fastScrollerBubbleEnabled="true"
app:fastScrollerBubblePosition="adjacent"
app:fastScrollerIgnoreTouchesOutsideHandle="false"
tools:visibility="visible">
</eu.davidea.fastscroller.FastScroller>

View File

@ -34,10 +34,15 @@
android:layout_centerVertical="true" android:layout_centerVertical="true"
android:layout_marginStart="@dimen/activity_horizontal_margin"> android:layout_marginStart="@dimen/activity_horizontal_margin">
<ImageView <com.nextcloud.talk.utils.MagicFlipView
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/avatar_image" android:id="@+id/avatar_image"
android:layout_width="@dimen/avatar_size" android:layout_width="@dimen/avatar_size"
android:layout_height="@dimen/avatar_size"/> android:layout_height="@dimen/avatar_size"
app:animationDuration="170"
app:checked="false"
app:enableInitialAnimation="true"
app:rearBackgroundColor="@color/colorPrimary"/>
<ImageView <ImageView
android:id="@+id/password_protected_image_view" android:id="@+id/password_protected_image_view"
@ -83,11 +88,15 @@
<ImageButton <ImageButton
android:id="@+id/more_menu" android:id="@+id/more_menu"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="match_parent"
android:layout_alignParentEnd="true" android:layout_alignParentEnd="true"
android:layout_centerVertical="true" android:layout_centerVertical="true"
android:layout_marginEnd="@dimen/activity_horizontal_margin" android:layout_marginEnd="@dimen/activity_horizontal_margin"
android:layout_marginStart="@dimen/margin_between_elements" android:layout_marginStart="@dimen/margin_between_elements"
android:background="@drawable/ic_more_horiz_black_24dp"/> android:background="?android:attr/selectableItemBackground"
android:paddingEnd="8dp"
android:paddingStart="8dp"
android:scaleType="center"
android:src="@drawable/ic_more_horiz_black_24dp"/>
</RelativeLayout> </RelativeLayout>

View File

@ -28,23 +28,27 @@
android:layout_height="@dimen/item_height" android:layout_height="@dimen/item_height"
android:orientation="vertical"> android:orientation="vertical">
<ImageView <com.nextcloud.talk.utils.MagicFlipView
android:id="@+id/avatar_image" xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/avatar_flip_view"
android:layout_width="@dimen/avatar_size" android:layout_width="@dimen/avatar_size"
android:layout_height="@dimen/avatar_size" android:layout_height="@dimen/avatar_size"
android:layout_centerVertical="true" android:layout_centerVertical="true"
android:layout_marginEnd="@dimen/activity_horizontal_margin" android:layout_marginEnd="@dimen/activity_horizontal_margin"
android:layout_marginStart="@dimen/activity_horizontal_margin"/> android:layout_marginStart="@dimen/activity_horizontal_margin"
app:animationDuration="170"
app:enableInitialAnimation="true"
app:rearBackgroundColor="@color/colorPrimary"/>
<TextView <TextView
android:id="@+id/name_text" android:id="@+id/name_text"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_centerVertical="true" android:layout_centerVertical="true"
android:ellipsize="end"
android:layout_marginEnd="@dimen/activity_horizontal_margin" android:layout_marginEnd="@dimen/activity_horizontal_margin"
android:layout_toEndOf="@id/avatar_flip_view"
android:ellipsize="end"
android:textAppearance="?android:attr/textAppearanceListItem" android:textAppearance="?android:attr/textAppearanceListItem"
android:layout_toEndOf="@id/avatar_image"
tools:text="Contact item text"/> tools:text="Contact item text"/>
</RelativeLayout> </RelativeLayout>

View File

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ 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/>.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="32dp"
android:orientation="vertical">
</LinearLayout>

View File

@ -0,0 +1,39 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ 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/>.
-->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:alpha="0.7"
android:background="@color/colorPrimary"
android:elevation="5dp">
<TextView
android:id="@+id/title_text_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginEnd="24dp"
android:layout_marginStart="12dp"
android:layout_marginTop="8dp"
android:textColor="@color/nc_white_color_complete"/>
</RelativeLayout>

View File

@ -36,8 +36,8 @@
android:layout_width="16dp" android:layout_width="16dp"
android:layout_height="16dp" android:layout_height="16dp"
android:layout_above="@id/peer_nick_text_view" android:layout_above="@id/peer_nick_text_view"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp" android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:src="@drawable/ic_videocam_off_white_24px" android:src="@drawable/ic_videocam_off_white_24px"
android:visibility="invisible"/> android:visibility="invisible"/>
@ -56,9 +56,9 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_alignParentBottom="true" android:layout_alignParentBottom="true"
android:layout_alignParentStart="true" android:layout_alignParentStart="true"
android:layout_marginTop="4dp"
android:layout_marginStart="8dp"
android:layout_marginBottom="8dp" android:layout_marginBottom="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="4dp"
android:textColor="@color/nc_white_color_complete"/> android:textColor="@color/nc_white_color_complete"/>
</RelativeLayout> </RelativeLayout>

View File

@ -28,6 +28,11 @@
android:icon="@drawable/ic_search_white_24dp" android:icon="@drawable/ic_search_white_24dp"
app:showAsAction="collapseActionView|always" app:showAsAction="collapseActionView|always"
android:animateLayoutChanges="true" android:animateLayoutChanges="true"
app:actionViewClass="android.support.v7.widget.SearchView"/> app:actionViewClass="android.support.v7.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"/>
</menu> </menu>

View File

@ -28,6 +28,7 @@
<string name="nc_never">Never joined</string> <string name="nc_never">Never joined</string>
<string name="nc_search">Search</string> <string name="nc_search">Search</string>
<string name="nc_new_conversation">Create a new conversation</string>
<string name="nc_certificate_dialog_title">Check out the certificate</string> <string name="nc_certificate_dialog_title">Check out the certificate</string>
<string name="nc_certificate_dialog_text">Do you trust the until now unknown SSL certificate, issued by %1$s for %2$s, valid from %3$s to %4$s?</string> <string name="nc_certificate_dialog_text">Do you trust the until now unknown SSL certificate, issued by %1$s for %2$s, valid from %3$s to %4$s?</string>
@ -84,8 +85,11 @@
<string name="nc_delete_call">Delete call</string> <string name="nc_delete_call">Delete call</string>
<!-- Contacts --> <!-- Contacts -->
<string name="nc_select_contacts">Select contacts</string>
<string name="nc_one_contact_selected">contact selected</string> <string name="nc_one_contact_selected">contact selected</string>
<string name="nc_more_contacts_selected">contacts selected</string> <string name="nc_more_contacts_selected">contacts selected</string>
<string name="nc_contacts_clear">Clear</string>
<string name="nc_contacts_done">Done</string>
<!-- Permissions --> <!-- Permissions -->
<string name="nc_permissions">Permissions need to be granted to establish a video and/or audio call. Please click \"ALLOW\" in the upcoming system dialog.</string> <string name="nc_permissions">Permissions need to be granted to establish a video and/or audio call. Please click \"ALLOW\" in the upcoming system dialog.</string>