refactored group chat members into seperate screen
This commit is contained in:
		
							parent
							
								
									0ba3f31cbc
								
							
						
					
					
						commit
						b9c4309a28
					
				| @ -1,52 +1,52 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <manifest xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|           xmlns:tools="http://schemas.android.com/tools" | ||||
|           package="eu.siacs.conversations"> | ||||
|     xmlns:tools="http://schemas.android.com/tools" | ||||
|     package="eu.siacs.conversations"> | ||||
| 
 | ||||
|     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> | ||||
|     <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> | ||||
|     <uses-permission android:name="android.permission.READ_CONTACTS"/> | ||||
|     <uses-permission android:name="android.permission.READ_PROFILE"/> | ||||
|     <uses-permission android:name="android.permission.INTERNET"/> | ||||
|     <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> | ||||
|     <uses-permission android:name="android.permission.WAKE_LOCK"/> | ||||
|     <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/> | ||||
|     <uses-permission android:name="android.permission.VIBRATE"/> | ||||
|     <uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"/> | ||||
|     <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/> | ||||
|     <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> | ||||
|     <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/> | ||||
|     <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/> | ||||
|     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> | ||||
|     <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> | ||||
|     <uses-permission android:name="android.permission.READ_CONTACTS" /> | ||||
|     <uses-permission android:name="android.permission.READ_PROFILE" /> | ||||
|     <uses-permission android:name="android.permission.INTERNET" /> | ||||
|     <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> | ||||
|     <uses-permission android:name="android.permission.WAKE_LOCK" /> | ||||
|     <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> | ||||
|     <uses-permission android:name="android.permission.VIBRATE" /> | ||||
|     <uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" /> | ||||
|     <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> | ||||
|     <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> | ||||
|     <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> | ||||
|     <uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> | ||||
| 
 | ||||
|     <uses-feature | ||||
|         android:name="android.hardware.location" | ||||
|         android:required="false"/> | ||||
|         android:required="false" /> | ||||
|     <uses-feature | ||||
|         android:name="android.hardware.location.gps" | ||||
|         android:required="false"/> | ||||
|         android:required="false" /> | ||||
|     <uses-feature | ||||
|         android:name="android.hardware.location.network" | ||||
|         android:required="false"/> | ||||
|         android:required="false" /> | ||||
| 
 | ||||
|     <uses-permission android:name="android.permission.CAMERA"/> | ||||
|     <uses-permission android:name="android.permission.RECORD_AUDIO"/> | ||||
|     <uses-permission android:name="android.permission.CAMERA" /> | ||||
|     <uses-permission android:name="android.permission.RECORD_AUDIO" /> | ||||
| 
 | ||||
|     <uses-permission | ||||
|         android:name="android.permission.READ_PHONE_STATE" | ||||
|         tools:node="remove"/> | ||||
|         tools:node="remove" /> | ||||
| 
 | ||||
|     <uses-sdk tools:overrideLibrary="net.ypresto.androidtranscoder"/> | ||||
|     <uses-sdk tools:overrideLibrary="net.ypresto.androidtranscoder" /> | ||||
| 
 | ||||
|     <uses-feature | ||||
|         android:name="android.hardware.camera" | ||||
|         android:required="false"/> | ||||
|         android:required="false" /> | ||||
|     <uses-feature | ||||
|         android:name="android.hardware.camera.autofocus" | ||||
|         android:required="false"/> | ||||
|         android:required="false" /> | ||||
| 
 | ||||
|     <uses-feature | ||||
|         android:name="android.hardware.microphone" | ||||
|         android:required="false"/> | ||||
|         android:required="false" /> | ||||
| 
 | ||||
| 
 | ||||
|     <application | ||||
| @ -61,82 +61,82 @@ | ||||
| 
 | ||||
|         <meta-data | ||||
|             android:name="com.google.android.gms.car.application" | ||||
|             android:resource="@xml/automotive_app_desc"/> | ||||
|             android:resource="@xml/automotive_app_desc" /> | ||||
| 
 | ||||
|         <service android:name=".services.XmppConnectionService"/> | ||||
|         <service android:name=".services.XmppConnectionService" /> | ||||
| 
 | ||||
|         <receiver android:name=".services.EventReceiver"> | ||||
|             <intent-filter> | ||||
|                 <action android:name="android.intent.action.BOOT_COMPLETED"/> | ||||
|                 <action android:name="android.net.conn.CONNECTIVITY_CHANGE"/> | ||||
|                 <action android:name="android.intent.action.ACTION_SHUTDOWN"/> | ||||
|                 <action android:name="android.media.RINGER_MODE_CHANGED"/> | ||||
|                 <action android:name="android.intent.action.BOOT_COMPLETED" /> | ||||
|                 <action android:name="android.net.conn.CONNECTIVITY_CHANGE" /> | ||||
|                 <action android:name="android.intent.action.ACTION_SHUTDOWN" /> | ||||
|                 <action android:name="android.media.RINGER_MODE_CHANGED" /> | ||||
|             </intent-filter> | ||||
|         </receiver> | ||||
| 
 | ||||
|         <activity | ||||
|             android:name=".ui.ShareLocationActivity" | ||||
|             android:label="@string/title_activity_share_location"/> | ||||
|             android:label="@string/title_activity_share_location" /> | ||||
|         <activity | ||||
|             android:name=".ui.SearchActivity" | ||||
|             android:label="@string/search_messages"/> | ||||
|             android:label="@string/search_messages" /> | ||||
|         <activity | ||||
|             android:name=".ui.RecordingActivity" | ||||
|             android:configChanges="orientation|screenSize" | ||||
|             android:theme="@style/ConversationsTheme.Dialog"/> | ||||
|             android:theme="@style/ConversationsTheme.Dialog" /> | ||||
|         <activity | ||||
|             android:name=".ui.ShowLocationActivity" | ||||
|             android:label="@string/title_activity_show_location"/> | ||||
|             android:label="@string/title_activity_show_location" /> | ||||
|         <activity | ||||
|             android:name=".ui.ConversationActivity" | ||||
|             android:theme="@style/SplashTheme"> | ||||
|             <intent-filter> | ||||
|                 <action android:name="android.intent.action.MAIN"/> | ||||
|                 <action android:name="android.intent.action.MAIN" /> | ||||
| 
 | ||||
|                 <category android:name="android.intent.category.LAUNCHER"/> | ||||
|                 <category android:name="android.intent.category.LAUNCHER" /> | ||||
|             </intent-filter> | ||||
|         </activity> | ||||
|         <activity | ||||
|             android:name=".ui.ConversationsActivity" | ||||
|             android:label="@string/app_name" | ||||
|             android:launchMode="singleTask" | ||||
|             android:minHeight="300dp" | ||||
|             android:minWidth="300dp" | ||||
|             android:windowSoftInputMode="stateHidden"/> | ||||
|             android:minHeight="300dp" | ||||
|             android:windowSoftInputMode="stateHidden" /> | ||||
|         <activity | ||||
|             android:name=".ui.ScanActivity" | ||||
|             android:screenOrientation="portrait" | ||||
|             android:theme="@style/ConversationsTheme.FullScreen" | ||||
|             android:windowSoftInputMode="stateAlwaysHidden"/> | ||||
|             android:windowSoftInputMode="stateAlwaysHidden" /> | ||||
|         <activity | ||||
|             android:name=".ui.UriHandlerActivity" | ||||
|             android:label="@string/app_name"> | ||||
|             <intent-filter> | ||||
|                 <action android:name="android.intent.action.VIEW"/> | ||||
|                 <action android:name="android.intent.action.VIEW" /> | ||||
| 
 | ||||
|                 <category android:name="android.intent.category.DEFAULT"/> | ||||
|                 <category android:name="android.intent.category.BROWSABLE"/> | ||||
|                 <category android:name="android.intent.category.DEFAULT" /> | ||||
|                 <category android:name="android.intent.category.BROWSABLE" /> | ||||
| 
 | ||||
|                 <data android:scheme="xmpp"/> | ||||
|                 <data android:scheme="xmpp" /> | ||||
|             </intent-filter> | ||||
|             <intent-filter android:autoVerify="true"> | ||||
|                 <action android:name="android.intent.action.VIEW"/> | ||||
|                 <action android:name="android.intent.action.VIEW" /> | ||||
| 
 | ||||
