Commit cdcbbbb0 authored by Adrien Béraud's avatar Adrien Béraud Committed by Sébastien Blin

tablet: add conversation selection

Change-Id: I1c0a7078031133e7442699720a4fb9874e47cced
parent 2ed1e7b3
......@@ -24,6 +24,7 @@ import cx.ring.databinding.ItemSmartlistBinding;
import cx.ring.databinding.ItemSmartlistHeaderBinding;
import net.jami.smartlist.SmartListViewModel;
import cx.ring.viewholders.SmartListViewHolder;
import io.reactivex.disposables.CompositeDisposable;
import android.os.Parcelable;
import android.view.LayoutInflater;
......@@ -40,10 +41,12 @@ public class SmartListAdapter extends RecyclerView.Adapter<SmartListViewHolder>
private List<SmartListViewModel> mSmartListViewModels = new ArrayList<>();
private final SmartListViewHolder.SmartListListeners listener;
private final CompositeDisposable mDisposable;
private RecyclerView recyclerView;
public SmartListAdapter(List<SmartListViewModel> smartListViewModels, SmartListViewHolder.SmartListListeners listener) {
public SmartListAdapter(List<SmartListViewModel> smartListViewModels, SmartListViewHolder.SmartListListeners listener, CompositeDisposable disposable) {
this.listener = listener;
mDisposable = disposable;
if (smartListViewModels != null)
mSmartListViewModels.addAll(smartListViewModels);
}
......@@ -54,10 +57,10 @@ public class SmartListAdapter extends RecyclerView.Adapter<SmartListViewHolder>
LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
if (viewType == 0) {
ItemSmartlistBinding itemBinding = ItemSmartlistBinding.inflate(layoutInflater, parent, false);
return new SmartListViewHolder(itemBinding);
return new SmartListViewHolder(itemBinding, mDisposable);
} else {
ItemSmartlistHeaderBinding itemBinding = ItemSmartlistHeaderBinding.inflate(layoutInflater, parent, false);
return new SmartListViewHolder(itemBinding);
return new SmartListViewHolder(itemBinding, mDisposable);
}
}
......
......@@ -343,6 +343,10 @@ public abstract class JamiApplication extends Application {
return mHardwareService;
}
public ConversationFacade getFacade() {
return mConversationFacade;
}
private void setupActivityListener() {
registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
......
......@@ -53,7 +53,7 @@ import io.reactivex.disposables.CompositeDisposable;
public class ConversationSelectionActivity extends AppCompatActivity {
private final static String TAG = ConversationSelectionActivity.class.getSimpleName();
private CompositeDisposable mDisposable = new CompositeDisposable();
private final CompositeDisposable mDisposable = new CompositeDisposable();
@Inject
@Singleton
......@@ -90,7 +90,7 @@ public class ConversationSelectionActivity extends AppCompatActivity {
@Override
public void onItemLongClick(SmartListViewModel smartListViewModel) {
}
});
}, mDisposable);
list.setLayoutManager(new LinearLayoutManager(this));
list.setAdapter(adapter);
}
......
......@@ -49,11 +49,13 @@ import androidx.fragment.app.FragmentTransaction;
import com.google.android.material.bottomnavigation.BottomNavigationView;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import net.jami.facades.ConversationFacade;
import net.jami.model.Account;
import net.jami.model.AccountConfig;
import net.jami.model.Conversation;
import net.jami.services.AccountService;
import net.jami.services.NotificationService;
import net.jami.smartlist.SmartListViewModel;
import java.util.ArrayList;
import java.util.Collection;
......@@ -87,6 +89,7 @@ import cx.ring.utils.ContentUriHandler;
import cx.ring.utils.ConversationPath;
import cx.ring.utils.DeviceUtils;
import cx.ring.views.SwitchButton;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.schedulers.Schedulers;
......@@ -195,7 +198,7 @@ public class HomeActivity extends AppCompatActivity implements BottomNavigationV
}
// if app opened from notification display trust request fragment when mService will connected
Intent intent = getIntent();
/*Intent intent = getIntent();
Bundle extra = intent.getExtras();
String action = intent.getAction();
if (ACTION_PRESENT_TRUST_REQUEST_FRAGMENT.equals(action)) {
......@@ -213,13 +216,12 @@ public class HomeActivity extends AppCompatActivity implements BottomNavigationV
fragmentManager.beginTransaction()
.replace(R.id.main_frame, fContent, HOME_TAG)
.commitNow();
} else if (fContent instanceof Refreshable) {
((Refreshable) fContent).refresh();
}
if (mAccountWithPendingrequests != null) {
presentTrustRequestFragment(mAccountWithPendingrequests);
mAccountWithPendingrequests = null;
}
}*/
handleIntent(getIntent());
}
@Override
......@@ -251,7 +253,7 @@ public class HomeActivity extends AppCompatActivity implements BottomNavigationV
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
Log.d(TAG, "onNewIntent: " + intent);
/*Log.d(TAG, "onNewIntent: " + intent);
String action = intent.getAction();
if (ACTION_PRESENT_TRUST_REQUEST_FRAGMENT.equals(action)) {
Bundle extra = intent.getExtras();
......@@ -265,11 +267,51 @@ public class HomeActivity extends AppCompatActivity implements BottomNavigationV
if (fContent instanceof SmartListFragment) {
((SmartListFragment)fContent).handleIntent(intent);
}
} else if (DRingService.ACTION_CONV_ACCEPT.equals(action)) {
if (DeviceUtils.isTablet(this)) {
} else if (DRingService.ACTION_CONV_ACCEPT.equals(action) || Intent.ACTION_VIEW.equals(action)) {
startConversation(ConversationPath.fromIntent(intent));
}*/
}
private void handleIntent(Intent intent) {
Log.d(TAG, "handleIntent: " + intent);
Bundle extra = intent.getExtras();
String action = intent.getAction();
if (ACTION_PRESENT_TRUST_REQUEST_FRAGMENT.equals(action)) {
if (extra == null || extra.getString(ContactRequestsFragment.ACCOUNT_ID) == null) {
return;
}
//mAccountWithPendingrequests = extra.getString(ContactRequestsFragment.ACCOUNT_ID);
presentTrustRequestFragment(extra.getString(ContactRequestsFragment.ACCOUNT_ID));
} else if (Intent.ACTION_SEND.equals(action) || Intent.ACTION_SEND_MULTIPLE.equals(action)) {
ConversationPath path = ConversationPath.fromBundle(extra);
if (path != null) {
intent.setClass(this, ConversationActivity.class);
startActivity(intent);
}
} else if (DRingService.ACTION_CONV_ACCEPT.equals(action) || Intent.ACTION_VIEW.equals(action)) {
startConversation(ConversationPath.fromIntent(intent));
/*if (DeviceUtils.isTablet(this)) {
startConversationTablet(ConversationPath.fromIntent(intent).toBundle());
}*/
} //else {
FragmentManager fragmentManager = getSupportFragmentManager();
fContent = fragmentManager.findFragmentById(R.id.main_frame);
if (fContent == null || Intent.ACTION_SEARCH.equals(action)) {
if (fContent instanceof SmartListFragment) {
((SmartListFragment)fContent).handleIntent(intent);
} else {
fContent = new SmartListFragment();
fragmentManager.beginTransaction()
.replace(R.id.main_frame, fContent, HOME_TAG)
.commitNow();
}
}
}
/*if (mAccountWithPendingrequests != null) {
presentTrustRequestFragment(mAccountWithPendingrequests);
mAccountWithPendingrequests = null;
}*/
//}
}
private void showMigrationDialog() {
......@@ -370,6 +412,39 @@ public class HomeActivity extends AppCompatActivity implements BottomNavigationV
if (DeviceUtils.isTablet(this)) {
selectNavigationItem(R.id.navigation_home);
showTabletToolbar();
} else {
// Remove ConversationFragment that might have been restored after an orientation change
if (fConversation == null)
fConversation = (ConversationFragment) getSupportFragmentManager().findFragmentByTag(ConversationFragment.class.getSimpleName());
if (fConversation != null) {
// fConversation = null;
// getSupportFragmentManager().findFragmentByTag(ConversationFragment.class.getSimpleName());
getSupportFragmentManager().beginTransaction().remove(fConversation).commitNow();
fConversation = null;
}
}
}
// Select first conversation in tablet mode
if (DeviceUtils.isTablet(this)) {
Intent intent = getIntent();
Uri uri = intent == null ? null : intent.getData();
if ((intent == null || uri == null) && fConversation == null) {
ConversationFacade facade = ((JamiApplication) getApplication()).getFacade();
Observable<List<Observable<SmartListViewModel>>> smartlist = null;
if (fContent instanceof SmartListFragment)
smartlist = facade.getSmartList(false);
else if (fContent instanceof ContactRequestsFragment)
smartlist = facade.getPendingList();
if (smartlist != null) {
mDisposable.add(smartlist
.filter(list -> !list.isEmpty())
.map(list -> list.get(0).firstOrError())
.firstElement()
.flatMapSingle(e -> e)
.subscribe(element -> startConversation(element.getAccountId(), element.getUri())));
}
}
}
}
......@@ -387,11 +462,14 @@ public class HomeActivity extends AppCompatActivity implements BottomNavigationV
.subscribe(account -> startConversation(account.getAccountID(), net.jami.model.Uri.fromString(conversationId))));
}
public void startConversation(String accountId, net.jami.model.Uri conversationId) {
Log.w(TAG, "startConversation " + accountId + " " + conversationId);
startConversation(new ConversationPath(accountId, conversationId));
}
public void startConversation(ConversationPath path) {
Log.w(TAG, "startConversation " + path);
if (!DeviceUtils.isTablet(this)) {
startActivity(new Intent(Intent.ACTION_VIEW, ConversationPath.toUri(accountId, conversationId), this, ConversationActivity.class));
startActivity(new Intent(Intent.ACTION_VIEW, path.toUri(), this, ConversationActivity.class));
} else {
startConversationTablet(ConversationPath.toBundle(accountId, conversationId));
startConversationTablet(path.toBundle());
}
}
......@@ -399,7 +477,6 @@ public class HomeActivity extends AppCompatActivity implements BottomNavigationV
fConversation = new ConversationFragment();
fConversation.setArguments(bundle);
//getSupportFragmentManager().get
if (!(fContent instanceof ContactRequestsFragment)) {
selectNavigationItem(R.id.navigation_home);
}
......@@ -584,10 +661,6 @@ public class HomeActivity extends AppCompatActivity implements BottomNavigationV
}
public interface Refreshable {
void refresh();
}
public void setBadge(int menuId, int number) {
if (number == 0)
mBinding.navigationView.removeBadge(menuId);
......
......@@ -45,6 +45,7 @@ import cx.ring.mvp.BaseSupportFragment;
import net.jami.smartlist.SmartListViewModel;
import cx.ring.viewholders.SmartListViewHolder;
import io.reactivex.disposables.CompositeDisposable;
public class ContactRequestsFragment extends BaseSupportFragment<ContactRequestsPresenter> implements ContactRequestsView,
SmartListViewHolder.SmartListListeners {
......@@ -100,7 +101,7 @@ public class ContactRequestsFragment extends BaseSupportFragment<ContactRequests
}
@Override
public void updateView(final List<SmartListViewModel> list) {
public void updateView(final List<SmartListViewModel> list, CompositeDisposable disposable) {
if (binding == null) {
return;
}
......@@ -114,7 +115,7 @@ public class ContactRequestsFragment extends BaseSupportFragment<ContactRequests
if (binding.requestsList.getAdapter() != null) {
mAdapter.update(list);
} else {
mAdapter = new SmartListAdapter(list, ContactRequestsFragment.this);
mAdapter = new SmartListAdapter(list, ContactRequestsFragment.this, disposable);
binding.requestsList.setAdapter(mAdapter);
LinearLayoutManager mLayoutManager = new LinearLayoutManager(getActivity());
binding.requestsList.setLayoutManager(mLayoutManager);
......
......@@ -141,7 +141,7 @@ public class ContactPickerFragment extends BottomSheetDialogFragment {
public void onItemLongClick(SmartListViewModel item) {
}
});
}, mDisposableBag);
binding.createGroupBtn.setOnClickListener(v -> mDisposableBag.add(mConversationFacade.createConversation(mAccountId, mCurrentSelection)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(conversation -> {
......
......@@ -833,16 +833,28 @@ public class ConversationFragment extends BaseSupportFragment<ConversationPresen
presenter.clickOnGoingPane();
}
@Override
public void onStart() {
super.onStart();
presenter.resume(mIsBubble);
}
@Override
public void onStop() {
super.onStop();
presenter.pause();
}
@Override
public void onPause() {
super.onPause();
presenter.pause();
//presenter.pause();
}
@Override
public void onResume() {
super.onResume();
presenter.resume(mIsBubble);
//presenter.resume(mIsBubble);
}
@Override
......
......@@ -156,7 +156,7 @@ public class ShareWithFragment extends Fragment {
public void onItemLongClick(SmartListViewModel smartListViewModel) {
}
});
}, mDisposable);
list.setLayoutManager(new LinearLayoutManager(context));
list.setAdapter(adapter);
return view;
......
......@@ -74,6 +74,7 @@ import cx.ring.utils.ClipboardHelper;
import cx.ring.utils.ConversationPath;
import cx.ring.utils.DeviceUtils;
import cx.ring.viewholders.SmartListViewHolder;
import io.reactivex.disposables.CompositeDisposable;
public class SmartListFragment extends BaseSupportFragment<SmartListPresenter> implements SearchView.OnQueryTextListener,
SmartListViewHolder.SmartListListeners,
......@@ -391,11 +392,11 @@ public class SmartListFragment extends BaseSupportFragment<SmartListPresenter> i
}
@Override
public void updateList(@Nullable final List<SmartListViewModel> smartListViewModels) {
public void updateList(@Nullable final List<SmartListViewModel> smartListViewModels, CompositeDisposable parentDisposable) {
if (binding == null)
return;
if (binding.confsList.getAdapter() == null) {
mSmartListAdapter = new SmartListAdapter(smartListViewModels, SmartListFragment.this);
mSmartListAdapter = new SmartListAdapter(smartListViewModels, SmartListFragment.this, parentDisposable);
binding.confsList.setAdapter(mSmartListAdapter);
binding.confsList.setHasFixedSize(true);
LinearLayoutManager llm = new LinearLayoutManager(getActivity());
......
......@@ -47,16 +47,18 @@ public class SmartListViewHolder extends RecyclerView.ViewHolder {
public final ItemSmartlistHeaderBinding headerBinding;
private final CompositeDisposable compositeDisposable = new CompositeDisposable();
public SmartListViewHolder(@NonNull ItemSmartlistBinding b) {
public SmartListViewHolder(@NonNull ItemSmartlistBinding b, @NonNull CompositeDisposable parentDisposable) {
super(b.getRoot());
binding = b;
headerBinding = null;
parentDisposable.add(compositeDisposable);
}
public SmartListViewHolder(@NonNull ItemSmartlistHeaderBinding b) {
public SmartListViewHolder(@NonNull ItemSmartlistHeaderBinding b, @NonNull CompositeDisposable parentDisposable) {
super(b.getRoot());
binding = null;
headerBinding = b;
parentDisposable.add(compositeDisposable);
}
public void bind(final SmartListListeners clickListener, final SmartListViewModel smartListViewModel) {
......@@ -67,6 +69,10 @@ public class SmartListViewHolder extends RecyclerView.ViewHolder {
compositeDisposable.add(Observable.create(e -> itemView.setOnClickListener(e::onNext))
.throttleFirst(1000, TimeUnit.MILLISECONDS)
.subscribe(v -> clickListener.onItemClick(smartListViewModel)));
Observable<Boolean> isSelected = smartListViewModel.getSelected();
if (isSelected != null) {
compositeDisposable.add(isSelected.subscribe(binding.itemLayout::setActivated));
}
itemView.setOnLongClickListener(v -> {
clickListener.onItemLongClick(smartListViewModel);
return true;
......@@ -101,6 +107,7 @@ public class SmartListViewHolder extends RecyclerView.ViewHolder {
.withViewModel(smartListViewModel)
.withCircleCrop(true)
.build(binding.photo.getContext()));
} else if (headerBinding != null) {
headerBinding.headerTitle.setText(smartListViewModel.getHeaderTitle() == SmartListViewModel.Title.Conversations
? R.string.navigation_item_conversation : R.string.search_results_public_directory);
......
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="?attr/colorControlHighlight">
<item>
<selector
android:exitFadeDuration="@android:integer/config_mediumAnimTime">
<item
android:drawable="@color/transparent_grey"
android:state_activated="true" />
<item android:drawable="@color/background" />
</selector>
</item>
</ripple>
\ No newline at end of file
......@@ -19,10 +19,10 @@ along with this program; if not, write to the Free Software
-->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/call_entry"
android:id="@+id/item_layout"
android:layout_width="match_parent"
android:layout_height="72dp"
android:background="?android:attr/selectableItemBackground"
android:background="@drawable/background_item_smartlist"
android:descendantFocusability="blocksDescendants"
android:paddingLeft="16dp"
android:paddingTop="8dp"
......
......@@ -64,7 +64,7 @@ public class ContactRequestsPresenter extends RootPresenter<net.jami.contactrequ
return vms;
}))
.observeOn(mUiScheduler)
.subscribe(viewModels -> getView().updateView(viewModels),
.subscribe(viewModels -> getView().updateView(viewModels, mCompositeDisposable),
e -> Log.d(TAG, "updateList subscribe onError", e)));
}
......
......@@ -24,9 +24,11 @@ import java.util.List;
import net.jami.model.Uri;
import net.jami.smartlist.SmartListViewModel;
import io.reactivex.disposables.CompositeDisposable;
public interface ContactRequestsView {
void updateView(List<SmartListViewModel> list);
void updateView(List<SmartListViewModel> list, CompositeDisposable disposable);
void updateItem(SmartListViewModel item);
void goToConversation(String accountId, Uri contactId);
......
......@@ -120,8 +120,8 @@ public class ConversationPresenter extends RootPresenter<ConversationView> {
Log.w(TAG, "setConversation " + conversation.getAggregateHistory().size());
if (mConversation == conversation)
return;
if (mConversation != null)
mConversation.setVisible(false);
//if (mConversation != null)
// mConversation.setVisible(false);
mConversation = conversation;
mConversationSubject.onNext(conversation);
ConversationView view = getView();
......
......@@ -75,6 +75,7 @@ public class Conversation extends ConversationHistory {
// runtime flag set to true if the user is currently viewing this conversation
private boolean mVisible = false;
private final Subject<Boolean> mVisibleSubject = BehaviorSubject.createDefault(mVisible);
// indicate the list needs sorting
private boolean mDirty = false;
......@@ -294,6 +295,10 @@ public class Conversation extends ConversationHistory {
return mVisible;
}
public Observable<Boolean> getVisible() {
return mVisibleSubject;
}
public void setLoaded(Single<Conversation> loaded) {
isLoaded = loaded;
}
......@@ -304,6 +309,7 @@ public class Conversation extends ConversationHistory {
public void setVisible(boolean visible) {
mVisible = visible;
mVisibleSubject.onNext(mVisible);
}
public List<Contact> getContacts() {
......
......@@ -184,7 +184,7 @@ public class SmartListPresenter extends RootPresenter<SmartListView> {
return;
}
view.hideNoConversationMessage();
view.updateList(viewModels);
view.updateList(viewModels, mConversationDisposable);
}, e -> Log.w(TAG, "showConversations error ", e)));
}
......
......@@ -24,13 +24,15 @@ import java.util.List;
import net.jami.model.Uri;
import net.jami.mvp.BaseView;
import io.reactivex.disposables.CompositeDisposable;
public interface SmartListView extends BaseView {
void displayChooseNumberDialog(CharSequence numbers[]);
void displayChooseNumberDialog(CharSequence[] numbers);
void displayNoConversationMessage();
void displayConversationDialog(net.jami.smartlist.SmartListViewModel smartListViewModel);
void displayConversationDialog(SmartListViewModel smartListViewModel);
void displayClearDialog(Uri callContact);
......@@ -46,7 +48,7 @@ public interface SmartListView extends BaseView {
void hideNoConversationMessage();
void updateList(List<net.jami.smartlist.SmartListViewModel> smartListViewModels);
void updateList(List<SmartListViewModel> smartListViewModels, CompositeDisposable parentDisposable);
void update(SmartListViewModel model);
void update(int position);
......
......@@ -49,6 +49,7 @@ public class SmartListViewModel
private final boolean showPresence;
private boolean isOnline = false;
private boolean isChecked = false;
private Observable<Boolean> isSelected = null;
private final Interaction lastEvent;
public enum Title {
......@@ -94,6 +95,7 @@ public class SmartListViewModel
hasUnreadTextMessage = (lastEvent != null) && !lastEvent.isRead();
this.hasOngoingCall = false;
this.lastEvent = lastEvent;
isSelected = conversation.getVisible();
for (Contact contact : contacts) {
if (contact.isUser())
continue;
......@@ -172,6 +174,8 @@ public class SmartListViewModel
isChecked = checked;
}
public Observable<Boolean> getSelected() { return isSelected; }
public void setHasOngoingCall(boolean hasOngoingCall) {
this.hasOngoingCall = hasOngoingCall;
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment