Missing imports after rebase

Signed-off-by: tobiasKaminsky <tobias@kaminsky.me>
This commit is contained in:
tobiasKaminsky 2020-12-14 14:42:35 +01:00
parent acff1b559c
commit 98e2117bdf
No known key found for this signature in database
GPG Key ID: 0E00D4D47D0C5AF7
17 changed files with 287 additions and 13 deletions

View File

@ -21,6 +21,7 @@ package com.nextcloud.talk.adapters.messages
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.graphics.PorterDuff
import android.net.Uri import android.net.Uri
import android.text.Spannable import android.text.Spannable
import android.text.SpannableString import android.text.SpannableString
@ -36,12 +37,12 @@ import butterknife.BindView
import butterknife.ButterKnife import butterknife.ButterKnife
import coil.api.load import coil.api.load
import coil.transform.CircleCropTransformation import coil.transform.CircleCropTransformation
import com.facebook.drawee.view.SimpleDraweeView
import com.google.android.flexbox.FlexboxLayout import com.google.android.flexbox.FlexboxLayout
import com.nextcloud.talk.R import com.nextcloud.talk.R
import com.nextcloud.talk.application.NextcloudTalkApplication import com.nextcloud.talk.application.NextcloudTalkApplication
import com.nextcloud.talk.application.NextcloudTalkApplication.Companion.sharedApplication import com.nextcloud.talk.application.NextcloudTalkApplication.Companion.sharedApplication
import com.nextcloud.talk.models.json.chat.ChatMessage import com.nextcloud.talk.models.json.chat.ChatMessage
import com.nextcloud.talk.models.json.chat.ReadStatus
import com.nextcloud.talk.utils.ApiUtils import com.nextcloud.talk.utils.ApiUtils
import com.nextcloud.talk.utils.DisplayUtils.getMessageSelector import com.nextcloud.talk.utils.DisplayUtils.getMessageSelector
import com.nextcloud.talk.utils.DisplayUtils.searchAndReplaceWithMentionSpan import com.nextcloud.talk.utils.DisplayUtils.searchAndReplaceWithMentionSpan
@ -88,6 +89,10 @@ class MagicOutcomingTextMessageViewHolder(itemView: View) : OutcomingTextMessage
@BindView(R.id.quoteColoredView) @BindView(R.id.quoteColoredView)
var quoteColoredView: View? = null var quoteColoredView: View? = null
@JvmField
@BindView(R.id.checkMark)
var checkMark: ImageView? = null
@JvmField @JvmField
@Inject @Inject
var context: Context? = null var context: Context? = null
@ -181,6 +186,18 @@ class MagicOutcomingTextMessageViewHolder(itemView: View) : OutcomingTextMessage
quotedChatMessageView?.visibility = View.GONE quotedChatMessageView?.visibility = View.GONE
} }
val readStatusDrawableInt = when (message.readStatus) {
ReadStatus.READ -> R.drawable.ic_check_all
ReadStatus.SENT -> R.drawable.ic_check
else -> null
}
readStatusDrawableInt?.let {
context?.resources?.getDrawable(it, null)?.let {
it.setColorFilter(context?.resources!!.getColor(R.color.warm_grey_four), PorterDuff.Mode.SRC_ATOP)
checkMark?.setImageDrawable(it)
}
}
} }
init { init {

View File

@ -0,0 +1,39 @@
/*
* Nextcloud Talk application
*
* @author Tobias Kaminsky
* Copyright (C) 2020 Tobias Kaminsky <tobias.kaminsky@nextcloud.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.nextcloud.talk.adapters.messages;
import com.stfalcon.chatkit.commons.ImageLoader;
import com.stfalcon.chatkit.commons.models.IMessage;
import com.stfalcon.chatkit.messages.MessageHolders;
import com.stfalcon.chatkit.messages.MessagesListAdapter;
import java.util.List;
public class TalkMessagesListAdapter<MESSAGE extends IMessage> extends MessagesListAdapter<MESSAGE> {
public TalkMessagesListAdapter(String senderId, MessageHolders holders, ImageLoader imageLoader) {
super(senderId, holders, imageLoader);
}
public List<MessagesListAdapter.Wrapper> getItems() {
return items;
}
}

View File

@ -342,6 +342,10 @@ public interface NcApi {
@Field("timer") Long timer); @Field("timer") Long timer);
@POST @POST
Observable<GenericOverall> setReadStatusPrivacy(@Header("Authorization") String authorization,
@Url String url,
@Body RequestBody body);
@POST
Observable<ContactsByNumberOverall> searchContactsByPhoneNumber(@Header("Authorization") String authorization, Observable<ContactsByNumberOverall> searchContactsByPhoneNumber(@Header("Authorization") String authorization,
@Url String url, @Url String url,
@Body RequestBody search); @Body RequestBody search);

View File

@ -73,6 +73,7 @@ import com.nextcloud.talk.events.WebSocketCommunicationEvent
import com.nextcloud.talk.models.database.UserEntity import com.nextcloud.talk.models.database.UserEntity
import com.nextcloud.talk.models.json.chat.ChatMessage import com.nextcloud.talk.models.json.chat.ChatMessage
import com.nextcloud.talk.models.json.chat.ChatOverall import com.nextcloud.talk.models.json.chat.ChatOverall
import com.nextcloud.talk.models.json.chat.ReadStatus
import com.nextcloud.talk.models.json.conversations.Conversation import com.nextcloud.talk.models.json.conversations.Conversation
import com.nextcloud.talk.models.json.conversations.RoomOverall import com.nextcloud.talk.models.json.conversations.RoomOverall
import com.nextcloud.talk.models.json.conversations.RoomsOverall import com.nextcloud.talk.models.json.conversations.RoomsOverall
@ -174,7 +175,7 @@ class ChatController(args: Bundle) : BaseController(args), MessagesListAdapter
var historyRead = false var historyRead = false
var globalLastKnownFutureMessageId = -1 var globalLastKnownFutureMessageId = -1
var globalLastKnownPastMessageId = -1 var globalLastKnownPastMessageId = -1
var adapter: MessagesListAdapter<ChatMessage>? = null var adapter: TalkMessagesListAdapter<ChatMessage>? = null
var mentionAutocomplete: Autocomplete<*>? = null var mentionAutocomplete: Autocomplete<*>? = null
var layoutManager: LinearLayoutManager? = null var layoutManager: LinearLayoutManager? = null
var lookingIntoFuture = false var lookingIntoFuture = false
@ -361,7 +362,7 @@ class ChatController(args: Bundle) : BaseController(args), MessagesListAdapter
MagicUnreadNoticeMessageViewHolder::class.java, R.layout.item_date_header, MagicUnreadNoticeMessageViewHolder::class.java, R.layout.item_date_header,
MagicUnreadNoticeMessageViewHolder::class.java, R.layout.item_date_header, this) MagicUnreadNoticeMessageViewHolder::class.java, R.layout.item_date_header, this)
adapter = MessagesListAdapter(conversationUser?.userId, messageHolders, ImageLoader { imageView, url, payload -> adapter = TalkMessagesListAdapter(conversationUser?.userId, messageHolders, ImageLoader { imageView, url, payload ->
val draweeController = Fresco.newDraweeControllerBuilder() val draweeController = Fresco.newDraweeControllerBuilder()
.setImageRequest(DisplayUtils.getImageRequestForUrl(url, conversationUser)) .setImageRequest(DisplayUtils.getImageRequestForUrl(url, conversationUser))
.setControllerListener(DisplayUtils.getImageControllerListener(imageView)) .setControllerListener(DisplayUtils.getImageControllerListener(imageView))
@ -932,7 +933,7 @@ class ChatController(args: Bundle) : BaseController(args), MessagesListAdapter
} }
} }
fun pullChatMessages(lookIntoFuture: Int, setReadMarker: Int = 1) { fun pullChatMessages(lookIntoFuture: Int, setReadMarker: Int = 1, xChatLastCommonRead: Int? = -1) {
if (!inConversation) { if (!inConversation) {
return return
} }
@ -974,6 +975,9 @@ class ChatController(args: Bundle) : BaseController(args), MessagesListAdapter
} }
fieldMap["lastKnownMessageId"] = lastKnown fieldMap["lastKnownMessageId"] = lastKnown
xChatLastCommonRead?.let {
fieldMap["lastCommonReadId"] = it
}
if (!wasDetached) { if (!wasDetached) {
if (lookIntoFuture > 0) { if (lookIntoFuture > 0) {
@ -989,10 +993,9 @@ class ChatController(args: Bundle) : BaseController(args), MessagesListAdapter
override fun onNext(response: Response<*>) { override fun onNext(response: Response<*>) {
if (response.code() == 304) { if (response.code() == 304) {
pullChatMessages(1, setReadMarker) pullChatMessages(1, setReadMarker, xChatLastCommonRead)
} else if (response.code() == 412) { } else if (response.code() == 412) {
futurePreconditionFailed = true futurePreconditionFailed = true
} else { } else {
processMessages(response, true, finalTimeout) processMessages(response, true, finalTimeout)
} }
@ -1038,6 +1041,9 @@ class ChatController(args: Bundle) : BaseController(args), MessagesListAdapter
private fun processMessages(response: Response<*>, isFromTheFuture: Boolean, timeout: Int) { private fun processMessages(response: Response<*>, isFromTheFuture: Boolean, timeout: Int) {
val xChatLastGivenHeader: String? = response.headers().get("X-Chat-Last-Given") val xChatLastGivenHeader: String? = response.headers().get("X-Chat-Last-Given")
val xChatLastCommonRead = response.headers().get("X-Chat-Last-Common-Read")?.let {
Integer.parseInt(it)
}
if (response.headers().size() > 0 && !TextUtils.isEmpty(xChatLastGivenHeader)) { if (response.headers().size() > 0 && !TextUtils.isEmpty(xChatLastGivenHeader)) {
val header = Integer.parseInt(xChatLastGivenHeader!!) val header = Integer.parseInt(xChatLastGivenHeader!!)
@ -1089,7 +1095,6 @@ class ChatController(args: Bundle) : BaseController(args), MessagesListAdapter
chatMessage.isOneToOneConversation = currentConversation?.type == Conversation.ConversationType.ROOM_TYPE_ONE_TO_ONE_CALL chatMessage.isOneToOneConversation = currentConversation?.type == Conversation.ConversationType.ROOM_TYPE_ONE_TO_ONE_CALL
chatMessage.isLinkPreviewAllowed = isLinkPreviewAllowed chatMessage.isLinkPreviewAllowed = isLinkPreviewAllowed
chatMessage.activeUser = conversationUser chatMessage.activeUser = conversationUser
} }
if (adapter != null) { if (adapter != null) {
@ -1155,8 +1160,24 @@ class ChatController(args: Bundle) : BaseController(args), MessagesListAdapter
} }
// update read status of all messages
for (message in adapter!!.items) {
xChatLastCommonRead?.let {
if (message.item is ChatMessage) {
val chatMessage = message.item as ChatMessage
if (chatMessage.jsonMessageId <= it) {
chatMessage.readStatus = ReadStatus.READ
} else {
chatMessage.readStatus = ReadStatus.SENT
}
}
}
}
adapter?.notifyDataSetChanged()
if (inConversation) { if (inConversation) {
pullChatMessages(1) pullChatMessages(1, 1, xChatLastCommonRead)
} }
} else if (response.code() == 304 && !isFromTheFuture) { } else if (response.code() == 304 && !isFromTheFuture) {
if (isFirstMessagesProcessing) { if (isFirstMessagesProcessing) {

View File

@ -57,6 +57,7 @@ import com.nextcloud.talk.jobs.AccountRemovalWorker;
import com.nextcloud.talk.jobs.ContactAddressBookWorker; import com.nextcloud.talk.jobs.ContactAddressBookWorker;
import com.nextcloud.talk.models.RingtoneSettings; import com.nextcloud.talk.models.RingtoneSettings;
import com.nextcloud.talk.models.database.UserEntity; import com.nextcloud.talk.models.database.UserEntity;
import com.nextcloud.talk.models.json.generic.GenericOverall;
import com.nextcloud.talk.utils.ApiUtils; import com.nextcloud.talk.utils.ApiUtils;
import com.nextcloud.talk.utils.DisplayUtils; import com.nextcloud.talk.utils.DisplayUtils;
import com.nextcloud.talk.utils.DoNotDisturbUtils; import com.nextcloud.talk.utils.DoNotDisturbUtils;
@ -98,9 +99,12 @@ import androidx.work.WorkManager;
import autodagger.AutoInjector; import autodagger.AutoInjector;
import butterknife.BindView; import butterknife.BindView;
import butterknife.OnClick; import butterknife.OnClick;
import io.reactivex.Observer;
import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable; import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers; import io.reactivex.schedulers.Schedulers;
import okhttp3.MediaType;
import okhttp3.RequestBody;
@AutoInjector(NextcloudTalkApplication.class) @AutoInjector(NextcloudTalkApplication.class)
public class SettingsController extends BaseController { public class SettingsController extends BaseController {
@ -157,6 +161,8 @@ public class SettingsController extends BaseController {
MaterialChoicePreference screenLockTimeoutChoicePreference; MaterialChoicePreference screenLockTimeoutChoicePreference;
@BindView(R.id.settings_phone_book_integration) @BindView(R.id.settings_phone_book_integration)
MaterialSwitchPreference phoneBookIntegretationPreference; MaterialSwitchPreference phoneBookIntegretationPreference;
@BindView(R.id.settings_read_privacy)
MaterialSwitchPreference readPrivacyPreference;
@BindView(R.id.message_text) @BindView(R.id.message_text)
TextView messageText; TextView messageText;
@ -177,6 +183,7 @@ public class SettingsController extends BaseController {
private OnPreferenceValueChangedListener<Boolean> screenLockChangeListener; private OnPreferenceValueChangedListener<Boolean> screenLockChangeListener;
private OnPreferenceValueChangedListener<String> screenLockTimeoutChangeListener; private OnPreferenceValueChangedListener<String> screenLockTimeoutChangeListener;
private OnPreferenceValueChangedListener<String> themeChangeListener; private OnPreferenceValueChangedListener<String> themeChangeListener;
private OnPreferenceValueChangedListener<Boolean> readPrivacyChangeListener;
private OnPreferenceValueChangedListener<Boolean> phoneBookIntegrationChangeListener; private OnPreferenceValueChangedListener<Boolean> phoneBookIntegrationChangeListener;
private Disposable profileQueryDisposable; private Disposable profileQueryDisposable;
@ -215,6 +222,7 @@ public class SettingsController extends BaseController {
appPreferences.registerThemeChangeListener(themeChangeListener = new ThemeChangeListener()); appPreferences.registerThemeChangeListener(themeChangeListener = new ThemeChangeListener());
appPreferences.registerPhoneBookIntegrationChangeListener( appPreferences.registerPhoneBookIntegrationChangeListener(
phoneBookIntegrationChangeListener = new PhoneBookIntegrationChangeListener(this)); phoneBookIntegrationChangeListener = new PhoneBookIntegrationChangeListener(this));
appPreferences.registerReadPrivacyChangeListener(readPrivacyChangeListener = new ReadPrivacyChangeListener());
List<String> listWithIntFields = new ArrayList<>(); List<String> listWithIntFields = new ArrayList<>();
listWithIntFields.add("proxy_port"); listWithIntFields.add("proxy_port");
@ -449,6 +457,8 @@ public class SettingsController extends BaseController {
((Checkable) incognitoKeyboardSwitchPreference.findViewById(R.id.mp_checkable)).setChecked(appPreferences.getIsKeyboardIncognito()); ((Checkable) incognitoKeyboardSwitchPreference.findViewById(R.id.mp_checkable)).setChecked(appPreferences.getIsKeyboardIncognito());
} }
((Checkable) readPrivacyPreference.findViewById(R.id.mp_checkable)).setChecked(!currentUser.isReadStatusPrivate());
((Checkable) linkPreviewsSwitchPreference.findViewById(R.id.mp_checkable)).setChecked(appPreferences.getAreLinkPreviewsAllowed()); ((Checkable) linkPreviewsSwitchPreference.findViewById(R.id.mp_checkable)).setChecked(appPreferences.getAreLinkPreviewsAllowed());
((Checkable) phoneBookIntegretationPreference.findViewById(R.id.mp_checkable)).setChecked(appPreferences.isPhoneBookIntegrationEnabled()); ((Checkable) phoneBookIntegretationPreference.findViewById(R.id.mp_checkable)).setChecked(appPreferences.isPhoneBookIntegrationEnabled());
@ -661,6 +671,7 @@ public class SettingsController extends BaseController {
appPreferences.unregisterScreenLockListener(screenLockChangeListener); appPreferences.unregisterScreenLockListener(screenLockChangeListener);
appPreferences.unregisterScreenLockTimeoutListener(screenLockTimeoutChangeListener); appPreferences.unregisterScreenLockTimeoutListener(screenLockTimeoutChangeListener);
appPreferences.unregisterThemeChangeListener(themeChangeListener); appPreferences.unregisterThemeChangeListener(themeChangeListener);
appPreferences.unregisterReadPrivacyChangeListener(readPrivacyChangeListener);
appPreferences.unregisterPhoneBookIntegrationChangeListener(phoneBookIntegrationChangeListener); appPreferences.unregisterPhoneBookIntegrationChangeListener(phoneBookIntegrationChangeListener);
} }
super.onDestroy(); super.onDestroy();
@ -847,4 +858,38 @@ public class SettingsController extends BaseController {
} }
} }
} }
private class ReadPrivacyChangeListener implements OnPreferenceValueChangedListener<Boolean> {
@Override
public void onChanged(Boolean newValue) {
String booleanValue = newValue ? "0" : "1";
String json = "{\"key\": \"read_status_privacy\", \"value\" : " + booleanValue + "}";
ncApi.setReadStatusPrivacy(
ApiUtils.getCredentials(currentUser.getUsername(), currentUser.getToken()),
ApiUtils.getUrlForUserSettings(currentUser.getBaseUrl()),
RequestBody.create(MediaType.parse("application/json"), json))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<GenericOverall>() {
@Override
public void onSubscribe(@io.reactivex.annotations.NonNull Disposable d) {
}
@Override
public void onNext(@io.reactivex.annotations.NonNull GenericOverall genericOverall) {
}
@Override
public void onError(@io.reactivex.annotations.NonNull Throwable e) {
appPreferences.setReadPrivacy(!newValue);
((Checkable) readPrivacyPreference.findViewById(R.id.mp_checkable)).setChecked(!newValue);
}
@Override
public void onComplete() {
}
});
}
}
} }

View File

@ -146,4 +146,25 @@ public interface User extends Parcelable, Persistable, Serializable {
} }
return false; return false;
} }
default boolean isReadStatusPrivate() {
if (getCapabilities() != null) {
Capabilities capabilities;
try {
capabilities = LoganSquare.parse(getCapabilities(), Capabilities.class);
if (capabilities != null &&
capabilities.getSpreedCapability() != null &&
capabilities.getSpreedCapability().getConfig() != null &&
capabilities.getSpreedCapability().getConfig().containsKey("chat")) {
HashMap<String, String> map = capabilities.getSpreedCapability().getConfig().get("chat");
if (map != null && map.containsKey("read-privacy")) {
return Integer.parseInt(map.get("read-privacy")) == 1;
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
return false;
}
} }

View File

@ -20,7 +20,7 @@
package com.nextcloud.talk.models.json.chat; package com.nextcloud.talk.models.json.chat;
import android.text.TextUtils; import android.text.TextUtils;
import androidx.annotation.Nullable;
import com.bluelinelabs.logansquare.annotation.JsonField; import com.bluelinelabs.logansquare.annotation.JsonField;
import com.bluelinelabs.logansquare.annotation.JsonIgnore; import com.bluelinelabs.logansquare.annotation.JsonIgnore;
import com.bluelinelabs.logansquare.annotation.JsonObject; import com.bluelinelabs.logansquare.annotation.JsonObject;
@ -33,10 +33,17 @@ import com.nextcloud.talk.utils.TextMatchers;
import com.stfalcon.chatkit.commons.models.IMessage; import com.stfalcon.chatkit.commons.models.IMessage;
import com.stfalcon.chatkit.commons.models.IUser; import com.stfalcon.chatkit.commons.models.IUser;
import com.stfalcon.chatkit.commons.models.MessageContentType; import com.stfalcon.chatkit.commons.models.MessageContentType;
import lombok.Data;
import org.parceler.Parcel; import org.parceler.Parcel;
import java.util.*; import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import androidx.annotation.Nullable;
import lombok.Data;
@Parcel @Parcel
@Data @Data
@ -77,6 +84,7 @@ public class ChatMessage implements IMessage, MessageContentType, MessageContent
public boolean replyable; public boolean replyable;
@JsonField(name = "parent") @JsonField(name = "parent")
public ChatMessage parentMessage; public ChatMessage parentMessage;
public Enum<ReadStatus> readStatus = ReadStatus.NONE;
@JsonIgnore @JsonIgnore
List<MessageType> messageTypesToIgnore = Arrays.asList(MessageType.REGULAR_TEXT_MESSAGE, List<MessageType> messageTypesToIgnore = Arrays.asList(MessageType.REGULAR_TEXT_MESSAGE,

View File

@ -0,0 +1,25 @@
/*
* Nextcloud Talk application
*
* @author Tobias Kaminsky
* Copyright (C) 2020 Tobias Kaminsky <tobias.kaminsky@nextcloud.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.nextcloud.talk.models.json.chat;
public enum ReadStatus {
NONE, SENT, READ
}

View File

@ -225,6 +225,10 @@ public class ApiUtils {
return baseUrl + ocsApiVersion + "/cloud/user"; return baseUrl + ocsApiVersion + "/cloud/user";
} }
public static String getUrlForUserSettings(String baseUrl) {
return baseUrl + ocsApiVersion + spreedApiVersion + "/settings/user";
}
public static String getUrlPostfixForStatus() { public static String getUrlPostfixForStatus() {
return "/status.php"; return "/status.php";
} }

View File

@ -302,6 +302,17 @@ public interface AppPreferences {
@KeyByString("phone_book_integration_last_run") @KeyByString("phone_book_integration_last_run")
long getPhoneBookIntegrationLastRun(Long defaultValue); long getPhoneBookIntegrationLastRun(Long defaultValue);
@KeyByResource(R.string.nc_settings_read_privacy_key)
void setReadPrivacy(boolean value);
@KeyByResource(R.string.nc_settings_read_privacy_key)
@RegisterChangeListenerMethod
void registerReadPrivacyChangeListener(OnPreferenceValueChangedListener<Boolean> listener);
@KeyByResource(R.string.nc_settings_read_privacy_key)
@UnregisterChangeListenerMethod
void unregisterReadPrivacyChangeListener(OnPreferenceValueChangedListener<Boolean> listener);
@ClearMethod @ClearMethod
void clear(); void clear();
} }

View File

@ -0,0 +1,30 @@
<!--
~ Nextcloud Talk application
~
~ @author Tobias Kaminsky
~ Copyright (C) 2020 Tobias Kaminsky <tobias.kaminsky@nextcloud.com>
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M9,16.17L4.83,12l-1.42,1.41L9,19 21,7l-1.41,-1.41z"/>
</vector>

View File

@ -0,0 +1,30 @@
<!--
~ Nextcloud Talk application
~
~ @author Tobias Kaminsky
~ Copyright (C) 2020 Tobias Kaminsky <tobias.kaminsky@nextcloud.com>
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M18,7l-1.41,-1.41 -6.34,6.34 1.41,1.41L18,7zM22.24,5.59L11.66,16.17 7.48,12l-1.41,1.41L11.66,19l12,-12 -1.42,-1.41zM0.41,13.41L6,19l1.41,-1.41L1.83,12 0.41,13.41z"/>
</vector>

View File

@ -226,6 +226,14 @@
apc:mp_key="@string/nc_settings_phone_book_integration_key" apc:mp_key="@string/nc_settings_phone_book_integration_key"
apc:mp_summary="@string/nc_settings_phone_book_integration_desc" apc:mp_summary="@string/nc_settings_phone_book_integration_desc"
apc:mp_title="@string/nc_settings_phone_book_integration_title" /> apc:mp_title="@string/nc_settings_phone_book_integration_title" />
<com.yarolegovich.mp.MaterialSwitchPreference
android:id="@+id/settings_read_privacy"
android:layout_width="match_parent"
android:layout_height="wrap_content"
apc:mp_key="@string/nc_settings_read_privacy_key"
apc:mp_summary="@string/nc_settings_read_privacy_desc"
apc:mp_title="@string/nc_settings_read_privacy_title" />
</com.yarolegovich.mp.MaterialPreferenceCategory> </com.yarolegovich.mp.MaterialPreferenceCategory>
<com.yarolegovich.mp.MaterialPreferenceCategory <com.yarolegovich.mp.MaterialPreferenceCategory

View File

@ -57,5 +57,13 @@
android:layout_marginStart="8dp" android:layout_marginStart="8dp"
app:layout_alignSelf="center" /> app:layout_alignSelf="center" />
<ImageView
android:id="@+id/checkMark"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/messageTime"
android:layout_marginStart="8dp"
app:layout_alignSelf="center" />
</com.google.android.flexbox.FlexboxLayout> </com.google.android.flexbox.FlexboxLayout>
</RelativeLayout> </RelativeLayout>

View File

@ -115,7 +115,10 @@
<string name="nc_settings_link_previews_title">Show link previews</string> <string name="nc_settings_link_previews_title">Show link previews</string>
<string name="nc_settings_link_previews_desc">Allows previews of content from received links for supported services</string> <string name="nc_settings_link_previews_desc">Allows previews of content from received links for supported services</string>
<string name="nc_settings_link_previews_key" translatable="false">link_previews</string> <string name="nc_settings_link_previews_key" translatable="false">link_previews</string>
<string name="nc_settings_read_privacy_key" translatable="false">read_privacy</string>
<string name="nc_locked">Tap to unlock</string> <string name="nc_locked">Tap to unlock</string>
<string name="nc_settings_read_privacy_desc">Share my read-status and show the read-status of others</string>
<string name="nc_settings_read_privacy_title">Read status</string>
<string name="nc_screen_lock_timeout_30">30 seconds</string> <string name="nc_screen_lock_timeout_30">30 seconds</string>
<string name="nc_screen_lock_timeout_60">1 minute</string> <string name="nc_screen_lock_timeout_60">1 minute</string>