|                 <category android:name="android.intent.category.DEFAULT"/> | ||||
|                 <category android:name="android.intent.category.BROWSABLE"/> | ||||
|                 <category android:name="android.intent.category.DEFAULT" /> | ||||
|                 <category android:name="android.intent.category.BROWSABLE" /> | ||||
| 
 | ||||
|                 <data android:scheme="https"/> | ||||
|                 <data android:host="conversations.im"/> | ||||
|                 <data android:pathPrefix="/i/"/> | ||||
|                 <data android:pathPrefix="/j/"/> | ||||
|                 <data android:scheme="https" /> | ||||
|                 <data android:host="conversations.im" /> | ||||
|                 <data android:pathPrefix="/i/" /> | ||||
|                 <data android:pathPrefix="/j/" /> | ||||
|             </intent-filter> | ||||
|             <intent-filter> | ||||
|                 <action android:name="android.intent.action.SENDTO"/> | ||||
|                 <action android:name="android.intent.action.SENDTO" /> | ||||
| 
 | ||||
|                 <category android:name="android.intent.category.DEFAULT"/> | ||||
|                 <category android:name="android.intent.category.DEFAULT" /> | ||||
| 
 | ||||
|                 <data android:scheme="imto"/> | ||||
|                 <data android:host="jabber"/> | ||||
|                 <data android:scheme="imto" /> | ||||
|                 <data android:host="jabber" /> | ||||
|             </intent-filter> | ||||
|         </activity> | ||||
|         <activity | ||||
| @ -144,7 +144,7 @@ | ||||
|             android:label="@string/title_activity_start_conversation" | ||||
|             android:launchMode="singleTop"> | ||||
|             <intent-filter> | ||||
|                 <action android:name="android.intent.action.VIEW"/> | ||||
|                 <action android:name="android.intent.action.VIEW" /> | ||||
|             </intent-filter> | ||||
|         </activity> | ||||
|         <activity | ||||
| @ -157,101 +157,104 @@ | ||||
|         </activity> | ||||
|         <activity | ||||
|             android:name=".ui.ChooseContactActivity" | ||||
|             android:label="@string/title_activity_choose_contact"/> | ||||
|             android:label="@string/title_activity_choose_contact" /> | ||||
|         <activity | ||||
|             android:name=".ui.BlocklistActivity" | ||||
|             android:label="@string/title_activity_block_list"/> | ||||
|             android:label="@string/title_activity_block_list" /> | ||||
|         <activity | ||||
|             android:name=".ui.ChangePasswordActivity" | ||||
|             android:label="@string/change_password_on_server"/> | ||||
|         <activity android:name=".ui.ChooseAccountForProfilePictureActivity" | ||||
|             android:label="@string/choose_account" | ||||
|             android:enabled="false"> | ||||
|             android:label="@string/change_password_on_server" /> | ||||
|         <activity | ||||
|             android:name=".ui.ChooseAccountForProfilePictureActivity" | ||||
|             android:enabled="false" | ||||
|             android:label="@string/choose_account"> | ||||
|             <intent-filter android:label="@string/set_profile_picture"> | ||||
|                 <action android:name="android.intent.action.ATTACH_DATA"/> | ||||
|                 <category android:name="android.intent.category.DEFAULT"/> | ||||
|                 <action android:name="android.intent.action.ATTACH_DATA" /> | ||||
|                 <category android:name="android.intent.category.DEFAULT" /> | ||||
| 
 | ||||
|                 <data android:mimeType="image/*"/> | ||||
|                 <data android:mimeType="image/*" /> | ||||
|             </intent-filter> | ||||
|         </activity> | ||||
|         <activity | ||||
|             android:name=".ui.ShareViaAccountActivity" | ||||
|             android:label="@string/title_activity_share_via_account" | ||||
|             android:launchMode="singleTop"/> | ||||
|             android:launchMode="singleTop" /> | ||||
|         <activity | ||||
|             android:name=".ui.EditAccountActivity" | ||||
|             android:launchMode="singleTop" | ||||
|             android:windowSoftInputMode="stateHidden|adjustResize"/> | ||||
|             android:windowSoftInputMode="stateHidden|adjustResize" /> | ||||
|         <activity | ||||
|             android:name=".ui.ConferenceDetailsActivity" | ||||
|             android:label="@string/action_muc_details" | ||||
|             android:windowSoftInputMode="stateHidden"/> | ||||
|             android:windowSoftInputMode="stateHidden" /> | ||||
|         <activity | ||||
|             android:name=".ui.ContactDetailsActivity" | ||||
|             android:windowSoftInputMode="stateHidden"/> | ||||
|             android:windowSoftInputMode="stateHidden" /> | ||||
|         <activity | ||||
|             android:name=".ui.PublishProfilePictureActivity" | ||||
|             android:label="@string/mgmt_account_publish_avatar" | ||||
|             android:windowSoftInputMode="stateHidden"/> | ||||
|             android:windowSoftInputMode="stateHidden" /> | ||||
|         <activity | ||||
|             android:name=".ui.PublishGroupChatProfilePictureActivity" | ||||
|             android:label="@string/group_chat_avatar"/> | ||||
|             android:label="@string/group_chat_avatar" /> | ||||
|         <activity | ||||
|             android:name=".ui.ShareWithActivity" | ||||
|             android:label="@string/app_name" | ||||
|             android:launchMode="singleTop"> | ||||
| 
 | ||||
|             <intent-filter> | ||||
|                 <action android:name="android.intent.action.SEND"/> | ||||
|                 <action android:name="android.intent.action.SEND_MULTIPLE"/> | ||||
|                 <action android:name="android.intent.action.SEND" /> | ||||
|                 <action android:name="android.intent.action.SEND_MULTIPLE" /> | ||||
| 
 | ||||
|                 <category android:name="android.intent.category.DEFAULT"/> | ||||
|                 <category android:name="android.intent.category.DEFAULT" /> | ||||
| 
 | ||||
|                 <data android:mimeType="text/plain"/> | ||||
|                 <data android:mimeType="text/plain" /> | ||||
|             </intent-filter> | ||||
| 
 | ||||
|             <intent-filter> | ||||
|                 <action android:name="android.intent.action.SEND"/> | ||||
|                 <action android:name="android.intent.action.SEND_MULTIPLE"/> | ||||
|                 <action android:name="android.intent.action.SEND" /> | ||||
|                 <action android:name="android.intent.action.SEND_MULTIPLE" /> | ||||
| 
 | ||||
|                 <category android:name="android.intent.category.DEFAULT"/> | ||||
|                 <category android:name="android.intent.category.DEFAULT" /> | ||||
| 
 | ||||
|                 <data android:mimeType="*/*"/> | ||||
|                 <data android:mimeType="*/*" /> | ||||
|             </intent-filter> | ||||
| 
 | ||||
|             <meta-data | ||||
|                 android:name="android.service.chooser.chooser_target_service" | ||||
|                 android:value=".services.ContactChooserTargetService"/> | ||||
|                 android:value=".services.ContactChooserTargetService" /> | ||||
|         </activity> | ||||
|         <activity | ||||
|             android:name=".ui.TrustKeysActivity" | ||||
|             android:label="@string/trust_omemo_fingerprints" | ||||
|             android:windowSoftInputMode="stateAlwaysHidden"/> | ||||
|             android:windowSoftInputMode="stateAlwaysHidden" /> | ||||
|         <activity | ||||
|             android:name=".ui.AboutActivity" | ||||
|             android:parentActivityName=".ui.SettingsActivity"> | ||||
|             <meta-data | ||||
|                 android:name="android.support.PARENT_ACTIVITY" | ||||
|                 android:value="eu.siacs.conversations.ui.SettingsActivity"/> | ||||
|                 android:value="eu.siacs.conversations.ui.SettingsActivity" /> | ||||
|             <intent-filter> | ||||
|                 <action android:name="android.intent.action.VIEW"/> | ||||
|                 <category android:name="android.intent.category.PREFERENCE"/> | ||||
|                 <action android:name="android.intent.action.VIEW" /> | ||||
|                 <category android:name="android.intent.category.PREFERENCE" /> | ||||
|             </intent-filter> | ||||
|         </activity> | ||||
|         <activity android:name="com.theartofdev.edmodo.cropper.CropImageActivity" | ||||
|                   android:theme="@style/Base.Theme.AppCompat"/> | ||||
|         <activity android:name=".ui.MemorizingActivity"/> | ||||
|         <activity | ||||
|             android:name="com.theartofdev.edmodo.cropper.CropImageActivity" | ||||
|             android:theme="@style/Base.Theme.AppCompat" /> | ||||
|         <activity android:name=".ui.MemorizingActivity" /> | ||||
| 
 | ||||
