WIP: set room avatar and slight redesign of group details
This commit is contained in:
parent
f434925753
commit
d7ebd7d453
|
@ -35,7 +35,7 @@ dependencies {
|
||||||
exclude group: 'com.google.firebase', module: 'firebase-core'
|
exclude group: 'com.google.firebase', module: 'firebase-core'
|
||||||
}
|
}
|
||||||
implementation 'org.sufficientlysecure:openpgp-api:10.0'
|
implementation 'org.sufficientlysecure:openpgp-api:10.0'
|
||||||
implementation 'com.soundcloud.android:android-crop:1.0.1@aar'
|
implementation 'com.theartofdev.edmodo:android-image-cropper:2.7.+'
|
||||||
implementation "com.android.support:support-v13:$supportLibVersion"
|
implementation "com.android.support:support-v13:$supportLibVersion"
|
||||||
implementation "com.android.support:appcompat-v7:$supportLibVersion"
|
implementation "com.android.support:appcompat-v7:$supportLibVersion"
|
||||||
implementation "com.android.support:cardview-v7:$supportLibVersion"
|
implementation "com.android.support:cardview-v7:$supportLibVersion"
|
||||||
|
|
|
@ -180,6 +180,7 @@
|
||||||
android:windowSoftInputMode="stateHidden|adjustResize"/>
|
android:windowSoftInputMode="stateHidden|adjustResize"/>
|
||||||
<activity
|
<activity
|
||||||
android:name=".ui.ConferenceDetailsActivity"
|
android:name=".ui.ConferenceDetailsActivity"
|
||||||
|
android:label="@string/action_muc_details"
|
||||||
android:windowSoftInputMode="stateHidden"/>
|
android:windowSoftInputMode="stateHidden"/>
|
||||||
<activity
|
<activity
|
||||||
android:name=".ui.ContactDetailsActivity"
|
android:name=".ui.ContactDetailsActivity"
|
||||||
|
@ -188,6 +189,9 @@
|
||||||
android:name=".ui.PublishProfilePictureActivity"
|
android:name=".ui.PublishProfilePictureActivity"
|
||||||
android:label="@string/mgmt_account_publish_avatar"
|
android:label="@string/mgmt_account_publish_avatar"
|
||||||
android:windowSoftInputMode="stateHidden"/>
|
android:windowSoftInputMode="stateHidden"/>
|
||||||
|
<activity
|
||||||
|
android:name=".ui.PublishGroupChatProfilePictureActivity"
|
||||||
|
android:label="@string/group_chat_avatar"/>
|
||||||
<activity
|
<activity
|
||||||
android:name=".ui.ShareWithActivity"
|
android:name=".ui.ShareWithActivity"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
|
@ -234,7 +238,8 @@
|
||||||
<category android:name="android.intent.category.PREFERENCE"/>
|
<category android:name="android.intent.category.PREFERENCE"/>
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
<activity android:name="com.soundcloud.android.crop.CropImageActivity"/>
|
<activity android:name="com.theartofdev.edmodo.cropper.CropImageActivity"
|
||||||
|
android:theme="@style/Base.Theme.AppCompat"/>
|
||||||
<activity android:name=".ui.MemorizingActivity"/>
|
<activity android:name=".ui.MemorizingActivity"/>
|
||||||
|
|
||||||
<service android:name=".services.ExportLogsService"/>
|
<service android:name=".services.ExportLogsService"/>
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package eu.siacs.conversations.entities;
|
package eu.siacs.conversations.entities;
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
@ -373,7 +374,7 @@ public class MucOptions {
|
||||||
this.self = new User(this, createJoinJid(getProposedNick()));
|
this.self = new User(this, createJoinJid(getProposedNick()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean updateConfiguration(List<String> features, Data data) {
|
public boolean updateConfiguration(List<String> features, String name, Data data) {
|
||||||
updateFeatures(features);
|
updateFeatures(features);
|
||||||
updateFormData(data == null ? new Data() : data);
|
updateFormData(data == null ? new Data() : data);
|
||||||
Field allowPmField = this.form.getFieldByName("muc#roomconfig_allowpm");
|
Field allowPmField = this.form.getFieldByName("muc#roomconfig_allowpm");
|
||||||
|
@ -382,6 +383,7 @@ public class MucOptions {
|
||||||
changed |= conversation.setAttribute(Conversation.ATTRIBUTE_MEMBERS_ONLY, this.hasFeature("muc_membersonly"));
|
changed |= conversation.setAttribute(Conversation.ATTRIBUTE_MEMBERS_ONLY, this.hasFeature("muc_membersonly"));
|
||||||
changed |= conversation.setAttribute(Conversation.ATTRIBUTE_MODERATED, this.hasFeature("muc_moderated"));
|
changed |= conversation.setAttribute(Conversation.ATTRIBUTE_MODERATED, this.hasFeature("muc_moderated"));
|
||||||
changed |= conversation.setAttribute(Conversation.ATTRIBUTE_NON_ANONYMOUS, this.hasFeature("muc_nonanonymous"));
|
changed |= conversation.setAttribute(Conversation.ATTRIBUTE_NON_ANONYMOUS, this.hasFeature("muc_nonanonymous"));
|
||||||
|
changed |= setName(name);
|
||||||
return changed;
|
return changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -402,6 +404,10 @@ public class MucOptions {
|
||||||
return this.features.contains(feature);
|
return this.features.contains(feature);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean hasVCards() {
|
||||||
|
return hasFeature("vcard-temp");
|
||||||
|
}
|
||||||
|
|
||||||
public boolean canInvite() {
|
public boolean canInvite() {
|
||||||
Field field = this.form.getFieldByName("muc#roomconfig_allowinvites");
|
Field field = this.form.getFieldByName("muc#roomconfig_allowinvites");
|
||||||
return !membersOnly() || self.getRole().ranks(Role.MODERATOR) || (field != null && "1".equals(field.getValue()));
|
return !membersOnly() || self.getRole().ranks(Role.MODERATOR) || (field != null && "1".equals(field.getValue()));
|
||||||
|
@ -688,6 +694,14 @@ public class MucOptions {
|
||||||
return this.conversation.getAttribute("subject");
|
return this.conversation.getAttribute("subject");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean setName(String name) {
|
||||||
|
return this.conversation.setAttribute("muc_name", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return this.conversation.getAttribute("muc_name");
|
||||||
|
}
|
||||||
|
|
||||||
public List<User> getFallbackUsersFromCryptoTargets() {
|
public List<User> getFallbackUsersFromCryptoTargets() {
|
||||||
List<User> users = new ArrayList<>();
|
List<User> users = new ArrayList<>();
|
||||||
for (Jid jid : conversation.getAcceptedCryptoTargets()) {
|
for (Jid jid : conversation.getAcceptedCryptoTargets()) {
|
||||||
|
|
|
@ -736,6 +736,15 @@ public class FileBackend {
|
||||||
}
|
}
|
||||||
|
|
||||||
public Avatar getPepAvatar(Uri image, int size, Bitmap.CompressFormat format) {
|
public Avatar getPepAvatar(Uri image, int size, Bitmap.CompressFormat format) {
|
||||||
|
|
||||||
|
final Avatar uncompressAvatar = getUncompressedAvatar(image);
|
||||||
|
if (uncompressAvatar != null && uncompressAvatar.image.length() <= Config.AVATAR_CHAR_LIMIT) {
|
||||||
|
return uncompressAvatar;
|
||||||
|
}
|
||||||
|
if (uncompressAvatar != null) {
|
||||||
|
Log.d(Config.LOGTAG,"uncompressed avatar exceeded char limit by "+(uncompressAvatar.image.length() - Config.AVATAR_CHAR_LIMIT));
|
||||||
|
}
|
||||||
|
|
||||||
Bitmap bm = cropCenterSquare(image, size);
|
Bitmap bm = cropCenterSquare(image, size);
|
||||||
if (bm == null) {
|
if (bm == null) {
|
||||||
return null;
|
return null;
|
||||||
|
@ -749,6 +758,19 @@ public class FileBackend {
|
||||||
return getPepAvatar(bm, format, 100);
|
return getPepAvatar(bm, format, 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Avatar getUncompressedAvatar(Uri uri) {
|
||||||
|
Bitmap bitmap = null;
|
||||||
|
try {
|
||||||
|
bitmap = BitmapFactory.decodeStream(mXmppConnectionService.getContentResolver().openInputStream(uri));
|
||||||
|
return getPepAvatar(bitmap, Bitmap.CompressFormat.PNG, 100);
|
||||||
|
} catch (Exception e) {
|
||||||
|
if (bitmap != null) {
|
||||||
|
bitmap.recycle();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
private Avatar getPepAvatar(Bitmap bitmap, Bitmap.CompressFormat format, int quality) {
|
private Avatar getPepAvatar(Bitmap bitmap, Bitmap.CompressFormat format, int quality) {
|
||||||
try {
|
try {
|
||||||
ByteArrayOutputStream mByteArrayOutputStream = new ByteArrayOutputStream();
|
ByteArrayOutputStream mByteArrayOutputStream = new ByteArrayOutputStream();
|
||||||
|
|
|
@ -60,6 +60,8 @@ import java.util.concurrent.CountDownLatch;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.concurrent.atomic.AtomicLong;
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
|
|
||||||
|
import javax.security.auth.callback.Callback;
|
||||||
|
|
||||||
import eu.siacs.conversations.Config;
|
import eu.siacs.conversations.Config;
|
||||||
import eu.siacs.conversations.R;
|
import eu.siacs.conversations.R;
|
||||||
import eu.siacs.conversations.crypto.OmemoSetting;
|
import eu.siacs.conversations.crypto.OmemoSetting;
|
||||||
|
@ -97,6 +99,7 @@ import eu.siacs.conversations.persistance.DatabaseBackend;
|
||||||
import eu.siacs.conversations.persistance.FileBackend;
|
import eu.siacs.conversations.persistance.FileBackend;
|
||||||
import eu.siacs.conversations.ui.SettingsActivity;
|
import eu.siacs.conversations.ui.SettingsActivity;
|
||||||
import eu.siacs.conversations.ui.UiCallback;
|
import eu.siacs.conversations.ui.UiCallback;
|
||||||
|
import eu.siacs.conversations.ui.interfaces.OnAvatarPublication;
|
||||||
import eu.siacs.conversations.ui.interfaces.OnSearchResultsAvailable;
|
import eu.siacs.conversations.ui.interfaces.OnSearchResultsAvailable;
|
||||||
import eu.siacs.conversations.utils.ConversationsFileObserver;
|
import eu.siacs.conversations.utils.ConversationsFileObserver;
|
||||||
import eu.siacs.conversations.utils.CryptoHelper;
|
import eu.siacs.conversations.utils.CryptoHelper;
|
||||||
|
@ -2446,18 +2449,21 @@ public class XmppConnectionService extends Service {
|
||||||
public void onIqPacketReceived(Account account, IqPacket packet) {
|
public void onIqPacketReceived(Account account, IqPacket packet) {
|
||||||
Element query = packet.findChild("query", "http://jabber.org/protocol/disco#info");
|
Element query = packet.findChild("query", "http://jabber.org/protocol/disco#info");
|
||||||
if (packet.getType() == IqPacket.TYPE.RESULT && query != null) {
|
if (packet.getType() == IqPacket.TYPE.RESULT && query != null) {
|
||||||
|
String name = null;
|
||||||
ArrayList<String> features = new ArrayList<>();
|
ArrayList<String> features = new ArrayList<>();
|
||||||
for (Element child : query.getChildren()) {
|
for (Element child : query.getChildren()) {
|
||||||
if (child != null && child.getName().equals("feature")) {
|
if (child.getName().equals("feature")) {
|
||||||
String var = child.getAttribute("var");
|
String var = child.getAttribute("var");
|
||||||
if (var != null) {
|
if (var != null) {
|
||||||
features.add(var);
|
features.add(var);
|
||||||
}
|
}
|
||||||
|
} else if (child.getName().equals("identity")) {
|
||||||
|
name = child.getAttribute("name");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Element form = query.findChild("x", Namespace.DATA);
|
Element form = query.findChild("x", Namespace.DATA);
|
||||||
Data data = form == null ? null : Data.parse(form);
|
Data data = form == null ? null : Data.parse(form);
|
||||||
if (conversation.getMucOptions().updateConfiguration(features, data)) {
|
if (conversation.getMucOptions().updateConfiguration(features, name, data)) {
|
||||||
Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": muc configuration changed for " + conversation.getJid().asBareJid());
|
Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": muc configuration changed for " + conversation.getJid().asBareJid());
|
||||||
updateConversation(conversation);
|
updateConversation(conversation);
|
||||||
}
|
}
|
||||||
|
@ -2681,25 +2687,78 @@ public class XmppConnectionService extends Service {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void publishAvatar(final Account account, final Uri image, final UiCallback<Avatar> callback) {
|
public void publishMucAvatar(final Conversation conversation, final Uri image, final OnAvatarPublication callback) {
|
||||||
new Thread(() -> {
|
new Thread(() -> {
|
||||||
final Bitmap.CompressFormat format = Config.AVATAR_FORMAT;
|
final Bitmap.CompressFormat format = Config.AVATAR_FORMAT;
|
||||||
final int size = Config.AVATAR_SIZE;
|
final int size = Config.AVATAR_SIZE;
|
||||||
final Avatar avatar = getFileBackend().getPepAvatar(image, size, format);
|
final Avatar avatar = getFileBackend().getPepAvatar(image, size, format);
|
||||||
if (avatar != null) {
|
if (avatar != null) {
|
||||||
if (!getFileBackend().save(avatar)) {
|
if (!getFileBackend().save(avatar)) {
|
||||||
callback.error(R.string.error_saving_avatar, avatar);
|
callback.onAvatarPublicationFailed(R.string.error_saving_avatar);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
avatar.owner = conversation.getJid().asBareJid();
|
||||||
|
publishMucAvatar(conversation, avatar, callback);
|
||||||
|
} else {
|
||||||
|
callback.onAvatarPublicationFailed(R.string.error_publish_avatar_converting);
|
||||||
|
}
|
||||||
|
}).start();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void publishAvatar(final Account account, final Uri image, final OnAvatarPublication callback) {
|
||||||
|
new Thread(() -> {
|
||||||
|
final Bitmap.CompressFormat format = Config.AVATAR_FORMAT;
|
||||||
|
final int size = Config.AVATAR_SIZE;
|
||||||
|
final Avatar avatar = getFileBackend().getPepAvatar(image, size, format);
|
||||||
|
if (avatar != null) {
|
||||||
|
if (!getFileBackend().save(avatar)) {
|
||||||
|
Log.d(Config.LOGTAG,"unable to save vcard");
|
||||||
|
callback.onAvatarPublicationFailed(R.string.error_saving_avatar);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
publishAvatar(account, avatar, callback);
|
publishAvatar(account, avatar, callback);
|
||||||
} else {
|
} else {
|
||||||
callback.error(R.string.error_publish_avatar_converting, null);
|
callback.onAvatarPublicationFailed(R.string.error_publish_avatar_converting);
|
||||||
}
|
}
|
||||||
}).start();
|
}).start();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void publishAvatar(Account account, final Avatar avatar, final UiCallback<Avatar> callback) {
|
private void publishMucAvatar(Conversation conversation, Avatar avatar, OnAvatarPublication callback) {
|
||||||
|
final IqPacket retrieve = mIqGenerator.retrieveVcardAvatar(avatar);
|
||||||
|
sendIqPacket(conversation.getAccount(), retrieve, (account, response) -> {
|
||||||
|
boolean itemNotFound = response.getType() == IqPacket.TYPE.ERROR && response.hasChild("error") && response.findChild("error").hasChild("item-not-found");
|
||||||
|
if (response.getType() == IqPacket.TYPE.RESULT || itemNotFound) {
|
||||||
|
Element vcard = response.findChild("vCard", "vcard-temp");
|
||||||
|
if (vcard == null) {
|
||||||
|
vcard = new Element("vCard", "vcard-temp");
|
||||||
|
}
|
||||||
|
Element photo = vcard.findChild("PHOTO");
|
||||||
|
if (photo == null) {
|
||||||
|
photo = vcard.addChild("PHOTO");
|
||||||
|
}
|
||||||
|
photo.clearChildren();
|
||||||
|
photo.addChild("TYPE").setContent(avatar.type);
|
||||||
|
photo.addChild("BINVAL").setContent(avatar.image);
|
||||||
|
IqPacket publication = new IqPacket(IqPacket.TYPE.SET);
|
||||||
|
publication.setTo(conversation.getJid().asBareJid());
|
||||||
|
publication.addChild(vcard);
|
||||||
|
sendIqPacket(account, publication, (a1, publicationResponse) -> {
|
||||||
|
if (publicationResponse.getType() == IqPacket.TYPE.RESULT) {
|
||||||
|
callback.onAvatarPublicationSucceeded();
|
||||||
|
} else {
|
||||||
|
Log.d(Config.LOGTAG, "failed to publish vcard " + publicationResponse.getError());
|
||||||
|
callback.onAvatarPublicationFailed(R.string.error_publish_avatar_server_reject);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
Log.d(Config.LOGTAG, "failed to request vcard " + response.toString());
|
||||||
|
callback.onAvatarPublicationFailed(R.string.error_publish_avatar_no_server_support);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void publishAvatar(Account account, final Avatar avatar, final OnAvatarPublication callback) {
|
||||||
IqPacket packet = this.mIqGenerator.publishAvatar(avatar);
|
IqPacket packet = this.mIqGenerator.publishAvatar(avatar);
|
||||||
this.sendIqPacket(account, packet, new OnIqPacketReceived() {
|
this.sendIqPacket(account, packet, new OnIqPacketReceived() {
|
||||||
|
|
||||||
|
@ -2717,11 +2776,11 @@ public class XmppConnectionService extends Service {
|
||||||
}
|
}
|
||||||
Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": published avatar " + (avatar.size / 1024) + "KiB");
|
Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": published avatar " + (avatar.size / 1024) + "KiB");
|
||||||
if (callback != null) {
|
if (callback != null) {
|
||||||
callback.success(avatar);
|
callback.onAvatarPublicationSucceeded();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (callback != null) {
|
if (callback != null) {
|
||||||
callback.error(R.string.error_publish_avatar_server_reject, avatar);
|
callback.onAvatarPublicationFailed(R.string.error_publish_avatar_server_reject);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2730,7 +2789,7 @@ public class XmppConnectionService extends Service {
|
||||||
Element error = result.findChild("error");
|
Element error = result.findChild("error");
|
||||||
Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": server rejected avatar " + (avatar.size / 1024) + "KiB " + (error != null ? error.toString() : ""));
|
Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": server rejected avatar " + (avatar.size / 1024) + "KiB " + (error != null ? error.toString() : ""));
|
||||||
if (callback != null) {
|
if (callback != null) {
|
||||||
callback.error(R.string.error_publish_avatar_server_reject, avatar);
|
callback.onAvatarPublicationFailed(R.string.error_publish_avatar_server_reject);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ package eu.siacs.conversations.ui;
|
||||||
|
|
||||||
import android.app.PendingIntent;
|
import android.app.PendingIntent;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
import android.content.IntentSender.SendIntentException;
|
import android.content.IntentSender.SendIntentException;
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
import android.databinding.DataBindingUtil;
|
import android.databinding.DataBindingUtil;
|
||||||
|
@ -12,6 +13,7 @@ import android.os.AsyncTask;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.v7.app.AlertDialog;
|
import android.support.v7.app.AlertDialog;
|
||||||
import android.support.v7.widget.Toolbar;
|
import android.support.v7.widget.Toolbar;
|
||||||
|
import android.util.Log;
|
||||||
import android.view.ContextMenu;
|
import android.view.ContextMenu;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
|
@ -247,6 +249,20 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers
|
||||||
this.mAdvancedMode = getPreferences().getBoolean("advanced_muc_mode", false);
|
this.mAdvancedMode = getPreferences().getBoolean("advanced_muc_mode", false);
|
||||||
this.binding.mucInfoMore.setVisibility(this.mAdvancedMode ? View.VISIBLE : View.GONE);
|
this.binding.mucInfoMore.setVisibility(this.mAdvancedMode ? View.VISIBLE : View.GONE);
|
||||||
this.binding.notificationStatusButton.setOnClickListener(this.mNotifyStatusClickListener);
|
this.binding.notificationStatusButton.setOnClickListener(this.mNotifyStatusClickListener);
|
||||||
|
this.binding.yourPhoto.setOnClickListener(v -> {
|
||||||
|
final MucOptions mucOptions = mConversation.getMucOptions();
|
||||||
|
if (!mucOptions.hasVCards()) {
|
||||||
|
Toast.makeText(this,R.string.host_does_not_support_group_chat_avatars, Toast.LENGTH_SHORT).show();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!mucOptions.getSelf().getAffiliation().ranks(MucOptions.Affiliation.OWNER)) {
|
||||||
|
Toast.makeText(this,R.string.only_the_owner_can_change_group_chat_avatar, Toast.LENGTH_SHORT).show();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final Intent intent = new Intent(this, PublishGroupChatProfilePictureActivity.class);
|
||||||
|
intent.putExtra("uuid",mConversation.getUuid());
|
||||||
|
startActivity(intent);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -267,14 +283,6 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers
|
||||||
case android.R.id.home:
|
case android.R.id.home:
|
||||||
finish();
|
finish();
|
||||||
break;
|
break;
|
||||||
case R.id.action_edit_subject:
|
|
||||||
if (mConversation != null) {
|
|
||||||
quickEdit(mConversation.getMucOptions().getSubject(),
|
|
||||||
R.string.edit_subject_hint,
|
|
||||||
this.onSubjectEdited,
|
|
||||||
true);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case R.id.action_share_http:
|
case R.id.action_share_http:
|
||||||
shareLink(true);
|
shareLink(true);
|
||||||
break;
|
break;
|
||||||
|
@ -318,7 +326,6 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers
|
||||||
MenuItem menuItemSaveBookmark = menu.findItem(R.id.action_save_as_bookmark);
|
MenuItem menuItemSaveBookmark = menu.findItem(R.id.action_save_as_bookmark);
|
||||||
MenuItem menuItemDeleteBookmark = menu.findItem(R.id.action_delete_bookmark);
|
MenuItem menuItemDeleteBookmark = menu.findItem(R.id.action_delete_bookmark);
|
||||||
MenuItem menuItemAdvancedMode = menu.findItem(R.id.action_advanced_mode);
|
MenuItem menuItemAdvancedMode = menu.findItem(R.id.action_advanced_mode);
|
||||||
MenuItem menuItemChangeSubject = menu.findItem(R.id.action_edit_subject);
|
|
||||||
menuItemAdvancedMode.setChecked(mAdvancedMode);
|
menuItemAdvancedMode.setChecked(mAdvancedMode);
|
||||||
if (mConversation == null) {
|
if (mConversation == null) {
|
||||||
return true;
|
return true;
|
||||||
|
@ -330,7 +337,6 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers
|
||||||
menuItemDeleteBookmark.setVisible(false);
|
menuItemDeleteBookmark.setVisible(false);
|
||||||
menuItemSaveBookmark.setVisible(true);
|
menuItemSaveBookmark.setVisible(true);
|
||||||
}
|
}
|
||||||
menuItemChangeSubject.setVisible(mConversation.getMucOptions().canChangeSubject());
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -525,21 +531,16 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers
|
||||||
account = mConversation.getAccount().getJid().asBareJid().toString();
|
account = mConversation.getAccount().getJid().asBareJid().toString();
|
||||||
}
|
}
|
||||||
this.binding.detailsAccount.setText(getString(R.string.using_account, account));
|
this.binding.detailsAccount.setText(getString(R.string.using_account, account));
|
||||||
this.binding.yourPhoto.setImageBitmap(avatarService().get(mConversation.getAccount(), getPixel(48)));
|
this.binding.yourPhoto.setImageBitmap(avatarService().get(mConversation, getPixel(72)));
|
||||||
setTitle(mConversation.getName());
|
this.binding.mucTitle.setText(mucOptions.getName());
|
||||||
this.binding.mucJabberid.setText(mConversation.getJid().asBareJid().toString());
|
this.binding.mucSubject.setText(mucOptions.getSubject());
|
||||||
this.binding.mucYourNick.setText(mucOptions.getActualNick());
|
this.binding.mucYourNick.setText(mucOptions.getActualNick());
|
||||||
if (mucOptions.online()) {
|
if (mucOptions.online()) {
|
||||||
this.binding.mucMoreDetails.setVisibility(View.VISIBLE);
|
this.binding.mucMoreDetails.setVisibility(View.VISIBLE);
|
||||||
this.binding.mucSettings.setVisibility(View.VISIBLE);
|
this.binding.mucSettings.setVisibility(View.VISIBLE);
|
||||||
this.binding.mucInfoMore.setVisibility(this.mAdvancedMode ? View.VISIBLE : View.GONE);
|
this.binding.mucInfoMore.setVisibility(this.mAdvancedMode ? View.VISIBLE : View.GONE);
|
||||||
final String status = getStatus(self);
|
|
||||||
if (status != null) {
|
|
||||||
this.binding.mucRole.setVisibility(View.VISIBLE);
|
this.binding.mucRole.setVisibility(View.VISIBLE);
|
||||||
this.binding.mucRole.setText(status);
|
this.binding.mucRole.setText(getStatus(self));
|
||||||
} else {
|
|
||||||
this.binding.mucRole.setVisibility(View.GONE);
|
|
||||||
}
|
|
||||||
if (mucOptions.membersOnly()) {
|
if (mucOptions.membersOnly()) {
|
||||||
this.binding.mucConferenceType.setText(R.string.private_conference);
|
this.binding.mucConferenceType.setText(R.string.private_conference);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -0,0 +1,157 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018, Daniel Gultsch All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
* are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
* list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation and/or
|
||||||
|
* other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* 3. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software without
|
||||||
|
* specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||||
|
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||||
|
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package eu.siacs.conversations.ui;
|
||||||
|
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.databinding.DataBindingUtil;
|
||||||
|
import android.graphics.Bitmap;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.support.annotation.StringRes;
|
||||||
|
import android.support.v7.widget.Toolbar;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.view.Menu;
|
||||||
|
import android.view.MenuItem;
|
||||||
|
import android.view.View;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import com.theartofdev.edmodo.cropper.CropImage;
|
||||||
|
|
||||||
|
import eu.siacs.conversations.Config;
|
||||||
|
import eu.siacs.conversations.R;
|
||||||
|
import eu.siacs.conversations.databinding.ActivityPublishProfilePictureBinding;
|
||||||
|
import eu.siacs.conversations.entities.Conversation;
|
||||||
|
import eu.siacs.conversations.ui.interfaces.OnAvatarPublication;
|
||||||
|
import eu.siacs.conversations.ui.util.PendingItem;
|
||||||
|
|
||||||
|
public class PublishGroupChatProfilePictureActivity extends XmppActivity implements OnAvatarPublication {
|
||||||
|
|
||||||
|
private static final int REQUEST_CHOOSE_FILE = 0xac24;
|
||||||
|
|
||||||
|
private ActivityPublishProfilePictureBinding binding;
|
||||||
|
|
||||||
|
private final PendingItem<String> pendingConversationUuid = new PendingItem<>();
|
||||||
|
|
||||||
|
private Conversation conversation;
|
||||||
|
private Uri uri;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void refreshUiReal() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
void onBackendConnected() {
|
||||||
|
String uuid = pendingConversationUuid.pop();
|
||||||
|
if (uuid != null) {
|
||||||
|
this.conversation = xmppConnectionService.findConversationByUuid(uuid);
|
||||||
|
}
|
||||||
|
if (this.conversation == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
reloadAvatar();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void reloadAvatar() {
|
||||||
|
final int size = (int) getResources().getDimension(R.dimen.publish_avatar_size);
|
||||||
|
Bitmap bitmap;
|
||||||
|
if (uri == null) {
|
||||||
|
bitmap = xmppConnectionService.getAvatarService().get(conversation, size);
|
||||||
|
} else {
|
||||||
|
Log.d(Config.LOGTAG, "loading " + uri.toString() + " into preview");
|
||||||
|
bitmap = xmppConnectionService.getFileBackend().cropCenterSquare(uri, size);
|
||||||
|
}
|
||||||
|
this.binding.accountImage.setImageBitmap(bitmap);
|
||||||
|
this.binding.publishButton.setEnabled(uri != null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
this.binding = DataBindingUtil.setContentView(this, R.layout.activity_publish_profile_picture);
|
||||||
|
setSupportActionBar((Toolbar) this.binding.toolbar);
|
||||||
|
configureActionBar(getSupportActionBar());
|
||||||
|
this.binding.cancelButton.setOnClickListener((v) -> this.finish());
|
||||||
|
this.binding.secondaryHint.setVisibility(View.GONE);
|
||||||
|
this.binding.accountImage.setOnClickListener((v) -> this.chooseAvatar());
|
||||||
|
Intent intent = getIntent();
|
||||||
|
String uuid = intent == null ? null : intent.getStringExtra("uuid");
|
||||||
|
if (uuid != null) {
|
||||||
|
pendingConversationUuid.push(uuid);
|
||||||
|
}
|
||||||
|
this.binding.publishButton.setEnabled(uri != null);
|
||||||
|
this.binding.publishButton.setOnClickListener(this::publish);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void publish(View view) {
|
||||||
|
xmppConnectionService.publishMucAvatar(conversation, uri, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||||
|
if (requestCode == CropImage.CROP_IMAGE_ACTIVITY_REQUEST_CODE) {
|
||||||
|
CropImage.ActivityResult result = CropImage.getActivityResult(data);
|
||||||
|
if (resultCode == RESULT_OK) {
|
||||||
|
this.uri = result.getUri();
|
||||||
|
if (xmppConnectionServiceBound) {
|
||||||
|
reloadAvatar();
|
||||||
|
}
|
||||||
|
} else if (resultCode == CropImage.CROP_IMAGE_ACTIVITY_RESULT_ERROR_CODE) {
|
||||||
|
Exception error = result.getError();
|
||||||
|
if (error != null) {
|
||||||
|
Toast.makeText(this, error.getMessage(), Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void chooseAvatar() {
|
||||||
|
CropImage.activity()
|
||||||
|
.setOutputCompressFormat(Bitmap.CompressFormat.PNG)
|
||||||
|
.setAspectRatio(1, 1)
|
||||||
|
.setMinCropResultSize(Config.AVATAR_SIZE, Config.AVATAR_SIZE)
|
||||||
|
.start(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAvatarPublicationSucceeded() {
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAvatarPublicationFailed(@StringRes int res) {
|
||||||
|
runOnUiThread(() -> {
|
||||||
|
Toast.makeText(this,res,Toast.LENGTH_SHORT).show();
|
||||||
|
this.binding.publishButton.setText(R.string.publish);
|
||||||
|
this.binding.publishButton.setEnabled(true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,16 +1,11 @@
|
||||||
package eu.siacs.conversations.ui;
|
package eu.siacs.conversations.ui;
|
||||||
|
|
||||||
import android.app.PendingIntent;
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.pm.PackageManager;
|
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.annotation.NonNull;
|
|
||||||
import android.support.annotation.StringRes;
|
import android.support.annotation.StringRes;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.Menu;
|
|
||||||
import android.view.MenuItem;
|
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.View.OnLongClickListener;
|
import android.view.View.OnLongClickListener;
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
|
@ -18,23 +13,17 @@ import android.widget.ImageView;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import com.soundcloud.android.crop.Crop;
|
import com.theartofdev.edmodo.cropper.CropImage;
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
|
|
||||||
import eu.siacs.conversations.Config;
|
import eu.siacs.conversations.Config;
|
||||||
import eu.siacs.conversations.R;
|
import eu.siacs.conversations.R;
|
||||||
import eu.siacs.conversations.entities.Account;
|
import eu.siacs.conversations.entities.Account;
|
||||||
import eu.siacs.conversations.persistance.FileBackend;
|
|
||||||
import eu.siacs.conversations.services.XmppConnectionService;
|
import eu.siacs.conversations.services.XmppConnectionService;
|
||||||
import eu.siacs.conversations.utils.FileUtils;
|
import eu.siacs.conversations.ui.interfaces.OnAvatarPublication;
|
||||||
import eu.siacs.conversations.utils.PhoneHelper;
|
import eu.siacs.conversations.utils.PhoneHelper;
|
||||||
import eu.siacs.conversations.xmpp.pep.Avatar;
|
|
||||||
|
|
||||||
public class PublishProfilePictureActivity extends XmppActivity implements XmppConnectionService.OnAccountUpdate {
|
public class PublishProfilePictureActivity extends XmppActivity implements XmppConnectionService.OnAccountUpdate, OnAvatarPublication {
|
||||||
|
|
||||||
private static final int REQUEST_CHOOSE_FILE_AND_CROP = 0xac23;
|
|
||||||
private static final int REQUEST_CHOOSE_FILE = 0xac24;
|
|
||||||
private ImageView avatar;
|
private ImageView avatar;
|
||||||
private TextView hintOrWarning;
|
private TextView hintOrWarning;
|
||||||
private TextView secondaryHint;
|
private TextView secondaryHint;
|
||||||
|
@ -55,10 +44,9 @@ public class PublishProfilePictureActivity extends XmppActivity implements XmppC
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
private boolean mInitialAccountSetup;
|
private boolean mInitialAccountSetup;
|
||||||
private UiCallback<Avatar> avatarPublication = new UiCallback<Avatar>() {
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void success(Avatar object) {
|
public void onAvatarPublicationSucceeded() {
|
||||||
runOnUiThread(() -> {
|
runOnUiThread(() -> {
|
||||||
if (mInitialAccountSetup) {
|
if (mInitialAccountSetup) {
|
||||||
Intent intent = new Intent(getApplicationContext(), StartConversationActivity.class);
|
Intent intent = new Intent(getApplicationContext(), StartConversationActivity.class);
|
||||||
|
@ -74,22 +62,16 @@ public class PublishProfilePictureActivity extends XmppActivity implements XmppC
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void error(final int errorCode, Avatar object) {
|
public void onAvatarPublicationFailed(int res) {
|
||||||
runOnUiThread(() -> {
|
runOnUiThread(() -> {
|
||||||
hintOrWarning.setText(errorCode);
|
hintOrWarning.setText(res);
|
||||||
hintOrWarning.setTextColor(getWarningTextColor());
|
hintOrWarning.setTextColor(getWarningTextColor());
|
||||||
hintOrWarning.setVisibility(View.VISIBLE);
|
hintOrWarning.setVisibility(View.VISIBLE);
|
||||||
publishing = false;
|
publishing = false;
|
||||||
togglePublishButton(true, R.string.publish);
|
togglePublishButton(true, R.string.publish);
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void userInputRequried(PendingIntent pi, Avatar object) {
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
@ -106,7 +88,7 @@ public class PublishProfilePictureActivity extends XmppActivity implements XmppC
|
||||||
if (avatarUri != null) {
|
if (avatarUri != null) {
|
||||||
publishing = true;
|
publishing = true;
|
||||||
togglePublishButton(false, R.string.publishing);
|
togglePublishButton(false, R.string.publishing);
|
||||||
xmppConnectionService.publishAvatar(account, avatarUri, avatarPublication);
|
xmppConnectionService.publishAvatar(account, avatarUri, this);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.cancelButton.setOnClickListener(v -> {
|
this.cancelButton.setOnClickListener(v -> {
|
||||||
|
@ -120,101 +102,37 @@ public class PublishProfilePictureActivity extends XmppActivity implements XmppC
|
||||||
}
|
}
|
||||||
finish();
|
finish();
|
||||||
});
|
});
|
||||||
this.avatar.setOnClickListener(v -> {
|
this.avatar.setOnClickListener(v -> chooseAvatar());
|
||||||
if (hasStoragePermission(REQUEST_CHOOSE_FILE)) {
|
|
||||||
chooseAvatar(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
this.defaultUri = PhoneHelper.getProfilePictureUri(getApplicationContext());
|
this.defaultUri = PhoneHelper.getProfilePictureUri(getApplicationContext());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void chooseAvatar(boolean crop) {
|
|
||||||
Intent attachFileIntent = new Intent();
|
|
||||||
attachFileIntent.setType("image/*");
|
|
||||||
attachFileIntent.setAction(Intent.ACTION_GET_CONTENT);
|
|
||||||
Intent chooser = Intent.createChooser(attachFileIntent, getString(R.string.attach_file));
|
|
||||||
startActivityForResult(chooser, crop ? REQUEST_CHOOSE_FILE_AND_CROP : REQUEST_CHOOSE_FILE);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onRequestPermissionsResult(int requestCode, @NonNull String permissions[], @NonNull int[] grantResults) {
|
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||||
if (grantResults.length > 0)
|
if (requestCode == CropImage.CROP_IMAGE_ACTIVITY_REQUEST_CODE) {
|
||||||
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
CropImage.ActivityResult result = CropImage.getActivityResult(data);
|
||||||
if (requestCode == REQUEST_CHOOSE_FILE_AND_CROP) {
|
|
||||||
chooseAvatar(true);
|
|
||||||
} else if (requestCode == REQUEST_CHOOSE_FILE) {
|
|
||||||
chooseAvatar(false);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Toast.makeText(this, R.string.no_storage_permission, Toast.LENGTH_SHORT).show();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onCreateOptionsMenu(Menu menu) {
|
|
||||||
getMenuInflater().inflate(R.menu.publish_avatar, menu);
|
|
||||||
return super.onCreateOptionsMenu(menu);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onOptionsItemSelected(final MenuItem item) {
|
|
||||||
if (item.getItemId() == R.id.action_crop_image) {
|
|
||||||
if (hasStoragePermission(REQUEST_CHOOSE_FILE_AND_CROP)) {
|
|
||||||
chooseAvatar(true);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return super.onOptionsItemSelected(item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onActivityResult(int requestCode, int resultCode, final Intent data) {
|
|
||||||
super.onActivityResult(requestCode, resultCode, data);
|
|
||||||
if (resultCode == RESULT_OK) {
|
if (resultCode == RESULT_OK) {
|
||||||
Uri source = data.getData();
|
this.avatarUri = result.getUri();
|
||||||
switch (requestCode) {
|
|
||||||
case REQUEST_CHOOSE_FILE_AND_CROP:
|
|
||||||
if (FileBackend.weOwnFile(this, source)) {
|
|
||||||
Toast.makeText(this,R.string.security_error_invalid_file_access,Toast.LENGTH_SHORT).show();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
String original = FileUtils.getPath(this, source);
|
|
||||||
if (original != null) {
|
|
||||||
source = Uri.parse("file://"+original);
|
|
||||||
}
|
|
||||||
Uri destination = Uri.fromFile(new File(getCacheDir(), "croppedAvatar"));
|
|
||||||
final int size = getPixel(192);
|
|
||||||
Crop.of(source, destination).asSquare().withMaxSize(size, size).start(this);
|
|
||||||
break;
|
|
||||||
case REQUEST_CHOOSE_FILE:
|
|
||||||
if (FileBackend.weOwnFile(this, source)) {
|
|
||||||
Toast.makeText(this,R.string.security_error_invalid_file_access,Toast.LENGTH_SHORT).show();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.avatarUri = source;
|
|
||||||
if (xmppConnectionServiceBound) {
|
if (xmppConnectionServiceBound) {
|
||||||
loadImageIntoPreview(this.avatarUri);
|
loadImageIntoPreview(this.avatarUri);
|
||||||
}
|
}
|
||||||
break;
|
} else if (resultCode == CropImage.CROP_IMAGE_ACTIVITY_RESULT_ERROR_CODE) {
|
||||||
case Crop.REQUEST_CROP:
|
Exception error = result.getError();
|
||||||
this.avatarUri = Uri.fromFile(new File(getCacheDir(), "croppedAvatar"));
|
if (error != null) {
|
||||||
if (xmppConnectionServiceBound) {
|
Toast.makeText(this, error.getMessage(), Toast.LENGTH_SHORT).show();
|
||||||
loadImageIntoPreview(this.avatarUri);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (requestCode == Crop.REQUEST_CROP && data != null) {
|
|
||||||
Throwable throwable = Crop.getError(data);
|
|
||||||
if (throwable != null && throwable instanceof OutOfMemoryError) {
|
|
||||||
Toast.makeText(this,R.string.selection_too_large, Toast.LENGTH_SHORT).show();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void chooseAvatar() {
|
||||||
|
CropImage.activity()
|
||||||
|
.setOutputCompressFormat(Bitmap.CompressFormat.PNG)
|
||||||
|
.setAspectRatio(1, 1)
|
||||||
|
.setMinCropResultSize(Config.AVATAR_SIZE, Config.AVATAR_SIZE)
|
||||||
|
.start(this);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onBackendConnected() {
|
protected void onBackendConnected() {
|
||||||
this.account = extractAccount(getIntent());
|
this.account = extractAccount(getIntent());
|
||||||
|
@ -307,4 +225,5 @@ public class PublishProfilePictureActivity extends XmppActivity implements XmppC
|
||||||
public void onAccountUpdate() {
|
public void onAccountUpdate() {
|
||||||
refreshUi();
|
refreshUi();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018, Daniel Gultsch All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
* are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
* list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation and/or
|
||||||
|
* other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* 3. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software without
|
||||||
|
* specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||||
|
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||||
|
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package eu.siacs.conversations.ui.interfaces;
|
||||||
|
|
||||||
|
import android.support.annotation.StringRes;
|
||||||
|
|
||||||
|
public interface OnAvatarPublication {
|
||||||
|
|
||||||
|
void onAvatarPublicationSucceeded();
|
||||||
|
void onAvatarPublicationFailed(@StringRes int res);
|
||||||
|
|
||||||
|
}
|
|
@ -8,7 +8,8 @@
|
||||||
android:background="?attr/color_background_secondary"
|
android:background="?attr/color_background_secondary"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
||||||
<include android:id="@+id/toolbar"
|
<include
|
||||||
|
android:id="@+id/toolbar"
|
||||||
layout="@layout/toolbar"/>
|
layout="@layout/toolbar"/>
|
||||||
|
|
||||||
<ScrollView
|
<ScrollView
|
||||||
|
@ -35,14 +36,6 @@
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:padding="@dimen/card_padding_regular">
|
android:padding="@dimen/card_padding_regular">
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/muc_jabberid"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginBottom="16dp"
|
|
||||||
android:text="@string/account_settings_example_jabber_id"
|
|
||||||
android:textAppearance="@style/TextAppearance.Conversations.Title"/>
|
|
||||||
|
|
||||||
<RelativeLayout
|
<RelativeLayout
|
||||||
android:layout_width="fill_parent"
|
android:layout_width="fill_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
@ -50,45 +43,53 @@
|
||||||
|
|
||||||
<com.makeramen.roundedimageview.RoundedImageView
|
<com.makeramen.roundedimageview.RoundedImageView
|
||||||
android:id="@+id/your_photo"
|
android:id="@+id/your_photo"
|
||||||
android:layout_width="48dp"
|
android:layout_width="72dp"
|
||||||
android:layout_height="48dp"
|
android:layout_height="72dp"
|
||||||
android:layout_alignParentLeft="true"
|
android:layout_alignParentLeft="true"
|
||||||
app:riv_corner_radius="2dp"/>
|
app:riv_corner_radius="2dp"/>
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="fill_parent"
|
android:layout_width="fill_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_centerVertical="true"
|
android:layout_alignParentTop="true"
|
||||||
android:layout_toRightOf="@+id/your_photo"
|
android:layout_toRightOf="@+id/your_photo"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:paddingLeft="@dimen/avatar_item_distance">
|
android:paddingLeft="@dimen/avatar_item_distance">
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/muc_your_nick"
|
android:id="@+id/muc_title"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:singleLine="true"
|
android:singleLine="true"
|
||||||
|
android:layout_alignParentLeft="true"
|
||||||
|
android:layout_toLeftOf="@+id/edit_muc_name_button"
|
||||||
|
android:textAppearance="@style/TextAppearance.Conversations.Title"/>
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/muc_subject"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_alignParentLeft="true"
|
||||||
|
android:layout_below="@+id/muc_title"
|
||||||
|
android:layout_toLeftOf="@+id/edit_muc_name_button"
|
||||||
android:textAppearance="@style/TextAppearance.Conversations.Subhead"/>
|
android:textAppearance="@style/TextAppearance.Conversations.Subhead"/>
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/muc_role"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:singleLine="true"
|
|
||||||
android:textAppearance="@style/TextAppearance.Conversations.Body1.Secondary"/>
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<ImageButton
|
<ImageButton
|
||||||
android:id="@+id/edit_nick_button"
|
android:id="@+id/edit_muc_name_button"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_alignParentRight="true"
|
android:layout_alignParentEnd="true"
|
||||||
android:layout_centerVertical="true"
|
android:layout_alignParentTop="true"
|
||||||
android:alpha="?attr/icon_alpha"
|
android:alpha="?attr/icon_alpha"
|
||||||
android:background="?attr/selectableItemBackgroundBorderless"
|
android:background="?attr/selectableItemBackgroundBorderless"
|
||||||
android:padding="@dimen/image_button_padding"
|
android:padding="@dimen/image_button_padding"
|
||||||
android:src="?attr/icon_edit_body"/>
|
android:src="?attr/icon_edit_body"/>
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
|
</LinearLayout>
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
<RelativeLayout
|
<RelativeLayout
|
||||||
android:id="@+id/muc_settings"
|
android:id="@+id/muc_settings"
|
||||||
|
@ -120,35 +121,6 @@
|
||||||
android:src="?attr/icon_settings"/>
|
android:src="?attr/icon_settings"/>
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
|
|
||||||
<RelativeLayout
|
|
||||||
android:layout_width="fill_parent"
|
|
||||||
android:layout_height="wrap_content">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/notification_status_text"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_alignParentLeft="true"
|
|
||||||
android:layout_centerVertical="true"
|
|
||||||
android:layout_toLeftOf="@+id/notification_status_button"
|
|
||||||
android:text="@string/notify_on_all_messages"
|
|
||||||
android:textAppearance="@style/TextAppearance.Conversations.Body1"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<ImageButton
|
|
||||||
android:id="@+id/notification_status_button"
|
|
||||||
style="?android:attr/buttonStyleSmall"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_alignParentRight="true"
|
|
||||||
android:layout_centerVertical="true"
|
|
||||||
android:layout_gravity="center_horizontal"
|
|
||||||
android:alpha="?attr/icon_alpha"
|
|
||||||
android:background="?attr/selectableItemBackgroundBorderless"
|
|
||||||
android:padding="@dimen/image_button_padding"
|
|
||||||
android:src="?attr/icon_notifications"/>
|
|
||||||
</RelativeLayout>
|
|
||||||
|
|
||||||
<TableLayout
|
<TableLayout
|
||||||
android:id="@+id/muc_info_more"
|
android:id="@+id/muc_info_more"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
@ -179,6 +151,88 @@
|
||||||
</TableRow>
|
</TableRow>
|
||||||
|
|
||||||
</TableLayout>
|
</TableLayout>
|
||||||
|
</LinearLayout>
|
||||||
|
</android.support.v7.widget.CardView>
|
||||||
|
|
||||||
|
<android.support.v7.widget.CardView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="@dimen/activity_vertical_margin"
|
||||||
|
android:layout_marginLeft="@dimen/activity_horizontal_margin"
|
||||||
|
android:layout_marginRight="@dimen/activity_horizontal_margin"
|
||||||
|
android:layout_marginTop="@dimen/activity_vertical_margin">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="@dimen/card_padding_regular">
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_centerVertical="true"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/muc_your_nick"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:textAppearance="@style/TextAppearance.Conversations.Subhead"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/muc_role"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:textAppearance="@style/TextAppearance.Conversations.Body1.Secondary"/>
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/edit_nick_button"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_alignParentRight="true"
|
||||||
|
android:layout_centerVertical="true"
|
||||||
|
android:alpha="?attr/icon_alpha"
|
||||||
|
android:background="?attr/selectableItemBackgroundBorderless"
|
||||||
|
android:padding="@dimen/image_button_padding"
|
||||||
|
android:src="?attr/icon_edit_body"/>
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/notification_status_text"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_alignParentLeft="true"
|
||||||
|
android:layout_centerVertical="true"
|
||||||
|
android:layout_toLeftOf="@+id/notification_status_button"
|
||||||
|
android:text="@string/notify_on_all_messages"
|
||||||
|
android:textAppearance="@style/TextAppearance.Conversations.Body1"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/notification_status_button"
|
||||||
|
style="?android:attr/buttonStyleSmall"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_alignParentRight="true"
|
||||||
|
android:layout_centerVertical="true"
|
||||||
|
android:layout_gravity="center_horizontal"
|
||||||
|
android:alpha="?attr/icon_alpha"
|
||||||
|
android:background="?attr/selectableItemBackgroundBorderless"
|
||||||
|
android:padding="@dimen/image_button_padding"
|
||||||
|
android:src="?attr/icon_notifications"/>
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/details_account"
|
android:id="@+id/details_account"
|
||||||
|
@ -193,7 +247,7 @@
|
||||||
|
|
||||||
<android.support.v7.widget.CardView
|
<android.support.v7.widget.CardView
|
||||||
android:id="@+id/muc_more_details"
|
android:id="@+id/muc_more_details"
|
||||||
android:layout_width="fill_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginBottom="@dimen/activity_vertical_margin"
|
android:layout_marginBottom="@dimen/activity_vertical_margin"
|
||||||
android:layout_marginLeft="@dimen/activity_horizontal_margin"
|
android:layout_marginLeft="@dimen/activity_horizontal_margin"
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<layout xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
||||||
android:background="?attr/color_background_secondary">
|
android:background="?attr/color_background_secondary">
|
||||||
|
|
||||||
<include layout="@layout/toolbar" />
|
<include android:id="@+id/toolbar" layout="@layout/toolbar"/>
|
||||||
|
|
||||||
<android.support.v7.widget.CardView
|
<android.support.v7.widget.CardView
|
||||||
android:layout_width="fill_parent"
|
android:layout_width="fill_parent"
|
||||||
|
@ -47,15 +48,15 @@
|
||||||
android:id="@+id/secondary_hint"
|
android:id="@+id/secondary_hint"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:textAppearance="@style/TextAppearance.Conversations.Body1"
|
android:text="@string/or_long_press_for_default"
|
||||||
android:text="@string/or_long_press_for_default"/>
|
android:textAppearance="@style/TextAppearance.Conversations.Body1"/>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/hint_or_warning"
|
android:id="@+id/hint_or_warning"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="8dp"
|
|
||||||
android:layout_marginBottom="8dp"
|
android:layout_marginBottom="8dp"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
android:textAppearance="@style/TextAppearance.Conversations.Body1"/>
|
android:textAppearance="@style/TextAppearance.Conversations.Body1"/>
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
@ -95,3 +96,4 @@
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
|
</layout>
|
|
@ -2,13 +2,6 @@
|
||||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||||
|
|
||||||
<item
|
|
||||||
android:id="@+id/action_edit_subject"
|
|
||||||
android:icon="?attr/icon_edit"
|
|
||||||
android:orderInCategory="10"
|
|
||||||
app:showAsAction="always"
|
|
||||||
android:title="@string/action_edit_subject"/>
|
|
||||||
|
|
||||||
<item
|
<item
|
||||||
android:id="@+id/action_share"
|
android:id="@+id/action_share"
|
||||||
android:icon="?attr/icon_share"
|
android:icon="?attr/icon_share"
|
||||||
|
|
|
@ -1,9 +0,0 @@
|
||||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
|
||||||
|
|
||||||
<item
|
|
||||||
android:id="@+id/action_crop_image"
|
|
||||||
app:showAsAction="always"
|
|
||||||
android:icon="@drawable/ic_crop_white_24dp"
|
|
||||||
android:title="@string/select_image_and_crop"/>
|
|
||||||
</menu>
|
|
|
@ -510,7 +510,6 @@
|
||||||
<string name="correct_message">Correct message</string>
|
<string name="correct_message">Correct message</string>
|
||||||
<string name="send_corrected_message">Send corrected message</string>
|
<string name="send_corrected_message">Send corrected message</string>
|
||||||
<string name="no_keys_just_confirm">You already trust this contact. By selecting \'done\' you are just confirming that %s is part of this group chat.</string>
|
<string name="no_keys_just_confirm">You already trust this contact. By selecting \'done\' you are just confirming that %s is part of this group chat.</string>
|
||||||
<string name="select_image_and_crop">Select image and crop</string>
|
|
||||||
<string name="this_account_is_disabled">You have disabled this account</string>
|
<string name="this_account_is_disabled">You have disabled this account</string>
|
||||||
<string name="security_error_invalid_file_access">Security error: Invalid file access</string>
|
<string name="security_error_invalid_file_access">Security error: Invalid file access</string>
|
||||||
<string name="no_application_to_share_uri">No application found to share URI</string>
|
<string name="no_application_to_share_uri">No application found to share URI</string>
|
||||||
|
@ -717,4 +716,7 @@
|
||||||
<string name="p1_s3_filetransfer">HTTP File Sharing for S3</string>
|
<string name="p1_s3_filetransfer">HTTP File Sharing for S3</string>
|
||||||
<string name="pref_start_search">Direct Search</string>
|
<string name="pref_start_search">Direct Search</string>
|
||||||
<string name="pref_start_search_summary">At ‘Start Conversation’ screen open keyboard and place cursor in search field</string>
|
<string name="pref_start_search_summary">At ‘Start Conversation’ screen open keyboard and place cursor in search field</string>
|
||||||
|
<string name="group_chat_avatar">Group chat avatar</string>
|
||||||
|
<string name="host_does_not_support_group_chat_avatars">Host does not support group chat avatars</string>
|
||||||
|
<string name="only_the_owner_can_change_group_chat_avatar">Only the owner can change group chat avatar</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
Loading…
Reference in a new issue