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' | ||||
|     } | ||||
|     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:appcompat-v7:$supportLibVersion" | ||||
|     implementation "com.android.support:cardview-v7:$supportLibVersion" | ||||
|  | ||||
| @ -180,6 +180,7 @@ | ||||
|             android:windowSoftInputMode="stateHidden|adjustResize"/> | ||||
|         <activity | ||||
|             android:name=".ui.ConferenceDetailsActivity" | ||||
|             android:label="@string/action_muc_details" | ||||
|             android:windowSoftInputMode="stateHidden"/> | ||||
|         <activity | ||||
|             android:name=".ui.ContactDetailsActivity" | ||||
| @ -188,6 +189,9 @@ | ||||
|             android:name=".ui.PublishProfilePictureActivity" | ||||
|             android:label="@string/mgmt_account_publish_avatar" | ||||
|             android:windowSoftInputMode="stateHidden"/> | ||||
|         <activity | ||||
|             android:name=".ui.PublishGroupChatProfilePictureActivity" | ||||
|             android:label="@string/group_chat_avatar"/> | ||||
|         <activity | ||||
|             android:name=".ui.ShareWithActivity" | ||||
|             android:label="@string/app_name" | ||||
| @ -234,7 +238,8 @@ | ||||
|                 <category android:name="android.intent.category.PREFERENCE"/> | ||||
|             </intent-filter> | ||||
|         </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"/> | ||||
| 
 | ||||
|         <service android:name=".services.ExportLogsService"/> | ||||
|  | ||||
| @ -1,6 +1,7 @@ | ||||
| package eu.siacs.conversations.entities; | ||||
| 
 | ||||
| import android.annotation.SuppressLint; | ||||
| import android.util.Log; | ||||
| 
 | ||||
| import java.util.ArrayList; | ||||
| import java.util.HashSet; | ||||
| @ -373,7 +374,7 @@ public class MucOptions { | ||||
| 		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); | ||||
| 		updateFormData(data == null ? new Data() : data); | ||||
| 		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_MODERATED, this.hasFeature("muc_moderated")); | ||||
| 		changed |= conversation.setAttribute(Conversation.ATTRIBUTE_NON_ANONYMOUS, this.hasFeature("muc_nonanonymous")); | ||||
| 		changed |= setName(name); | ||||
| 		return changed; | ||||
| 	} | ||||
| 
 | ||||
| @ -402,6 +404,10 @@ public class MucOptions { | ||||
| 		return this.features.contains(feature); | ||||
| 	} | ||||
| 
 | ||||
| 	public boolean hasVCards() { | ||||
| 	    return hasFeature("vcard-temp"); | ||||
|     } | ||||
| 
 | ||||
| 	public boolean canInvite() { | ||||
| 		Field field = this.form.getFieldByName("muc#roomconfig_allowinvites"); | ||||
| 		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"); | ||||
| 	} | ||||
| 
 | ||||