|         <activity android:name=".ui.MediaBrowserActivity" | ||||
|             android:label="@string/media_browser"/> | ||||
|         <activity | ||||
|             android:name=".ui.MediaBrowserActivity" | ||||
|             android:label="@string/media_browser" /> | ||||
| 
 | ||||
|         <service android:name=".services.ExportBackupService"/> | ||||
|         <service android:name=".services.ImportBackupService"/> | ||||
|         <service android:name=".services.ExportBackupService" /> | ||||
|         <service android:name=".services.ImportBackupService" /> | ||||
|         <service | ||||
|             android:name=".services.ContactChooserTargetService" | ||||
|             android:permission="android.permission.BIND_CHOOSER_TARGET_SERVICE"> | ||||
|             <intent-filter> | ||||
|                 <action android:name="android.service.chooser.ChooserTargetService"/> | ||||
|                 <action android:name="android.service.chooser.ChooserTargetService" /> | ||||
|             </intent-filter> | ||||
|         </service> | ||||
| 
 | ||||
| @ -262,21 +265,24 @@ | ||||
|             android:grantUriPermissions="true"> | ||||
|             <meta-data | ||||
|                 android:name="android.support.FILE_PROVIDER_PATHS" | ||||
|                 android:resource="@xml/file_paths"/> | ||||
|                 android:resource="@xml/file_paths" /> | ||||
|         </provider> | ||||
|         <provider | ||||
|             android:name=".services.BarcodeProvider" | ||||
|             android:authorities="${applicationId}.barcodes" | ||||
|             android:exported="false" | ||||
|             android:grantUriPermissions="true"/> | ||||
|             android:grantUriPermissions="true" /> | ||||
| 
 | ||||
|         <activity | ||||
|             android:name=".ui.ShortcutActivity" | ||||
|             android:label="@string/contact"> | ||||
|             <intent-filter> | ||||
|                 <action android:name="android.intent.action.CREATE_SHORTCUT"/> | ||||
|                 <action android:name="android.intent.action.CREATE_SHORTCUT" /> | ||||
|             </intent-filter> | ||||
|         </activity> | ||||
|         <activity | ||||
|             android:name=".ui.MucUsersActivity" | ||||
|             android:label="@string/group_chat_members" /> | ||||
|     </application> | ||||
| 
 | ||||
| </manifest> | ||||
|  | ||||
| @ -13,6 +13,7 @@ import java.util.Set; | ||||
| 
 | ||||
| import eu.siacs.conversations.Config; | ||||
| import eu.siacs.conversations.R; | ||||
| import eu.siacs.conversations.services.AvatarService; | ||||
| import eu.siacs.conversations.services.MessageArchiveService; | ||||
| import eu.siacs.conversations.utils.JidHelper; | ||||
| import eu.siacs.conversations.utils.UIHelper; | ||||
| @ -382,6 +383,21 @@ public class MucOptions { | ||||
|         return subset; | ||||
|     } | ||||
| 
 | ||||
|     public static List<User> sub(List<User> users, int max) { | ||||
|         ArrayList<User> subset = new ArrayList<>(); | ||||
|         HashSet<Jid> jids = new HashSet<>(); | ||||
|         for (User user : users) { | ||||
|             jids.add(user.getAccount().getJid().asBareJid()); | ||||
|             if (user.getRealJid() == null || (user.getRealJid().getLocal() != null && jids.add(user.getRealJid()))) { | ||||
|                 subset.add(user); | ||||
|             } | ||||
|             if (subset.size() >= max) { | ||||
|                 break; | ||||
|             } | ||||
|         } | ||||
|         return subset; | ||||
|     } | ||||
| 
 | ||||
