@ -173,6 +173,16 @@
|
|||||||
|
|
||||||
</activity-alias>
|
</activity-alias>
|
||||||
|
|
||||||
|
<activity android:name=".ConversationListArchiveActivity"
|
||||||
|
android:label="@string/AndroidManifeset_conversations_archive"
|
||||||
|
android:launchMode="singleTask"
|
||||||
|
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"
|
||||||
|
android:parentActivityName=".ConversationListActivity">
|
||||||
|
<meta-data
|
||||||
|
android:name="android.support.PARENT_ACTIVITY"
|
||||||
|
android:value="org.thoughtcrime.securesms.ConversationListActivity" />
|
||||||
|
</activity>
|
||||||
|
|
||||||
<activity android:name=".ConversationActivity"
|
<activity android:name=".ConversationActivity"
|
||||||
android:windowSoftInputMode="stateUnchanged"
|
android:windowSoftInputMode="stateUnchanged"
|
||||||
android:launchMode="singleTask"
|
android:launchMode="singleTask"
|
||||||
|
BIN
res/drawable-hdpi/ic_archive_white_24dp.png
Normal file
After Width: | Height: | Size: 247 B |
BIN
res/drawable-hdpi/ic_unarchive_white_24dp.png
Normal file
After Width: | Height: | Size: 258 B |
BIN
res/drawable-hdpi/ic_unarchive_white_36dp.png
Normal file
After Width: | Height: | Size: 354 B |
BIN
res/drawable-mdpi/ic_archive_white_24dp.png
Normal file
After Width: | Height: | Size: 181 B |
BIN
res/drawable-mdpi/ic_unarchive_white_24dp.png
Normal file
After Width: | Height: | Size: 181 B |
BIN
res/drawable-mdpi/ic_unarchive_white_36dp.png
Normal file
After Width: | Height: | Size: 258 B |
11
res/drawable-v21/conversation_list_item_read_background.xml
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:color="@color/textsecure_primary">
|
||||||
|
<item android:id="@android:id/mask" android:drawable="@android:color/black" />
|
||||||
|
<item>
|
||||||
|
<selector>
|
||||||
|
<item android:drawable="@color/textsecure_primary_alpha33" android:state_selected="true" />
|
||||||
|
<item android:drawable="@color/conversation_list_item_background_read_light" />
|
||||||
|
</selector>
|
||||||
|
</item>
|
||||||
|
</ripple>
|
@ -5,6 +5,7 @@
|
|||||||
<item>
|
<item>
|
||||||
<selector>
|
<selector>
|
||||||
<item android:drawable="@color/textsecure_primary_alpha33" android:state_selected="true" />
|
<item android:drawable="@color/textsecure_primary_alpha33" android:state_selected="true" />
|
||||||
|
<item android:drawable="@color/conversation_list_item_background_read_dark" />
|
||||||
</selector>
|
</selector>
|
||||||
</item>
|
</item>
|
||||||
</ripple>
|
</ripple>
|
BIN
res/drawable-xhdpi/ic_archive_white_24dp.png
Normal file
After Width: | Height: | Size: 267 B |
BIN
res/drawable-xhdpi/ic_unarchive_white_24dp.png
Normal file
After Width: | Height: | Size: 273 B |
BIN
res/drawable-xhdpi/ic_unarchive_white_36dp.png
Normal file
After Width: | Height: | Size: 391 B |
BIN
res/drawable-xxhdpi/ic_archive_white_24dp.png
Normal file
After Width: | Height: | Size: 390 B |
BIN
res/drawable-xxhdpi/ic_unarchive_white_24dp.png
Normal file
After Width: | Height: | Size: 391 B |
BIN
res/drawable-xxhdpi/ic_unarchive_white_36dp.png
Normal file
After Width: | Height: | Size: 600 B |
BIN
res/drawable-xxxhdpi/ic_archive_white_24dp.png
Normal file
After Width: | Height: | Size: 489 B |
BIN
res/drawable-xxxhdpi/ic_archive_white_36dp.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
res/drawable-xxxhdpi/ic_archive_white_48dp.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
res/drawable-xxxhdpi/ic_unarchive_white_24dp.png
Normal file
After Width: | Height: | Size: 503 B |
BIN
res/drawable-xxxhdpi/ic_unarchive_white_36dp.png
Normal file
After Width: | Height: | Size: 753 B |
6
res/drawable/conversation_list_item_read_background.xml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item android:drawable="@color/textsecure_primary_alpha33" android:state_selected="true" />
|
||||||
|
<item android:drawable="@color/textsecure_primary_alpha33" android:state_pressed="true" />
|
||||||
|
<item android:drawable="@color/conversation_list_item_background_read_light" />
|
||||||
|
</selector>
|
@ -2,4 +2,5 @@
|
|||||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<item android:drawable="@color/textsecure_primary_alpha33" android:state_selected="true" />
|
<item android:drawable="@color/textsecure_primary_alpha33" android:state_selected="true" />
|
||||||
<item android:drawable="@color/textsecure_primary_alpha33" android:state_pressed="true" />
|
<item android:drawable="@color/textsecure_primary_alpha33" android:state_pressed="true" />
|
||||||
|
<item android:drawable="@color/conversation_list_item_background_read_dark" />
|
||||||
</selector>
|
</selector>
|
7
res/drawable/rounded_rectangle.xml
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle" >
|
||||||
|
<solid android:color="@color/transparent"/>
|
||||||
|
<stroke android:width="1dp" android:color="#ffbbbbbb"/>
|
||||||
|
<corners android:radius="5dp"/>
|
||||||
|
<padding android:bottom="5dp" android:left="5dp" android:right="5dp" android:top="5dp"/>
|
||||||
|
</shape>
|
@ -8,7 +8,6 @@
|
|||||||
android:layout_height="?android:attr/listPreferredItemHeight"
|
android:layout_height="?android:attr/listPreferredItemHeight"
|
||||||
android:orientation="horizontal"
|
android:orientation="horizontal"
|
||||||
android:gravity="center_vertical"
|
android:gravity="center_vertical"
|
||||||
android:background="@drawable/conversation_list_item_background"
|
|
||||||
android:paddingLeft="48dp"
|
android:paddingLeft="48dp"
|
||||||
android:paddingRight="20dp">
|
android:paddingRight="20dp">
|
||||||
|
|
||||||
@ -18,7 +17,7 @@
|
|||||||
android:layout_height="40dp"
|
android:layout_height="40dp"
|
||||||
android:foreground="@drawable/contact_photo_background"
|
android:foreground="@drawable/contact_photo_background"
|
||||||
android:cropToPadding="true"
|
android:cropToPadding="true"
|
||||||
tools:src="@color/md_material_blue_600"
|
tools:src="@color/blue_600"
|
||||||
android:layout_marginRight="10dp"
|
android:layout_marginRight="10dp"
|
||||||
android:contentDescription="@string/SingleContactSelectionActivity_contact_photo" />
|
android:contentDescription="@string/SingleContactSelectionActivity_contact_photo" />
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
|
||||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<android.support.design.widget.CoordinatorLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
xmlns:fab="http://schemas.android.com/apk/res-auto"
|
xmlns:fab="http://schemas.android.com/apk/res-auto"
|
||||||
android:layout_width="fill_parent"
|
android:layout_width="fill_parent"
|
||||||
@ -27,7 +28,7 @@
|
|||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<com.melnykov.fab.FloatingActionButton
|
<android.support.design.widget.FloatingActionButton
|
||||||
android:id="@+id/fab"
|
android:id="@+id/fab"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
@ -35,9 +36,6 @@
|
|||||||
android:layout_margin="16dp"
|
android:layout_margin="16dp"
|
||||||
android:src="@drawable/ic_create_white_24dp"
|
android:src="@drawable/ic_create_white_24dp"
|
||||||
android:focusable="true"
|
android:focusable="true"
|
||||||
android:contentDescription="@string/conversation_list_fragment__fab_content_description"
|
android:contentDescription="@string/conversation_list_fragment__fab_content_description"/>
|
||||||
fab:fab_colorNormal="?fab_color"
|
|
||||||
fab:fab_colorPressed="@color/textsecure_primary_dark"
|
|
||||||
fab:fab_colorRipple="@color/textsecure_primary_dark" />
|
|
||||||
|
|
||||||
</FrameLayout>
|
</android.support.design.widget.CoordinatorLayout>
|
||||||
|
17
res/layout/conversation_list_item_action.xml
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<org.thoughtcrime.securesms.ConversationListItemAction
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="70dp">
|
||||||
|
|
||||||
|
<TextView android:id="@+id/description"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:gravity="center"
|
||||||
|
android:textSize="14sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
tools:text="Archived conversations (2)"/>
|
||||||
|
|
||||||
|
</org.thoughtcrime.securesms.ConversationListItemAction>
|
@ -4,7 +4,6 @@
|
|||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:background="@drawable/conversation_list_item_background"
|
|
||||||
android:layout_height="70dp">
|
android:layout_height="70dp">
|
||||||
|
|
||||||
<org.thoughtcrime.securesms.components.AvatarImageView
|
<org.thoughtcrime.securesms.components.AvatarImageView
|
||||||
@ -62,6 +61,7 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_below="@id/from"
|
android:layout_below="@id/from"
|
||||||
android:layout_toRightOf="@id/error"
|
android:layout_toRightOf="@id/error"
|
||||||
|
android:layout_toLeftOf="@+id/archived"
|
||||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||||
android:textColor="?attr/conversation_list_item_subject_color"
|
android:textColor="?attr/conversation_list_item_subject_color"
|
||||||
android:fontFamily="sans-serif-light"
|
android:fontFamily="sans-serif-light"
|
||||||
@ -98,5 +98,19 @@
|
|||||||
tools:text="30 mins"
|
tools:text="30 mins"
|
||||||
android:singleLine="true"/>
|
android:singleLine="true"/>
|
||||||
|
|
||||||
|
<TextView android:id="@+id/archived"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_below="@id/date"
|
||||||
|
android:layout_alignParentRight="true"
|
||||||
|
android:layout_alignBaseline="@id/subject"
|
||||||
|
android:layout_marginLeft="5dp"
|
||||||
|
android:text="@string/conversation_list_item_view__archived"
|
||||||
|
android:textColor="#ffbbbbbb"
|
||||||
|
android:background="@drawable/rounded_rectangle"
|
||||||
|
android:textSize="12sp"
|
||||||
|
/>
|
||||||
|
|
||||||
|
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
</org.thoughtcrime.securesms.ConversationListItem>
|
</org.thoughtcrime.securesms.ConversationListItem>
|
||||||
|
@ -7,9 +7,6 @@
|
|||||||
<item android:title="@string/conversation__menu_view_media"
|
<item android:title="@string/conversation__menu_view_media"
|
||||||
android:id="@+id/menu_view_media" />
|
android:id="@+id/menu_view_media" />
|
||||||
|
|
||||||
<item android:title="@string/conversation__menu_delete_thread"
|
|
||||||
android:id="@+id/menu_delete_thread" />
|
|
||||||
|
|
||||||
<item android:title="@string/conversation__menu_conversation_settings"
|
<item android:title="@string/conversation__menu_conversation_settings"
|
||||||
android:id="@+id/menu_conversation_settings"/>
|
android:id="@+id/menu_conversation_settings"/>
|
||||||
|
|
||||||
|
@ -5,10 +5,11 @@
|
|||||||
<item android:title="@string/conversation_list_batch__menu_delete_selected"
|
<item android:title="@string/conversation_list_batch__menu_delete_selected"
|
||||||
android:id="@+id/menu_delete_selected"
|
android:id="@+id/menu_delete_selected"
|
||||||
android:icon="?menu_trash_icon"
|
android:icon="?menu_trash_icon"
|
||||||
app:showAsAction="ifRoom" />
|
app:showAsAction="always" />
|
||||||
|
|
||||||
<item android:title="@string/conversation_list_batch__menu_select_all"
|
<item android:title="@string/conversation_list_batch__menu_select_all"
|
||||||
android:id="@+id/menu_select_all"
|
android:id="@+id/menu_select_all"
|
||||||
android:icon="?menu_selectall_icon" />
|
android:icon="?menu_selectall_icon"
|
||||||
|
app:showAsAction="always"/>
|
||||||
|
|
||||||
</menu>
|
</menu>
|
10
res/menu/conversation_list_batch_archive.xml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||||
|
|
||||||
|
<item android:title="@string/conversation_list_batch__archive_selected"
|
||||||
|
android:id="@+id/menu_archive_selected"
|
||||||
|
android:icon="@drawable/ic_archive_white_24dp"
|
||||||
|
app:showAsAction="always"/>
|
||||||
|
|
||||||
|
</menu>
|
10
res/menu/conversation_list_batch_unarchive.xml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||||
|
|
||||||
|
<item android:title="@string/conversation_list_batch__archive_selected"
|
||||||
|
android:id="@+id/menu_archive_selected"
|
||||||
|
android:icon="@drawable/ic_unarchive_white_24dp"
|
||||||
|
app:showAsAction="always"/>
|
||||||
|
|
||||||
|
</menu>
|
@ -24,7 +24,7 @@
|
|||||||
|
|
||||||
<color name="gray95_transparent50">#7F111111</color>
|
<color name="gray95_transparent50">#7F111111</color>
|
||||||
|
|
||||||
<color name="conversation_list_item_background_read_light">#ffffffff</color>
|
<color name="conversation_list_item_background_read_light">@color/gray5</color>
|
||||||
<color name="conversation_list_item_background_unread_light">#ffffffff</color>
|
<color name="conversation_list_item_background_unread_light">#ffffffff</color>
|
||||||
<color name="conversation_list_item_background_read_dark">#ff000000</color>
|
<color name="conversation_list_item_background_read_dark">#ff000000</color>
|
||||||
<color name="conversation_list_item_background_unread_dark">#ff333333</color>
|
<color name="conversation_list_item_background_unread_dark">#ff333333</color>
|
||||||
|
@ -37,6 +37,7 @@
|
|||||||
|
|
||||||
<dimen name="transfer_controls_expanded_width">150dp</dimen>
|
<dimen name="transfer_controls_expanded_width">150dp</dimen>
|
||||||
<dimen name="transfer_controls_contracted_width">70dp</dimen>
|
<dimen name="transfer_controls_contracted_width">70dp</dimen>
|
||||||
|
<dimen name="conversation_list_fragment_archive_padding">16dp</dimen>
|
||||||
|
|
||||||
<!-- RedPhone -->
|
<!-- RedPhone -->
|
||||||
<dimen name="incoming_widget_outer_radius">135dip</dimen>
|
<dimen name="incoming_widget_outer_radius">135dip</dimen>
|
||||||
|
@ -174,10 +174,18 @@
|
|||||||
</plurals>
|
</plurals>
|
||||||
<string name="ConversationListFragment_deleting">Deleting</string>
|
<string name="ConversationListFragment_deleting">Deleting</string>
|
||||||
<string name="ConversationListFragment_deleting_selected_threads">Deleting selected threads...</string>
|
<string name="ConversationListFragment_deleting_selected_threads">Deleting selected threads...</string>
|
||||||
|
<string name="ConversationListFragment_archived_conversations">Archived conversations</string>
|
||||||
|
<string name="ConversationListFragment_undo">UNDO</string>
|
||||||
|
<string name="ConversationListFragment_moved_conversation_to_inbox">Moved conversation to inbox</string>
|
||||||
|
<string name="ConversationListFragment_archived_conversation">Archived conversation</string>
|
||||||
|
<string name="ConversationListFragment_moved_conversations_to_inbox">Moved conversations to inbox</string>
|
||||||
|
|
||||||
<!-- ConversationListItem -->
|
<!-- ConversationListItem -->
|
||||||
<string name="ConversationListItem_key_exchange_message">Key exchange message...</string>
|
<string name="ConversationListItem_key_exchange_message">Key exchange message...</string>
|
||||||
|
|
||||||
|
<!-- ConversationListItemAction -->
|
||||||
|
<string name="ConversationListItemAction_archived_conversations_d">Archived conversations (%d)</string>
|
||||||
|
|
||||||
<!-- CustomDefaultPreference -->
|
<!-- CustomDefaultPreference -->
|
||||||
<string name="CustomDefaultPreference_using_custom">Using custom: %s</string>
|
<string name="CustomDefaultPreference_using_custom">Using custom: %s</string>
|
||||||
<string name="CustomDefaultPreference_using_default">Using default: %s</string>
|
<string name="CustomDefaultPreference_using_default">Using default: %s</string>
|
||||||
@ -867,6 +875,7 @@
|
|||||||
<string name="AndroidManifest__message_details">Message details</string>
|
<string name="AndroidManifest__message_details">Message details</string>
|
||||||
<string name="AndroidManifest_manage_linked_devices">Manage linked devices</string>
|
<string name="AndroidManifest_manage_linked_devices">Manage linked devices</string>
|
||||||
<string name="AndroidManifest__invite_friends">Invite friends</string>
|
<string name="AndroidManifest__invite_friends">Invite friends</string>
|
||||||
|
<string name="AndroidManifeset_conversations_archive">Conversations archive</string>
|
||||||
|
|
||||||
<!-- arrays.xml -->
|
<!-- arrays.xml -->
|
||||||
<string name="arrays__import_export">Import / export</string>
|
<string name="arrays__import_export">Import / export</string>
|
||||||
@ -1048,6 +1057,7 @@
|
|||||||
<!-- conversation_list_batch -->
|
<!-- conversation_list_batch -->
|
||||||
<string name="conversation_list_batch__menu_delete_selected">Delete selected</string>
|
<string name="conversation_list_batch__menu_delete_selected">Delete selected</string>
|
||||||
<string name="conversation_list_batch__menu_select_all">Select all</string>
|
<string name="conversation_list_batch__menu_select_all">Select all</string>
|
||||||
|
<string name="conversation_list_batch__archive_selected">Archive selected</string>
|
||||||
|
|
||||||
<!-- conversation_list -->
|
<!-- conversation_list -->
|
||||||
<string name="conversation_list__menu_search">Search</string>
|
<string name="conversation_list__menu_search">Search</string>
|
||||||
@ -1055,6 +1065,7 @@
|
|||||||
<!-- conversation_list_item_view -->
|
<!-- conversation_list_item_view -->
|
||||||
<string name="conversation_list_item_view__contact_photo_image">Contact Photo Image</string>
|
<string name="conversation_list_item_view__contact_photo_image">Contact Photo Image</string>
|
||||||
<string name="conversation_list_item_view__error_alert">Error alert</string>
|
<string name="conversation_list_item_view__error_alert">Error alert</string>
|
||||||
|
<string name="conversation_list_item_view__archived">Archived</string>
|
||||||
|
|
||||||
<!-- conversation_list_fragment -->
|
<!-- conversation_list_fragment -->
|
||||||
<string name="conversation_list_fragment__fab_content_description">New conversation</string>
|
<string name="conversation_list_fragment__fab_content_description">New conversation</string>
|
||||||
@ -1151,6 +1162,7 @@
|
|||||||
<!-- transport_selection_list_item -->
|
<!-- transport_selection_list_item -->
|
||||||
<string name="transport_selection_list_item__transport_icon">Transport icon</string>
|
<string name="transport_selection_list_item__transport_icon">Transport icon</string>
|
||||||
|
|
||||||
|
|
||||||
<!-- EOF -->
|
<!-- EOF -->
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -95,7 +95,7 @@
|
|||||||
<item name="attachment_type_selector_background">@color/white</item>
|
<item name="attachment_type_selector_background">@color/white</item>
|
||||||
<item name="conversation_list_item_background_selected">@drawable/list_selected_holo_light</item>
|
<item name="conversation_list_item_background_selected">@drawable/list_selected_holo_light</item>
|
||||||
<item name="conversation_list_item_background_unread">@drawable/conversation_list_item_unread_background</item>
|
<item name="conversation_list_item_background_unread">@drawable/conversation_list_item_unread_background</item>
|
||||||
<item name="conversation_list_item_background_read">@drawable/conversation_list_item_background</item>
|
<item name="conversation_list_item_background_read">@drawable/conversation_list_item_read_background</item>
|
||||||
<item name="conversation_list_item_count_color">#66333333</item>
|
<item name="conversation_list_item_count_color">#66333333</item>
|
||||||
<item name="conversation_list_item_contact_color">#FF333333</item>
|
<item name="conversation_list_item_contact_color">#FF333333</item>
|
||||||
<item name="conversation_list_item_subject_color">#FF444444</item>
|
<item name="conversation_list_item_subject_color">#FF444444</item>
|
||||||
@ -205,12 +205,13 @@
|
|||||||
<item name="actionBarPopupTheme">@style/ThemeOverlay.AppCompat.Dark</item>
|
<item name="actionBarPopupTheme">@style/ThemeOverlay.AppCompat.Dark</item>
|
||||||
<item name="android:textColor">@color/text_color_dark_theme</item>
|
<item name="android:textColor">@color/text_color_dark_theme</item>
|
||||||
<item name="android:textColorSecondary">@color/text_color_secondary_dark_theme</item>
|
<item name="android:textColorSecondary">@color/text_color_secondary_dark_theme</item>
|
||||||
|
<item name="colorAccent">@color/textsecure_primary_dark</item>
|
||||||
<item name="colorControlActivated">@color/signal_primary_dark</item>
|
<item name="colorControlActivated">@color/signal_primary_dark</item>
|
||||||
<item name="colorControlHighlight">@color/signal_primary_dark</item>
|
<item name="colorControlHighlight">@color/signal_primary_dark</item>
|
||||||
<item name="android:windowBackground">@color/black</item>
|
<item name="android:windowBackground">@color/black</item>
|
||||||
<item name="conversation_list_item_background_selected">@drawable/list_selected_holo_dark</item>
|
<item name="conversation_list_item_background_selected">@drawable/list_selected_holo_dark</item>
|
||||||
<item name="conversation_list_item_background_unread">@drawable/conversation_list_item_unread_background_dark</item>
|
<item name="conversation_list_item_background_unread">@drawable/conversation_list_item_unread_background_dark</item>
|
||||||
<item name="conversation_list_item_background_read">@drawable/conversation_list_item_background</item>
|
<item name="conversation_list_item_background_read">@drawable/conversation_list_item_read_background_dark</item>
|
||||||
<item name="conversation_list_item_count_color">#66dddddd</item>
|
<item name="conversation_list_item_count_color">#66dddddd</item>
|
||||||
<item name="conversation_list_item_contact_color">#ffdddddd</item>
|
<item name="conversation_list_item_contact_color">#ffdddddd</item>
|
||||||
<item name="conversation_list_item_subject_color">#ffdddddd</item>
|
<item name="conversation_list_item_subject_color">#ffdddddd</item>
|
||||||
|
@ -0,0 +1,15 @@
|
|||||||
|
package org.thoughtcrime.securesms;
|
||||||
|
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
|
||||||
|
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||||
|
import org.thoughtcrime.securesms.database.model.ThreadRecord;
|
||||||
|
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public interface BindableConversationListItem extends Unbindable {
|
||||||
|
|
||||||
|
public void bind(@NonNull MasterSecret masterSecret, @NonNull ThreadRecord thread,
|
||||||
|
@NonNull Locale locale, @NonNull Set<Long> selectedThreads, boolean batchMode);
|
||||||
|
}
|
@ -392,7 +392,6 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||||||
switch (item.getItemId()) {
|
switch (item.getItemId()) {
|
||||||
case R.id.menu_call_secure:
|
case R.id.menu_call_secure:
|
||||||
case R.id.menu_call_insecure: handleDial(getRecipients().getPrimaryRecipient()); return true;
|
case R.id.menu_call_insecure: handleDial(getRecipients().getPrimaryRecipient()); return true;
|
||||||
case R.id.menu_delete_thread: handleDeleteThread(); return true;
|
|
||||||
case R.id.menu_add_attachment: handleAddAttachment(); return true;
|
case R.id.menu_add_attachment: handleAddAttachment(); return true;
|
||||||
case R.id.menu_view_media: handleViewMedia(); return true;
|
case R.id.menu_view_media: handleViewMedia(); return true;
|
||||||
case R.id.menu_add_to_contacts: handleAddToContacts(); return true;
|
case R.id.menu_add_to_contacts: handleAddToContacts(); return true;
|
||||||
@ -650,28 +649,6 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||||||
new GroupMembersDialog(this, getRecipients()).display();
|
new GroupMembersDialog(this, getRecipients()).display();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleDeleteThread() {
|
|
||||||
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
|
||||||
builder.setTitle(R.string.ConversationActivity_delete_thread_question);
|
|
||||||
builder.setIconAttribute(R.attr.dialog_alert_icon);
|
|
||||||
builder.setCancelable(true);
|
|
||||||
builder.setMessage(R.string.ConversationActivity_this_will_permanently_delete_all_messages_in_this_conversation);
|
|
||||||
builder.setPositiveButton(R.string.delete, new DialogInterface.OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
|
||||||
if (threadId > 0) {
|
|
||||||
DatabaseFactory.getThreadDatabase(ConversationActivity.this).deleteConversation(threadId);
|
|
||||||
}
|
|
||||||
composeText.getText().clear();
|
|
||||||
threadId = -1;
|
|
||||||
finish();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
builder.setNegativeButton(android.R.string.cancel, null);
|
|
||||||
builder.show();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void handleAddToContacts() {
|
private void handleAddToContacts() {
|
||||||
final Intent intent = new Intent(Intent.ACTION_INSERT_OR_EDIT);
|
final Intent intent = new Intent(Intent.ACTION_INSERT_OR_EDIT);
|
||||||
intent.putExtra(ContactsContract.Intents.Insert.PHONE, recipients.getPrimaryRecipient().getNumber());
|
intent.putExtra(ContactsContract.Intents.Insert.PHONE, recipients.getPrimaryRecipient().getNumber());
|
||||||
@ -1089,9 +1066,9 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||||||
draftDatabase.insertDrafts(new MasterCipher(thisMasterSecret), threadId, drafts);
|
draftDatabase.insertDrafts(new MasterCipher(thisMasterSecret), threadId, drafts);
|
||||||
threadDatabase.updateSnippet(threadId, drafts.getSnippet(ConversationActivity.this),
|
threadDatabase.updateSnippet(threadId, drafts.getSnippet(ConversationActivity.this),
|
||||||
drafts.getUriSnippet(ConversationActivity.this),
|
drafts.getUriSnippet(ConversationActivity.this),
|
||||||
System.currentTimeMillis(), Types.BASE_DRAFT_TYPE);
|
System.currentTimeMillis(), Types.BASE_DRAFT_TYPE, true);
|
||||||
} else if (threadId > 0) {
|
} else if (threadId > 0) {
|
||||||
threadDatabase.update(threadId);
|
threadDatabase.update(threadId, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
return threadId;
|
return threadId;
|
||||||
|
@ -57,7 +57,7 @@ import org.thoughtcrime.securesms.mms.Slide;
|
|||||||
import org.thoughtcrime.securesms.recipients.RecipientFactory;
|
import org.thoughtcrime.securesms.recipients.RecipientFactory;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipients;
|
import org.thoughtcrime.securesms.recipients.Recipients;
|
||||||
import org.thoughtcrime.securesms.sms.MessageSender;
|
import org.thoughtcrime.securesms.sms.MessageSender;
|
||||||
import org.thoughtcrime.securesms.util.ProgressDialogAsyncTask;
|
import org.thoughtcrime.securesms.util.task.ProgressDialogAsyncTask;
|
||||||
import org.thoughtcrime.securesms.util.SaveAttachmentTask;
|
import org.thoughtcrime.securesms.util.SaveAttachmentTask;
|
||||||
import org.thoughtcrime.securesms.util.SaveAttachmentTask.Attachment;
|
import org.thoughtcrime.securesms.util.SaveAttachmentTask.Attachment;
|
||||||
import org.thoughtcrime.securesms.util.ViewUtil;
|
import org.thoughtcrime.securesms.util.ViewUtil;
|
||||||
|
@ -161,15 +161,6 @@ public class ConversationListActivity extends PassphraseRequiredActionBarActivit
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreateConversation(long threadId, Recipients recipients, int distributionType) {
|
public void onCreateConversation(long threadId, Recipients recipients, int distributionType) {
|
||||||
createConversation(threadId, recipients, distributionType);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void createGroup() {
|
|
||||||
Intent intent = new Intent(this, GroupCreateActivity.class);
|
|
||||||
startActivity(intent);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void createConversation(long threadId, Recipients recipients, int distributionType) {
|
|
||||||
Intent intent = new Intent(this, ConversationActivity.class);
|
Intent intent = new Intent(this, ConversationActivity.class);
|
||||||
intent.putExtra(ConversationActivity.RECIPIENTS_EXTRA, recipients.getIds());
|
intent.putExtra(ConversationActivity.RECIPIENTS_EXTRA, recipients.getIds());
|
||||||
intent.putExtra(ConversationActivity.THREAD_ID_EXTRA, threadId);
|
intent.putExtra(ConversationActivity.THREAD_ID_EXTRA, threadId);
|
||||||
@ -179,6 +170,17 @@ public class ConversationListActivity extends PassphraseRequiredActionBarActivit
|
|||||||
overridePendingTransition(R.anim.slide_from_right, R.anim.fade_scale_out);
|
overridePendingTransition(R.anim.slide_from_right, R.anim.fade_scale_out);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSwitchToArchive() {
|
||||||
|
Intent intent = new Intent(this, ConversationListArchiveActivity.class);
|
||||||
|
startActivity(intent);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createGroup() {
|
||||||
|
Intent intent = new Intent(this, GroupCreateActivity.class);
|
||||||
|
startActivity(intent);
|
||||||
|
}
|
||||||
|
|
||||||
private void handleDisplaySettings() {
|
private void handleDisplaySettings() {
|
||||||
Intent preferencesIntent = new Intent(this, ApplicationPreferencesActivity.class);
|
Intent preferencesIntent = new Intent(this, ApplicationPreferencesActivity.class);
|
||||||
startActivity(preferencesIntent);
|
startActivity(preferencesIntent);
|
||||||
|
@ -49,6 +49,9 @@ import java.util.Set;
|
|||||||
*/
|
*/
|
||||||
public class ConversationListAdapter extends CursorRecyclerViewAdapter<ConversationListAdapter.ViewHolder> {
|
public class ConversationListAdapter extends CursorRecyclerViewAdapter<ConversationListAdapter.ViewHolder> {
|
||||||
|
|
||||||
|
private static final int MESSAGE_TYPE_SWITCH_ARCHIVE = 1;
|
||||||
|
private static final int MESSAGE_TYPE_THREAD = 2;
|
||||||
|
|
||||||
private final ThreadDatabase threadDatabase;
|
private final ThreadDatabase threadDatabase;
|
||||||
private final MasterSecret masterSecret;
|
private final MasterSecret masterSecret;
|
||||||
private final MasterCipher masterCipher;
|
private final MasterCipher masterCipher;
|
||||||
@ -61,37 +64,25 @@ public class ConversationListAdapter extends CursorRecyclerViewAdapter<Conversat
|
|||||||
private boolean batchMode = false;
|
private boolean batchMode = false;
|
||||||
|
|
||||||
protected static class ViewHolder extends RecyclerView.ViewHolder {
|
protected static class ViewHolder extends RecyclerView.ViewHolder {
|
||||||
public ViewHolder(final @NonNull ConversationListItem itemView,
|
public <V extends View & BindableConversationListItem> ViewHolder(final @NonNull V itemView)
|
||||||
final @Nullable ItemClickListener clickListener)
|
|
||||||
{
|
{
|
||||||
super(itemView);
|
super(itemView);
|
||||||
itemView.setOnClickListener(new OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(View view) {
|
|
||||||
if (clickListener != null) clickListener.onItemClick(itemView);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
itemView.setOnLongClickListener(new OnLongClickListener() {
|
|
||||||
@Override
|
|
||||||
public boolean onLongClick(View view) {
|
|
||||||
if (clickListener != null) clickListener.onItemLongClick(itemView);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ConversationListItem getItem() {
|
public BindableConversationListItem getItem() {
|
||||||
return (ConversationListItem)itemView;
|
return (BindableConversationListItem)itemView;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getItemId(@NonNull Cursor cursor) {
|
public long getItemId(@NonNull Cursor cursor) {
|
||||||
ThreadRecord record = getThreadRecord(cursor);
|
ThreadRecord record = getThreadRecord(cursor);
|
||||||
StringBuilder builder = new StringBuilder(""+record.getThreadId());
|
StringBuilder builder = new StringBuilder("" + record.getThreadId());
|
||||||
|
|
||||||
for (long recipientId : record.getRecipients().getIds()) {
|
for (long recipientId : record.getRecipients().getIds()) {
|
||||||
builder.append("::").append(recipientId);
|
builder.append("::").append(recipientId);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Conversions.byteArrayToLong(digest.digest(builder.toString().getBytes()));
|
return Conversions.byteArrayToLong(digest.digest(builder.toString().getBytes()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -116,10 +107,51 @@ public class ConversationListAdapter extends CursorRecyclerViewAdapter<Conversat
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, boolean archived) {
|
||||||
|
ConversationListItem listItem = (ConversationListItem)viewHolder.itemView;
|
||||||
|
|
||||||
|
if (!archived) {
|
||||||
|
DatabaseFactory.getThreadDatabase(getContext()).archiveConversation(listItem.getThreadId());
|
||||||
|
} else {
|
||||||
|
DatabaseFactory.getThreadDatabase(getContext()).unarchiveConversation(listItem.getThreadId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ViewHolder onCreateItemViewHolder(ViewGroup parent, int viewType) {
|
public ViewHolder onCreateItemViewHolder(ViewGroup parent, int viewType) {
|
||||||
return new ViewHolder((ConversationListItem)inflater.inflate(R.layout.conversation_list_item_view,
|
if (viewType == MESSAGE_TYPE_SWITCH_ARCHIVE) {
|
||||||
parent, false), clickListener);
|
ConversationListItemAction action = (ConversationListItemAction)inflater.inflate(R.layout.conversation_list_item_action,
|
||||||
|
parent, false);
|
||||||
|
|
||||||
|
action.setOnClickListener(new OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
if (clickListener != null) clickListener.onSwitchToArchive();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return new ViewHolder(action);
|
||||||
|
} else {
|
||||||
|
final ConversationListItem item = (ConversationListItem)inflater.inflate(R.layout.conversation_list_item_view,
|
||||||
|
parent, false);
|
||||||
|
|
||||||
|
item.setOnClickListener(new OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View view) {
|
||||||
|
if (clickListener != null) clickListener.onItemClick(item);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
item.setOnLongClickListener(new OnLongClickListener() {
|
||||||
|
@Override
|
||||||
|
public boolean onLongClick(View view) {
|
||||||
|
if (clickListener != null) clickListener.onItemLongClick(item);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return new ViewHolder(item);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -129,7 +161,18 @@ public class ConversationListAdapter extends CursorRecyclerViewAdapter<Conversat
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBindItemViewHolder(ViewHolder viewHolder, @NonNull Cursor cursor) {
|
public void onBindItemViewHolder(ViewHolder viewHolder, @NonNull Cursor cursor) {
|
||||||
viewHolder.getItem().set(masterSecret, getThreadRecord(cursor), locale, batchSet, batchMode);
|
viewHolder.getItem().bind(masterSecret, getThreadRecord(cursor), locale, batchSet, batchMode);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getItemViewType(@NonNull Cursor cursor) {
|
||||||
|
ThreadRecord threadRecord = getThreadRecord(cursor);
|
||||||
|
|
||||||
|
if (threadRecord.getDistributionType() == ThreadDatabase.DistributionTypes.ARCHIVE) {
|
||||||
|
return MESSAGE_TYPE_SWITCH_ARCHIVE;
|
||||||
|
} else {
|
||||||
|
return MESSAGE_TYPE_THREAD;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private ThreadRecord getThreadRecord(@NonNull Cursor cursor) {
|
private ThreadRecord getThreadRecord(@NonNull Cursor cursor) {
|
||||||
@ -168,5 +211,6 @@ public class ConversationListAdapter extends CursorRecyclerViewAdapter<Conversat
|
|||||||
public interface ItemClickListener {
|
public interface ItemClickListener {
|
||||||
void onItemClick(ConversationListItem item);
|
void onItemClick(ConversationListItem item);
|
||||||
void onItemLongClick(ConversationListItem item);
|
void onItemLongClick(ConversationListItem item);
|
||||||
|
void onSwitchToArchive();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,71 @@
|
|||||||
|
package org.thoughtcrime.securesms;
|
||||||
|
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
import android.view.MenuItem;
|
||||||
|
|
||||||
|
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||||
|
import org.thoughtcrime.securesms.recipients.Recipients;
|
||||||
|
import org.thoughtcrime.securesms.util.DynamicLanguage;
|
||||||
|
import org.thoughtcrime.securesms.util.DynamicTheme;
|
||||||
|
|
||||||
|
public class ConversationListArchiveActivity extends PassphraseRequiredActionBarActivity
|
||||||
|
implements ConversationListFragment.ConversationSelectedListener
|
||||||
|
{
|
||||||
|
|
||||||
|
private final DynamicTheme dynamicTheme = new DynamicTheme();
|
||||||
|
private final DynamicLanguage dynamicLanguage = new DynamicLanguage();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPreCreate() {
|
||||||
|
dynamicTheme.onCreate(this);
|
||||||
|
dynamicLanguage.onCreate(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle icicle, @NonNull MasterSecret masterSecret) {
|
||||||
|
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||||
|
|
||||||
|
Bundle bundle = new Bundle();
|
||||||
|
bundle.putBoolean(ConversationListFragment.ARCHIVE, true);
|
||||||
|
|
||||||
|
initFragment(android.R.id.content, new ConversationListFragment(),
|
||||||
|
masterSecret, dynamicLanguage.getCurrentLocale(), bundle);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onResume() {
|
||||||
|
super.onResume();
|
||||||
|
dynamicTheme.onResume(this);
|
||||||
|
dynamicLanguage.onResume(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onOptionsItemSelected(MenuItem item) {
|
||||||
|
super.onOptionsItemSelected(item);
|
||||||
|
|
||||||
|
switch (item.getItemId()) {
|
||||||
|
case R.id.home: super.onBackPressed(); return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreateConversation(long threadId, Recipients recipients, int distributionType) {
|
||||||
|
Intent intent = new Intent(this, ConversationActivity.class);
|
||||||
|
intent.putExtra(ConversationActivity.RECIPIENTS_EXTRA, recipients.getIds());
|
||||||
|
intent.putExtra(ConversationActivity.THREAD_ID_EXTRA, threadId);
|
||||||
|
intent.putExtra(ConversationActivity.DISTRIBUTION_TYPE_EXTRA, distributionType);
|
||||||
|
|
||||||
|
startActivity(intent);
|
||||||
|
overridePendingTransition(R.anim.slide_from_right, R.anim.fade_scale_out);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSwitchToArchive() {
|
||||||
|
throw new AssertionError();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (C) 2011 Whisper Systems
|
* Copyright (C) 2015 Open Whisper Systems
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
@ -20,21 +20,31 @@ import android.app.ProgressDialog;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.content.res.Resources;
|
||||||
import android.content.res.TypedArray;
|
import android.content.res.TypedArray;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
|
import android.graphics.Bitmap;
|
||||||
|
import android.graphics.BitmapFactory;
|
||||||
|
import android.graphics.Canvas;
|
||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
|
import android.graphics.Paint;
|
||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
|
import android.support.design.widget.FloatingActionButton;
|
||||||
|
import android.support.design.widget.Snackbar;
|
||||||
import android.support.v4.app.Fragment;
|
import android.support.v4.app.Fragment;
|
||||||
import android.support.v4.app.LoaderManager;
|
import android.support.v4.app.LoaderManager;
|
||||||
import android.support.v4.content.Loader;
|
import android.support.v4.content.Loader;
|
||||||
import android.support.v7.app.AppCompatActivity;
|
|
||||||
import android.support.v7.app.AlertDialog;
|
import android.support.v7.app.AlertDialog;
|
||||||
|
import android.support.v7.app.AppCompatActivity;
|
||||||
import android.support.v7.view.ActionMode;
|
import android.support.v7.view.ActionMode;
|
||||||
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.support.v7.widget.helper.ItemTouchHelper;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
import android.util.DisplayMetrics;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
import android.view.MenuInflater;
|
import android.view.MenuInflater;
|
||||||
@ -43,7 +53,6 @@ import android.view.View;
|
|||||||
import android.view.View.OnClickListener;
|
import android.view.View.OnClickListener;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
import com.melnykov.fab.FloatingActionButton;
|
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.ConversationListAdapter.ItemClickListener;
|
import org.thoughtcrime.securesms.ConversationListAdapter.ItemClickListener;
|
||||||
import org.thoughtcrime.securesms.components.reminder.DefaultSmsReminder;
|
import org.thoughtcrime.securesms.components.reminder.DefaultSmsReminder;
|
||||||
@ -60,8 +69,11 @@ import org.thoughtcrime.securesms.database.loaders.ConversationListLoader;
|
|||||||
import org.thoughtcrime.securesms.notifications.MessageNotifier;
|
import org.thoughtcrime.securesms.notifications.MessageNotifier;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipients;
|
import org.thoughtcrime.securesms.recipients.Recipients;
|
||||||
import org.thoughtcrime.securesms.util.Util;
|
import org.thoughtcrime.securesms.util.Util;
|
||||||
|
import org.thoughtcrime.securesms.util.ViewUtil;
|
||||||
|
import org.thoughtcrime.securesms.util.task.SnackbarAsyncTask;
|
||||||
import org.whispersystems.libaxolotl.util.guava.Optional;
|
import org.whispersystems.libaxolotl.util.guava.Optional;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
@ -69,6 +81,9 @@ import java.util.Set;
|
|||||||
public class ConversationListFragment extends Fragment
|
public class ConversationListFragment extends Fragment
|
||||||
implements LoaderManager.LoaderCallbacks<Cursor>, ActionMode.Callback, ItemClickListener
|
implements LoaderManager.LoaderCallbacks<Cursor>, ActionMode.Callback, ItemClickListener
|
||||||
{
|
{
|
||||||
|
|
||||||
|
public static final String ARCHIVE = "archive";
|
||||||
|
|
||||||
private MasterSecret masterSecret;
|
private MasterSecret masterSecret;
|
||||||
private ActionMode actionMode;
|
private ActionMode actionMode;
|
||||||
private RecyclerView list;
|
private RecyclerView list;
|
||||||
@ -76,27 +91,39 @@ public class ConversationListFragment extends Fragment
|
|||||||
private FloatingActionButton fab;
|
private FloatingActionButton fab;
|
||||||
private Locale locale;
|
private Locale locale;
|
||||||
private String queryFilter = "";
|
private String queryFilter = "";
|
||||||
|
private boolean archive;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle icicle) {
|
public void onCreate(Bundle icicle) {
|
||||||
super.onCreate(icicle);
|
super.onCreate(icicle);
|
||||||
masterSecret = getArguments().getParcelable("master_secret");
|
masterSecret = getArguments().getParcelable("master_secret");
|
||||||
locale = (Locale) getArguments().getSerializable(PassphraseRequiredActionBarActivity.LOCALE_EXTRA);
|
locale = (Locale) getArguments().getSerializable(PassphraseRequiredActionBarActivity.LOCALE_EXTRA);
|
||||||
|
archive = getArguments().getBoolean(ARCHIVE, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) {
|
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) {
|
||||||
final View view = inflater.inflate(R.layout.conversation_list_fragment, container, false);
|
final View view = inflater.inflate(R.layout.conversation_list_fragment, container, false);
|
||||||
reminderView = (ReminderView) view.findViewById(R.id.reminder);
|
|
||||||
list = (RecyclerView) view.findViewById(R.id.list);
|
reminderView = ViewUtil.findById(view, R.id.reminder);
|
||||||
fab = (FloatingActionButton) view.findViewById(R.id.fab);
|
list = ViewUtil.findById(view, R.id.list);
|
||||||
|
fab = ViewUtil.findById(view, R.id.fab);
|
||||||
|
|
||||||
|
if (archive) fab.setVisibility(View.GONE);
|
||||||
|
else fab.setVisibility(View.VISIBLE);
|
||||||
|
|
||||||
reminderView.setOnDismissListener(new OnDismissListener() {
|
reminderView.setOnDismissListener(new OnDismissListener() {
|
||||||
@Override public void onDismiss() {
|
@Override
|
||||||
|
public void onDismiss() {
|
||||||
updateReminders();
|
updateReminders();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
list.setHasFixedSize(true);
|
list.setHasFixedSize(true);
|
||||||
list.setLayoutManager(new LinearLayoutManager(getActivity()));
|
list.setLayoutManager(new LinearLayoutManager(getActivity()));
|
||||||
|
|
||||||
|
new ItemTouchHelper(new ArchiveListenerCallback()).attachToRecyclerView(list);
|
||||||
|
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -170,6 +197,49 @@ public class ConversationListFragment extends Fragment
|
|||||||
getLoaderManager().restartLoader(0, null, this);
|
getLoaderManager().restartLoader(0, null, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void handleArchiveAllSelected() {
|
||||||
|
final Set<Long> selectedConversations = new HashSet<>(getListAdapter().getBatchSelections());
|
||||||
|
final boolean archive = this.archive;
|
||||||
|
|
||||||
|
String snackBarTitle;
|
||||||
|
|
||||||
|
if (archive) snackBarTitle = getString(R.string.ConversationListFragment_moved_conversations_to_inbox);
|
||||||
|
else snackBarTitle = getString(R.string.ConversationListFragment_archived_conversations);
|
||||||
|
|
||||||
|
new SnackbarAsyncTask<Void>(getView(), snackBarTitle,
|
||||||
|
getString(R.string.ConversationListFragment_undo),
|
||||||
|
getResources().getColor(R.color.amber_500),
|
||||||
|
Snackbar.LENGTH_LONG, true)
|
||||||
|
{
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPostExecute(Void result) {
|
||||||
|
super.onPostExecute(result);
|
||||||
|
|
||||||
|
if (actionMode != null) {
|
||||||
|
actionMode.finish();
|
||||||
|
actionMode = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void executeAction(@Nullable Void parameter) {
|
||||||
|
for (long threadId : selectedConversations) {
|
||||||
|
if (!archive) DatabaseFactory.getThreadDatabase(getActivity()).archiveConversation(threadId);
|
||||||
|
else DatabaseFactory.getThreadDatabase(getActivity()).unarchiveConversation(threadId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void reverseAction(@Nullable Void parameter) {
|
||||||
|
for (long threadId : selectedConversations) {
|
||||||
|
if (!archive) DatabaseFactory.getThreadDatabase(getActivity()).unarchiveConversation(threadId);
|
||||||
|
else DatabaseFactory.getThreadDatabase(getActivity()).archiveConversation(threadId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.execute();
|
||||||
|
}
|
||||||
|
|
||||||
private void handleDeleteAllSelected() {
|
private void handleDeleteAllSelected() {
|
||||||
int conversationsCount = getListAdapter().getBatchSelections().size();
|
int conversationsCount = getListAdapter().getBatchSelections().size();
|
||||||
AlertDialog.Builder alert = new AlertDialog.Builder(getActivity());
|
AlertDialog.Builder alert = new AlertDialog.Builder(getActivity());
|
||||||
@ -234,7 +304,7 @@ public class ConversationListFragment extends Fragment
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Loader<Cursor> onCreateLoader(int arg0, Bundle arg1) {
|
public Loader<Cursor> onCreateLoader(int arg0, Bundle arg1) {
|
||||||
return new ConversationListLoader(getActivity(), queryFilter);
|
return new ConversationListLoader(getActivity(), queryFilter, archive);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -276,21 +346,30 @@ public class ConversationListFragment extends Fragment
|
|||||||
getListAdapter().notifyDataSetChanged();
|
getListAdapter().notifyDataSetChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSwitchToArchive() {
|
||||||
|
((ConversationSelectedListener)getActivity()).onSwitchToArchive();
|
||||||
|
}
|
||||||
|
|
||||||
public interface ConversationSelectedListener {
|
public interface ConversationSelectedListener {
|
||||||
void onCreateConversation(long threadId, Recipients recipients, int distributionType);
|
void onCreateConversation(long threadId, Recipients recipients, int distributionType);
|
||||||
|
void onSwitchToArchive();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
|
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
|
||||||
MenuInflater inflater = getActivity().getMenuInflater();
|
MenuInflater inflater = getActivity().getMenuInflater();
|
||||||
|
|
||||||
|
if (archive) inflater.inflate(R.menu.conversation_list_batch_unarchive, menu);
|
||||||
|
else inflater.inflate(R.menu.conversation_list_batch_archive, menu);
|
||||||
|
|
||||||
inflater.inflate(R.menu.conversation_list_batch, menu);
|
inflater.inflate(R.menu.conversation_list_batch, menu);
|
||||||
|
|
||||||
mode.setTitle(R.string.conversation_fragment_cab__batch_selection_mode);
|
mode.setTitle(R.string.conversation_fragment_cab__batch_selection_mode);
|
||||||
mode.setSubtitle(getString(R.string.conversation_fragment_cab__batch_selection_amount, 1));
|
mode.setSubtitle(getString(R.string.conversation_fragment_cab__batch_selection_amount, 1));
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||||
getActivity().getWindow()
|
getActivity().getWindow().setStatusBarColor(getResources().getColor(R.color.action_mode_status_bar));
|
||||||
.setStatusBarColor(getResources().getColor(R.color.action_mode_status_bar));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -306,6 +385,7 @@ public class ConversationListFragment extends Fragment
|
|||||||
switch (item.getItemId()) {
|
switch (item.getItemId()) {
|
||||||
case R.id.menu_select_all: handleSelectAllThreads(); return true;
|
case R.id.menu_select_all: handleSelectAllThreads(); return true;
|
||||||
case R.id.menu_delete_selected: handleDeleteAllSelected(); return true;
|
case R.id.menu_delete_selected: handleDeleteAllSelected(); return true;
|
||||||
|
case R.id.menu_archive_selected: handleArchiveAllSelected(); return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@ -316,8 +396,7 @@ public class ConversationListFragment extends Fragment
|
|||||||
getListAdapter().initializeBatchMode(false);
|
getListAdapter().initializeBatchMode(false);
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||||
TypedArray color = getActivity().getTheme()
|
TypedArray color = getActivity().getTheme().obtainStyledAttributes(new int[] {android.R.attr.statusBarColor});
|
||||||
.obtainStyledAttributes(new int[] { android.R.attr.statusBarColor });
|
|
||||||
getActivity().getWindow().setStatusBarColor(color.getColor(0, Color.BLACK));
|
getActivity().getWindow().setStatusBarColor(color.getColor(0, Color.BLACK));
|
||||||
color.recycle();
|
color.recycle();
|
||||||
}
|
}
|
||||||
@ -325,6 +404,114 @@ public class ConversationListFragment extends Fragment
|
|||||||
actionMode = null;
|
actionMode = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class ArchiveListenerCallback extends ItemTouchHelper.SimpleCallback {
|
||||||
|
|
||||||
|
public ArchiveListenerCallback() {
|
||||||
|
super(0, ItemTouchHelper.RIGHT);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onMove(RecyclerView recyclerView,
|
||||||
|
RecyclerView.ViewHolder viewHolder,
|
||||||
|
RecyclerView.ViewHolder target)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getSwipeDirs(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
|
||||||
|
if (viewHolder.itemView instanceof ConversationListItemAction) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (actionMode != null) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.getSwipeDirs(recyclerView, viewHolder);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
|
||||||
|
final long threadId = ((ConversationListItem)viewHolder.itemView).getThreadId();
|
||||||
|
|
||||||
|
if (archive) {
|
||||||
|
new SnackbarAsyncTask<Long>(getView(),
|
||||||
|
getString(R.string.ConversationListFragment_moved_conversation_to_inbox),
|
||||||
|
getString(R.string.ConversationListFragment_undo),
|
||||||
|
getResources().getColor(R.color.amber_500),
|
||||||
|
Snackbar.LENGTH_SHORT, false)
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
protected void executeAction(@Nullable Long parameter) {
|
||||||
|
DatabaseFactory.getThreadDatabase(getActivity()).unarchiveConversation(threadId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void reverseAction(@Nullable Long parameter) {
|
||||||
|
DatabaseFactory.getThreadDatabase(getActivity()).archiveConversation(threadId);
|
||||||
|
}
|
||||||
|
}.execute(threadId);
|
||||||
|
} else {
|
||||||
|
new SnackbarAsyncTask<Long>(getView(),
|
||||||
|
getString(R.string.ConversationListFragment_archived_conversation),
|
||||||
|
getString(R.string.ConversationListFragment_undo),
|
||||||
|
getResources().getColor(R.color.amber_500),
|
||||||
|
Snackbar.LENGTH_SHORT, false)
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
protected void executeAction(@Nullable Long parameter) {
|
||||||
|
DatabaseFactory.getThreadDatabase(getActivity()).archiveConversation(threadId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void reverseAction(@Nullable Long parameter) {
|
||||||
|
DatabaseFactory.getThreadDatabase(getActivity()).unarchiveConversation(threadId);
|
||||||
|
}
|
||||||
|
}.execute(threadId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onChildDraw(Canvas c, RecyclerView recyclerView,
|
||||||
|
RecyclerView.ViewHolder viewHolder,
|
||||||
|
float dX, float dY, int actionState,
|
||||||
|
boolean isCurrentlyActive)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE) {
|
||||||
|
View itemView = viewHolder.itemView;
|
||||||
|
Paint p = new Paint();
|
||||||
|
|
||||||
|
if (dX > 0) {
|
||||||
|
Bitmap icon;
|
||||||
|
|
||||||
|
if (archive) icon = BitmapFactory.decodeResource(getResources(), R.drawable.ic_unarchive_white_36dp);
|
||||||
|
else icon = BitmapFactory.decodeResource(getResources(), R.drawable.ic_archive_white_36dp);
|
||||||
|
|
||||||
|
p.setColor(getResources().getColor(R.color.green_500));
|
||||||
|
|
||||||
|
c.drawRect((float) itemView.getLeft(), (float) itemView.getTop(), dX,
|
||||||
|
(float) itemView.getBottom(), p);
|
||||||
|
|
||||||
|
c.drawBitmap(icon,
|
||||||
|
(float) itemView.getLeft() + getResources().getDimension(R.dimen.conversation_list_fragment_archive_padding),
|
||||||
|
(float) itemView.getTop() + ((float) itemView.getBottom() - (float) itemView.getTop() - icon.getHeight())/2,
|
||||||
|
p);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Build.VERSION.SDK_INT >= 11) {
|
||||||
|
float alpha = 1.0f - Math.abs(dX) / (float) viewHolder.itemView.getWidth();
|
||||||
|
viewHolder.itemView.setAlpha(alpha);
|
||||||
|
viewHolder.itemView.setTranslationX(dX);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -39,6 +39,7 @@ import org.thoughtcrime.securesms.database.model.ThreadRecord;
|
|||||||
import org.thoughtcrime.securesms.recipients.Recipients;
|
import org.thoughtcrime.securesms.recipients.Recipients;
|
||||||
import org.thoughtcrime.securesms.util.DateUtils;
|
import org.thoughtcrime.securesms.util.DateUtils;
|
||||||
import org.thoughtcrime.securesms.util.ResUtil;
|
import org.thoughtcrime.securesms.util.ResUtil;
|
||||||
|
import org.thoughtcrime.securesms.util.ViewUtil;
|
||||||
|
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@ -53,7 +54,8 @@ import static org.thoughtcrime.securesms.util.SpanUtil.color;
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
public class ConversationListItem extends RelativeLayout
|
public class ConversationListItem extends RelativeLayout
|
||||||
implements Recipients.RecipientsModifiedListener, Unbindable
|
implements Recipients.RecipientsModifiedListener,
|
||||||
|
BindableConversationListItem, Unbindable
|
||||||
{
|
{
|
||||||
private final static String TAG = ConversationListItem.class.getSimpleName();
|
private final static String TAG = ConversationListItem.class.getSimpleName();
|
||||||
|
|
||||||
@ -66,6 +68,7 @@ public class ConversationListItem extends RelativeLayout
|
|||||||
private TextView subjectView;
|
private TextView subjectView;
|
||||||
private FromTextView fromView;
|
private FromTextView fromView;
|
||||||
private TextView dateView;
|
private TextView dateView;
|
||||||
|
private TextView archivedView;
|
||||||
private boolean read;
|
private boolean read;
|
||||||
private AvatarImageView contactPhotoImage;
|
private AvatarImageView contactPhotoImage;
|
||||||
private ThumbnailView thumbnailView;
|
private ThumbnailView thumbnailView;
|
||||||
@ -94,10 +97,11 @@ public class ConversationListItem extends RelativeLayout
|
|||||||
this.dateView = (TextView) findViewById(R.id.date);
|
this.dateView = (TextView) findViewById(R.id.date);
|
||||||
this.contactPhotoImage = (AvatarImageView) findViewById(R.id.contact_photo_image);
|
this.contactPhotoImage = (AvatarImageView) findViewById(R.id.contact_photo_image);
|
||||||
this.thumbnailView = (ThumbnailView) findViewById(R.id.thumbnail);
|
this.thumbnailView = (ThumbnailView) findViewById(R.id.thumbnail);
|
||||||
|
this.archivedView = ViewUtil.findById(this, R.id.archived);
|
||||||
thumbnailView.setClickable(false);
|
thumbnailView.setClickable(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void set(@NonNull MasterSecret masterSecret, @NonNull ThreadRecord thread,
|
public void bind(@NonNull MasterSecret masterSecret, @NonNull ThreadRecord thread,
|
||||||
@NonNull Locale locale, @NonNull Set<Long> selectedThreads, boolean batchMode)
|
@NonNull Locale locale, @NonNull Set<Long> selectedThreads, boolean batchMode)
|
||||||
{
|
{
|
||||||
this.selectedThreads = selectedThreads;
|
this.selectedThreads = selectedThreads;
|
||||||
@ -118,6 +122,12 @@ public class ConversationListItem extends RelativeLayout
|
|||||||
dateView.setTypeface(read ? LIGHT_TYPEFACE : BOLD_TYPEFACE);
|
dateView.setTypeface(read ? LIGHT_TYPEFACE : BOLD_TYPEFACE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (thread.isArchived()) {
|
||||||
|
this.archivedView.setVisibility(View.VISIBLE);
|
||||||
|
} else {
|
||||||
|
this.archivedView.setVisibility(View.GONE);
|
||||||
|
}
|
||||||
|
|
||||||
setThumbnailSnippet(masterSecret, thread);
|
setThumbnailSnippet(masterSecret, thread);
|
||||||
setBatchState(batchMode);
|
setBatchState(batchMode);
|
||||||
setBackground(thread);
|
setBackground(thread);
|
||||||
@ -158,7 +168,7 @@ public class ConversationListItem extends RelativeLayout
|
|||||||
this.thumbnailView.setVisibility(View.GONE);
|
this.thumbnailView.setVisibility(View.GONE);
|
||||||
|
|
||||||
LayoutParams subjectParams = (RelativeLayout.LayoutParams)this.subjectView.getLayoutParams();
|
LayoutParams subjectParams = (RelativeLayout.LayoutParams)this.subjectView.getLayoutParams();
|
||||||
subjectParams.addRule(RelativeLayout.LEFT_OF, 0);
|
subjectParams.addRule(RelativeLayout.LEFT_OF, R.id.archived);
|
||||||
this.subjectView.setLayoutParams(subjectParams);
|
this.subjectView.setLayoutParams(subjectParams);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -187,4 +197,5 @@ public class ConversationListItem extends RelativeLayout
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,50 @@
|
|||||||
|
package org.thoughtcrime.securesms;
|
||||||
|
|
||||||
|
import android.annotation.TargetApi;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.os.Build;
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
import android.util.AttributeSet;
|
||||||
|
import android.widget.LinearLayout;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||||
|
import org.thoughtcrime.securesms.database.model.ThreadRecord;
|
||||||
|
import org.thoughtcrime.securesms.util.ViewUtil;
|
||||||
|
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public class ConversationListItemAction extends LinearLayout implements BindableConversationListItem {
|
||||||
|
|
||||||
|
private TextView description;
|
||||||
|
|
||||||
|
public ConversationListItemAction(Context context) {
|
||||||
|
super(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConversationListItemAction(Context context, AttributeSet attrs) {
|
||||||
|
super(context, attrs);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
|
||||||
|
public ConversationListItemAction(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||||
|
super(context, attrs, defStyleAttr);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFinishInflate() {
|
||||||
|
super.onFinishInflate();
|
||||||
|
this.description = ViewUtil.findById(this, R.id.description);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void bind(@NonNull MasterSecret masterSecret, @NonNull ThreadRecord thread, @NonNull Locale locale, @NonNull Set<Long> selectedThreads, boolean batchMode) {
|
||||||
|
this.description.setText(getContext().getString(R.string.ConversationListItemAction_archived_conversations_d, thread.getCount()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void unbind() {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -20,7 +20,7 @@ import org.thoughtcrime.securesms.push.TextSecureCommunicationFactory;
|
|||||||
import org.thoughtcrime.securesms.util.Base64;
|
import org.thoughtcrime.securesms.util.Base64;
|
||||||
import org.thoughtcrime.securesms.util.DynamicLanguage;
|
import org.thoughtcrime.securesms.util.DynamicLanguage;
|
||||||
import org.thoughtcrime.securesms.util.DynamicTheme;
|
import org.thoughtcrime.securesms.util.DynamicTheme;
|
||||||
import org.thoughtcrime.securesms.util.ProgressDialogAsyncTask;
|
import org.thoughtcrime.securesms.util.task.ProgressDialogAsyncTask;
|
||||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||||
import org.thoughtcrime.securesms.util.Util;
|
import org.thoughtcrime.securesms.util.Util;
|
||||||
import org.whispersystems.libaxolotl.IdentityKeyPair;
|
import org.whispersystems.libaxolotl.IdentityKeyPair;
|
||||||
|
@ -22,7 +22,7 @@ import com.melnykov.fab.FloatingActionButton;
|
|||||||
|
|
||||||
import org.thoughtcrime.securesms.database.loaders.DeviceListLoader;
|
import org.thoughtcrime.securesms.database.loaders.DeviceListLoader;
|
||||||
import org.thoughtcrime.securesms.dependencies.InjectableType;
|
import org.thoughtcrime.securesms.dependencies.InjectableType;
|
||||||
import org.thoughtcrime.securesms.util.ProgressDialogAsyncTask;
|
import org.thoughtcrime.securesms.util.task.ProgressDialogAsyncTask;
|
||||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||||
import org.thoughtcrime.securesms.util.ViewUtil;
|
import org.thoughtcrime.securesms.util.ViewUtil;
|
||||||
import org.whispersystems.textsecure.api.TextSecureAccountManager;
|
import org.whispersystems.textsecure.api.TextSecureAccountManager;
|
||||||
|
@ -16,7 +16,7 @@ import org.thoughtcrime.securesms.crypto.IdentityKeyUtil;
|
|||||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||||
import org.thoughtcrime.securesms.push.TextSecureCommunicationFactory;
|
import org.thoughtcrime.securesms.push.TextSecureCommunicationFactory;
|
||||||
import org.thoughtcrime.securesms.util.Base64;
|
import org.thoughtcrime.securesms.util.Base64;
|
||||||
import org.thoughtcrime.securesms.util.ProgressDialogAsyncTask;
|
import org.thoughtcrime.securesms.util.task.ProgressDialogAsyncTask;
|
||||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||||
import org.whispersystems.libaxolotl.IdentityKeyPair;
|
import org.whispersystems.libaxolotl.IdentityKeyPair;
|
||||||
import org.whispersystems.libaxolotl.InvalidKeyException;
|
import org.whispersystems.libaxolotl.InvalidKeyException;
|
||||||
|
@ -65,7 +65,7 @@ import org.thoughtcrime.securesms.util.BitmapUtil;
|
|||||||
import org.thoughtcrime.securesms.util.DynamicLanguage;
|
import org.thoughtcrime.securesms.util.DynamicLanguage;
|
||||||
import org.thoughtcrime.securesms.util.DynamicTheme;
|
import org.thoughtcrime.securesms.util.DynamicTheme;
|
||||||
import org.thoughtcrime.securesms.util.GroupUtil;
|
import org.thoughtcrime.securesms.util.GroupUtil;
|
||||||
import org.thoughtcrime.securesms.util.ProgressDialogAsyncTask;
|
import org.thoughtcrime.securesms.util.task.ProgressDialogAsyncTask;
|
||||||
import org.thoughtcrime.securesms.util.SelectedRecipientsAdapter;
|
import org.thoughtcrime.securesms.util.SelectedRecipientsAdapter;
|
||||||
import org.thoughtcrime.securesms.util.SelectedRecipientsAdapter.OnRecipientDeletedListener;
|
import org.thoughtcrime.securesms.util.SelectedRecipientsAdapter.OnRecipientDeletedListener;
|
||||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||||
|
@ -32,7 +32,7 @@ import org.thoughtcrime.securesms.recipients.RecipientFactory;
|
|||||||
import org.thoughtcrime.securesms.recipients.Recipients;
|
import org.thoughtcrime.securesms.recipients.Recipients;
|
||||||
import org.thoughtcrime.securesms.sms.MessageSender;
|
import org.thoughtcrime.securesms.sms.MessageSender;
|
||||||
import org.thoughtcrime.securesms.sms.OutgoingTextMessage;
|
import org.thoughtcrime.securesms.sms.OutgoingTextMessage;
|
||||||
import org.thoughtcrime.securesms.util.ProgressDialogAsyncTask;
|
import org.thoughtcrime.securesms.util.task.ProgressDialogAsyncTask;
|
||||||
import org.thoughtcrime.securesms.util.ViewUtil;
|
import org.thoughtcrime.securesms.util.ViewUtil;
|
||||||
import org.thoughtcrime.securesms.util.concurrent.ListenableFuture.Listener;
|
import org.thoughtcrime.securesms.util.concurrent.ListenableFuture.Listener;
|
||||||
|
|
||||||
|
@ -90,7 +90,7 @@ public class ShareFragment extends ListFragment implements LoaderManager.LoaderC
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Loader<Cursor> onCreateLoader(int arg0, Bundle arg1) {
|
public Loader<Cursor> onCreateLoader(int arg0, Bundle arg1) {
|
||||||
return new ConversationListLoader(getActivity(), null);
|
return new ConversationListLoader(getActivity(), null, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -68,7 +68,8 @@ public class DatabaseFactory {
|
|||||||
private static final int INTRODUCED_DB_OPTIMIZATIONS_VERSION = 21;
|
private static final int INTRODUCED_DB_OPTIMIZATIONS_VERSION = 21;
|
||||||
private static final int INTRODUCED_INVITE_REMINDERS_VERSION = 22;
|
private static final int INTRODUCED_INVITE_REMINDERS_VERSION = 22;
|
||||||
private static final int INTRODUCED_CONVERSATION_LIST_THUMBNAILS_VERSION = 23;
|
private static final int INTRODUCED_CONVERSATION_LIST_THUMBNAILS_VERSION = 23;
|
||||||
private static final int DATABASE_VERSION = 23;
|
private static final int INTRODUCED_ARCHIVE_VERSION = 24;
|
||||||
|
private static final int DATABASE_VERSION = 24;
|
||||||
|
|
||||||
private static final String DATABASE_NAME = "messages.db";
|
private static final String DATABASE_NAME = "messages.db";
|
||||||
private static final Object lock = new Object();
|
private static final Object lock = new Object();
|
||||||
@ -778,6 +779,11 @@ public class DatabaseFactory {
|
|||||||
db.execSQL("ALTER TABLE thread ADD COLUMN snippet_uri TEXT DEFAULT NULL");
|
db.execSQL("ALTER TABLE thread ADD COLUMN snippet_uri TEXT DEFAULT NULL");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (oldVersion < INTRODUCED_ARCHIVE_VERSION) {
|
||||||
|
db.execSQL("ALTER TABLE thread ADD COLUMN archived INTEGER DEFAULT 0");
|
||||||
|
db.execSQL("CREATE INDEX IF NOT EXISTS archived_index ON thread (archived)");
|
||||||
|
}
|
||||||
|
|
||||||
db.setTransactionSuccessful();
|
db.setTransactionSuccessful();
|
||||||
db.endTransaction();
|
db.endTransaction();
|
||||||
}
|
}
|
||||||
|
@ -449,7 +449,7 @@ public class MmsDatabase extends MessagingDatabase {
|
|||||||
|
|
||||||
long threadId = getThreadIdForMessage(messageId);
|
long threadId = getThreadIdForMessage(messageId);
|
||||||
|
|
||||||
DatabaseFactory.getThreadDatabase(context).update(threadId);
|
DatabaseFactory.getThreadDatabase(context).update(threadId, true);
|
||||||
notifyConversationListeners(threadId);
|
notifyConversationListeners(threadId);
|
||||||
notifyConversationListListeners();
|
notifyConversationListListeners();
|
||||||
|
|
||||||
@ -604,7 +604,7 @@ public class MmsDatabase extends MessagingDatabase {
|
|||||||
contentValues);
|
contentValues);
|
||||||
|
|
||||||
DatabaseFactory.getThreadDatabase(context).setUnread(threadId);
|
DatabaseFactory.getThreadDatabase(context).setUnread(threadId);
|
||||||
DatabaseFactory.getThreadDatabase(context).update(threadId);
|
DatabaseFactory.getThreadDatabase(context).update(threadId, true);
|
||||||
notifyConversationListeners(threadId);
|
notifyConversationListeners(threadId);
|
||||||
jobManager.add(new TrimThreadJob(context, threadId));
|
jobManager.add(new TrimThreadJob(context, threadId));
|
||||||
|
|
||||||
@ -692,7 +692,7 @@ public class MmsDatabase extends MessagingDatabase {
|
|||||||
|
|
||||||
public void markIncomingNotificationReceived(long threadId) {
|
public void markIncomingNotificationReceived(long threadId) {
|
||||||
notifyConversationListeners(threadId);
|
notifyConversationListeners(threadId);
|
||||||
DatabaseFactory.getThreadDatabase(context).update(threadId);
|
DatabaseFactory.getThreadDatabase(context).update(threadId, true);
|
||||||
|
|
||||||
if (org.thoughtcrime.securesms.util.Util.isDefaultSmsProvider(context)) {
|
if (org.thoughtcrime.securesms.util.Util.isDefaultSmsProvider(context)) {
|
||||||
DatabaseFactory.getThreadDatabase(context).setUnread(threadId);
|
DatabaseFactory.getThreadDatabase(context).setUnread(threadId);
|
||||||
@ -808,7 +808,7 @@ public class MmsDatabase extends MessagingDatabase {
|
|||||||
db.endTransaction();
|
db.endTransaction();
|
||||||
|
|
||||||
notifyConversationListeners(contentValues.getAsLong(THREAD_ID));
|
notifyConversationListeners(contentValues.getAsLong(THREAD_ID));
|
||||||
DatabaseFactory.getThreadDatabase(context).update(contentValues.getAsLong(THREAD_ID));
|
DatabaseFactory.getThreadDatabase(context).update(contentValues.getAsLong(THREAD_ID), true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -821,7 +821,7 @@ public class MmsDatabase extends MessagingDatabase {
|
|||||||
|
|
||||||
SQLiteDatabase database = databaseHelper.getWritableDatabase();
|
SQLiteDatabase database = databaseHelper.getWritableDatabase();
|
||||||
database.delete(TABLE_NAME, ID_WHERE, new String[] {messageId+""});
|
database.delete(TABLE_NAME, ID_WHERE, new String[] {messageId+""});
|
||||||
boolean threadDeleted = DatabaseFactory.getThreadDatabase(context).update(threadId);
|
boolean threadDeleted = DatabaseFactory.getThreadDatabase(context).update(threadId, false);
|
||||||
notifyConversationListeners(threadId);
|
notifyConversationListeners(threadId);
|
||||||
return threadDeleted;
|
return threadDeleted;
|
||||||
}
|
}
|
||||||
|
@ -83,7 +83,7 @@ public class PlaintextBackupImporter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (long threadId : modifiedThreads) {
|
for (long threadId : modifiedThreads) {
|
||||||
threads.update(threadId);
|
threads.update(threadId, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
Log.w("PlaintextBackupImporter", "Exited loop");
|
Log.w("PlaintextBackupImporter", "Exited loop");
|
||||||
|
@ -118,7 +118,7 @@ public class SmsDatabase extends MessagingDatabase {
|
|||||||
|
|
||||||
long threadId = getThreadIdForMessage(id);
|
long threadId = getThreadIdForMessage(id);
|
||||||
|
|
||||||
DatabaseFactory.getThreadDatabase(context).update(threadId);
|
DatabaseFactory.getThreadDatabase(context).update(threadId, false);
|
||||||
notifyConversationListeners(threadId);
|
notifyConversationListeners(threadId);
|
||||||
notifyConversationListListeners();
|
notifyConversationListListeners();
|
||||||
}
|
}
|
||||||
@ -310,7 +310,7 @@ public class SmsDatabase extends MessagingDatabase {
|
|||||||
|
|
||||||
long threadId = getThreadIdForMessage(messageId);
|
long threadId = getThreadIdForMessage(messageId);
|
||||||
|
|
||||||
DatabaseFactory.getThreadDatabase(context).update(threadId);
|
DatabaseFactory.getThreadDatabase(context).update(threadId, true);
|
||||||
notifyConversationListeners(threadId);
|
notifyConversationListeners(threadId);
|
||||||
notifyConversationListListeners();
|
notifyConversationListListeners();
|
||||||
|
|
||||||
@ -335,7 +335,7 @@ public class SmsDatabase extends MessagingDatabase {
|
|||||||
SQLiteDatabase db = databaseHelper.getWritableDatabase();
|
SQLiteDatabase db = databaseHelper.getWritableDatabase();
|
||||||
long newMessageId = db.insert(TABLE_NAME, null, contentValues);
|
long newMessageId = db.insert(TABLE_NAME, null, contentValues);
|
||||||
|
|
||||||
DatabaseFactory.getThreadDatabase(context).update(record.getThreadId());
|
DatabaseFactory.getThreadDatabase(context).update(record.getThreadId(), true);
|
||||||
notifyConversationListeners(record.getThreadId());
|
notifyConversationListeners(record.getThreadId());
|
||||||
|
|
||||||
jobManager.add(new TrimThreadJob(context, record.getThreadId()));
|
jobManager.add(new TrimThreadJob(context, record.getThreadId()));
|
||||||
@ -372,7 +372,7 @@ public class SmsDatabase extends MessagingDatabase {
|
|||||||
SQLiteDatabase db = databaseHelper.getWritableDatabase();
|
SQLiteDatabase db = databaseHelper.getWritableDatabase();
|
||||||
long messageId = db.insert(TABLE_NAME, null, values);
|
long messageId = db.insert(TABLE_NAME, null, values);
|
||||||
|
|
||||||
DatabaseFactory.getThreadDatabase(context).update(threadId);
|
DatabaseFactory.getThreadDatabase(context).update(threadId, true);
|
||||||
notifyConversationListeners(threadId);
|
notifyConversationListeners(threadId);
|
||||||
jobManager.add(new TrimThreadJob(context, threadId));
|
jobManager.add(new TrimThreadJob(context, threadId));
|
||||||
|
|
||||||
@ -450,7 +450,7 @@ public class SmsDatabase extends MessagingDatabase {
|
|||||||
DatabaseFactory.getThreadDatabase(context).setUnread(threadId);
|
DatabaseFactory.getThreadDatabase(context).setUnread(threadId);
|
||||||
}
|
}
|
||||||
|
|
||||||
DatabaseFactory.getThreadDatabase(context).update(threadId);
|
DatabaseFactory.getThreadDatabase(context).update(threadId, true);
|
||||||
notifyConversationListeners(threadId);
|
notifyConversationListeners(threadId);
|
||||||
jobManager.add(new TrimThreadJob(context, threadId));
|
jobManager.add(new TrimThreadJob(context, threadId));
|
||||||
|
|
||||||
@ -481,7 +481,7 @@ public class SmsDatabase extends MessagingDatabase {
|
|||||||
SQLiteDatabase db = databaseHelper.getWritableDatabase();
|
SQLiteDatabase db = databaseHelper.getWritableDatabase();
|
||||||
long messageId = db.insert(TABLE_NAME, ADDRESS, contentValues);
|
long messageId = db.insert(TABLE_NAME, ADDRESS, contentValues);
|
||||||
|
|
||||||
DatabaseFactory.getThreadDatabase(context).update(threadId);
|
DatabaseFactory.getThreadDatabase(context).update(threadId, true);
|
||||||
notifyConversationListeners(threadId);
|
notifyConversationListeners(threadId);
|
||||||
jobManager.add(new TrimThreadJob(context, threadId));
|
jobManager.add(new TrimThreadJob(context, threadId));
|
||||||
|
|
||||||
@ -526,7 +526,7 @@ public class SmsDatabase extends MessagingDatabase {
|
|||||||
SQLiteDatabase db = databaseHelper.getWritableDatabase();
|
SQLiteDatabase db = databaseHelper.getWritableDatabase();
|
||||||
long threadId = getThreadIdForMessage(messageId);
|
long threadId = getThreadIdForMessage(messageId);
|
||||||
db.delete(TABLE_NAME, ID_WHERE, new String[] {messageId+""});
|
db.delete(TABLE_NAME, ID_WHERE, new String[] {messageId+""});
|
||||||
boolean threadDeleted = DatabaseFactory.getThreadDatabase(context).update(threadId);
|
boolean threadDeleted = DatabaseFactory.getThreadDatabase(context).update(threadId, false);
|
||||||
notifyConversationListeners(threadId);
|
notifyConversationListeners(threadId);
|
||||||
return threadDeleted;
|
return threadDeleted;
|
||||||
}
|
}
|
||||||
|
@ -197,7 +197,7 @@ public class SmsMigrator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ourSmsDatabase.endTransaction(transaction);
|
ourSmsDatabase.endTransaction(transaction);
|
||||||
DatabaseFactory.getThreadDatabase(context).update(ourThreadId);
|
DatabaseFactory.getThreadDatabase(context).update(ourThreadId, true);
|
||||||
DatabaseFactory.getThreadDatabase(context).notifyConversationListeners(ourThreadId);
|
DatabaseFactory.getThreadDatabase(context).notifyConversationListeners(ourThreadId);
|
||||||
|
|
||||||
} finally {
|
} finally {
|
||||||
|
@ -59,19 +59,21 @@ public class ThreadDatabase extends Database {
|
|||||||
public static final String SNIPPET = "snippet";
|
public static final String SNIPPET = "snippet";
|
||||||
private static final String SNIPPET_CHARSET = "snippet_cs";
|
private static final String SNIPPET_CHARSET = "snippet_cs";
|
||||||
public static final String READ = "read";
|
public static final String READ = "read";
|
||||||
private static final String TYPE = "type";
|
public static final String TYPE = "type";
|
||||||
private static final String ERROR = "error";
|
private static final String ERROR = "error";
|
||||||
public static final String SNIPPET_TYPE = "snippet_type";
|
public static final String SNIPPET_TYPE = "snippet_type";
|
||||||
private static final String SNIPPET_URI = "snippet_uri";
|
public static final String SNIPPET_URI = "snippet_uri";
|
||||||
|
public static final String ARCHIVED = "archived";
|
||||||
|
|
||||||
public static final String CREATE_TABLE = "CREATE TABLE " + TABLE_NAME + " (" + ID + " INTEGER PRIMARY KEY, " +
|
public static final String CREATE_TABLE = "CREATE TABLE " + TABLE_NAME + " (" + ID + " INTEGER PRIMARY KEY, " +
|
||||||
DATE + " INTEGER DEFAULT 0, " + MESSAGE_COUNT + " INTEGER DEFAULT 0, " +
|
DATE + " INTEGER DEFAULT 0, " + MESSAGE_COUNT + " INTEGER DEFAULT 0, " +
|
||||||
RECIPIENT_IDS + " TEXT, " + SNIPPET + " TEXT, " + SNIPPET_CHARSET + " INTEGER DEFAULT 0, " +
|
RECIPIENT_IDS + " TEXT, " + SNIPPET + " TEXT, " + SNIPPET_CHARSET + " INTEGER DEFAULT 0, " +
|
||||||
READ + " INTEGER DEFAULT 1, " + TYPE + " INTEGER DEFAULT 0, " + ERROR + " INTEGER DEFAULT 0, " +
|
READ + " INTEGER DEFAULT 1, " + TYPE + " INTEGER DEFAULT 0, " + ERROR + " INTEGER DEFAULT 0, " +
|
||||||
SNIPPET_TYPE + " INTEGER DEFAULT 0, " + SNIPPET_URI + " TEXT DEFAULT NULL);";
|
SNIPPET_TYPE + " INTEGER DEFAULT 0, " + SNIPPET_URI + " TEXT DEFAULT NULL, " + ARCHIVED + " INTEGER DEFAULT 0);";
|
||||||
|
|
||||||
public static final String[] CREATE_INDEXS = {
|
public static final String[] CREATE_INDEXS = {
|
||||||
"CREATE INDEX IF NOT EXISTS thread_recipient_ids_index ON " + TABLE_NAME + " (" + RECIPIENT_IDS + ");",
|
"CREATE INDEX IF NOT EXISTS thread_recipient_ids_index ON " + TABLE_NAME + " (" + RECIPIENT_IDS + ");",
|
||||||
|
"CREATE INDEX IF NOT EXISTS archived_index ON " + TABLE_NAME + " (" + ARCHIVED + ");",
|
||||||
};
|
};
|
||||||
|
|
||||||
public ThreadDatabase(Context context, SQLiteOpenHelper databaseHelper) {
|
public ThreadDatabase(Context context, SQLiteOpenHelper databaseHelper) {
|
||||||
@ -124,27 +126,36 @@ public class ThreadDatabase extends Database {
|
|||||||
return db.insert(TABLE_NAME, null, contentValues);
|
return db.insert(TABLE_NAME, null, contentValues);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateThread(long threadId, long count, String body, @Nullable Uri attachment, long date, long type)
|
private void updateThread(long threadId, long count, String body, @Nullable Uri attachment, long date, long type, boolean unarchive)
|
||||||
{
|
{
|
||||||
ContentValues contentValues = new ContentValues(4);
|
ContentValues contentValues = new ContentValues(5);
|
||||||
contentValues.put(DATE, date - date % 1000);
|
contentValues.put(DATE, date - date % 1000);
|
||||||
contentValues.put(MESSAGE_COUNT, count);
|
contentValues.put(MESSAGE_COUNT, count);
|
||||||
contentValues.put(SNIPPET, body);
|
contentValues.put(SNIPPET, body);
|
||||||
contentValues.put(SNIPPET_URI, attachment == null ? null : attachment.toString());
|
contentValues.put(SNIPPET_URI, attachment == null ? null : attachment.toString());
|
||||||
contentValues.put(SNIPPET_TYPE, type);
|
contentValues.put(SNIPPET_TYPE, type);
|
||||||
|
|
||||||
|
if (unarchive) {
|
||||||
|
contentValues.put(ARCHIVED, 0);
|
||||||
|
}
|
||||||
|
|
||||||
SQLiteDatabase db = databaseHelper.getWritableDatabase();
|
SQLiteDatabase db = databaseHelper.getWritableDatabase();
|
||||||
db.update(TABLE_NAME, contentValues, ID + " = ?", new String[] {threadId + ""});
|
db.update(TABLE_NAME, contentValues, ID + " = ?", new String[] {threadId + ""});
|
||||||
notifyConversationListListeners();
|
notifyConversationListListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateSnippet(long threadId, String snippet, @Nullable Uri attachment, long date, long type) {
|
public void updateSnippet(long threadId, String snippet, @Nullable Uri attachment, long date, long type, boolean unarchive) {
|
||||||
ContentValues contentValues = new ContentValues(3);
|
ContentValues contentValues = new ContentValues(3);
|
||||||
|
|
||||||
contentValues.put(DATE, date - date % 1000);
|
contentValues.put(DATE, date - date % 1000);
|
||||||
contentValues.put(SNIPPET, snippet);
|
contentValues.put(SNIPPET, snippet);
|
||||||
contentValues.put(SNIPPET_TYPE, type);
|
contentValues.put(SNIPPET_TYPE, type);
|
||||||
contentValues.put(SNIPPET_URI, attachment == null ? null : attachment.toString());
|
contentValues.put(SNIPPET_URI, attachment == null ? null : attachment.toString());
|
||||||
|
|
||||||
|
if (unarchive) {
|
||||||
|
contentValues.put(ARCHIVED, 0);
|
||||||
|
}
|
||||||
|
|
||||||
SQLiteDatabase db = databaseHelper.getWritableDatabase();
|
SQLiteDatabase db = databaseHelper.getWritableDatabase();
|
||||||
db.update(TABLE_NAME, contentValues, ID + " = ?", new String[] {threadId + ""});
|
db.update(TABLE_NAME, contentValues, ID + " = ?", new String[] {threadId + ""});
|
||||||
notifyConversationListListeners();
|
notifyConversationListListeners();
|
||||||
@ -217,7 +228,7 @@ public class ThreadDatabase extends Database {
|
|||||||
DatabaseFactory.getSmsDatabase(context).deleteMessagesInThreadBeforeDate(threadId, lastTweetDate);
|
DatabaseFactory.getSmsDatabase(context).deleteMessagesInThreadBeforeDate(threadId, lastTweetDate);
|
||||||
DatabaseFactory.getMmsDatabase(context).deleteMessagesInThreadBeforeDate(threadId, lastTweetDate);
|
DatabaseFactory.getMmsDatabase(context).deleteMessagesInThreadBeforeDate(threadId, lastTweetDate);
|
||||||
|
|
||||||
update(threadId);
|
update(threadId, false);
|
||||||
notifyConversationListeners(threadId);
|
notifyConversationListeners(threadId);
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
@ -303,11 +314,59 @@ public class ThreadDatabase extends Database {
|
|||||||
|
|
||||||
public Cursor getConversationList() {
|
public Cursor getConversationList() {
|
||||||
SQLiteDatabase db = databaseHelper.getReadableDatabase();
|
SQLiteDatabase db = databaseHelper.getReadableDatabase();
|
||||||
Cursor cursor = db.query(TABLE_NAME, null, null, null, null, null, DATE + " DESC");
|
Cursor cursor = db.query(TABLE_NAME, null, ARCHIVED + " = ?", new String[] {"0"}, null, null, DATE + " DESC");
|
||||||
|
|
||||||
setNotifyConverationListListeners(cursor);
|
setNotifyConverationListListeners(cursor);
|
||||||
|
|
||||||
return cursor;
|
return cursor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Cursor getArchivedConversationList() {
|
||||||
|
SQLiteDatabase db = databaseHelper.getReadableDatabase();
|
||||||
|
Cursor cursor = db.query(TABLE_NAME, null, ARCHIVED + " = ?", new String[] {"1"}, null, null, DATE + " DESC");
|
||||||
|
|
||||||
|
setNotifyConverationListListeners(cursor);
|
||||||
|
|
||||||
|
return cursor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getArchivedConversationListCount() {
|
||||||
|
SQLiteDatabase db = databaseHelper.getReadableDatabase();
|
||||||
|
Cursor cursor = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
cursor = db.query(TABLE_NAME, new String[] {"COUNT(*)"}, ARCHIVED + " = ?",
|
||||||
|
new String[] {"1"}, null, null, null);
|
||||||
|
|
||||||
|
if (cursor != null && cursor.moveToFirst()) {
|
||||||
|
return cursor.getInt(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
if (cursor != null) cursor.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void archiveConversation(long threadId) {
|
||||||
|
SQLiteDatabase db = databaseHelper.getWritableDatabase();
|
||||||
|
ContentValues contentValues = new ContentValues(1);
|
||||||
|
contentValues.put(ARCHIVED, 1);
|
||||||
|
|
||||||
|
db.update(TABLE_NAME, contentValues, ID_WHERE, new String[] {threadId + ""});
|
||||||
|
notifyConversationListListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void unarchiveConversation(long threadId) {
|
||||||
|
SQLiteDatabase db = databaseHelper.getWritableDatabase();
|
||||||
|
ContentValues contentValues = new ContentValues(1);
|
||||||
|
contentValues.put(ARCHIVED, 0);
|
||||||
|
|
||||||
|
db.update(TABLE_NAME, contentValues, ID_WHERE, new String[] {threadId + ""});
|
||||||
|
notifyConversationListListeners();
|
||||||
|
}
|
||||||
|
|
||||||
public void deleteConversation(long threadId) {
|
public void deleteConversation(long threadId) {
|
||||||
DatabaseFactory.getSmsDatabase(context).deleteThread(threadId);
|
DatabaseFactory.getSmsDatabase(context).deleteThread(threadId);
|
||||||
DatabaseFactory.getMmsDatabase(context).deleteThread(threadId);
|
DatabaseFactory.getMmsDatabase(context).deleteThread(threadId);
|
||||||
@ -317,7 +376,6 @@ public class ThreadDatabase extends Database {
|
|||||||
notifyConversationListListeners();
|
notifyConversationListListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void deleteConversations(Set<Long> selectedConversations) {
|
public void deleteConversations(Set<Long> selectedConversations) {
|
||||||
DatabaseFactory.getSmsDatabase(context).deleteThreads(selectedConversations);
|
DatabaseFactory.getSmsDatabase(context).deleteThreads(selectedConversations);
|
||||||
DatabaseFactory.getMmsDatabase(context).deleteThreads(selectedConversations);
|
DatabaseFactory.getMmsDatabase(context).deleteThreads(selectedConversations);
|
||||||
@ -399,7 +457,7 @@ public class ThreadDatabase extends Database {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean update(long threadId) {
|
public boolean update(long threadId, boolean unarchive) {
|
||||||
MmsSmsDatabase mmsSmsDatabase = DatabaseFactory.getMmsSmsDatabase(context);
|
MmsSmsDatabase mmsSmsDatabase = DatabaseFactory.getMmsSmsDatabase(context);
|
||||||
long count = mmsSmsDatabase.getConversationCount(threadId);
|
long count = mmsSmsDatabase.getConversationCount(threadId);
|
||||||
|
|
||||||
@ -421,7 +479,10 @@ public class ThreadDatabase extends Database {
|
|||||||
if (record.isPush()) timestamp = record.getDateSent();
|
if (record.isPush()) timestamp = record.getDateSent();
|
||||||
else timestamp = record.getDateReceived();
|
else timestamp = record.getDateReceived();
|
||||||
|
|
||||||
updateThread(threadId, count, record.getBody().getBody(), getAttachmentUriFor(record), timestamp, record.getType());
|
updateThread(threadId, count, record.getBody().getBody(),
|
||||||
|
getAttachmentUriFor(record), timestamp,
|
||||||
|
record.getType(), unarchive);
|
||||||
|
|
||||||
notifyConversationListListeners();
|
notifyConversationListListeners();
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
@ -456,6 +517,7 @@ public class ThreadDatabase extends Database {
|
|||||||
public static final int DEFAULT = 2;
|
public static final int DEFAULT = 2;
|
||||||
public static final int BROADCAST = 1;
|
public static final int BROADCAST = 1;
|
||||||
public static final int CONVERSATION = 2;
|
public static final int CONVERSATION = 2;
|
||||||
|
public static final int ARCHIVE = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Reader {
|
public class Reader {
|
||||||
@ -486,10 +548,11 @@ public class ThreadDatabase extends Database {
|
|||||||
long read = cursor.getLong(cursor.getColumnIndexOrThrow(ThreadDatabase.READ));
|
long read = cursor.getLong(cursor.getColumnIndexOrThrow(ThreadDatabase.READ));
|
||||||
long type = cursor.getLong(cursor.getColumnIndexOrThrow(ThreadDatabase.SNIPPET_TYPE));
|
long type = cursor.getLong(cursor.getColumnIndexOrThrow(ThreadDatabase.SNIPPET_TYPE));
|
||||||
int distributionType = cursor.getInt(cursor.getColumnIndexOrThrow(ThreadDatabase.TYPE));
|
int distributionType = cursor.getInt(cursor.getColumnIndexOrThrow(ThreadDatabase.TYPE));
|
||||||
|
boolean archived = cursor.getInt(cursor.getColumnIndex(ThreadDatabase.ARCHIVED)) != 0;
|
||||||
Uri snippetUri = getSnippetUri(cursor);
|
Uri snippetUri = getSnippetUri(cursor);
|
||||||
|
|
||||||
return new ThreadRecord(context, body, snippetUri, recipients, date, count,
|
return new ThreadRecord(context, body, snippetUri, recipients, date, count,
|
||||||
read == 1, threadId, type, distributionType);
|
read == 1, threadId, type, distributionType, archived);
|
||||||
}
|
}
|
||||||
|
|
||||||
private DisplayRecord.Body getPlaintextBody(Cursor cursor) {
|
private DisplayRecord.Body getPlaintextBody(Cursor cursor) {
|
||||||
|
@ -2,30 +2,64 @@ package org.thoughtcrime.securesms.database.loaders;
|
|||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
|
import android.database.MatrixCursor;
|
||||||
|
import android.database.MergeCursor;
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.contacts.ContactAccessor;
|
import org.thoughtcrime.securesms.contacts.ContactAccessor;
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||||
|
import org.thoughtcrime.securesms.database.ThreadDatabase;
|
||||||
import org.thoughtcrime.securesms.util.AbstractCursorLoader;
|
import org.thoughtcrime.securesms.util.AbstractCursorLoader;
|
||||||
|
|
||||||
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class ConversationListLoader extends AbstractCursorLoader {
|
public class ConversationListLoader extends AbstractCursorLoader {
|
||||||
|
|
||||||
private final String filter;
|
private final String filter;
|
||||||
|
private final boolean archived;
|
||||||
|
|
||||||
public ConversationListLoader(Context context, String filter) {
|
public ConversationListLoader(Context context, String filter, boolean archived) {
|
||||||
super(context);
|
super(context);
|
||||||
this.filter = filter;
|
this.filter = filter;
|
||||||
|
this.archived = archived;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Cursor getCursor() {
|
public Cursor getCursor() {
|
||||||
if (filter != null && filter.trim().length() != 0) {
|
if (filter != null && filter.trim().length() != 0) return getFilteredConversationList(filter);
|
||||||
List<String> numbers = ContactAccessor.getInstance().getNumbersForThreadSearchFilter(context, filter);
|
else if (!archived) return getUnarchivedConversationList();
|
||||||
|
else return getArchivedConversationList();
|
||||||
return DatabaseFactory.getThreadDatabase(context).getFilteredConversationList(numbers);
|
|
||||||
} else {
|
|
||||||
return DatabaseFactory.getThreadDatabase(context).getConversationList();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Cursor getUnarchivedConversationList() {
|
||||||
|
List<Cursor> cursorList = new LinkedList<>();
|
||||||
|
cursorList.add(DatabaseFactory.getThreadDatabase(context).getConversationList());
|
||||||
|
|
||||||
|
int archivedCount = DatabaseFactory.getThreadDatabase(context)
|
||||||
|
.getArchivedConversationListCount();
|
||||||
|
|
||||||
|
if (archivedCount > 0) {
|
||||||
|
MatrixCursor switchToArchiveCursor = new MatrixCursor(new String[] {
|
||||||
|
ThreadDatabase.ID, ThreadDatabase.DATE, ThreadDatabase.MESSAGE_COUNT,
|
||||||
|
ThreadDatabase.RECIPIENT_IDS, ThreadDatabase.SNIPPET, ThreadDatabase.READ,
|
||||||
|
ThreadDatabase.TYPE, ThreadDatabase.SNIPPET_TYPE, ThreadDatabase.SNIPPET_URI,
|
||||||
|
ThreadDatabase.ARCHIVED}, 1);
|
||||||
|
|
||||||
|
switchToArchiveCursor.addRow(new Object[] {-1L, System.currentTimeMillis(), archivedCount,
|
||||||
|
"-1", null, 1, ThreadDatabase.DistributionTypes.ARCHIVE, 0, null, 0});
|
||||||
|
|
||||||
|
cursorList.add(switchToArchiveCursor);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new MergeCursor(cursorList.toArray(new Cursor[0]));
|
||||||
|
}
|
||||||
|
|
||||||
|
private Cursor getArchivedConversationList() {
|
||||||
|
return DatabaseFactory.getThreadDatabase(context).getArchivedConversationList();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Cursor getFilteredConversationList(String filter) {
|
||||||
|
List<String> numbers = ContactAccessor.getInstance().getNumbersForThreadSearchFilter(context, filter);
|
||||||
|
return DatabaseFactory.getThreadDatabase(context).getFilteredConversationList(numbers);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -44,10 +44,11 @@ public class ThreadRecord extends DisplayRecord {
|
|||||||
private final long count;
|
private final long count;
|
||||||
private final boolean read;
|
private final boolean read;
|
||||||
private final int distributionType;
|
private final int distributionType;
|
||||||
|
private final boolean archived;
|
||||||
|
|
||||||
public ThreadRecord(@NonNull Context context, @NonNull Body body, @Nullable Uri snippetUri,
|
public ThreadRecord(@NonNull Context context, @NonNull Body body, @Nullable Uri snippetUri,
|
||||||
@NonNull Recipients recipients, long date, long count, boolean read,
|
@NonNull Recipients recipients, long date, long count, boolean read,
|
||||||
long threadId, long snippetType, int distributionType)
|
long threadId, long snippetType, int distributionType, boolean archived)
|
||||||
{
|
{
|
||||||
super(context, body, recipients, date, date, threadId, snippetType);
|
super(context, body, recipients, date, date, threadId, snippetType);
|
||||||
this.context = context.getApplicationContext();
|
this.context = context.getApplicationContext();
|
||||||
@ -55,6 +56,7 @@ public class ThreadRecord extends DisplayRecord {
|
|||||||
this.count = count;
|
this.count = count;
|
||||||
this.read = read;
|
this.read = read;
|
||||||
this.distributionType = distributionType;
|
this.distributionType = distributionType;
|
||||||
|
this.archived = archived;
|
||||||
}
|
}
|
||||||
|
|
||||||
public @Nullable Uri getSnippetUri() {
|
public @Nullable Uri getSnippetUri() {
|
||||||
@ -124,6 +126,10 @@ public class ThreadRecord extends DisplayRecord {
|
|||||||
return getDateReceived();
|
return getDateReceived();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isArchived() {
|
||||||
|
return archived;
|
||||||
|
}
|
||||||
|
|
||||||
public int getDistributionType() {
|
public int getDistributionType() {
|
||||||
return distributionType;
|
return distributionType;
|
||||||
}
|
}
|
||||||
|
@ -31,7 +31,7 @@ import org.thoughtcrime.securesms.contacts.ContactAccessor;
|
|||||||
import org.thoughtcrime.securesms.contacts.ContactIdentityManager;
|
import org.thoughtcrime.securesms.contacts.ContactIdentityManager;
|
||||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||||
import org.thoughtcrime.securesms.push.TextSecureCommunicationFactory;
|
import org.thoughtcrime.securesms.push.TextSecureCommunicationFactory;
|
||||||
import org.thoughtcrime.securesms.util.ProgressDialogAsyncTask;
|
import org.thoughtcrime.securesms.util.task.ProgressDialogAsyncTask;
|
||||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||||
import org.whispersystems.libaxolotl.util.guava.Optional;
|
import org.whispersystems.libaxolotl.util.guava.Optional;
|
||||||
import org.whispersystems.textsecure.api.TextSecureAccountManager;
|
import org.whispersystems.textsecure.api.TextSecureAccountManager;
|
||||||
|
@ -13,6 +13,7 @@ import android.widget.Toast;
|
|||||||
import org.thoughtcrime.securesms.R;
|
import org.thoughtcrime.securesms.R;
|
||||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||||
import org.thoughtcrime.securesms.mms.PartAuthority;
|
import org.thoughtcrime.securesms.mms.PartAuthority;
|
||||||
|
import org.thoughtcrime.securesms.util.task.ProgressDialogAsyncTask;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package org.thoughtcrime.securesms.util;
|
package org.thoughtcrime.securesms.util.task;
|
||||||
|
|
||||||
import android.app.ProgressDialog;
|
import android.app.ProgressDialog;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
@ -7,6 +7,7 @@ import android.os.AsyncTask;
|
|||||||
import java.lang.ref.WeakReference;
|
import java.lang.ref.WeakReference;
|
||||||
|
|
||||||
public abstract class ProgressDialogAsyncTask<Params, Progress, Result> extends AsyncTask<Params, Progress, Result> {
|
public abstract class ProgressDialogAsyncTask<Params, Progress, Result> extends AsyncTask<Params, Progress, Result> {
|
||||||
|
|
||||||
private final WeakReference<Context> contextReference;
|
private final WeakReference<Context> contextReference;
|
||||||
private ProgressDialog progress;
|
private ProgressDialog progress;
|
||||||
private final String title;
|
private final String title;
|
@ -0,0 +1,94 @@
|
|||||||
|
package org.thoughtcrime.securesms.util.task;
|
||||||
|
|
||||||
|
import android.app.ProgressDialog;
|
||||||
|
import android.os.AsyncTask;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
|
import android.support.design.widget.Snackbar;
|
||||||
|
import android.view.View;
|
||||||
|
|
||||||
|
public abstract class SnackbarAsyncTask<Params>
|
||||||
|
extends AsyncTask<Params, Void, Void>
|
||||||
|
implements View.OnClickListener
|
||||||
|
{
|
||||||
|
|
||||||
|
private final View view;
|
||||||
|
private final String snackbarText;
|
||||||
|
private final String snackbarActionText;
|
||||||
|
private final int snackbarActionColor;
|
||||||
|
private final int snackbarDuration;
|
||||||
|
private final boolean showProgress;
|
||||||
|
|
||||||
|
private @Nullable Params reversibleParameter;
|
||||||
|
private @Nullable ProgressDialog progressDialog;
|
||||||
|
|
||||||
|
public SnackbarAsyncTask(View view,
|
||||||
|
String snackbarText,
|
||||||
|
String snackbarActionText,
|
||||||
|
int snackbarActionColor,
|
||||||
|
int snackbarDuration,
|
||||||
|
boolean showProgress)
|
||||||
|
{
|
||||||
|
this.view = view;
|
||||||
|
this.snackbarText = snackbarText;
|
||||||
|
this.snackbarActionText = snackbarActionText;
|
||||||
|
this.snackbarActionColor = snackbarActionColor;
|
||||||
|
this.snackbarDuration = snackbarDuration;
|
||||||
|
this.showProgress = showProgress;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPreExecute() {
|
||||||
|
if (this.showProgress) this.progressDialog = ProgressDialog.show(view.getContext(), "", "", true);
|
||||||
|
else this.progressDialog = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SafeVarargs
|
||||||
|
@Override
|
||||||
|
protected final Void doInBackground(Params... params) {
|
||||||
|
this.reversibleParameter = params != null && params.length > 0 ?params[0] : null;
|
||||||
|
executeAction(reversibleParameter);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPostExecute(Void result) {
|
||||||
|
if (this.showProgress && this.progressDialog != null) {
|
||||||
|
this.progressDialog.dismiss();
|
||||||
|
this.progressDialog = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Snackbar.make(view, snackbarText, snackbarDuration)
|
||||||
|
.setAction(snackbarActionText, this)
|
||||||
|
.setActionTextColor(snackbarActionColor)
|
||||||
|
.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
new AsyncTask<Void, Void, Void>() {
|
||||||
|
@Override
|
||||||
|
protected void onPreExecute() {
|
||||||
|
if (showProgress) progressDialog = ProgressDialog.show(view.getContext(), "", "", true);
|
||||||
|
else progressDialog = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Void doInBackground(Void... params) {
|
||||||
|
reverseAction(reversibleParameter);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPostExecute(Void result) {
|
||||||
|
if (showProgress && progressDialog != null) {
|
||||||
|
progressDialog.dismiss();
|
||||||
|
progressDialog = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract void executeAction(@Nullable Params parameter);
|
||||||
|
protected abstract void reverseAction(@Nullable Params parameter);
|
||||||
|
|
||||||
|
}
|