| 	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() { | ||||
| 		List<User> users = new ArrayList<>(); | ||||
| 		for (Jid jid : conversation.getAcceptedCryptoTargets()) { | ||||
|  | ||||
| @ -736,6 +736,15 @@ public class FileBackend { | ||||
| 	} | ||||
| 
 | ||||
| 	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); | ||||
| 		if (bm == null) { | ||||
| 			return null; | ||||
| @ -749,6 +758,19 @@ public class FileBackend { | ||||
| 		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) { | ||||
| 		try { | ||||
| 			ByteArrayOutputStream mByteArrayOutputStream = new ByteArrayOutputStream(); | ||||
|  | ||||
| @ -60,6 +60,8 @@ import java.util.concurrent.CountDownLatch; | ||||
| import java.util.concurrent.atomic.AtomicBoolean; | ||||
| import java.util.concurrent.atomic.AtomicLong; | ||||
| 
 | ||||
| import javax.security.auth.callback.Callback; | ||||
| 
 | ||||
| import eu.siacs.conversations.Config; | ||||
| import eu.siacs.conversations.R; | ||||
| 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.ui.SettingsActivity; | ||||
| import eu.siacs.conversations.ui.UiCallback; | ||||
| import eu.siacs.conversations.ui.interfaces.OnAvatarPublication; | ||||
| import eu.siacs.conversations.ui.interfaces.OnSearchResultsAvailable; | ||||
| import eu.siacs.conversations.utils.ConversationsFileObserver; | ||||
| import eu.siacs.conversations.utils.CryptoHelper; | ||||
| @ -2446,18 +2449,21 @@ public class XmppConnectionService extends Service { | ||||
| 			public void onIqPacketReceived(Account account, IqPacket packet) { | ||||
| 				Element query = packet.findChild("query", "http://jabber.org/protocol/disco#info"); | ||||
| 				if (packet.getType() == IqPacket.TYPE.RESULT && query != null) { | ||||
| 					String name = null; | ||||
| 					ArrayList<String> features = new ArrayList<>(); | ||||
| 					for (Element child : query.getChildren()) { | ||||
| 						if (child != null && child.getName().equals("feature")) { | ||||
| 						if (child.getName().equals("feature")) { | ||||
| 							String var = child.getAttribute("var"); | ||||
| 							if (var != null) { | ||||
| 								features.add(var); | ||||
| 							} | ||||
| 						} else if (child.getName().equals("identity")) { | ||||
| 							name = child.getAttribute("name"); | ||||
| 						} | ||||
| 					} | ||||
| 					Element form = query.findChild("x", Namespace.DATA); | ||||
| 					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()); | ||||
| 						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(() -> { | ||||
| 			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)) { | ||||
| 					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; | ||||
| 				} | ||||
| 				publishAvatar(account, avatar, callback); | ||||
| 			} else { | ||||
| 				callback.error(R.string.error_publish_avatar_converting, null); | ||||
| 				callback.onAvatarPublicationFailed(R.string.error_publish_avatar_converting); | ||||
| 			} | ||||
| 		}).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); | ||||
| 		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"); | ||||
| 								if (callback != null) { | ||||
| 									callback.success(avatar); | ||||
| 									callback.onAvatarPublicationSucceeded(); | ||||
| 								} | ||||
| 							} else { | ||||
| 								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"); | ||||
| 					Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": server rejected avatar " + (avatar.size / 1024) + "KiB " + (error != null ? error.toString() : "")); | ||||
| 					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.content.Context; | ||||
| import android.content.Intent; | ||||
| import android.content.IntentSender.SendIntentException; | ||||
| import android.content.res.Resources; | ||||
| import android.databinding.DataBindingUtil; | ||||
| @ -12,6 +13,7 @@ import android.os.AsyncTask; | ||||
| import android.os.Bundle; | ||||
| import android.support.v7.app.AlertDialog; | ||||
| import android.support.v7.widget.Toolbar; | ||||
| import android.util.Log; | ||||
| import android.view.ContextMenu; | ||||
| import android.view.LayoutInflater; | ||||
| import android.view.Menu; | ||||
| @ -247,6 +249,20 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers | ||||
| 		this.mAdvancedMode = getPreferences().getBoolean("advanced_muc_mode", false); | ||||
| 		this.binding.mucInfoMore.setVisibility(this.mAdvancedMode ? View.VISIBLE : View.GONE); | ||||
| 		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 | ||||
| @ -267,14 +283,6 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers | ||||
| 			case android.R.id.home: | ||||
| 				finish(); | ||||
| 				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: | ||||
| 				shareLink(true); | ||||
| 				break; | ||||
| @ -318,7 +326,6 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers | ||||
| 		MenuItem menuItemSaveBookmark = menu.findItem(R.id.action_save_as_bookmark); | ||||
| 		MenuItem menuItemDeleteBookmark = menu.findItem(R.id.action_delete_bookmark); | ||||
| 		MenuItem menuItemAdvancedMode = menu.findItem(R.id.action_advanced_mode); | ||||
| 		MenuItem menuItemChangeSubject = menu.findItem(R.id.action_edit_subject); | ||||
| 		menuItemAdvancedMode.setChecked(mAdvancedMode); | ||||
| 		if (mConversation == null) { | ||||
| 			return true; | ||||
| @ -330,7 +337,6 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers | ||||
| 			menuItemDeleteBookmark.setVisible(false); | ||||
| 			menuItemSaveBookmark.setVisible(true); | ||||
| 		} | ||||
| 		menuItemChangeSubject.setVisible(mConversation.getMucOptions().canChangeSubject()); | ||||
| 		return true; | ||||
| 	} | ||||
| 
 | ||||
| @ -525,21 +531,16 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers | ||||
| 			account = mConversation.getAccount().getJid().asBareJid().toString(); | ||||
| 		} | ||||
| 		this.binding.detailsAccount.setText(getString(R.string.using_account, account)); | ||||
| 		this.binding.yourPhoto.setImageBitmap(avatarService().get(mConversation.getAccount(), getPixel(48))); | ||||
| 		setTitle(mConversation.getName()); | ||||
| 		this.binding.mucJabberid.setText(mConversation.getJid().asBareJid().toString()); | ||||
| 		this.binding.yourPhoto.setImageBitmap(avatarService().get(mConversation, getPixel(72))); | ||||
| 		this.binding.mucTitle.setText(mucOptions.getName()); | ||||
| 		this.binding.mucSubject.setText(mucOptions.getSubject()); | ||||
| 		this.binding.mucYourNick.setText(mucOptions.getActualNick()); | ||||
| 		if (mucOptions.online()) { | ||||
| 			this.binding.mucMoreDetails.setVisibility(View.VISIBLE); | ||||
| 			this.binding.mucSettings.setVisibility(View.VISIBLE); | ||||
| 			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.setText(status); | ||||
| 			} else { | ||||
| 				this.binding.mucRole.setVisibility(View.GONE); | ||||
| 			} | ||||
| 			this.binding.mucRole.setVisibility(View.VISIBLE); | ||||
| 			this.binding.mucRole.setText(getStatus(self)); | ||||
| 			if (mucOptions.membersOnly()) { | ||||
| 				this.binding.mucConferenceType.setText(R.string.private_conference); | ||||
| 			} 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; | ||||
| 
 | ||||