|     public int getUserCount() { | ||||
|         synchronized (users) { | ||||
|             return users.size(); | ||||
| @ -705,7 +721,7 @@ public class MucOptions { | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     public static class User implements Comparable<User> { | ||||
|     public static class User implements Comparable<User>, AvatarService.Avatarable { | ||||
|         private Role role = Role.NONE; | ||||
|         private Affiliation affiliation = Affiliation.NONE; | ||||
|         private Jid realJid; | ||||
| @ -841,7 +857,7 @@ public class MucOptions { | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         private String getComparableName() { | ||||
|         public String getComparableName() { | ||||
|             Contact contact = getContact(); | ||||
|             if (contact != null) { | ||||
|                 return contact.getDisplayName(); | ||||
| @ -866,5 +882,11 @@ public class MucOptions { | ||||
|             this.chatState = chatState; | ||||
|             return true; | ||||
|         } | ||||
| 
 | ||||
|         @Override | ||||
|         public int getAvatarBackgroundColor() { | ||||
|             final String seed = realJid != null ? realJid.asBareJid().toString() : null; | ||||
|             return UIHelper.getColorForName(seed == null ? getName() : seed); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -80,6 +80,8 @@ public class AvatarService implements OnAdvancedStreamFeaturesLoaded { | ||||
| 			return get((Message) avatarable, size, cachedOnly); | ||||
| 		} else if (avatarable instanceof ListItem) { | ||||
| 			return get((ListItem) avatarable, size, cachedOnly); | ||||
| 		} else if (avatarable instanceof MucOptions.User) { | ||||
| 			return get((MucOptions.User) avatarable, size, cachedOnly); | ||||
| 		} | ||||
| 		throw new AssertionError("AvatarService does not know how to generate avatar from "+avatarable.getClass().getName()); | ||||
| 
 | ||||
|  | ||||
| @ -4,47 +4,29 @@ 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; | ||||
| import android.graphics.Bitmap; | ||||
| import android.graphics.drawable.BitmapDrawable; | ||||
| import android.graphics.drawable.Drawable; | ||||
| import android.os.AsyncTask; | ||||
| import android.os.Bundle; | ||||
| import android.support.v4.content.ContextCompat; | ||||
| import android.support.v7.app.AlertDialog; | ||||
| import android.support.v7.widget.Toolbar; | ||||
| import android.text.Editable; | ||||
| import android.text.SpannableStringBuilder; | ||||
| import android.text.TextWatcher; | ||||
| import android.util.Log; | ||||
| import android.view.ContextMenu; | ||||
| import android.view.LayoutInflater; | ||||
| import android.view.Menu; | ||||
| import android.view.MenuItem; | ||||
| import android.view.View; | ||||
| import android.view.View.OnClickListener; | ||||
| import android.view.WindowManager; | ||||
| import android.widget.ImageView; | ||||
| import android.widget.Toast; | ||||
| 
 | ||||
| import org.openintents.openpgp.util.OpenPgpUtils; | ||||
| 
 | ||||
| import java.lang.ref.WeakReference; | ||||
| import java.util.ArrayList; | ||||
| import java.util.Collections; | ||||
| import java.util.List; | ||||
| import java.util.concurrent.RejectedExecutionException; | ||||
| import java.util.concurrent.atomic.AtomicInteger; | ||||
| 
 | ||||
| import eu.siacs.conversations.Config; | ||||
| import eu.siacs.conversations.R; | ||||
| import eu.siacs.conversations.crypto.PgpEngine; | ||||
| import eu.siacs.conversations.databinding.ActivityMucDetailsBinding; | ||||
| import eu.siacs.conversations.databinding.ContactBinding; | ||||
| import eu.siacs.conversations.entities.Account; | ||||
| import eu.siacs.conversations.entities.Bookmark; | ||||
| import eu.siacs.conversations.entities.Contact; | ||||
| import eu.siacs.conversations.entities.Conversation; | ||||
| import eu.siacs.conversations.entities.MucOptions; | ||||
| import eu.siacs.conversations.entities.MucOptions.User; | ||||
| @ -52,13 +34,12 @@ import eu.siacs.conversations.services.XmppConnectionService; | ||||
| import eu.siacs.conversations.services.XmppConnectionService.OnConversationUpdate; | ||||
| import eu.siacs.conversations.services.XmppConnectionService.OnMucRosterUpdate; | ||||
| import eu.siacs.conversations.ui.adapter.MediaAdapter; | ||||
| import eu.siacs.conversations.ui.adapter.UserPreviewAdapter; | ||||
| import eu.siacs.conversations.ui.interfaces.OnMediaLoaded; | ||||
| import eu.siacs.conversations.ui.service.EmojiService; | ||||
| import eu.siacs.conversations.ui.util.Attachment; | ||||
| import eu.siacs.conversations.ui.util.AvatarWorkerTask; | ||||
| import eu.siacs.conversations.ui.util.GridManager; | ||||
| import eu.siacs.conversations.ui.util.MenuDoubleTabUtil; | ||||
| import eu.siacs.conversations.ui.util.MucDetailsContextMenuHelper; | ||||
| import eu.siacs.conversations.ui.util.MyLinkify; | ||||
| import eu.siacs.conversations.ui.util.SoftKeyboardUtils; | ||||
| import eu.siacs.conversations.utils.AccountUtils; | ||||
| @ -66,7 +47,6 @@ import eu.siacs.conversations.utils.Compatibility; | ||||
| import eu.siacs.conversations.utils.EmojiWrapper; | ||||
| import eu.siacs.conversations.utils.StringUtils; | ||||
| import eu.siacs.conversations.utils.StylingHelper; | ||||
| import eu.siacs.conversations.utils.UIHelper; | ||||
| import eu.siacs.conversations.utils.XmppUri; | ||||
| import me.drakeet.support.toast.ToastCompat; | ||||
| import rocks.xmpp.addr.Jid; | ||||
| @ -77,20 +57,11 @@ import static eu.siacs.conversations.utils.StringUtils.changed; | ||||
| public class ConferenceDetailsActivity extends XmppActivity implements OnConversationUpdate, OnMucRosterUpdate, XmppConnectionService.OnAffiliationChanged, XmppConnectionService.OnRoleChanged, XmppConnectionService.OnConfigurationPushed, XmppConnectionService.OnRoomDestroy, TextWatcher, OnMediaLoaded { | ||||
|     public static final String ACTION_VIEW_MUC = "view_muc"; | ||||
| 
 | ||||
|     private static final float INACTIVE_ALPHA = 0.4684f; //compromise between dark and light theme | ||||
| 
 | ||||
|     private Conversation mConversation; | ||||
|     private OnClickListener inviteListener = new OnClickListener() { | ||||
| 
 | ||||
|         @Override | ||||
|         public void onClick(View v) { | ||||
|             inviteToConversation(mConversation); | ||||
|         } | ||||
|     }; | ||||
|     private ActivityMucDetailsBinding binding; | ||||
|     private MediaAdapter mMediaAdapter; | ||||
|     private UserPreviewAdapter mUserPreviewAdapter; | ||||
|     private String uuid = null; | ||||
|     private User mSelectedUser = null; | ||||
| 
 | ||||
|     private boolean mAdvancedMode = false; | ||||
| 
 | ||||
| @ -205,31 +176,6 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
|     public static boolean cancelPotentialWork(User user, ImageView imageView) { | ||||
|         final BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(imageView); | ||||
| 
 | ||||
|         if (bitmapWorkerTask != null) { | ||||
|             final User old = bitmapWorkerTask.o; | ||||
|             if (old == null || user != old) { | ||||
|                 bitmapWorkerTask.cancel(true); | ||||
|             } else { | ||||
|                 return false; | ||||
|             } | ||||
|         } | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
|     private static BitmapWorkerTask getBitmapWorkerTask(ImageView imageView) { | ||||
|         if (imageView != null) { | ||||
|             final Drawable drawable = imageView.getDrawable(); | ||||
|             if (drawable instanceof AsyncDrawable) { | ||||
|                 final AsyncDrawable asyncDrawable = (AsyncDrawable) drawable; | ||||
|                 return asyncDrawable.getBitmapWorkerTask(); | ||||
|             } | ||||
|         } | ||||
|         return null; | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     @Override | ||||
|     public void onConversationUpdate() { | ||||
| @ -250,9 +196,7 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers | ||||
|     protected void onCreate(Bundle savedInstanceState) { | ||||
|         super.onCreate(savedInstanceState); | ||||
|         this.binding = DataBindingUtil.setContentView(this, R.layout.activity_muc_details); | ||||
|         this.binding.mucMoreDetails.setVisibility(View.GONE); | ||||
|         this.binding.changeConferenceButton.setOnClickListener(this.mChangeConferenceSettings); | ||||
|         this.binding.invite.setOnClickListener(inviteListener); | ||||
|         setSupportActionBar((Toolbar) binding.toolbar); | ||||
|         configureActionBar(getSupportActionBar()); | ||||
|         this.binding.editNickButton.setOnClickListener(v -> quickEdit(mConversation.getMucOptions().getActualNick(), | ||||
| @ -285,9 +229,18 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers | ||||
|         this.binding.mucEditTitle.addTextChangedListener(this); | ||||
|         this.binding.mucEditSubject.addTextChangedListener(this); | ||||
|         this.binding.mucEditSubject.addTextChangedListener(new StylingHelper.MessageEditorStyler(this.binding.mucEditSubject)); | ||||
|         mMediaAdapter = new MediaAdapter(this,R.dimen.media_size); | ||||
|         this.mMediaAdapter = new MediaAdapter(this, R.dimen.media_size); | ||||
|         this.mUserPreviewAdapter = new UserPreviewAdapter(); | ||||
|         this.binding.media.setAdapter(mMediaAdapter); | ||||
|         this.binding.users.setAdapter(mUserPreviewAdapter); | ||||
|         GridManager.setupLayoutManager(this, this.binding.media, R.dimen.media_size); | ||||
|         GridManager.setupLayoutManager(this, this.binding.users, R.dimen.media_size); | ||||
|         this.binding.invite.setOnClickListener(v -> inviteToConversation(mConversation)); | ||||
|         this.binding.showUsers.setOnClickListener(v -> { | ||||
|             Intent intent = new Intent(this, MucUsersActivity.class); | ||||
|             intent.putExtra("uuid", mConversation.getUuid()); | ||||
|             startActivity(intent); | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
| @ -434,41 +387,11 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers | ||||
|         return super.onCreateOptionsMenu(menu); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) { | ||||
|         Object tag = v.getTag(); | ||||
|         if (tag instanceof User) { | ||||
|             getMenuInflater().inflate(R.menu.muc_details_context, menu); | ||||
|             final User user = (User) tag; | ||||
|             this.mSelectedUser = user; | ||||
|             String name; | ||||
|             final Contact contact = user.getContact(); | ||||
|             if (contact != null && contact.showInContactList()) { | ||||
|                 name = contact.getDisplayName(); | ||||
|             } else if (user.getRealJid() != null) { | ||||
|                 name = user.getRealJid().asBareJid().toString(); | ||||
|             } else { | ||||
|                 name = user.getName(); | ||||
|             } | ||||
|             menu.setHeaderTitle(name); | ||||
|             MucDetailsContextMenuHelper.configureMucDetailsContextMenu(this, menu, mConversation, user); | ||||
|         } | ||||
|         super.onCreateContextMenu(menu, v, menuInfo); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public boolean onContextItemSelected(MenuItem item) { | ||||
|         if (!MucDetailsContextMenuHelper.onContextItemSelected(item, mSelectedUser, mConversation, this)) { | ||||
|             return super.onContextItemSelected(item); | ||||
|         } | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void onMediaLoaded(List<Attachment> attachments) { | ||||
|         runOnUiThread(() -> { | ||||
|             int limit = GridManager.getCurrentColumnCount(binding.media); | ||||
|             mMediaAdapter.setAttachments(attachments.subList(0, Math.min(limit,attachments.size()))); | ||||
|             mMediaAdapter.setAttachments(attachments.subList(0, Math.min(limit, attachments.size()))); | ||||
|             binding.mediaWrapper.setVisibility(attachments.size() > 0 ? View.VISIBLE : View.GONE); | ||||
|         }); | ||||
| 
 | ||||
| @ -545,7 +468,7 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers | ||||
|         this.binding.editMucNameButton.setVisibility((self.getAffiliation().ranks(MucOptions.Affiliation.OWNER) || mucOptions.canChangeSubject()) ? View.VISIBLE : View.GONE); | ||||
|         this.binding.detailsAccount.setText(getString(R.string.using_account, account)); | ||||
|         this.binding.jid.setText(mConversation.getJid().asBareJid().toEscapedString()); | ||||
|         AvatarWorkerTask.loadAvatar(mConversation,binding.yourPhoto,R.dimen.avatar_on_details_screen_size); | ||||
|         AvatarWorkerTask.loadAvatar(mConversation, binding.yourPhoto, R.dimen.avatar_on_details_screen_size); | ||||
|         String roomName = mucOptions.getName(); | ||||
|         String subject = mucOptions.getSubject(); | ||||
|         final boolean hasTitle; | ||||
| @ -566,7 +489,7 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers | ||||
|             StylingHelper.format(spannable, this.binding.mucSubject.getCurrentTextColor()); | ||||
|             MyLinkify.addLinks(spannable, false); | ||||
|             this.binding.mucSubject.setText(EmojiWrapper.transform(spannable)); | ||||
|             this.binding.mucSubject.setTextAppearance(this,subject.length() > (hasTitle ? 128 : 196) ? R.style.TextAppearance_Conversations_Body1_Linkified : R.style.TextAppearance_Conversations_Subhead); | ||||
|             this.binding.mucSubject.setTextAppearance(this, subject.length() > (hasTitle ? 128 : 196) ? R.style.TextAppearance_Conversations_Body1_Linkified : R.style.TextAppearance_Conversations_Subhead); | ||||
|             this.binding.mucSubject.setAutoLinkMask(0); | ||||
|             this.binding.mucSubject.setVisibility(View.VISIBLE); | ||||
|         } else { | ||||
| @ -574,7 +497,7 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers | ||||
|         } | ||||
|         this.binding.mucYourNick.setText(mucOptions.getActualNick()); | ||||
|         if (mucOptions.online()) { | ||||
|             this.binding.mucMoreDetails.setVisibility(View.VISIBLE); | ||||
|             this.binding.usersWrapper.setVisibility(View.VISIBLE); | ||||
|             this.binding.mucSettings.setVisibility(View.VISIBLE); | ||||
|             this.binding.mucInfoMore.setVisibility(this.mAdvancedMode ? View.VISIBLE : View.GONE); | ||||
|             this.binding.mucRole.setVisibility(View.VISIBLE); | ||||
| @ -595,7 +518,7 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers | ||||
|                 this.binding.changeConferenceButton.setVisibility(View.INVISIBLE); | ||||
|             } | ||||
|         } else { | ||||
|             this.binding.mucMoreDetails.setVisibility(View.GONE); | ||||
|             this.binding.usersWrapper.setVisibility(View.GONE); | ||||
|             this.binding.mucInfoMore.setVisibility(View.GONE); | ||||
|             this.binding.mucSettings.setVisibility(View.GONE); | ||||
|         } | ||||
| @ -619,73 +542,39 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers | ||||
|             this.binding.notificationStatusText.setText(R.string.notify_only_when_highlighted); | ||||
|             this.binding.notificationStatusButton.setImageResource(ic_notifications_none); | ||||
|         } | ||||
| 
 | ||||
|         final LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE); | ||||
|         this.binding.mucMembers.removeAllViews(); | ||||
|         if (inflater == null) { | ||||
|             return; | ||||
|         } | ||||
|         final ArrayList<User> users = mucOptions.getUsers(); | ||||
|         Collections.sort(users); | ||||
|         for (final User user : users) { | ||||
|             ContactBinding binding = DataBindingUtil.inflate(inflater, R.layout.contact, this.binding.mucMembers, false); | ||||
|             this.setListItemBackgroundOnView(binding.getRoot()); | ||||
|             binding.getRoot().setOnClickListener(view1 -> highlightInMuc(mConversation, user.getName())); | ||||
|             registerForContextMenu(binding.getRoot()); | ||||
|             binding.getRoot().setTag(user); | ||||
|             if (mAdvancedMode && user.getPgpKeyId() != 0) { | ||||
|                 binding.key.setVisibility(View.VISIBLE); | ||||
|                 binding.key.setOnClickListener(v -> viewPgpKey(user)); | ||||
|                 binding.key.setText(OpenPgpUtils.convertKeyIdToHex(user.getPgpKeyId())); | ||||
|             } | ||||
|             Contact contact = user.getContact(); | ||||
|             String name = user.getName(); | ||||
|             if (contact != null) { | ||||
|                 binding.contactDisplayName.setText(contact.getDisplayName()); | ||||
|                 binding.contactJid.setText((name != null ? name + " \u2022 " : "") + getStatus(user)); | ||||
|         List<User> users = mucOptions.getUsers(); | ||||
|         Collections.sort(users, (a, b) -> { | ||||
|             if (b.getAffiliation().outranks(a.getAffiliation())) { | ||||
|                 return 1; | ||||
|             } else if (a.getAffiliation().outranks(b.getAffiliation())) { | ||||
|                 return -1; | ||||
|             } else { | ||||
|                 binding.contactDisplayName.setText(name == null ? "" : name); | ||||
|                 binding.contactJid.setText(getStatus(user)); | ||||
|                 if (a.getAvatar() != null && b.getAvatar() == null) { | ||||
|                     return -1; | ||||
|                 } else if (a.getAvatar() == null && b.getAvatar() != null) { | ||||
|                     return 1; | ||||
|                 } else { | ||||
|                     return a.getComparableName().compareToIgnoreCase(b.getComparableName()); | ||||
|                 } | ||||
|             } | ||||
|         }); | ||||
|         this.mUserPreviewAdapter.setUserList(MucOptions.sub(users, GridManager.getCurrentColumnCount(binding.users))); | ||||
|         this.binding.invite.setVisibility(mucOptions.canInvite() ? View.VISIBLE : View.GONE); | ||||
| 
 | ||||
|             } | ||||
|             loadAvatar(user, binding.contactPhoto); | ||||
|             if (user.getRole() == MucOptions.Role.NONE) { | ||||
|                 binding.contactJid.setAlpha(INACTIVE_ALPHA); | ||||
|                 binding.key.setAlpha(INACTIVE_ALPHA); | ||||
|                 binding.contactDisplayName.setAlpha(INACTIVE_ALPHA); | ||||
|                 binding.contactPhoto.setAlpha(INACTIVE_ALPHA); | ||||
|             } | ||||
|             this.binding.mucMembers.addView(binding.getRoot()); | ||||
|             if (mConversation.getMucOptions().canInvite()) { | ||||
|                 this.binding.invite.setVisibility(View.VISIBLE); | ||||
|             } else { | ||||
|                 this.binding.invite.setVisibility(View.GONE); | ||||
|             } | ||||
|     } | ||||
| 
 | ||||
|     public static String getStatus(Context context, User user, final boolean advanced) { | ||||
|         if (advanced) { | ||||
|             return String.format("%s (%s)", context.getString(user.getAffiliation().getResId()), context.getString(user.getRole().getResId())); | ||||
|         } else { | ||||
|             return context.getString(user.getAffiliation().getResId()); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     private String getStatus(User user) { | ||||
|         if (mAdvancedMode) { | ||||
|             return getString(user.getAffiliation().getResId()) + | ||||
|                     " (" + getString(user.getRole().getResId()) + ')'; | ||||
|         } else { | ||||
|             return getString(user.getAffiliation().getResId()); | ||||
|         } | ||||
|         return getStatus(this, user, mAdvancedMode); | ||||
|     } | ||||
| 
 | ||||
|     private void viewPgpKey(User user) { | ||||
|         PgpEngine pgp = xmppConnectionService.getPgpEngine(); | ||||
|         if (pgp != null) { | ||||
|             PendingIntent intent = pgp.getIntentForKey(user.getPgpKeyId()); | ||||
|             if (intent != null) { | ||||
|                 try { | ||||
|                     startIntentSenderForResult(intent.getIntentSender(), 0, null, 0, 0, 0); | ||||
|                 } catch (SendIntentException ignored) { | ||||
| 
 | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void onAffiliationChangedSuccessful(Jid jid) { | ||||
| @ -711,6 +600,7 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers | ||||
|     public void onRoomDestroySucceeded() { | ||||
|         finish(); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void onRoomDestroyFailed() { | ||||
|         displayToast(getString(R.string.could_not_destroy_room)); | ||||
| @ -735,28 +625,6 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     public void loadAvatar(User user, ImageView imageView) { | ||||
|         if (cancelPotentialWork(user, imageView)) { | ||||
|             final Bitmap bm = avatarService().get(user, getPixel(48), true); | ||||
|             if (bm != null) { | ||||
|                 cancelPotentialWork(user, imageView); | ||||
|                 imageView.setImageBitmap(bm); | ||||
|                 imageView.setBackgroundColor(0x00000000); | ||||
|             } else { | ||||
|                 String seed = user.getRealJid() != null ? user.getRealJid().asBareJid().toString() : null; | ||||
|                 imageView.setBackgroundColor(UIHelper.getColorForName(seed == null ? user.getName() : seed)); | ||||
|                 imageView.setImageDrawable(null); | ||||
|                 final BitmapWorkerTask task = new BitmapWorkerTask(imageView); | ||||
|                 final AsyncDrawable asyncDrawable = new AsyncDrawable(getResources(), null, task); | ||||
|                 imageView.setImageDrawable(asyncDrawable); | ||||
|                 try { | ||||
|                     task.execute(user); | ||||
|                 } catch (final RejectedExecutionException ignored) { | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void beforeTextChanged(CharSequence s, int start, int count, int after) { | ||||
| 
 | ||||
| @ -784,46 +652,4 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     static class AsyncDrawable extends BitmapDrawable { | ||||
|         private final WeakReference<BitmapWorkerTask> bitmapWorkerTaskReference; | ||||
| 
 | ||||
|         AsyncDrawable(Resources res, Bitmap bitmap, BitmapWorkerTask bitmapWorkerTask) { | ||||
|             super(res, bitmap); | ||||
|             bitmapWorkerTaskReference = new WeakReference<>(bitmapWorkerTask); | ||||
|         } | ||||
| 
 | ||||
|         BitmapWorkerTask getBitmapWorkerTask() { | ||||
|             return bitmapWorkerTaskReference.get(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     class BitmapWorkerTask extends AsyncTask<User, Void, Bitmap> { | ||||
|         private final WeakReference<ImageView> imageViewReference; | ||||
|         private User o = null; | ||||
| 
 | ||||
|         private BitmapWorkerTask(ImageView imageView) { | ||||
|             imageViewReference = new WeakReference<>(imageView); | ||||
|         } | ||||
| 
 | ||||
|         @Override | ||||
|         protected Bitmap doInBackground(User... params) { | ||||
|             this.o = params[0]; | ||||
|             if (imageViewReference.get() == null) { | ||||
|                 return null; | ||||
|             } | ||||
|             return avatarService().get(this.o, getPixel(48), isCancelled()); | ||||
|         } | ||||
| 
 | ||||
|         @Override | ||||
|         protected void onPostExecute(Bitmap bitmap) { | ||||
|             if (bitmap != null && !isCancelled()) { | ||||
|                 final ImageView imageView = imageViewReference.get(); | ||||
|                 if (imageView != null) { | ||||
|                     imageView.setImageBitmap(bitmap); | ||||
|                     imageView.setBackgroundColor(0x00000000); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| } | ||||
|  | ||||
| @ -0,0 +1,71 @@ | ||||
| package eu.siacs.conversations.ui; | ||||
| 
 | ||||
| import android.content.Intent; | ||||
| import android.databinding.DataBindingUtil; | ||||
| import android.os.Bundle; | ||||
| import android.support.v7.widget.Toolbar; | ||||
| import android.view.MenuItem; | ||||
| 
 | ||||
| import java.util.ArrayList; | ||||
| import java.util.Collections; | ||||
| 
 | ||||
| import eu.siacs.conversations.R; | ||||
| import eu.siacs.conversations.databinding.ActivityMucUsersBinding; | ||||
| import eu.siacs.conversations.entities.Conversation; | ||||
| import eu.siacs.conversations.entities.MucOptions; | ||||
| import eu.siacs.conversations.services.XmppConnectionService; | ||||
| import eu.siacs.conversations.ui.adapter.UserAdapter; | ||||
| import eu.siacs.conversations.ui.util.MucDetailsContextMenuHelper; | ||||
| 
 | ||||
| public class MucUsersActivity extends XmppActivity implements XmppConnectionService.OnRosterUpdate { | ||||
| 
 | ||||
|     private UserAdapter userAdapter; | ||||
| 
 | ||||
|     private Conversation mConversation = null; | ||||
| 
 | ||||
|     @Override | ||||
|     protected void refreshUiReal() { | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     void onBackendConnected() { | ||||
|         final Intent intent = getIntent(); | ||||
|         final String uuid = intent == null ? null : intent.getStringExtra("uuid"); | ||||
|         if (uuid != null) { | ||||
|             mConversation = xmppConnectionService.findConversationByUuid(uuid); | ||||
|         } | ||||
|         loadAndSubmitUsers(); | ||||
|     } | ||||
| 
 | ||||
|     private void loadAndSubmitUsers() { | ||||
|         if (mConversation != null) { | ||||
|             ArrayList<MucOptions.User> users = mConversation.getMucOptions().getUsers(); | ||||
|             Collections.sort(users); | ||||
|             userAdapter.submitList(users); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|      @Override | ||||
|     public boolean onContextItemSelected(MenuItem item) { | ||||
|         if (!MucDetailsContextMenuHelper.onContextItemSelected(item, userAdapter.getSelectedUser(), mConversation, this)) { | ||||
|             return super.onContextItemSelected(item); | ||||
|         } | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     protected void onCreate(final Bundle savedInstanceState) { | ||||
|         super.onCreate(savedInstanceState); | ||||
|         ActivityMucUsersBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_muc_users); | ||||
|         setSupportActionBar((Toolbar) binding.toolbar); | ||||
|         configureActionBar(getSupportActionBar(), true); | ||||
|         this.userAdapter = new UserAdapter(true); | ||||
|         binding.list.setAdapter(this.userAdapter); | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     @Override | ||||
|     public void onRosterUpdate() { | ||||
|         loadAndSubmitUsers(); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										147
									
								
								src/main/java/eu/siacs/conversations/ui/adapter/UserAdapter.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										147
									
								
								src/main/java/eu/siacs/conversations/ui/adapter/UserAdapter.java
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,147 @@ | ||||
| package eu.siacs.conversations.ui.adapter; | ||||
| 
 | ||||
| import android.app.PendingIntent; | ||||
| import android.content.IntentSender; | ||||
| import android.databinding.DataBindingUtil; | ||||
| import android.support.annotation.NonNull; | ||||
| import android.support.v7.recyclerview.extensions.ListAdapter; | ||||
| import android.support.v7.util.DiffUtil; | ||||
| import android.support.v7.widget.RecyclerView; | ||||
| import android.view.ContextMenu; | ||||
| import android.view.LayoutInflater; | ||||
| import android.view.Menu; | ||||
| import android.view.View; | ||||
| import android.view.ViewGroup; | ||||
| import android.widget.PopupMenu; | ||||
| 
 | ||||
| import org.openintents.openpgp.util.OpenPgpUtils; | ||||
| 
 | ||||
| import java.util.List; | ||||
| 
 | ||||
| import eu.siacs.conversations.R; | ||||
| import eu.siacs.conversations.crypto.PgpEngine; | ||||
| import eu.siacs.conversations.databinding.ContactBinding; | ||||
| import eu.siacs.conversations.databinding.UserPreviewBinding; | ||||
| import eu.siacs.conversations.entities.Contact; | ||||
| import eu.siacs.conversations.entities.MucOptions; | ||||
| import eu.siacs.conversations.services.XmppConnectionService; | ||||
| import eu.siacs.conversations.ui.ConferenceDetailsActivity; | ||||
| import eu.siacs.conversations.ui.XmppActivity; | ||||
| import eu.siacs.conversations.ui.util.AvatarWorkerTask; | ||||
| import eu.siacs.conversations.ui.util.MucDetailsContextMenuHelper; | ||||
| 
 | ||||
| public class UserAdapter extends ListAdapter<MucOptions.User, UserAdapter.ViewHolder> implements View.OnCreateContextMenuListener { | ||||
| 
 | ||||
|     private MucOptions.User selectedUser = null; | ||||
| 
 | ||||
|     static final DiffUtil.ItemCallback<MucOptions.User> DIFF = new DiffUtil.ItemCallback<MucOptions.User>() { | ||||
|         @Override | ||||
|         public boolean areItemsTheSame(@NonNull MucOptions.User a, @NonNull MucOptions.User b) { | ||||
|             return a == b; | ||||
|         } | ||||
| 
 | ||||
|         @Override | ||||
|         public boolean areContentsTheSame(@NonNull MucOptions.User a, @NonNull MucOptions.User b) { | ||||
|             return a.equals(b); | ||||
|         } | ||||
|     }; | ||||
|     private final boolean advancedMode; | ||||
| 
 | ||||
|     public UserAdapter(final boolean advancedMode) { | ||||
|         super(DIFF); | ||||
|         this.advancedMode = advancedMode; | ||||
|     } | ||||
| 
 | ||||
|     @NonNull | ||||
|     @Override | ||||
|     public ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int position) { | ||||
|         return new ViewHolder(DataBindingUtil.inflate(LayoutInflater.from(viewGroup.getContext()), R.layout.contact, viewGroup, false)); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void onBindViewHolder(@NonNull ViewHolder viewHolder, int position) { | ||||
|         final MucOptions.User user = getItem(position); | ||||
|         AvatarWorkerTask.loadAvatar(user, viewHolder.binding.contactPhoto, R.dimen.avatar); | ||||
|         viewHolder.binding.getRoot().setOnClickListener(v -> { | ||||
|             final XmppActivity activity = XmppActivity.find(v); | ||||
|             if (activity != null) { | ||||
|                 activity.highlightInMuc(user.getConversation(), user.getName()); | ||||
|             } | ||||
|         }); | ||||
|         viewHolder.binding.getRoot().setTag(user); | ||||
|         viewHolder.binding.getRoot().setOnCreateContextMenuListener(this); | ||||
|         viewHolder.binding.getRoot().setOnLongClickListener(v -> { | ||||
|             selectedUser = user; | ||||
|             return false; | ||||
|         }); | ||||
|         final String name = user.getName(); | ||||
|         final Contact contact = user.getContact(); | ||||
|         if (contact != null) { | ||||
|             viewHolder.binding.contactDisplayName.setText(contact.getDisplayName()); | ||||
|             if (name != null) { | ||||
|                 viewHolder.binding.contactJid.setText(String.format("%s \u2022 %s", name, ConferenceDetailsActivity.getStatus(viewHolder.binding.getRoot().getContext(), user, advancedMode))); | ||||
|             } else { | ||||
|                 viewHolder.binding.contactJid.setText(ConferenceDetailsActivity.getStatus(viewHolder.binding.getRoot().getContext(), user, advancedMode)); | ||||
|             } | ||||
|         } else { | ||||
|             viewHolder.binding.contactDisplayName.setText(name == null ? "" : name); | ||||
|             viewHolder.binding.contactJid.setText(ConferenceDetailsActivity.getStatus(viewHolder.binding.getRoot().getContext(), user, advancedMode)); | ||||
|         } | ||||
|         if (advancedMode && user.getPgpKeyId() != 0) { | ||||
|             viewHolder.binding.key.setVisibility(View.VISIBLE); | ||||
|             viewHolder.binding.key.setOnClickListener(v -> { | ||||
|                 final XmppActivity activity = XmppActivity.find(v); | ||||
|                 final XmppConnectionService service = activity == null ? null : activity.xmppConnectionService; | ||||
|                 final PgpEngine pgpEngine = service == null ? null : service.getPgpEngine(); | ||||
|                 if (pgpEngine != null) { | ||||
|                     PendingIntent intent = pgpEngine.getIntentForKey(user.getPgpKeyId()); | ||||
|                     if (intent != null) { | ||||
|                         try { | ||||
|                             activity.startIntentSenderForResult(intent.getIntentSender(), 0, null, 0, 0, 0); | ||||
|                         } catch (IntentSender.SendIntentException ignored) { | ||||
| 
 | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|             }); | ||||
|             viewHolder.binding.key.setText(OpenPgpUtils.convertKeyIdToHex(user.getPgpKeyId())); | ||||
|         } | ||||
| 
 | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     public MucOptions.User getSelectedUser() { | ||||
|         return selectedUser; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) { | ||||
|         final XmppActivity activity = XmppActivity.find(v); | ||||
|         final Object tag = v.getTag(); | ||||
|         if (tag instanceof MucOptions.User && activity != null) { | ||||
|             activity.getMenuInflater().inflate(R.menu.muc_details_context, menu); | ||||
|             final MucOptions.User user = (MucOptions.User) tag; | ||||
|             String name; | ||||
|             final Contact contact = user.getContact(); | ||||
|             if (contact != null && contact.showInContactList()) { | ||||
|                 name = contact.getDisplayName(); | ||||
|             } else if (user.getRealJid() != null) { | ||||
|                 name = user.getRealJid().asBareJid().toString(); | ||||
|             } else { | ||||
|                 name = user.getName(); | ||||
|             } | ||||
|             menu.setHeaderTitle(name); | ||||
|             MucDetailsContextMenuHelper.configureMucDetailsContextMenu(activity, menu, user.getConversation(), user); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     class ViewHolder extends RecyclerView.ViewHolder { | ||||
| 
 | ||||
|         private final ContactBinding binding; | ||||
| 
 | ||||
|         private ViewHolder(ContactBinding binding) { | ||||
|             super(binding.getRoot()); | ||||
|             this.binding = binding; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,73 @@ | ||||
| package eu.siacs.conversations.ui.adapter; | ||||
| 
 | ||||
| import android.databinding.DataBindingUtil; | ||||
| import android.support.annotation.NonNull; | ||||
| import android.support.v7.recyclerview.extensions.ListAdapter; | ||||
| import android.support.v7.widget.RecyclerView; | ||||
| import android.view.LayoutInflater; | ||||
| import android.view.Menu; | ||||
| import android.view.ViewGroup; | ||||
| import android.widget.PopupMenu; | ||||
| 
 | ||||
| import java.util.List; | ||||
| 
 | ||||
| import eu.siacs.conversations.R; | ||||
| import eu.siacs.conversations.databinding.UserPreviewBinding; | ||||
| import eu.siacs.conversations.entities.Contact; | ||||
| import eu.siacs.conversations.entities.MucOptions; | ||||
| import eu.siacs.conversations.ui.XmppActivity; | ||||
| import eu.siacs.conversations.ui.util.AvatarWorkerTask; | ||||
| import eu.siacs.conversations.ui.util.MucDetailsContextMenuHelper; | ||||
| 
 | ||||
| public class UserPreviewAdapter extends ListAdapter<MucOptions.User,UserPreviewAdapter.ViewHolder> { | ||||
| 
 | ||||
|     public UserPreviewAdapter() { | ||||
|         super(UserAdapter.DIFF); | ||||
|     } | ||||
| 
 | ||||
|     @NonNull | ||||
|     @Override | ||||
|     public ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int position) { | ||||
|         return new ViewHolder(DataBindingUtil.inflate(LayoutInflater.from(viewGroup.getContext()), R.layout.user_preview, viewGroup, false)); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void onBindViewHolder(@NonNull ViewHolder viewHolder, int position) { | ||||
|         final MucOptions.User user = getItem(position); | ||||
|         AvatarWorkerTask.loadAvatar(user, viewHolder.binding.avatar, R.dimen.media_size); | ||||
|         viewHolder.binding.getRoot().setOnClickListener(v -> { | ||||
|             final XmppActivity activity = XmppActivity.find(v); | ||||
|             if (activity != null) { | ||||
|                 activity.highlightInMuc(user.getConversation(), user.getName()); | ||||
|             } | ||||
|         }); | ||||
|         viewHolder.binding.getRoot().setOnLongClickListener(v -> { | ||||
|             final XmppActivity activity = XmppActivity.find(v); | ||||
|             if (activity == null) { | ||||
|                 return true; | ||||
|             } | ||||
|             final PopupMenu popupMenu = new PopupMenu(activity, v); | ||||
|             popupMenu.inflate(R.menu.muc_details_context); | ||||
|             final Menu menu = popupMenu.getMenu(); | ||||
|             MucDetailsContextMenuHelper.configureMucDetailsContextMenu(activity, menu, user.getConversation(), user); | ||||
|             popupMenu.setOnMenuItemClickListener(menuItem -> MucDetailsContextMenuHelper.onContextItemSelected(menuItem, user, user.getConversation(), activity)); | ||||
|             popupMenu.show(); | ||||
|             return true; | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     public void setUserList(List<MucOptions.User> users) { | ||||
|         submitList(users); | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     class ViewHolder extends RecyclerView.ViewHolder { | ||||
| 
 | ||||
|         private final UserPreviewBinding binding; | ||||
| 
 | ||||
|         private ViewHolder(UserPreviewBinding binding) { | ||||
|             super(binding.getRoot()); | ||||
|             this.binding = binding; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -29,7 +29,8 @@ public class GridManager { | ||||
|                 } | ||||
|                 final ColumnInfo columnInfo = calculateColumnCount(context, recyclerView.getMeasuredWidth(), desiredSize); | ||||
|                 Log.d(Config.LOGTAG, "final count " + columnInfo.count); | ||||
|                 if (recyclerView.getAdapter().getItemCount() != 0) { | ||||
|                 final RecyclerView.Adapter adapter = recyclerView.getAdapter(); | ||||
|                 if (adapter != null && adapter.getItemCount() != 0) { | ||||
|                     Log.e(Config.LOGTAG, "adapter already has items; just go with it now"); | ||||
|                     return; | ||||
|                 } | ||||
|  | ||||
| @ -5,7 +5,7 @@ | ||||
|     <RelativeLayout | ||||
|         android:layout_width="match_parent" | ||||
|         android:layout_height="wrap_content" | ||||
|         android:background="?android:selectableItemBackground" | ||||
|         android:background="?selectableItemBackground" | ||||
|         android:paddingLeft="8dp" | ||||
|         android:paddingBottom="8dp" | ||||
|         android:paddingTop="8dp"> | ||||
|  | ||||
| @ -360,8 +360,8 @@ | ||||
|                 </android.support.v7.widget.CardView> | ||||
| 
 | ||||
|                 <android.support.v7.widget.CardView | ||||
|                     android:id="@+id/muc_more_details" | ||||
|                     android:layout_width="match_parent" | ||||
|                     android:id="@+id/users_wrapper" | ||||
|                     android:layout_width="fill_parent" | ||||
|                     android:layout_height="wrap_content" | ||||
|                     android:layout_marginBottom="@dimen/activity_vertical_margin" | ||||
|                     android:layout_marginLeft="@dimen/activity_horizontal_margin" | ||||
| @ -373,21 +373,23 @@ | ||||
|                         android:layout_height="wrap_content" | ||||
|                         android:orientation="vertical"> | ||||
| 
 | ||||
|                         <LinearLayout | ||||
|                             android:id="@+id/muc_members" | ||||
|                         <android.support.v7.widget.RecyclerView | ||||
|                             android:id="@+id/users" | ||||
|                             android:layout_width="match_parent" | ||||
|                             android:layout_height="wrap_content" | ||||
|                             android:orientation="vertical" | ||||
|                             android:padding="@dimen/card_padding_list"> | ||||
|                         </LinearLayout> | ||||
|                             android:orientation="horizontal" | ||||
|                             android:paddingEnd="@dimen/card_padding_regular" | ||||
|                             android:paddingStart="@dimen/card_padding_regular" | ||||
|                             android:paddingTop="@dimen/card_padding_regular" | ||||
|                             android:paddingBottom="@dimen/card_padding_list" | ||||
|                             android:layout_marginStart="-2dp" | ||||
|                             android:layout_marginEnd="-2dp"/> | ||||
| 
 | ||||
|                         <LinearLayout | ||||
|                             android:layout_width="wrap_content" | ||||
|                             android:layout_height="match_parent" | ||||
|                             android:layout_gravity="center_horizontal" | ||||
|                             android:layout_marginTop="8dp" | ||||
|                             android:orientation="horizontal"> | ||||
| 
 | ||||
|                             android:orientation="horizontal" | ||||
|                             android:layout_gravity="end"> | ||||
| 
 | ||||
|                             <Button | ||||
|                                 android:id="@+id/invite" | ||||
| @ -397,9 +399,19 @@ | ||||
|                                 android:minWidth="0dp" | ||||
|                                 android:paddingLeft="16dp" | ||||
|                                 android:paddingRight="16dp" | ||||
|                                 android:text="@string/invite_contact" | ||||
|                                 android:textColor="?attr/colorAccent"/> | ||||
|                                 android:text="@string/invite" | ||||
|                                 android:textColor="?attr/colorAccent" /> | ||||
| 
 | ||||
|                             <Button | ||||
|                                 android:id="@+id/show_users" | ||||
|                                 style="@style/Widget.Conversations.Button.Borderless" | ||||
|                                 android:layout_width="wrap_content" | ||||
|                                 android:layout_height="wrap_content" | ||||
|                                 android:minWidth="0dp" | ||||
|                                 android:paddingLeft="16dp" | ||||
|                                 android:paddingRight="16dp" | ||||
|                                 android:text="@string/view_users" | ||||
|                                 android:textColor="?attr/colorAccent" /> | ||||
|                         </LinearLayout> | ||||
|                     </LinearLayout> | ||||
|                 </android.support.v7.widget.CardView> | ||||
|  | ||||
							
								
								
									
										33
									
								
								src/main/res/layout/activity_muc_users.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								src/main/res/layout/activity_muc_users.xml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,33 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <layout xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     xmlns:app="http://schemas.android.com/apk/res-auto"> | ||||
| 
 | ||||
| 
 | ||||
|     <LinearLayout | ||||
|         android:layout_width="fill_parent" | ||||
|         android:layout_height="fill_parent" | ||||
|         android:background="?attr/color_background_primary" | ||||
|         android:orientation="vertical"> | ||||
| 
 | ||||
|         <include | ||||
|             android:id="@+id/toolbar" | ||||
|             layout="@layout/toolbar" /> | ||||
| 
 | ||||
| 
 | ||||
|         <android.support.design.widget.CoordinatorLayout | ||||
|             android:id="@+id/coordinator" | ||||
|             android:layout_width="match_parent" | ||||
|             android:layout_height="match_parent" | ||||
|             android:background="?attr/color_background_primary"> | ||||
| 
 | ||||
|             <android.support.v7.widget.RecyclerView | ||||
|                 android:id="@+id/list" | ||||
|                 android:layout_width="match_parent" | ||||
|                 android:layout_height="match_parent" | ||||
|                 android:background="?attr/color_background_primary" | ||||
|                 android:orientation="vertical" | ||||
|                 app:layoutManager="android.support.v7.widget.LinearLayoutManager" /> | ||||
|         </android.support.design.widget.CoordinatorLayout> | ||||
| 
 | ||||
|     </LinearLayout> | ||||
| </layout> | ||||
| @ -5,7 +5,7 @@ | ||||
|     <RelativeLayout | ||||
|         android:layout_width="match_parent" | ||||
|         android:layout_height="wrap_content" | ||||
|         android:background="?attr/list_item_background" | ||||
|         android:background="?selectableItemBackground" | ||||
|         android:padding="@dimen/list_padding"> | ||||
| 
 | ||||
|         <com.makeramen.roundedimageview.RoundedImageView | ||||
|  | ||||
							
								
								
									
										15
									
								
								src/main/res/layout/user_preview.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								src/main/res/layout/user_preview.xml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,15 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <layout xmlns:android="http://schemas.android.com/apk/res/android"> | ||||
|     <eu.siacs.conversations.ui.widget.SquareFrameLayout | ||||
|         android:layout_width="match_parent" | ||||
|         android:layout_height="match_parent" | ||||
|         android:padding="2dp" | ||||
|         android:background="?selectableItemBackground"> | ||||
|         <ImageView | ||||
|             android:id="@+id/avatar" | ||||
|             android:layout_width="match_parent" | ||||
|             android:layout_height="match_parent" | ||||
|             android:background="@color/black54" | ||||
|             android:scaleType="centerInside"/> | ||||
|     </eu.siacs.conversations.ui.widget.SquareFrameLayout> | ||||
| </layout> | ||||
| @ -51,6 +51,7 @@ | ||||
|     <string name="share_with">Share with…</string> | ||||
|     <string name="start_conversation">Start conversation</string> | ||||
|     <string name="invite_contact">Invite contact</string> | ||||
|     <string name="invite">Invite</string> | ||||
|     <string name="contacts">Contacts</string> | ||||
|     <string name="contact">Contact</string> | ||||
|     <string name="cancel">Cancel</string> | ||||
| @ -748,6 +749,8 @@ | ||||
|     <string name="pref_more_notification_settings_summary">Importance, Sound, Vibrate</string> | ||||
|     <string name="video_compression_channel_name">Video compression</string> | ||||
|     <string name="view_media">View media</string> | ||||
|     <string name="view_users">View members</string> | ||||
|     <string name="group_chat_members">Group chat members</string> | ||||
|     <string name="media_browser">Media browser</string> | ||||
|     <string name="security_violation_not_attaching_file">File omitted due to security violation.</string> | ||||
|     <string name="pref_video_compression">Video Quality</string> | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 Daniel Gultsch
						Daniel Gultsch