Enable end-conversation by swipe gesture

Add EnhancedListView library de.timroes.android:EnhancedListView:0.3.4
to enable swipe-out for ListViews

Re-enable selectableItemBackground

Dont end selectedConversation on swipe

Call mConversationFragment.reinit() instead.
Add separate undo string for swipe MUC.

Add blacklistedConversation for undo swipe

Update title_undo_swipe_* strings

Fix undo(), rename blacklistedConversation

Fix discardUndo(); re-init selectedConversation

maintain scroll position after undo

clear notification when dismissing a conversation

modified / simplified maintain scroll position code

simplify handling of selectedConversation

change undo_muc string, remove notifyDataSetChanged()
This commit is contained in:
BrianBlade 2015-04-03 00:06:37 +02:00
parent 59ea143147
commit dace8ba3d3
9 changed files with 185 additions and 71 deletions

View File

@ -34,6 +34,7 @@ dependencies {
compile 'com.google.zxing:core:3.1.0' compile 'com.google.zxing:core:3.1.0'
compile 'com.google.zxing:android-integration:3.1.0' compile 'com.google.zxing:android-integration:3.1.0'
compile 'de.measite.minidns:minidns:0.1.3' compile 'de.measite.minidns:minidns:0.1.3'
compile 'de.timroes.android:EnhancedListView:0.3.4'
} }
android { android {

View File

@ -1129,6 +1129,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
} }
public void archiveConversation(Conversation conversation) { public void archiveConversation(Conversation conversation) {
getNotificationService().clear(conversation);
conversation.setStatus(Conversation.STATUS_ARCHIVED); conversation.setStatus(Conversation.STATUS_ARCHIVED);
conversation.setNextEncryption(-1); conversation.setNextEncryption(-1);
synchronized (this.conversations) { synchronized (this.conversations) {

View File

@ -22,12 +22,12 @@ import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener; import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter; import android.widget.ArrayAdapter;
import android.widget.CheckBox; import android.widget.CheckBox;
import android.widget.ListView;
import android.widget.PopupMenu; import android.widget.PopupMenu;
import android.widget.PopupMenu.OnMenuItemClickListener; import android.widget.PopupMenu.OnMenuItemClickListener;
import android.widget.Toast; import android.widget.Toast;
import net.java.otr4j.session.SessionStatus; import net.java.otr4j.session.SessionStatus;
import de.timroes.android.listview.EnhancedListView;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -76,8 +76,9 @@ public class ConversationActivity extends XmppActivity
private View mContentView; private View mContentView;
private List<Conversation> conversationList = new ArrayList<>(); private List<Conversation> conversationList = new ArrayList<>();
private Conversation swipedConversation = null;
private Conversation mSelectedConversation = null; private Conversation mSelectedConversation = null;
private ListView listView; private EnhancedListView listView;
private ConversationFragment mConversationFragment; private ConversationFragment mConversationFragment;
private ArrayAdapter<Conversation> listAdapter; private ArrayAdapter<Conversation> listAdapter;
@ -156,7 +157,7 @@ public class ConversationActivity extends XmppActivity
transaction.replace(R.id.selected_conversation, this.mConversationFragment, "conversation"); transaction.replace(R.id.selected_conversation, this.mConversationFragment, "conversation");
transaction.commit(); transaction.commit();
listView = (ListView) findViewById(R.id.list); listView = (EnhancedListView) findViewById(R.id.list);
this.listAdapter = new ConversationAdapter(this, conversationList); this.listAdapter = new ConversationAdapter(this, conversationList);
listView.setAdapter(this.listAdapter); listView.setAdapter(this.listAdapter);
@ -178,6 +179,73 @@ public class ConversationActivity extends XmppActivity
openConversation(); openConversation();
} }
}); });
listView.setDismissCallback(new EnhancedListView.OnDismissCallback() {
@Override
public EnhancedListView.Undoable onDismiss(final EnhancedListView enhancedListView, final int position) {
final int index = listView.getFirstVisiblePosition();
View v = listView.getChildAt(0);
final int top = (v == null) ? 0 : (v.getTop() - listView.getPaddingTop());
swipedConversation = listAdapter.getItem(position);
listAdapter.remove(swipedConversation);
swipedConversation.markRead();
xmppConnectionService.getNotificationService().clear(swipedConversation);
final boolean formerlySelected = (getSelectedConversation() == swipedConversation);
if (position == 0 && listAdapter.getCount() == 0) {
endConversation(swipedConversation, false, true);
return null;
} else if (formerlySelected) {
setSelectedConversation(listAdapter.getItem(0));
ConversationActivity.this.mConversationFragment
.reInit(getSelectedConversation());
}
return new EnhancedListView.Undoable() {
@Override
public void undo() {
listAdapter.insert(swipedConversation, position);
if (formerlySelected) {
setSelectedConversation(swipedConversation);
ConversationActivity.this.mConversationFragment
.reInit(getSelectedConversation());
}
swipedConversation = null;
listView.setSelectionFromTop(index + (listView.getChildCount() < position ? 1 : 0), top);
}
@Override
public void discard() {
if (!swipedConversation.isRead()
&& swipedConversation.getMode() == Conversation.MODE_SINGLE) {
swipedConversation = null;
return;
}
endConversation(swipedConversation, false, false);
swipedConversation = null;
}
@Override
public String getTitle() {
if (swipedConversation.getMode() == Conversation.MODE_MULTI) {
return getResources().getString(R.string.title_undo_swipe_out_muc);
} else {
return getResources().getString(R.string.title_undo_swipe_out_conversation);
}
}
};
}
});
listView.enableSwipeToDismiss();
listView.setSwipingLayout(R.id.swipeable_item);
listView.setUndoStyle(EnhancedListView.UndoStyle.SINGLE_POPUP);
listView.setUndoHideDelay(3000);
listView.setRequireTouchBeforeDismiss(false);
mContentView = findViewById(R.id.content_view_spl); mContentView = findViewById(R.id.content_view_spl);
if (mContentView == null) { if (mContentView == null) {
mContentView = findViewById(R.id.content_view_ll); mContentView = findViewById(R.id.content_view_ll);
@ -204,6 +272,7 @@ public class ConversationActivity extends XmppActivity
@Override @Override
public void onPanelClosed(View arg0) { public void onPanelClosed(View arg0) {
listView.discardUndo();
openConversation(); openConversation();
} }
@ -485,13 +554,21 @@ public class ConversationActivity extends XmppActivity
} }
public void endConversation(Conversation conversation) { public void endConversation(Conversation conversation) {
showConversationsOverview(); endConversation(conversation, true, true);
}
public void endConversation(Conversation conversation, boolean showOverview, boolean reinit) {
if (showOverview) {
showConversationsOverview();
}
xmppConnectionService.archiveConversation(conversation); xmppConnectionService.archiveConversation(conversation);
if (conversationList.size() > 0) { if (reinit) {
setSelectedConversation(conversationList.get(0)); if (conversationList.size() > 0) {
this.mConversationFragment.reInit(getSelectedConversation()); setSelectedConversation(conversationList.get(0));
} else { this.mConversationFragment.reInit(getSelectedConversation());
setSelectedConversation(null); } else {
setSelectedConversation(null);
}
} }
} }
@ -744,6 +821,7 @@ public class ConversationActivity extends XmppActivity
@Override @Override
public void onPause() { public void onPause() {
listView.discardUndo();
super.onPause(); super.onPause();
this.mActivityPaused = true; this.mActivityPaused = true;
if (this.xmppConnectionServiceBound) { if (this.xmppConnectionServiceBound) {
@ -1013,6 +1091,13 @@ public class ConversationActivity extends XmppActivity
public void updateConversationList() { public void updateConversationList() {
xmppConnectionService xmppConnectionService
.populateWithOrderedConversations(conversationList); .populateWithOrderedConversations(conversationList);
if (swipedConversation != null) {
if (swipedConversation.isRead()) {
conversationList.remove(swipedConversation);
} else {
listView.discardUndo();
}
}
listAdapter.notifyDataSetChanged(); listAdapter.notifyDataSetChanged();
} }

View File

@ -12,7 +12,7 @@
android:background="@color/primarybackground" android:background="@color/primarybackground"
android:orientation="vertical" > android:orientation="vertical" >
<ListView <de.timroes.android.listview.EnhancedListView
android:id="@+id/list" android:id="@+id/list"
android:layout_width="fill_parent" android:layout_width="fill_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"

View File

@ -1,68 +1,86 @@
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent" android:layout_width="fill_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="horizontal" android:descendantFocusability="blocksDescendants">
android:padding="8dp" >
<ImageView <View
android:id="@+id/conversation_image" android:layout_width="fill_parent"
android:layout_width="56dp" android:layout_height="fill_parent"
android:layout_height="56dp" android:background="@color/divider"/>
android:layout_alignParentLeft="true"
android:scaleType="centerCrop" />
<RelativeLayout <FrameLayout
android:layout_width="fill_parent" android:id="@+id/swipeable_item"
android:layout_height="wrap_content" android:layout_width="fill_parent"
android:layout_centerVertical="true" android:layout_height="fill_parent"
android:layout_toRightOf="@+id/conversation_image" android:background="@color/primarybackground">
android:paddingLeft="8dp" >
<TextView <RelativeLayout
android:id="@+id/conversation_name" android:layout_width="fill_parent"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:layout_height="wrap_content" android:background="?android:selectableItemBackground"
android:layout_alignLeft="@+id/conversation_lastwrapper" android:orientation="horizontal"
android:layout_toLeftOf="@+id/conversation_lastupdate" android:padding="8dp" >
android:singleLine="true"
android:textColor="@color/primarytext"
android:textSize="?attr/TextSizeHeadline"
android:typeface="sans" />
<LinearLayout <ImageView
android:id="@+id/conversation_lastwrapper" android:id="@+id/conversation_image"
android:layout_width="fill_parent" android:layout_width="56dp"
android:layout_height="wrap_content" android:layout_height="56dp"
android:layout_below="@id/conversation_name" android:layout_alignParentLeft="true"
android:orientation="vertical" android:scaleType="centerCrop" />
android:paddingTop="3dp" >
<TextView <RelativeLayout
android:id="@+id/conversation_lastmsg" android:layout_width="fill_parent"
android:layout_width="fill_parent" android:layout_height="wrap_content"
android:layout_height="wrap_content" android:layout_centerVertical="true"
android:scrollHorizontally="false" android:layout_toRightOf="@+id/conversation_image"
android:singleLine="true" android:paddingLeft="8dp" >
android:textColor="@color/primarytext"
android:textSize="?attr/TextSizeBody" />
<ImageView <TextView
android:id="@+id/conversation_lastimage" android:id="@+id/conversation_name"
android:layout_width="fill_parent" android:layout_width="wrap_content"
android:layout_height="36dp" android:layout_height="wrap_content"
android:background="@color/primarytext" android:layout_alignLeft="@+id/conversation_lastwrapper"
android:scaleType="centerCrop" /> android:layout_toLeftOf="@+id/conversation_lastupdate"
</LinearLayout> android:singleLine="true"
android:textColor="@color/primarytext"
android:textSize="?attr/TextSizeHeadline"
android:typeface="sans" />
<TextView <LinearLayout
android:id="@+id/conversation_lastupdate" android:id="@+id/conversation_lastwrapper"
android:layout_width="wrap_content" android:layout_width="fill_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_alignBaseline="@+id/conversation_name" android:layout_below="@id/conversation_name"
android:layout_alignParentRight="true" android:orientation="vertical"
android:gravity="right" android:paddingTop="3dp" >
android:textColor="@color/secondarytext"
android:textSize="?attr/TextSizeInfo" />
</RelativeLayout>
</RelativeLayout> <TextView
android:id="@+id/conversation_lastmsg"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:scrollHorizontally="false"
android:singleLine="true"
android:textColor="@color/primarytext"
android:textSize="?attr/TextSizeBody" />
<ImageView
android:id="@+id/conversation_lastimage"
android:layout_width="fill_parent"
android:layout_height="36dp"
android:background="@color/primarytext"
android:scaleType="centerCrop" />
</LinearLayout>
<TextView
android:id="@+id/conversation_lastupdate"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBaseline="@+id/conversation_name"
android:layout_alignParentRight="true"
android:gravity="right"
android:textColor="@color/secondarytext"
android:textSize="?attr/TextSizeInfo" />
</RelativeLayout>
</RelativeLayout>
</FrameLayout>
</FrameLayout>

View File

@ -10,7 +10,7 @@
android:background="@color/primarybackground" android:background="@color/primarybackground"
android:orientation="vertical" > android:orientation="vertical" >
<ListView <de.timroes.android.listview.EnhancedListView
android:id="@+id/list" android:id="@+id/list"
android:layout_width="fill_parent" android:layout_width="fill_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"

View File

@ -427,6 +427,8 @@
<string name="no_application_found_to_display_location">Keine App für die Standort-Anzeige gefunden</string> <string name="no_application_found_to_display_location">Keine App für die Standort-Anzeige gefunden</string>
<string name="location">Standort</string> <string name="location">Standort</string>
<string name="received_location">Standort empfangen</string> <string name="received_location">Standort empfangen</string>
<string name="title_undo_swipe_out_conversation">Unterhaltung beendet</string>
<string name="title_undo_swipe_out_muc">Konferenz verlassen</string>
<plurals name="select_contact"> <plurals name="select_contact">
<item quantity="one">%d Kontakt ausgewählt</item> <item quantity="one">%d Kontakt ausgewählt</item>
<item quantity="other">%d Kontakte ausgewählt</item> <item quantity="other">%d Kontakte ausgewählt</item>

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<dimen name="elv_undo_bottom_offset">63dp</dimen> <!-- 48dp + 15dp -->
</resources>

View File

@ -296,6 +296,7 @@
\n\nhttps://developer.android.com/tools/support-library\n(Apache License, Version 2.0) \n\nhttps://developer.android.com/tools/support-library\n(Apache License, Version 2.0)
\n\nhttps://github.com/zxing/zxing\n(Apache License, Version 2.0) \n\nhttps://github.com/zxing/zxing\n(Apache License, Version 2.0)
\n\nhttps://github.com/google/material-design-icons\n(CC BY 4.0) \n\nhttps://github.com/google/material-design-icons\n(CC BY 4.0)
\n\nhttps://github.com/timroes/EnhancedListView\n(Apache License, Version 2.0)
</string> </string>
<string name="title_pref_quiet_hours">Quiet Hours</string> <string name="title_pref_quiet_hours">Quiet Hours</string>
<string name="title_pref_quiet_hours_start_time">Start time</string> <string name="title_pref_quiet_hours_start_time">Start time</string>
@ -454,6 +455,8 @@
<string name="no_application_found_to_display_location">No application found to display location</string> <string name="no_application_found_to_display_location">No application found to display location</string>
<string name="location">Location</string> <string name="location">Location</string>
<string name="received_location">Received location</string> <string name="received_location">Received location</string>
<string name="title_undo_swipe_out_conversation">Conversation closed</string>
<string name="title_undo_swipe_out_muc">Left conference</string>
<plurals name="select_contact"> <plurals name="select_contact">
<item quantity="one">Select %d contact</item> <item quantity="one">Select %d contact</item>
<item quantity="other">Select %d contacts</item> <item quantity="other">Select %d contacts</item>