| import android.app.PendingIntent; | ||||
| import android.content.Intent; | ||||
| import android.content.pm.PackageManager; | ||||
| import android.graphics.Bitmap; | ||||
| import android.net.Uri; | ||||
| import android.os.Bundle; | ||||
| import android.support.annotation.NonNull; | ||||
| import android.support.annotation.StringRes; | ||||
| import android.util.Log; | ||||
| import android.view.Menu; | ||||
| import android.view.MenuItem; | ||||
| import android.view.View; | ||||
| import android.view.View.OnLongClickListener; | ||||
| import android.widget.Button; | ||||
| @ -18,293 +13,217 @@ import android.widget.ImageView; | ||||
| import android.widget.TextView; | ||||
| import android.widget.Toast; | ||||
| 
 | ||||
| import com.soundcloud.android.crop.Crop; | ||||
| 
 | ||||
| import java.io.File; | ||||
| import com.theartofdev.edmodo.cropper.CropImage; | ||||
| 
 | ||||
| import eu.siacs.conversations.Config; | ||||
| import eu.siacs.conversations.R; | ||||
| import eu.siacs.conversations.entities.Account; | ||||
| import eu.siacs.conversations.persistance.FileBackend; | ||||
| 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.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 TextView hintOrWarning; | ||||
| 	private TextView secondaryHint; | ||||
| 	private Button cancelButton; | ||||
| 	private Button publishButton; | ||||
| 	private Uri avatarUri; | ||||
| 	private Uri defaultUri; | ||||
| 	private Account account; | ||||
| 	private boolean support = false; | ||||
| 	private boolean publishing = false; | ||||
| 	private OnLongClickListener backToDefaultListener = new OnLongClickListener() { | ||||
|     private ImageView avatar; | ||||
|     private TextView hintOrWarning; | ||||
|     private TextView secondaryHint; | ||||
|     private Button cancelButton; | ||||
|     private Button publishButton; | ||||
|     private Uri avatarUri; | ||||
|     private Uri defaultUri; | ||||
|     private Account account; | ||||
|     private boolean support = false; | ||||
|     private boolean publishing = false; | ||||
|     private OnLongClickListener backToDefaultListener = new OnLongClickListener() { | ||||
| 
 | ||||
| 		@Override | ||||
| 		public boolean onLongClick(View v) { | ||||
| 			avatarUri = defaultUri; | ||||
| 			loadImageIntoPreview(defaultUri); | ||||
| 			return true; | ||||
| 		} | ||||
| 	}; | ||||
| 	private boolean mInitialAccountSetup; | ||||
| 	private UiCallback<Avatar> avatarPublication = new UiCallback<Avatar>() { | ||||
|         @Override | ||||
|         public boolean onLongClick(View v) { | ||||
|             avatarUri = defaultUri; | ||||
|             loadImageIntoPreview(defaultUri); | ||||
|             return true; | ||||
|         } | ||||
|     }; | ||||
|     private boolean mInitialAccountSetup; | ||||
| 
 | ||||
| 		@Override | ||||
| 		public void success(Avatar object) { | ||||
| 			runOnUiThread(() -> { | ||||
| 				if (mInitialAccountSetup) { | ||||
| 					Intent intent = new Intent(getApplicationContext(), StartConversationActivity.class); | ||||
| 					WelcomeActivity.addInviteUri(intent, getIntent()); | ||||
| 					intent.putExtra("init", true); | ||||
| 					startActivity(intent); | ||||
| 				} | ||||
| 				Toast.makeText(PublishProfilePictureActivity.this, | ||||
| 						R.string.avatar_has_been_published, | ||||
| 						Toast.LENGTH_SHORT).show(); | ||||
| 				finish(); | ||||
| 			}); | ||||
| 		} | ||||
|     @Override | ||||
|     public void onAvatarPublicationSucceeded() { | ||||
|         runOnUiThread(() -> { | ||||
|             if (mInitialAccountSetup) { | ||||
|                 Intent intent = new Intent(getApplicationContext(), StartConversationActivity.class); | ||||
|                 WelcomeActivity.addInviteUri(intent, getIntent()); | ||||
|                 intent.putExtra("init", true); | ||||
|                 startActivity(intent); | ||||
|             } | ||||
|             Toast.makeText(PublishProfilePictureActivity.this, | ||||
|                     R.string.avatar_has_been_published, | ||||
|                     Toast.LENGTH_SHORT).show(); | ||||
|             finish(); | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
| 		@Override | ||||
| 		public void error(final int errorCode, Avatar object) { | ||||
| 			runOnUiThread(() -> { | ||||
| 				hintOrWarning.setText(errorCode); | ||||
| 				hintOrWarning.setTextColor(getWarningTextColor()); | ||||
| 				hintOrWarning.setVisibility(View.VISIBLE); | ||||
| 				publishing = false; | ||||
| 				togglePublishButton(true,R.string.publish); | ||||
| 			}); | ||||
|     @Override | ||||
|     public void onAvatarPublicationFailed(int res) { | ||||
|         runOnUiThread(() -> { | ||||
|             hintOrWarning.setText(res); | ||||
|             hintOrWarning.setTextColor(getWarningTextColor()); | ||||
|             hintOrWarning.setVisibility(View.VISIBLE); | ||||
|             publishing = false; | ||||
|             togglePublishButton(true, R.string.publish); | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
| 		} | ||||
|     @Override | ||||
|     public void onCreate(Bundle savedInstanceState) { | ||||
|         super.onCreate(savedInstanceState); | ||||
|         setContentView(R.layout.activity_publish_profile_picture); | ||||
|         setSupportActionBar(findViewById(R.id.toolbar)); | ||||
|         configureActionBar(getSupportActionBar()); | ||||
| 
 | ||||
| 		@Override | ||||
| 		public void userInputRequried(PendingIntent pi, Avatar object) { | ||||
| 		} | ||||
| 	}; | ||||
|         this.avatar = findViewById(R.id.account_image); | ||||
|         this.cancelButton = findViewById(R.id.cancel_button); | ||||
|         this.publishButton = findViewById(R.id.publish_button); | ||||
|         this.hintOrWarning = findViewById(R.id.hint_or_warning); | ||||
|         this.secondaryHint = findViewById(R.id.secondary_hint); | ||||
|         this.publishButton.setOnClickListener(v -> { | ||||
|             if (avatarUri != null) { | ||||
|                 publishing = true; | ||||
|                 togglePublishButton(false, R.string.publishing); | ||||
|                 xmppConnectionService.publishAvatar(account, avatarUri, this); | ||||
|             } | ||||
|         }); | ||||
|         this.cancelButton.setOnClickListener(v -> { | ||||
|             if (mInitialAccountSetup) { | ||||
|                 Intent intent = new Intent(getApplicationContext(), StartConversationActivity.class); | ||||
|                 if (xmppConnectionService != null && xmppConnectionService.getAccounts().size() == 1) { | ||||
|                     WelcomeActivity.addInviteUri(intent, getIntent()); | ||||
|                     intent.putExtra("init", true); | ||||
|                 } | ||||
|                 startActivity(intent); | ||||
|             } | ||||
|             finish(); | ||||
|         }); | ||||
|         this.avatar.setOnClickListener(v -> chooseAvatar()); | ||||
|         this.defaultUri = PhoneHelper.getProfilePictureUri(getApplicationContext()); | ||||
|     } | ||||
| 
 | ||||
| 	@Override | ||||
| 	public void onCreate(Bundle savedInstanceState) { | ||||
| 		super.onCreate(savedInstanceState); | ||||
| 		setContentView(R.layout.activity_publish_profile_picture); | ||||
| 		setSupportActionBar(findViewById(R.id.toolbar)); | ||||
| 		configureActionBar(getSupportActionBar()); | ||||
| 
 | ||||
| 		this.avatar = findViewById(R.id.account_image); | ||||
| 		this.cancelButton = findViewById(R.id.cancel_button); | ||||
| 		this.publishButton = findViewById(R.id.publish_button); | ||||
| 		this.hintOrWarning = findViewById(R.id.hint_or_warning); | ||||
| 		this.secondaryHint = findViewById(R.id.secondary_hint); | ||||
| 		this.publishButton.setOnClickListener(v -> { | ||||
| 			if (avatarUri != null) { | ||||
| 				publishing = true; | ||||
| 				togglePublishButton(false,R.string.publishing); | ||||
| 				xmppConnectionService.publishAvatar(account, avatarUri, avatarPublication); | ||||
| 			} | ||||
| 		}); | ||||
| 		this.cancelButton.setOnClickListener(v -> { | ||||
| 			if (mInitialAccountSetup) { | ||||
| 				Intent intent = new Intent(getApplicationContext(), StartConversationActivity.class); | ||||
| 				if (xmppConnectionService != null && xmppConnectionService.getAccounts().size() == 1) { | ||||
| 					WelcomeActivity.addInviteUri(intent, getIntent()); | ||||
| 					intent.putExtra("init", true); | ||||
| 				} | ||||
| 				startActivity(intent); | ||||
| 			} | ||||
| 			finish(); | ||||
| 		}); | ||||
| 		this.avatar.setOnClickListener(v -> { | ||||
| 			if (hasStoragePermission(REQUEST_CHOOSE_FILE)) { | ||||
| 				chooseAvatar(false); | ||||
| 			} | ||||
|     @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.avatarUri = result.getUri(); | ||||
|                 if (xmppConnectionServiceBound) { | ||||
|                     loadImageIntoPreview(this.avatarUri); | ||||
|                 } | ||||
|             } 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(); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| 		}); | ||||
| 		this.defaultUri = PhoneHelper.getProfilePictureUri(getApplicationContext()); | ||||
| 	} | ||||
|     private void chooseAvatar() { | ||||
|         CropImage.activity() | ||||
|                 .setOutputCompressFormat(Bitmap.CompressFormat.PNG) | ||||
|                 .setAspectRatio(1, 1) | ||||
|                 .setMinCropResultSize(Config.AVATAR_SIZE, Config.AVATAR_SIZE) | ||||
|                 .start(this); | ||||
|     } | ||||
| 
 | ||||
| 	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 | ||||
|     protected void onBackendConnected() { | ||||
|         this.account = extractAccount(getIntent()); | ||||
|         if (this.account != null) { | ||||
|             reloadAvatar(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| 	@Override | ||||
| 	public void onRequestPermissionsResult(int requestCode, @NonNull String permissions[], @NonNull int[] grantResults) { | ||||
| 		if (grantResults.length > 0) | ||||
| 			if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { | ||||
| 				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(); | ||||
| 			} | ||||
| 	} | ||||
|     private void reloadAvatar() { | ||||
|         this.support = this.account.getXmppConnection() != null && this.account.getXmppConnection().getFeatures().pep(); | ||||
|         if (this.avatarUri == null) { | ||||
|             if (this.account.getAvatar() != null || this.defaultUri == null) { | ||||
|                 loadImageIntoPreview(null); | ||||
|             } else { | ||||
|                 this.avatarUri = this.defaultUri; | ||||
|                 loadImageIntoPreview(this.defaultUri); | ||||
|             } | ||||
|         } else { | ||||
|             loadImageIntoPreview(avatarUri); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| 	@Override | ||||
| 	public boolean onCreateOptionsMenu(Menu menu) { | ||||
| 		getMenuInflater().inflate(R.menu.publish_avatar, menu); | ||||
| 		return super.onCreateOptionsMenu(menu); | ||||
| 	} | ||||
|     @Override | ||||
|     protected void onStart() { | ||||
|         super.onStart(); | ||||
|         if (getIntent() != null) { | ||||
|             this.mInitialAccountSetup = getIntent().getBooleanExtra("setup", false); | ||||
|         } | ||||
|         if (this.mInitialAccountSetup) { | ||||
|             this.cancelButton.setText(R.string.skip); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| 	@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); | ||||
| 		} | ||||
| 	} | ||||
|     protected void loadImageIntoPreview(Uri uri) { | ||||
| 
 | ||||
| 	@Override | ||||
| 	protected void onActivityResult(int requestCode, int resultCode, final Intent data) { | ||||
| 		super.onActivityResult(requestCode, resultCode, data); | ||||
| 		if (resultCode == RESULT_OK) { | ||||
| 			Uri source = data.getData(); | ||||
| 			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) { | ||||
| 						loadImageIntoPreview(this.avatarUri); | ||||
| 					} | ||||
| 					break; | ||||
| 				case Crop.REQUEST_CROP: | ||||
| 					this.avatarUri = Uri.fromFile(new File(getCacheDir(), "croppedAvatar")); | ||||
| 					if (xmppConnectionServiceBound) { | ||||
| 						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(); | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|         Bitmap bm = null; | ||||
|         if (uri == null) { | ||||
|             bm = avatarService().get(account, getPixel(192)); | ||||
|         } else { | ||||
|             try { | ||||
|                 bm = xmppConnectionService.getFileBackend().cropCenterSquare(uri, getPixel(192)); | ||||
|             } catch (Exception e) { | ||||
|                 Log.d(Config.LOGTAG, "unable to load bitmap into image view", e); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
| 	@Override | ||||
| 	protected void onBackendConnected() { | ||||
| 		this.account = extractAccount(getIntent()); | ||||
| 		if (this.account != null) { | ||||
| 			reloadAvatar(); | ||||
| 		} | ||||
| 	} | ||||
|         if (bm == null) { | ||||
|             togglePublishButton(false, R.string.publish); | ||||
|             this.hintOrWarning.setVisibility(View.VISIBLE); | ||||
|             this.hintOrWarning.setTextColor(getWarningTextColor()); | ||||
|             this.hintOrWarning.setText(R.string.error_publish_avatar_converting); | ||||
|             return; | ||||
|         } | ||||
|         this.avatar.setImageBitmap(bm); | ||||
|         if (support) { | ||||
|             togglePublishButton(uri != null, R.string.publish); | ||||
|             this.hintOrWarning.setVisibility(View.INVISIBLE); | ||||
|         } else { | ||||
|             togglePublishButton(false, R.string.publish); | ||||
|             this.hintOrWarning.setVisibility(View.VISIBLE); | ||||
|             this.hintOrWarning.setTextColor(getWarningTextColor()); | ||||
|             if (account.getStatus() == Account.State.ONLINE) { | ||||
|                 this.hintOrWarning.setText(R.string.error_publish_avatar_no_server_support); | ||||
|             } else { | ||||
|                 this.hintOrWarning.setText(R.string.error_publish_avatar_offline); | ||||
|             } | ||||
|         } | ||||
|         if (this.defaultUri == null || this.defaultUri.equals(uri)) { | ||||
|             this.secondaryHint.setVisibility(View.INVISIBLE); | ||||
|             this.avatar.setOnLongClickListener(null); | ||||
|         } else if (this.defaultUri != null) { | ||||
|             this.secondaryHint.setVisibility(View.VISIBLE); | ||||
|             this.avatar.setOnLongClickListener(this.backToDefaultListener); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| 	private void reloadAvatar() { | ||||
| 		this.support = this.account.getXmppConnection() != null && this.account.getXmppConnection().getFeatures().pep(); | ||||
| 		if (this.avatarUri == null) { | ||||
| 			if (this.account.getAvatar() != null || this.defaultUri == null) { | ||||
| 				loadImageIntoPreview(null); | ||||
| 			} else { | ||||
| 				this.avatarUri = this.defaultUri; | ||||
| 				loadImageIntoPreview(this.defaultUri); | ||||
| 			} | ||||
| 		} else { | ||||
| 			loadImageIntoPreview(avatarUri); | ||||
| 		} | ||||
| 	} | ||||
|     protected void togglePublishButton(boolean enabled, @StringRes int res) { | ||||
|         final boolean status = enabled && !publishing; | ||||
|         this.publishButton.setText(publishing ? R.string.publishing : res); | ||||
|         this.publishButton.setEnabled(status); | ||||
|     } | ||||
| 
 | ||||
| 	@Override | ||||
| 	protected void onStart() { | ||||
| 		super.onStart(); | ||||
| 		if (getIntent() != null) { | ||||
| 			this.mInitialAccountSetup = getIntent().getBooleanExtra("setup", false); | ||||
| 		} | ||||
| 		if (this.mInitialAccountSetup) { | ||||
| 			this.cancelButton.setText(R.string.skip); | ||||
| 		} | ||||
| 	} | ||||
|     public void refreshUiReal() { | ||||
|         if (this.account != null) { | ||||
|             reloadAvatar(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| 	protected void loadImageIntoPreview(Uri uri) { | ||||
|     @Override | ||||
|     public void onAccountUpdate() { | ||||
|         refreshUi(); | ||||
|     } | ||||
| 
 | ||||
| 		Bitmap bm = null; | ||||
| 		if (uri == null) { | ||||
| 			bm = avatarService().get(account, getPixel(192)); | ||||
| 		} else { | ||||
| 			try { | ||||
| 				bm = xmppConnectionService.getFileBackend().cropCenterSquare(uri, getPixel(192)); | ||||
| 			} catch (Exception e) { | ||||
| 				Log.d(Config.LOGTAG,"unable to load bitmap into image view",e); | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		if (bm == null) { | ||||
| 			togglePublishButton(false,R.string.publish); | ||||
| 			this.hintOrWarning.setVisibility(View.VISIBLE); | ||||
| 			this.hintOrWarning.setTextColor(getWarningTextColor()); | ||||
| 			this.hintOrWarning.setText(R.string.error_publish_avatar_converting); | ||||
| 			return; | ||||
| 		} | ||||
| 		this.avatar.setImageBitmap(bm); | ||||
| 		if (support) { | ||||
| 			togglePublishButton(uri != null,R.string.publish); | ||||
| 			this.hintOrWarning.setVisibility(View.INVISIBLE); | ||||
| 		} else { | ||||
| 			togglePublishButton(false,R.string.publish); | ||||
| 			this.hintOrWarning.setVisibility(View.VISIBLE); | ||||
| 			this.hintOrWarning.setTextColor(getWarningTextColor()); | ||||
| 			if (account.getStatus() == Account.State.ONLINE) { | ||||
| 				this.hintOrWarning.setText(R.string.error_publish_avatar_no_server_support); | ||||
| 			} else { | ||||
| 				this.hintOrWarning.setText(R.string.error_publish_avatar_offline); | ||||
| 			} | ||||
| 		} | ||||
| 		if (this.defaultUri == null || this.defaultUri.equals(uri)) { | ||||
| 			this.secondaryHint.setVisibility(View.INVISIBLE); | ||||
| 			this.avatar.setOnLongClickListener(null); | ||||
| 		} else if (this.defaultUri != null) { | ||||
| 			this.secondaryHint.setVisibility(View.VISIBLE); | ||||
| 			this.avatar.setOnLongClickListener(this.backToDefaultListener); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	protected void togglePublishButton(boolean enabled, @StringRes int res) { | ||||
| 		final boolean status = enabled && !publishing; | ||||
| 		this.publishButton.setText(publishing ? R.string.publishing : res); | ||||
| 		this.publishButton.setEnabled(status); | ||||
| 	} | ||||
| 
 | ||||
| 	public void refreshUiReal() { | ||||
| 		if (this.account != null) { | ||||
| 			reloadAvatar(); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	@Override | ||||
| 	public void onAccountUpdate() { | ||||
| 		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,8 +8,9 @@ | ||||
|         android:background="?attr/color_background_secondary" | ||||
|         android:orientation="vertical"> | ||||
| 
 | ||||
|         <include android:id="@+id/toolbar" | ||||
|             layout="@layout/toolbar" /> | ||||
|         <include | ||||
|             android:id="@+id/toolbar" | ||||
|             layout="@layout/toolbar"/> | ||||
| 
 | ||||
|         <ScrollView | ||||
|             android:layout_width="fill_parent" | ||||
| @ -35,14 +36,6 @@ | ||||
|                         android:orientation="vertical" | ||||
|                         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 | ||||
|                             android:layout_width="fill_parent" | ||||
|                             android:layout_height="wrap_content" | ||||
| @ -50,44 +43,52 @@ | ||||
| 
 | ||||
|                             <com.makeramen.roundedimageview.RoundedImageView | ||||
|                                 android:id="@+id/your_photo" | ||||
|                                 android:layout_width="48dp" | ||||
|                                 android:layout_height="48dp" | ||||
|                                 android:layout_width="72dp" | ||||
|                                 android:layout_height="72dp" | ||||
|                                 android:layout_alignParentLeft="true" | ||||
|                                 app:riv_corner_radius="2dp"/> | ||||
| 
 | ||||
|                             <LinearLayout | ||||
|                                 android:layout_width="fill_parent" | ||||
|                                 android:layout_height="wrap_content" | ||||
|                                 android:layout_centerVertical="true" | ||||
|                                 android:layout_alignParentTop="true" | ||||
|                                 android:layout_toRightOf="@+id/your_photo" | ||||
|                                 android:orientation="vertical" | ||||
|                                 android:paddingLeft="@dimen/avatar_item_distance"> | ||||
| 
 | ||||
|                                 <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"/> | ||||
|                                 <RelativeLayout | ||||
|                                     android:layout_width="match_parent" | ||||
|                                     android:layout_height="wrap_content"> | ||||
| 
 | ||||
|                                 <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"/> | ||||
|                                     <TextView | ||||
|                                         android:id="@+id/muc_title" | ||||
|                                         android:layout_width="wrap_content" | ||||
|                                         android:layout_height="wrap_content" | ||||
|                                         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"/> | ||||
| 
 | ||||
|                                     <ImageButton | ||||
|                                         android:id="@+id/edit_muc_name_button" | ||||
|                                         android:layout_width="wrap_content" | ||||
|                                         android:layout_height="wrap_content" | ||||
|                                         android:layout_alignParentEnd="true" | ||||
|                                         android:layout_alignParentTop="true" | ||||
|                                         android:alpha="?attr/icon_alpha" | ||||
|                                         android:background="?attr/selectableItemBackgroundBorderless" | ||||
|                                         android:padding="@dimen/image_button_padding" | ||||
|                                         android:src="?attr/icon_edit_body"/> | ||||
|                                 </RelativeLayout> | ||||
|                             </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 | ||||
| @ -120,35 +121,6 @@ | ||||
|                                 android:src="?attr/icon_settings"/> | ||||
|                         </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 | ||||
|                             android:id="@+id/muc_info_more" | ||||
|                             android:layout_width="match_parent" | ||||
| @ -179,6 +151,88 @@ | ||||
|                             </TableRow> | ||||
| 
 | ||||
|                         </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 | ||||
|                             android:id="@+id/details_account" | ||||
| @ -193,7 +247,7 @@ | ||||
| 
 | ||||
|                 <android.support.v7.widget.CardView | ||||
|                     android:id="@+id/muc_more_details" | ||||
|                     android:layout_width="fill_parent" | ||||
|                     android:layout_width="match_parent" | ||||
|                     android:layout_height="wrap_content" | ||||
|                     android:layout_marginBottom="@dimen/activity_vertical_margin" | ||||
|                     android:layout_marginLeft="@dimen/activity_horizontal_margin" | ||||
|  | ||||
| @ -1,97 +1,99 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     android:layout_width="match_parent" | ||||
|     android:layout_height="match_parent" | ||||
|     xmlns:app="http://schemas.android.com/apk/res-auto" | ||||
|     android:background="?attr/color_background_secondary"> | ||||
| <layout xmlns:android="http://schemas.android.com/apk/res/android"> | ||||
| 
 | ||||
|     <include layout="@layout/toolbar" /> | ||||
|     <RelativeLayout | ||||
|         android:layout_width="match_parent" | ||||
|         android:layout_height="match_parent" | ||||
|         android:background="?attr/color_background_secondary"> | ||||
| 
 | ||||
|     <android.support.v7.widget.CardView | ||||
|         android:layout_width="fill_parent" | ||||
|         android:layout_height="wrap_content" | ||||
|         android:layout_below="@id/toolbar" | ||||
|         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"> | ||||
|         <include android:id="@+id/toolbar" layout="@layout/toolbar"/> | ||||
| 
 | ||||
|         <android.support.v7.widget.CardView | ||||
|             android:layout_width="fill_parent" | ||||
|             android:layout_height="wrap_content" | ||||
|             android:layout_below="@id/toolbar" | ||||
|             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:gravity="center_horizontal" | ||||
|                 android:orientation="vertical"> | ||||
| 
 | ||||
|                 <FrameLayout | ||||
|                     android:id="@+id/account_image_wrapper" | ||||
|                     android:layout_width="wrap_content" | ||||
|                     android:layout_height="wrap_content" | ||||
|                     android:layout_marginBottom="8dp" | ||||
|                     android:layout_marginTop="@dimen/publish_avatar_top_margin" | ||||
|                     android:background="@drawable/account_image_border"> | ||||
| 
 | ||||
|                     <ImageView | ||||
|                         android:id="@+id/account_image" | ||||
|                         android:layout_width="@dimen/publish_avatar_size" | ||||
|                         android:layout_height="@dimen/publish_avatar_size"/> | ||||
|                 </FrameLayout> | ||||
| 
 | ||||
|                 <TextView | ||||
|                     android:id="@+id/hint" | ||||
|                     android:layout_width="wrap_content" | ||||
|                     android:layout_height="wrap_content" | ||||
|                     android:text="@string/touch_to_choose_picture" | ||||
|                     android:textAppearance="@style/TextAppearance.Conversations.Body1"/> | ||||
| 
 | ||||
|                 <TextView | ||||
|                     android:id="@+id/secondary_hint" | ||||
|                     android:layout_width="wrap_content" | ||||
|                     android:layout_height="wrap_content" | ||||
|                     android:text="@string/or_long_press_for_default" | ||||
|                     android:textAppearance="@style/TextAppearance.Conversations.Body1"/> | ||||
| 
 | ||||
|                 <TextView | ||||
|                     android:id="@+id/hint_or_warning" | ||||
|                     android:layout_width="wrap_content" | ||||
|                     android:layout_height="wrap_content" | ||||
|                     android:layout_marginBottom="8dp" | ||||
|                     android:layout_marginTop="8dp" | ||||
|                     android:textAppearance="@style/TextAppearance.Conversations.Body1"/> | ||||
| 
 | ||||
|             </LinearLayout> | ||||
|         </android.support.v7.widget.CardView> | ||||
| 
 | ||||
|         <LinearLayout | ||||
|             android:layout_width="match_parent" | ||||
|             android:id="@+id/button_bar" | ||||
|             android:layout_width="wrap_content" | ||||
|             android:layout_height="wrap_content" | ||||
|             android:gravity="center_horizontal" | ||||
|             android:orientation="vertical"> | ||||
|             android:layout_alignParentBottom="true" | ||||
|             android:layout_alignParentLeft="true" | ||||
|             android:layout_alignParentRight="true"> | ||||
| 
 | ||||
|             <FrameLayout | ||||
|                 android:id="@+id/account_image_wrapper" | ||||
|                 android:layout_width="wrap_content" | ||||
|             <Button | ||||
|                 android:id="@+id/cancel_button" | ||||
|                 style="@style/Widget.Conversations.Button.Borderless" | ||||
|                 android:layout_width="0dp" | ||||
|                 android:layout_height="wrap_content" | ||||
|                 android:layout_marginBottom="8dp" | ||||
|                 android:layout_marginTop="@dimen/publish_avatar_top_margin" | ||||
|                 android:background="@drawable/account_image_border"> | ||||
|                 android:layout_weight="1" | ||||
|                 android:text="@string/cancel"/> | ||||
| 
 | ||||
|                 <ImageView | ||||
|                     android:id="@+id/account_image" | ||||
|                     android:layout_width="@dimen/publish_avatar_size" | ||||
|                     android:layout_height="@dimen/publish_avatar_size"/> | ||||
|             </FrameLayout> | ||||
|             <View | ||||
|                 android:layout_width="1dp" | ||||
|                 android:layout_height="fill_parent" | ||||
|                 android:layout_marginBottom="7dp" | ||||
|                 android:layout_marginTop="7dp" | ||||
|                 android:background="?attr/divider"/> | ||||
| 
 | ||||
|             <TextView | ||||
|                 android:id="@+id/hint" | ||||
|                 android:layout_width="wrap_content" | ||||
|             <Button | ||||
|                 android:id="@+id/publish_button" | ||||
|                 style="@style/Widget.Conversations.Button.Borderless" | ||||
|                 android:layout_width="0dp" | ||||
|                 android:layout_height="wrap_content" | ||||
|                 android:text="@string/touch_to_choose_picture" | ||||
|                 android:textAppearance="@style/TextAppearance.Conversations.Body1"/> | ||||
| 
 | ||||
|             <TextView | ||||
|                 android:id="@+id/secondary_hint" | ||||
|                 android:layout_width="wrap_content" | ||||
|                 android:layout_height="wrap_content" | ||||
|                 android:textAppearance="@style/TextAppearance.Conversations.Body1" | ||||
|                 android:text="@string/or_long_press_for_default"/> | ||||
| 
 | ||||
|             <TextView | ||||
|                 android:id="@+id/hint_or_warning" | ||||
|                 android:layout_width="wrap_content" | ||||
|                 android:layout_height="wrap_content" | ||||
|                 android:layout_marginTop="8dp" | ||||
|                 android:layout_marginBottom="8dp" | ||||
|                 android:textAppearance="@style/TextAppearance.Conversations.Body1"/> | ||||
| 
 | ||||
|                 android:layout_weight="1" | ||||
|                 android:enabled="false" | ||||
|                 android:text="@string/publish"/> | ||||
|         </LinearLayout> | ||||
|     </android.support.v7.widget.CardView> | ||||
| 
 | ||||
|     <LinearLayout | ||||
|         android:id="@+id/button_bar" | ||||
|         android:layout_width="wrap_content" | ||||
|         android:layout_height="wrap_content" | ||||
|         android:layout_alignParentBottom="true" | ||||
|         android:layout_alignParentLeft="true" | ||||
|         android:layout_alignParentRight="true"> | ||||
| 
 | ||||
|         <Button | ||||
|             android:id="@+id/cancel_button" | ||||
|             style="@style/Widget.Conversations.Button.Borderless" | ||||
|             android:layout_width="0dp" | ||||
|             android:layout_height="wrap_content" | ||||
|             android:layout_weight="1" | ||||
|             android:text="@string/cancel"/> | ||||
| 
 | ||||
|         <View | ||||
|             android:layout_width="1dp" | ||||
|             android:layout_height="fill_parent" | ||||
|             android:layout_marginBottom="7dp" | ||||
|             android:layout_marginTop="7dp" | ||||
|             android:background="?attr/divider"/> | ||||
| 
 | ||||
|         <Button | ||||
|             android:id="@+id/publish_button" | ||||
|             style="@style/Widget.Conversations.Button.Borderless" | ||||
|             android:layout_width="0dp" | ||||
|             android:layout_height="wrap_content" | ||||
|             android:layout_weight="1" | ||||
|             android:enabled="false" | ||||
|             android:text="@string/publish"/> | ||||
|     </LinearLayout> | ||||
| 
 | ||||
| </RelativeLayout> | ||||
|     </RelativeLayout> | ||||
| </layout> | ||||
| @ -2,13 +2,6 @@ | ||||
| <menu xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|       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 | ||||
|         android:id="@+id/action_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="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="select_image_and_crop">Select image and crop</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="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="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="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> | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 Daniel Gultsch
						Daniel Gultsch