add expiring messages option in conversation info screen

Signed-off-by: Marcel Hibbe <dev@mhibbe.de>
This commit is contained in:
Marcel Hibbe 2022-08-18 20:56:03 +02:00
parent 77f69a676b
commit 4bdb78372e
No known key found for this signature in database
GPG Key ID: C793F8B59F43CE7B
8 changed files with 244 additions and 105 deletions

View File

@ -550,4 +550,10 @@ public interface NcApi {
@DELETE @DELETE
Observable<PollOverall> closePoll(@Header("Authorization") String authorization, Observable<PollOverall> closePoll(@Header("Authorization") String authorization,
@Url String url); @Url String url);
@FormUrlEncoded
@POST
Observable<GenericOverall> setMessageExpiration(@Header("Authorization") String authorization,
@Url String url,
@Field("seconds") Integer seconds);
} }

View File

@ -2217,7 +2217,7 @@ class ChatController(args: Bundle) :
Log.i(TAG, "UI destroyed - view binding already gone") Log.i(TAG, "UI destroyed - view binding already gone")
} }
deleteExpiredMessages() processExpiredMessages()
} }
override fun onError(e: Throwable) { override fun onError(e: Throwable) {
@ -2259,7 +2259,7 @@ class ChatController(args: Bundle) :
Log.i(TAG, "UI destroyed - view binding already gone", e) Log.i(TAG, "UI destroyed - view binding already gone", e)
} }
deleteExpiredMessages() processExpiredMessages()
} }
override fun onError(e: Throwable) { override fun onError(e: Throwable) {
@ -2274,8 +2274,8 @@ class ChatController(args: Bundle) :
} }
} }
private fun deleteExpiredMessages() { private fun processExpiredMessages() {
if (CapabilitiesUtilNew.hasSpreedFeatureCapability(conversationUser, "message-expiration")) { fun deleteExpiredMessages() {
val messagesToDelete: ArrayList<ChatMessage> = ArrayList() val messagesToDelete: ArrayList<ChatMessage> = ArrayList()
val systemTime = System.currentTimeMillis() / ONE_SECOND_IN_MILLIS val systemTime = System.currentTimeMillis() / ONE_SECOND_IN_MILLIS
@ -2290,6 +2290,10 @@ class ChatController(args: Bundle) :
adapter!!.delete(messagesToDelete) adapter!!.delete(messagesToDelete)
adapter!!.notifyDataSetChanged() adapter!!.notifyDataSetChanged()
} }
if (CapabilitiesUtilNew.hasSpreedFeatureCapability(conversationUser, "message-expiration")) {
deleteExpiredMessages()
}
} }
private fun processMessages(response: Response<*>, isFromTheFuture: Boolean, timeout: Int) { private fun processMessages(response: Response<*>, isFromTheFuture: Boolean, timeout: Int) {

View File

@ -677,6 +677,7 @@ class ConversationInfoController(args: Bundle) :
loadConversationAvatar() loadConversationAvatar()
adjustNotificationLevelUI() adjustNotificationLevelUI()
initExpiringMessageOption()
binding.notificationSettingsView.notificationSettings.visibility = View.VISIBLE binding.notificationSettingsView.notificationSettings.visibility = View.VISIBLE
} }
@ -697,6 +698,18 @@ class ConversationInfoController(args: Bundle) :
}) })
} }
private fun initExpiringMessageOption() {
if (conversation!!.isParticipantOwnerOrModerator &&
CapabilitiesUtilNew.hasSpreedFeatureCapability(conversationUser, "message-expiration")
) {
databaseStorageModule?.setMessageExpiration(conversation!!.messageExpiration)
binding.conversationInfoExpireMessages.setStorageModule(databaseStorageModule)
binding.conversationInfoExpireMessages.visibility = View.VISIBLE
} else {
binding.categoryConversationSettings.visibility = View.GONE
}
}
private fun adjustNotificationLevelUI() { private fun adjustNotificationLevelUI() {
if (conversation != null) { if (conversation != null) {
if ( if (

View File

@ -147,7 +147,7 @@ public class ApiUtils {
return version; return version;
} }
if (version == APIv1 && if (version == APIv1 &&
user.hasSpreedFeatureCapability( "mention-flag") && user.hasSpreedFeatureCapability("mention-flag") &&
!user.hasSpreedFeatureCapability("conversation-v4")) { !user.hasSpreedFeatureCapability("conversation-v4")) {
return version; return version;
} }
@ -479,4 +479,8 @@ public class ApiUtils {
return baseUrl + ocsApiVersion + spreedApiVersion + "/poll/" + roomToken; return baseUrl + ocsApiVersion + spreedApiVersion + "/poll/" + roomToken;
} }
public static String getUrlForMessageExpiration(int version, String baseUrl, String token) {
return getUrlForRoom(version, baseUrl, token) + "/message-expiration";
}
} }

View File

@ -60,6 +60,7 @@ public class DatabaseStorageModule implements StorageModule {
@Inject @Inject
NcApi ncApi; NcApi ncApi;
private int messageExpiration;
private final User conversationUser; private final User conversationUser;
private final String conversationToken; private final String conversationToken;
private final long accountIdentifier; private final long accountIdentifier;
@ -78,7 +79,7 @@ public class DatabaseStorageModule implements StorageModule {
@Override @Override
public void saveBoolean(String key, boolean value) { public void saveBoolean(String key, boolean value) {
if(key.equals("call_notifications")) { if (key.equals("call_notifications")) {
int apiVersion = ApiUtils.getConversationApiVersion(conversationUser, new int[]{4}); int apiVersion = ApiUtils.getConversationApiVersion(conversationUser, new int[]{4});
ncApi.notificationCalls(ApiUtils.getCredentials(conversationUser.getUsername(), ncApi.notificationCalls(ApiUtils.getCredentials(conversationUser.getUsername(),
conversationUser.getToken()), conversationUser.getToken()),
@ -89,27 +90,27 @@ public class DatabaseStorageModule implements StorageModule {
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<GenericOverall>() { .subscribe(new Observer<GenericOverall>() {
@Override @Override
public void onSubscribe(@NotNull Disposable d) { public void onSubscribe(@NotNull Disposable d) {
// unused atm // unused atm
} }
@Override @Override
public void onNext(@NotNull GenericOverall genericOverall) { public void onNext(@NotNull GenericOverall genericOverall) {
Log.d(TAG, "Toggled notification calls"); Log.d(TAG, "Toggled notification calls");
} }
@Override @Override
public void onError(@NotNull Throwable e) { public void onError(@NotNull Throwable e) {
Log.e(TAG, "Error when trying to toggle notification calls", e); Log.e(TAG, "Error when trying to toggle notification calls", e);
} }
@Override @Override
public void onComplete() { public void onComplete() {
// unused atm // unused atm
} }
} }
); );
} }
if (!key.equals("conversation_lobby")) { if (!key.equals("conversation_lobby")) {
@ -124,9 +125,46 @@ public class DatabaseStorageModule implements StorageModule {
@Override @Override
public void saveString(String key, String value) { public void saveString(String key, String value) {
if (!key.equals("message_notification_level")) { if (key.equals("message_expire_key")) {
arbitraryStorageManager.storeStorageSetting(accountIdentifier, key, value, conversationToken); int apiVersion = ApiUtils.getConversationApiVersion(conversationUser, new int[]{4});
} else {
String trimmedValue = value.replace("expire_", "");
int valueInt = Integer.parseInt(trimmedValue);
ncApi.setMessageExpiration(
ApiUtils.getCredentials(
conversationUser.getUsername(),
conversationUser.getToken()),
ApiUtils.getUrlForMessageExpiration(
apiVersion,
conversationUser.getBaseUrl(),
conversationToken),
valueInt)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<GenericOverall>() {
@Override
public void onSubscribe(@NotNull Disposable d) {
// unused atm
}
@Override
public void onNext(@NotNull GenericOverall genericOverall) {
messageExpiration = valueInt;
}
@Override
public void onError(@NotNull Throwable e) {
Log.e(TAG, "Error when trying to set message expiration", e);
}
@Override
public void onComplete() {
// unused atm
}
});
} else if (key.equals("message_notification_level")) {
if (CapabilitiesUtilNew.hasSpreedFeatureCapability(conversationUser, "notification-levels")) { if (CapabilitiesUtilNew.hasSpreedFeatureCapability(conversationUser, "notification-levels")) {
if (!TextUtils.isEmpty(messageNotificationLevel) && !messageNotificationLevel.equals(value)) { if (!TextUtils.isEmpty(messageNotificationLevel) && !messageNotificationLevel.equals(value)) {
int intValue; int intValue;
@ -144,40 +182,42 @@ public class DatabaseStorageModule implements StorageModule {
intValue = 0; intValue = 0;
} }
int apiVersion = ApiUtils.getConversationApiVersion(conversationUser, new int[] {ApiUtils.APIv4, 1}); int apiVersion = ApiUtils.getConversationApiVersion(conversationUser, new int[]{ApiUtils.APIv4, 1});
ncApi.setNotificationLevel(ApiUtils.getCredentials(conversationUser.getUsername(), ncApi.setNotificationLevel(ApiUtils.getCredentials(conversationUser.getUsername(),
conversationUser.getToken()), conversationUser.getToken()),
ApiUtils.getUrlForRoomNotificationLevel(apiVersion, ApiUtils.getUrlForRoomNotificationLevel(apiVersion,
conversationUser.getBaseUrl(), conversationUser.getBaseUrl(),
conversationToken), conversationToken),
intValue) intValue)
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())
.subscribe(new Observer<GenericOverall>() { .subscribe(new Observer<GenericOverall>() {
@Override @Override
public void onSubscribe(Disposable d) { public void onSubscribe(Disposable d) {
// unused atm // unused atm
} }
@Override @Override
public void onNext(GenericOverall genericOverall) { public void onNext(GenericOverall genericOverall) {
messageNotificationLevel = value; messageNotificationLevel = value;
} }
@Override @Override
public void onError(Throwable e) { public void onError(Throwable e) {
// unused atm // unused atm
} }
@Override @Override
public void onComplete() { public void onComplete() {
// unused atm // unused atm
} }
}); });
} else { } else {
messageNotificationLevel = value; messageNotificationLevel = value;
} }
} }
} else {
arbitraryStorageManager.storeStorageSetting(accountIdentifier, key, value, conversationToken);
} }
} }
@ -205,7 +245,22 @@ public class DatabaseStorageModule implements StorageModule {
@Override @Override
public String getString(String key, String defaultVal) { public String getString(String key, String defaultVal) {
if (key.equals("message_notification_level")) { if (key.equals("message_expire_key")) {
switch (messageExpiration) {
case 2419200:
return "expire_2419200";
case 604800:
return "expire_604800";
case 86400:
return "expire_86400";
case 28800:
return "expire_28800";
case 3600:
return "expire_3600";
default:
return "expire_0";
}
} else if (key.equals("message_notification_level")) {
return messageNotificationLevel; return messageNotificationLevel;
} else { } else {
return arbitraryStorageManager return arbitraryStorageManager
@ -243,4 +298,8 @@ public class DatabaseStorageModule implements StorageModule {
public void onRestoreInstanceState(Bundle savedState) { public void onRestoreInstanceState(Bundle savedState) {
// unused atm // unused atm
} }
public void setMessageExpiration(int messageExpiration) {
this.messageExpiration = messageExpiration;
}
} }

View File

@ -3,6 +3,8 @@
~ ~
~ @author Mario Danic ~ @author Mario Danic
~ @author Andy Scherzinger ~ @author Andy Scherzinger
~ @author Marcel Hibbe
~ Copyright (C) 2022 Marcel Hibbe <dev@mhibbe.de>
~ Copyright (C) 2021 Andy Scherzinger <info@andy-scherzinger.de> ~ Copyright (C) 2021 Andy Scherzinger <info@andy-scherzinger.de>
~ Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com> ~ Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
~ ~
@ -45,9 +47,10 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content"> android:layout_height="wrap_content">
<RelativeLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content"> android:layout_height="wrap_content"
android:orientation="vertical">
<com.yarolegovich.mp.MaterialPreferenceCategory <com.yarolegovich.mp.MaterialPreferenceCategory
android:id="@+id/conversation_info_name" android:id="@+id/conversation_info_name"
@ -87,7 +90,6 @@
android:id="@+id/conversation_description" android:id="@+id/conversation_description"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_below="@id/conversation_info_name"
android:animateLayoutChanges="true" android:animateLayoutChanges="true"
android:visibility="gone" android:visibility="gone"
apc:cardBackgroundColor="@color/bg_default" apc:cardBackgroundColor="@color/bg_default"
@ -109,7 +111,6 @@
android:id="@+id/otherRoomOptions" android:id="@+id/otherRoomOptions"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_below="@id/conversation_description"
android:visibility="gone" android:visibility="gone"
apc:cardBackgroundColor="@color/bg_default" apc:cardBackgroundColor="@color/bg_default"
apc:cardElevation="0dp" apc:cardElevation="0dp"
@ -127,11 +128,76 @@
</com.yarolegovich.mp.MaterialPreferenceCategory> </com.yarolegovich.mp.MaterialPreferenceCategory>
<LinearLayout
android:id="@+id/settings"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<include
android:id="@+id/notification_settings_view"
layout="@layout/notification_settings_item"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone"
tools:visibility="visible" />
<include
android:id="@+id/webinar_info_view"
layout="@layout/webinar_info_item"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone"
tools:visibility="visible" />
</LinearLayout>
<com.yarolegovich.mp.MaterialPreferenceCategory
android:id="@+id/category_shared_items"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:animateLayoutChanges="true"
apc:cardBackgroundColor="@color/bg_default"
apc:cardElevation="0dp"
apc:mpc_title="@string/nc_shared_items">
<com.yarolegovich.mp.MaterialStandardPreference
android:id="@+id/show_shared_items_action"
android:layout_width="match_parent"
android:layout_height="wrap_content"
apc:mp_icon="@drawable/ic_folder_multiple_image"
apc:mp_icon_tint="@color/grey_600"
apc:mp_title="@string/nc_shared_items_description" />
</com.yarolegovich.mp.MaterialPreferenceCategory>
<com.yarolegovich.mp.MaterialPreferenceCategory
android:id="@+id/category_conversation_settings"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:animateLayoutChanges="true"
apc:cardBackgroundColor="@color/bg_default"
apc:cardElevation="0dp"
apc:mpc_title="@string/nc_conversation_settings">
<com.yarolegovich.mp.MaterialChoicePreference
android:id="@+id/conversation_info_expire_messages"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone"
apc:mp_entry_descriptions="@array/message_expiring_descriptions"
apc:mp_entry_values="@array/message_expiring_values"
apc:mp_key="message_expire_key"
apc:mp_show_value="onBottom"
apc:mp_title="@string/nc_expire_messages">
</com.yarolegovich.mp.MaterialChoicePreference>
</com.yarolegovich.mp.MaterialPreferenceCategory>
<com.yarolegovich.mp.MaterialPreferenceCategory <com.yarolegovich.mp.MaterialPreferenceCategory
android:id="@+id/participants_list_category" android:id="@+id/participants_list_category"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_below="@+id/category_shared_items"
android:visibility="gone" android:visibility="gone"
apc:cardBackgroundColor="@color/bg_default" apc:cardBackgroundColor="@color/bg_default"
apc:cardElevation="0dp" apc:cardElevation="0dp"
@ -159,7 +225,6 @@
android:id="@+id/ownOptions" android:id="@+id/ownOptions"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_below="@id/participants_list_category"
android:visibility="gone" android:visibility="gone"
apc:cardBackgroundColor="@color/bg_default" apc:cardBackgroundColor="@color/bg_default"
apc:cardElevation="0dp" apc:cardElevation="0dp"
@ -191,52 +256,6 @@
</com.yarolegovich.mp.MaterialPreferenceCategory> </com.yarolegovich.mp.MaterialPreferenceCategory>
<LinearLayout </LinearLayout>
android:id="@+id/settings"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/otherRoomOptions"
android:orientation="vertical">
<include
android:id="@+id/notification_settings_view"
layout="@layout/notification_settings_item"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone"
tools:visibility="gone" />
<include
android:id="@+id/webinar_info_view"
layout="@layout/webinar_info_item"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone"
tools:visibility="visible" />
</LinearLayout>
<com.yarolegovich.mp.MaterialPreferenceCategory
android:id="@+id/category_shared_items"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/settings"
android:animateLayoutChanges="true"
apc:cardBackgroundColor="@color/bg_default"
apc:cardElevation="0dp"
apc:mpc_title="@string/nc_shared_items">
<com.yarolegovich.mp.MaterialStandardPreference
android:id="@+id/show_shared_items_action"
android:layout_width="match_parent"
android:layout_height="wrap_content"
apc:mp_icon="@drawable/ic_folder_multiple_image"
apc:mp_icon_tint="@color/grey_600"
apc:mp_title="@string/nc_shared_items_description" />
</com.yarolegovich.mp.MaterialPreferenceCategory>
</RelativeLayout>
</ScrollView> </ScrollView>
</RelativeLayout> </RelativeLayout>

View File

@ -3,6 +3,8 @@
~ Nextcloud Talk application ~ Nextcloud Talk application
~ ~
~ @author Mario Danic ~ @author Mario Danic
~ @author Marcel Hibbe
~ Copyright (C) 2022 Marcel Hibbe <dev@mhibbe.de>
~ Copyright (C) 2017 Mario Danic <mario@lovelyhq.com> ~ Copyright (C) 2017 Mario Danic <mario@lovelyhq.com>
~ ~
~ This program is free software: you can redistribute it and/or modify ~ This program is free software: you can redistribute it and/or modify
@ -39,6 +41,24 @@
<item>always</item> <item>always</item>
</array> </array>
<array name="message_expiring_descriptions">
<item>@string/nc_expire_message_off</item>
<item>@string/nc_expire_message_four_weeks</item>
<item>@string/nc_expire_message_one_week</item>
<item>@string/nc_expire_message_one_day</item>
<item>@string/nc_expire_message_eight_hours</item>
<item>@string/nc_expire_message_one_hour</item>
</array>
<array name="message_expiring_values">
<item>expire_0</item>
<item>expire_2419200</item>
<item>expire_604800</item>
<item>expire_86400</item>
<item>expire_28800</item>
<item>expire_3600</item>
</array>
<array name="screen_lock_timeout_descriptions"> <array name="screen_lock_timeout_descriptions">
<item>@string/nc_screen_lock_timeout_30</item> <item>@string/nc_screen_lock_timeout_30</item>
<item>@string/nc_screen_lock_timeout_60</item> <item>@string/nc_screen_lock_timeout_60</item>

View File

@ -3,6 +3,8 @@
~ ~
~ @author Mario Danic ~ @author Mario Danic
~ @author Andy Scherzinger ~ @author Andy Scherzinger
~ @author Marcel Hibbe
~ Copyright (C) 2022 Marcel Hibbe <dev@mhibbe.de>
~ Copyright (C) 2021 Andy Scherzinger <info@andy-scherzinger.de> ~ Copyright (C) 2021 Andy Scherzinger <info@andy-scherzinger.de>
~ Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com> ~ Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
~ ~
@ -564,4 +566,16 @@
<string name="call_without_notification">Call without notification</string> <string name="call_without_notification">Call without notification</string>
<string name="set_avatar_from_camera">Set avatar from camera</string> <string name="set_avatar_from_camera">Set avatar from camera</string>
<string name="nc_conversation_settings">Conversation settings</string>
<!-- Expiring messages -->
<string name="nc_expire_messages">Expire chat messages</string>
<string name="nc_expire_message_off">Off</string>
<string name="nc_expire_message_four_weeks">4 weeks</string>
<string name="nc_expire_message_one_week">1 week</string>
<string name="nc_expire_message_one_day">1 day</string>
<string name="nc_expire_message_eight_hours">8 hours</string>
<string name="nc_expire_message_one_hour">1 hour</string>
</resources> </resources>