[NEW] Display preferences screen (#3318)

Co-authored-by: Gerzon Z <gerzonc@icloud.com>
Co-authored-by: Diego Mello <diegolmello@gmail.com>
Co-authored-by: AlexAlexandre <alexalexandrejr@gmail.com>
This commit is contained in:
Reinaldo Neto 2021-10-06 17:30:10 -03:00 committed by GitHub
parent aba0e49194
commit 27dd007874
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
44 changed files with 7532 additions and 4442 deletions

File diff suppressed because it is too large Load Diff

View File

@ -18,8 +18,6 @@ export const ROOMS = createRequestTypes('ROOMS', [
'SET_SEARCH',
'CLOSE_SERVER_DROPDOWN',
'TOGGLE_SERVER_DROPDOWN',
'CLOSE_SORT_DROPDOWN',
'TOGGLE_SORT_DROPDOWN',
'OPEN_SEARCH_HEADER',
'CLOSE_SEARCH_HEADER'
]);

View File

@ -45,18 +45,6 @@ export function toggleServerDropdown() {
};
}
export function closeSortDropdown() {
return {
type: types.ROOMS.CLOSE_SORT_DROPDOWN
};
}
export function toggleSortDropdown() {
return {
type: types.ROOMS.TOGGLE_SORT_DROPDOWN
};
}
export function openSearchHeader() {
return {
type: types.ROOMS.OPEN_SEARCH_HEADER

View File

@ -0,0 +1,2 @@
export const DISPLAY_MODE_CONDENSED = 'condensed';
export const DISPLAY_MODE_EXPANDED = 'expanded';

View File

@ -85,7 +85,7 @@ const Avatar = React.memo(
}
return (
<View style={[avatarStyle, style]}>
<View style={[avatarStyle, style]} testID='avatar'>
{image}
{children}
</View>

View File

@ -51,7 +51,9 @@ class QueueListView extends React.Component {
server: PropTypes.string,
useRealName: PropTypes.bool,
navigation: PropTypes.object,
theme: PropTypes.string
theme: PropTypes.string,
showAvatar: PropTypes.bool,
displayMode: PropTypes.string
};
shouldComponentUpdate(nextProps) {
@ -95,7 +97,9 @@ class QueueListView extends React.Component {
useRealName,
theme,
isMasterDetail,
width
width,
showAvatar,
displayMode
} = this.props;
const id = this.getUidDirectMessage(item);
@ -117,6 +121,8 @@ class QueueListView extends React.Component {
getRoomAvatar={this.getRoomAvatar}
visitor={item.v}
swipeEnabled={false}
showAvatar={showAvatar}
displayMode={displayMode}
/>
);
};
@ -151,6 +157,8 @@ const mapStateToProps = state => ({
isMasterDetail: state.app.isMasterDetail,
server: state.server.server,
useRealName: state.settings.UI_Use_Real_Name,
queued: getInquiryQueueSelector(state)
queued: getInquiryQueueSelector(state),
showAvatar: state.sortPreferences.showAvatar,
displayMode: state.sortPreferences.displayMode
});
export default connect(mapStateToProps)(withDimensions(withTheme(QueueListView)));

View File

@ -79,7 +79,6 @@
"error-user-registration-secret": "التسجيل مسموح به عبر عنوان الويب السري فقط",
"error-you-are-last-owner": "أنت المالك الأخير. يرجى تعيين مالك جديد قبل مغادرة الغرفة",
"Actions": "الإجراءات",
"activity": "نشاط",
"Activity": "النشاط",
"Add_Reaction": "إضافة تفاعل",
"Add_Server": "إضافة خادم",
@ -224,7 +223,6 @@
"Everyone_can_access_this_channel": "يمكن للجميع الوصول إلى هذه القناة",
"Error_uploading": "خطأ في الرفع",
"Expiration_Days": "انتهاء (أيام)",
"Favorite": "مفضل",
"Favorites": "مفضلات",
"Files": "ملفات",
"File_description": "وصف الملف",
@ -241,9 +239,6 @@
"Forward_to_user": "إعادة توجيه لمستخدم",
"Full_table": "انقر لرؤية الجدول كاملاً",
"Generate_New_Link": "إنشاء رابط جديد",
"Group_by_favorites": "جمع حسب المفضلة",
"Group_by_type": "جمع حسب النوع",
"Hide": "إخفاء",
"Has_joined_the_channel": "انضم إلى القناة",
"Has_joined_the_conversation": "انضم إلى المحادثة",
"Has_left_the_channel": "غادر القناة",
@ -321,7 +316,6 @@
"My_servers": "الخوادم",
"N_people_reacted": "{{n}} تفاعل الناس",
"N_users": "{{n}} مستخدمين",
"name": "اسم",
"Name": "اسم",
"Navigation_history": "تاريخ التصفح",
"Never": "أبداً",
@ -398,7 +392,6 @@
"Reactions_are_disabled": "التفاعل معطل",
"Reactions_are_enabled": "التفاعل مفعل",
"Reactions": "التفاعلات",
"Read": "قراءة",
"Read_External_Permission_Message": "يحتاج Rocket.chat للوصول إلى الصور والملفات الموجودة على الجهاز",
"Read_External_Permission": "صلاحية قراءة الوسائط",
"Read_Only_Channel": "قناة للقراءة فقط",
@ -490,7 +483,6 @@
"Sign_in_your_server": "تسجيل الدخول إلى الخادم الخاص بك",
"Sign_Up": "تسجيل جديد",
"Some_field_is_invalid_or_empty": "بعض الحقول غير صالحة أو فارغة",
"Sorting_by": "فرز حسب {{key}}",
"Sound": "الصوت",
"Star_room": "تمييز الغرفة",
"Star": "تمييز",
@ -529,7 +521,6 @@
"unarchive": "إلغاء الأرشفة",
"UNARCHIVE": "إلغاء الأرشفة",
"Unblock_user": "إلغاء حظر عن مستخدم",
"Unfavorite": "إزالة من المفضلة",
"Unfollowed_thread": "موضوع غير متابع",
"Unmute": "إلغاء كتم",
"unmuted": "إلغاء كتم",

View File

@ -81,7 +81,6 @@
"error-you-are-last-owner": "Du bist der letzte Besitzer. Bitte setze einen neuen Besitzer, bevor du den Raum verlässt.",
"error-status-not-allowed": "Unsichtbar-Status ist deaktiviert",
"Actions": "Aktionen",
"activity": "Aktivität",
"Activity": "Aktivität",
"Add_Reaction": "Reaktion hinzufügen",
"Add_Server": "Server hinzufügen",
@ -232,7 +231,6 @@
"Everyone_can_access_this_team": "Jeder kann auf dieses Team zugreifen",
"Error_uploading": "Fehler beim Hochladen",
"Expiration_Days": "läuft ab (Tage)",
"Favorite": "Favorisieren",
"Favorites": "Favoriten",
"Files": "Dateien",
"File_description": "Dateibeschreibung",
@ -249,9 +247,6 @@
"Forward_to_user": "Weiterleiten an Benutzer",
"Full_table": "Klicken um die ganze Tabelle anzuzeigen",
"Generate_New_Link": "Neuen Link erstellen",
"Group_by_favorites": "Nach Favoriten gruppieren",
"Group_by_type": "Gruppieren nach Typ",
"Hide": "Ausblenden",
"Has_joined_the_channel": "Ist dem Kanal beigetreten",
"Has_joined_the_conversation": "Hat sich dem Gespräch angeschlossen",
"Has_left_the_channel": "Hat den Kanal verlassen",
@ -334,7 +329,6 @@
"N_people_reacted": "{{n}} Leute haben reagiert",
"N_users": "{{n}} Benutzer",
"N_channels": "{{n}} Kanäle",
"name": "Name",
"Name": "Name",
"Navigation_history": "Navigations-Verlauf",
"Never": "Niemals",
@ -412,7 +406,6 @@
"Reactions_are_disabled": "Reaktionen sind deaktiviert",
"Reactions_are_enabled": "Reaktionen sind aktiviert",
"Reactions": "Reaktionen",
"Read": "Gelesen",
"Read_External_Permission_Message": "Rocket.Chat benötigt Zugriff auf deine Fotos, Medien und Dateien auf deinem Gerät",
"Read_External_Permission": "Lese-Zugriff auf Medien",
"Read_Only_Channel": "Nur-Lese-Kanal",
@ -507,7 +500,6 @@
"Sign_in_your_server": "Melde dich bei deinem Server an",
"Sign_Up": "Anmelden",
"Some_field_is_invalid_or_empty": "Ein Feld ist ungültig oder leer",
"Sorting_by": "Sortierung nach {{key}}",
"Sound": "Ton",
"Star_room": "Favorisierter Raum",
"Star": "Favoriten",
@ -546,7 +538,6 @@
"unarchive": "wiederherstellen",
"UNARCHIVE": "WIEDERHERSTELLEN",
"Unblock_user": "Benutzer entsperren",
"Unfavorite": "Nicht mehr favorisieren",
"Unfollowed_thread": "Thread nicht mehr folgen",
"Unmute": "Stummschaltung aufheben",
"unmuted": "Stummschaltung aufgehoben",

View File

@ -81,7 +81,6 @@
"error-you-are-last-owner": "You are the last owner. Please set new owner before leaving the room.",
"error-status-not-allowed": "Invisible status is disabled",
"Actions": "Actions",
"activity": "activity",
"Activity": "Activity",
"Add_Reaction": "Add Reaction",
"Add_Server": "Add Server",
@ -232,7 +231,6 @@
"Everyone_can_access_this_team": "Everyone can access this team",
"Error_uploading": "Error uploading",
"Expiration_Days": "Expiration (Days)",
"Favorite": "Favorite",
"Favorites": "Favorites",
"Files": "Files",
"File_description": "File description",
@ -249,9 +247,6 @@
"Forward_to_user": "Forward to user",
"Full_table": "Click to see full table",
"Generate_New_Link": "Generate New Link",
"Group_by_favorites": "Group favorites",
"Group_by_type": "Group by type",
"Hide": "Hide",
"Has_joined_the_channel": "has joined the channel",
"Has_joined_the_conversation": "has joined the conversation",
"Has_left_the_channel": "has left the channel",
@ -334,7 +329,6 @@
"N_people_reacted": "{{n}} people reacted",
"N_users": "{{n}} users",
"N_channels": "{{n}} channels",
"name": "name",
"Name": "Name",
"Navigation_history": "Navigation history",
"Never": "Never",
@ -412,7 +406,6 @@
"Reactions_are_disabled": "Reactions are disabled",
"Reactions_are_enabled": "Reactions are enabled",
"Reactions": "Reactions",
"Read": "Read",
"Read_External_Permission_Message": "Rocket.Chat needs to access photos, media, and files on your device",
"Read_External_Permission": "Read Media Permission",
"Read_Only_Channel": "Read Only Channel",
@ -507,7 +500,6 @@
"Sign_in_your_server": "Sign in your server",
"Sign_Up": "Sign Up",
"Some_field_is_invalid_or_empty": "Some field is invalid or empty",
"Sorting_by": "Sorting by {{key}}",
"Sound": "Sound",
"Star_room": "Star room",
"Star": "Star",
@ -546,7 +538,6 @@
"unarchive": "unarchive",
"UNARCHIVE": "UNARCHIVE",
"Unblock_user": "Unblock user",
"Unfavorite": "Unfavorite",
"Unfollowed_thread": "Unfollowed thread",
"Unmute": "Unmute",
"unmuted": "unmuted",
@ -772,6 +763,13 @@
"Converting_Team_To_Channel": "Converting Team to Channel",
"Select_Team_Channels_To_Delete": "Select the Teams Channels you would like to delete, the ones you do not select will be moved to the Workspace. \n\nNotice that public Channels will be public and visible to everyone.",
"You_are_converting_the_team": "You are converting this Team to a Channel",
"Display": "Display",
"Avatars": "Avatars",
"Sort_by": "Sort by",
"Group_by": "Group by",
"Types": "Types",
"Expanded": "Expanded",
"Condensed": "Condensed",
"creating_discussion": "creating discussion",
"Canned_Responses": "Canned Responses",
"No_match_found": "No match found.",

View File

@ -76,7 +76,6 @@
"error-user-registration-secret": "El registro de usuarios sólo está permitido por URL secretas",
"error-you-are-last-owner": "Eres el único propietario existente. Debes establecer un nuevo propietario antes de abandonar la sala.",
"Actions": "Acciones",
"activity": "actividad",
"Activity": "Actividad",
"Add_Reaction": "Añadir reacción",
"Add_Server": "Añadir servidor",
@ -176,7 +175,6 @@
"Enable_notifications": "Permitir notificaciones",
"Everyone_can_access_this_channel": "Todos los usuarios pueden acceder a este canal",
"Error_uploading": "Error en la subida",
"Favorite": "Favorito",
"Favorites": "Favoritos",
"Files": "Archivos",
"File_description": "Descripción del archivo",
@ -188,9 +186,6 @@
"Forgot_password": "¿Ha olvidado su contraseña?",
"Forgot_Password": "Olvidé la contraseña",
"Full_table": "Click para ver la tabla completa",
"Group_by_favorites": "Agrupar por favoritos",
"Group_by_type": "Agrupar por tipo",
"Hide": "Ocultar",
"Has_joined_the_channel": "se ha unido al canal",
"Has_joined_the_conversation": "se ha unido a la conversación",
"Has_left_the_channel": "ha dejado el canal",
@ -237,7 +232,6 @@
"My_servers": "Mis servidores",
"N_people_reacted": "Han reaccionado {{n}} personas",
"N_users": "{{n}} usuarios",
"name": "nombre",
"Name": "Nombre",
"New_Message": "Nuevo mensaje",
"New_Password": "Nueva contraseña",
@ -292,7 +286,6 @@
"Reactions_are_disabled": "Las reacciones están desactivadas",
"Reactions_are_enabled": "Las reacciones están activadas",
"Reactions": "Reacciones",
"Read": "Leer",
"Read_Only_Channel": "Canal de sólo lectura",
"Read_Only": "Sólo lectura ",
"Read_Receipt": "Comprobante de lectura",
@ -356,7 +349,6 @@
"Sign_in_your_server": "Accede a tu servidor",
"Sign_Up": "Registrarse",
"Some_field_is_invalid_or_empty": "Algún campo no es correcto o está vacío",
"Sorting_by": "Ordenado por {{key}}",
"Sound": "Sonido",
"Star_room": "Destacar sala",
"Star": "Destacar",
@ -390,7 +382,6 @@
"unarchive": "desarchivar",
"UNARCHIVE": "DESARCHIVAR",
"Unblock_user": "Desbloquear usuario",
"Unfavorite": "Quitar favorito",
"Unfollowed_thread": "Dejar de seguir el hilo",
"Unmute": "Desmutear",
"unmuted": "Desmuteado",

View File

@ -81,7 +81,6 @@
"error-you-are-last-owner": "Vous êtes le dernier propriétaire. Veuillez définir un nouveau propriétaire avant de quitter le salon.",
"error-status-not-allowed": "Le statut invisible est désactivé",
"Actions": "Actions",
"activity": "activité",
"Activity": "Activité",
"Add_Reaction": "Ajouter une réaction",
"Add_Server": "Ajouter un serveur",
@ -232,7 +231,6 @@
"Everyone_can_access_this_team": "Tout le monde peut accéder à cette équipe",
"Error_uploading": "Erreur lors de l'envoi",
"Expiration_Days": "Expiration (Jours)",
"Favorite": "Favori",
"Favorites": "Favoris",
"Files": "Fichiers",
"File_description": "Description du fichier",
@ -249,9 +247,6 @@
"Forward_to_user": "Transmettre à l'utilisateur",
"Full_table": "Cliquez pour voir le tableau complet",
"Generate_New_Link": "Générer un nouveau lien",
"Group_by_favorites": "Grouper par favoris",
"Group_by_type": "Grouper par type",
"Hide": "Cacher",
"Has_joined_the_channel": "a rejoint le canal",
"Has_joined_the_conversation": "a rejoint la conversation",
"Has_left_the_channel": "a quitté le canal",
@ -334,7 +329,6 @@
"N_people_reacted": "{{n}} personnes ont réagi",
"N_users": "{{n}} utilisateurs",
"N_channels": "{{n}} canaux",
"name": "nom",
"Name": "Nom",
"Navigation_history": "Historique de navigation",
"Never": "Jamais",
@ -412,7 +406,6 @@
"Reactions_are_disabled": "Les réactions sont désactivées",
"Reactions_are_enabled": "Les réactions sont activées",
"Reactions": "Réactions",
"Read": "Lecture",
"Read_External_Permission_Message": "Rocket.Chat doit accéder aux photos, aux médias et aux fichiers sur votre appareil",
"Read_External_Permission": "Permission de lecture des fichiers",
"Read_Only_Channel": "Canal en lecture seule",
@ -507,7 +500,6 @@
"Sign_in_your_server": "Connectez-vous à votre serveur",
"Sign_Up": "S'inscrire",
"Some_field_is_invalid_or_empty": "Certains champs sont invalides ou vides",
"Sorting_by": "Tri par {{key}}",
"Sound": "Son",
"Star_room": "Canal favoris",
"Star": "Mettre en favoris",
@ -546,7 +538,6 @@
"unarchive": "désarchiver",
"UNARCHIVE": "DÉSARCHIVER",
"Unblock_user": "Débloquer l'utilisateur",
"Unfavorite": "Supprimer des favoris",
"Unfollowed_thread": "Ne plus suivre ce fil",
"Unmute": "Rendre la parole",
"unmuted": "rendu la parole",

View File

@ -79,7 +79,6 @@
"error-user-registration-secret": "Registrazione utente permessa solo via URL segreto",
"error-you-are-last-owner": "Sei l'ultimo proprietario rimasto. Imposta un nuovo proprietario prima di lasciare la stanza.",
"Actions": "Azioni",
"activity": "attività",
"Activity": "Attività",
"Add_Reaction": "Aggiungi reazione",
"Add_Server": "Aggiungi server",
@ -227,7 +226,6 @@
"Everyone_can_access_this_channel": "Tutti hanno accesso a questo canale",
"Error_uploading": "Errore nel caricamento di",
"Expiration_Days": "Scadenza (giorni)",
"Favorite": "Preferito",
"Favorites": "Preferiti",
"Files": "File",
"File_description": "Descrizione file",
@ -244,9 +242,6 @@
"Forward_to_user": "Inoltra ad udente",
"Full_table": "Clicca per la tabella completa",
"Generate_New_Link": "Genera nuovo link",
"Group_by_favorites": "Raggruppa per preferiti",
"Group_by_type": "Raggruppa per tipo",
"Hide": "Nascondi",
"Has_joined_the_channel": "si è unito al canale",
"Has_joined_the_conversation": "si è unito alla conversazione",
"Has_left_the_channel": "ha lasciato il canale",
@ -326,7 +321,6 @@
"My_servers": "I miei server",
"N_people_reacted": "{{n}} persone hanno reagito",
"N_users": "{{n}} utenti",
"name": "nome",
"Name": "Nome",
"Navigation_history": "Cronologia di navigazione",
"Never": "Mai",
@ -404,7 +398,6 @@
"Reactions_are_disabled": "Le reazioni sono disabilitate",
"Reactions_are_enabled": "Le reazioni sono abilitate",
"Reactions": "Reazioni",
"Read": "Letto",
"Read_External_Permission_Message": "Rocket.Chat deve accedere alle foto, media, e documenti sul tuo dispositivo",
"Read_External_Permission": "Permesso di Lettura della Memoria",
"Read_Only_Channel": "Canale in sola lettura",
@ -498,7 +491,6 @@
"Sign_in_your_server": "Accedi al tuo server",
"Sign_Up": "Registrati",
"Some_field_is_invalid_or_empty": "Un campo non è valido o è vuoto",
"Sorting_by": "Ordina per {{key}}",
"Sound": "Suono",
"Star_room": "Aggiungi stanza ai preferiti",
"Star": "Aggiungi ai preferiti",
@ -537,7 +529,6 @@
"unarchive": "rimuovi dall'archivio",
"UNARCHIVE": "RIMUOVI DALL'ARCHIVIO",
"Unblock_user": "Sblocca utente",
"Unfavorite": "Rimuovi preferito",
"Unfollowed_thread": "Non segui più il thread",
"Unmute": "Attiva notifiche",
"unmuted": "notifiche attivate",

View File

@ -77,7 +77,6 @@
"error-user-registration-secret": "ユーザーの登録は登録用URLからのみ許可されています",
"error-you-are-last-owner": "あなたは最後のオーナーです。ルームを退出する前に別のオーナーを設定してください。",
"Actions": "アクション",
"activity": "アクティビティ",
"Activity": "アクティビティ順",
"Add_Reaction": "リアクションを追加",
"Add_Server": "サーバーを追加",
@ -183,7 +182,6 @@
"Everyone_can_access_this_channel": "全員このチャンネルにアクセスできます",
"Error_uploading": "アップロードエラー",
"Expiration_Days": "期限切れ (日)",
"Favorite": "お気に入り",
"Favorites": "お気に入り",
"Files": "ファイル",
"File_description": "ファイルの説明",
@ -196,9 +194,6 @@
"Forgot_Password": "パスワードを忘れた",
"Full_table": "クリックしてテーブル全体を見る",
"Generate_New_Link": "新しいリンクを生成",
"Group_by_favorites": "お気に入りをグループ化",
"Group_by_type": "タイプ別にグループ化",
"Hide": "隠す",
"Has_joined_the_channel": "はチャンネルに参加しました",
"Has_joined_the_conversation": "は会話に参加しました",
"Has_left_the_channel": "はチャンネルを退出しました",
@ -251,7 +246,6 @@
"My_servers": "自分のサーバー",
"N_people_reacted": "{{n}}人がリアクションしました",
"N_users": "{{n}}人",
"name": "アルファベット",
"Name": "名前",
"Never": "ずっと受け取らない",
"New_Message": "メッセージ",
@ -308,7 +302,6 @@
"Reactions_are_disabled": "リアクションは無効化されています",
"Reactions_are_enabled": "リアクションは有効化されています",
"Reactions": "リアクション",
"Read": "読む",
"Read_Only_Channel": "読み取り専用チャンネル",
"Read_Only": "読み取り専用",
"Read_Receipt": "レシートを見る",
@ -382,7 +375,6 @@
"Sign_in_your_server": "サーバーに接続",
"Sign_Up": "登録",
"Some_field_is_invalid_or_empty": "不正、または空の入力欄があります。",
"Sorting_by": "{{key}}順",
"Sound": "音",
"Star_room": "お気に入りルーム",
"Star": "お気に入り",
@ -416,7 +408,6 @@
"unarchive": "アーカイブ解除",
"UNARCHIVE": "アーカイブ解除",
"Unblock_user": "ブロックを解除",
"Unfavorite": "お気に入り解除",
"Unfollowed_thread": "スレッド更新時に通知しない",
"Unmute": "ミュート解除",
"unmuted": "ミュート解除しました",

View File

@ -81,7 +81,6 @@
"error-you-are-last-owner": "Je bent de laatste eigenaar. Stel een nieuwe eigenaar in voordat je de kamer verlaat.",
"error-status-not-allowed": "Onzichtbare status is uitgeschakeld",
"Actions": "Acties",
"activity": "activiteit",
"Activity": "Activiteit",
"Add_Reaction": "Reactie toevoegen",
"Add_Server": "Server toevoegen",
@ -232,7 +231,6 @@
"Everyone_can_access_this_team": "Iedereen heeft toegang tot dit team",
"Error_uploading": "Fout bij uploaden",
"Expiration_Days": "Vervaldatum (Dagen)",
"Favorite": "Favoriet",
"Favorites": "Favorieten",
"Files": "Bestanden",
"File_description": "Bestandsbeschrijving",
@ -249,9 +247,6 @@
"Forward_to_user": "Doorsturen naar gebruiker",
"Full_table": "Klik om de volledige tabel te zien",
"Generate_New_Link": "Nieuwe link genereren",
"Group_by_favorites": "Groepeer favorieten",
"Group_by_type": "Groeperen op type",
"Hide": "Verberg",
"Has_joined_the_channel": "is bij het kanaal gekomen",
"Has_joined_the_conversation": "heeft zich bij het gesprek aangesloten",
"Has_left_the_channel": "heeft het kanaal verlaten",
@ -334,7 +329,6 @@
"N_people_reacted": "{{n}} mensen hebben gereageerd",
"N_users": "{{n}} gebruikers",
"N_channels": "{{n}} kanalen",
"name": "naam",
"Name": "Naam",
"Navigation_history": "Navigatie geschiedenis",
"Never": "Nooit",
@ -412,7 +406,6 @@
"Reactions_are_disabled": "Reacties zijn uitgeschakeld",
"Reactions_are_enabled": "Reacties zijn ingeschakeld",
"Reactions": "Reacties",
"Read": "Lezen",
"Read_External_Permission_Message": "Rocket.Chat heeft toegang nodig tot foto's, media en bestanden op je apparaat",
"Read_External_Permission": "Lees toestemming voor media",
"Read_Only_Channel": "Alleen-lezen kanaal",
@ -507,7 +500,6 @@
"Sign_in_your_server": "Log in op je server",
"Sign_Up": "Registreren",
"Some_field_is_invalid_or_empty": "Sommige velden zijn ongeldig of leeg",
"Sorting_by": "Sorteren op {{key}}",
"Sound": "Geluid",
"Star_room": "Favoriete kanalen",
"Star": "Ster",
@ -546,7 +538,6 @@
"unarchive": "dearchiveren",
"UNARCHIVE": "DEARCHIVEREN",
"Unblock_user": "Deblokkeer gebruiker",
"Unfavorite": "Uit favorieten halen",
"Unfollowed_thread": "Draad ontvolgd",
"Unmute": "Dempen opheffen",
"unmuted": "ongedempt",

View File

@ -77,7 +77,6 @@
"error-you-are-last-owner": "Você é o último proprietário da sala. Por favor defina um novo proprietário antes de sair.",
"error-status-not-allowed": "O status invisível está desativado",
"Actions": "Ações",
"activity": "atividade",
"Activity": "Atividade",
"Add_Reaction": "Reagir",
"Add_Server": "Adicionar servidor",
@ -219,7 +218,6 @@
"Everyone_can_access_this_channel": "Todos podem acessar este canal",
"Error_uploading": "Erro subindo",
"Expiration_Days": "Expira em (dias)",
"Favorite": "Adicionar aos Favoritos",
"Favorites": "Favoritos",
"Files": "Arquivos",
"File_description": "Descrição do arquivo",
@ -236,9 +234,6 @@
"Forward_to_user": "Encaminhar para usuário",
"Full_table": "Clique para ver a tabela completa",
"Generate_New_Link": "Gerar novo convite",
"Group_by_favorites": "Agrupar favoritos",
"Group_by_type": "Agrupar por tipo",
"Hide": "Ocultar",
"Has_joined_the_channel": "entrou no canal",
"Has_joined_the_conversation": "entrou na conversa",
"Has_left_the_channel": "saiu da conversa",
@ -307,7 +302,6 @@
"muted": "mudo",
"N_people_reacted": "{{n}} pessoas reagiram",
"N_users": "{{n}} usuários",
"name": "nome",
"Name": "Nome",
"Navigation_history": "Histórico de navegação",
"Never": "Nunca",
@ -466,7 +460,6 @@
"Sign_in_your_server": "Entrar no seu servidor",
"Sign_Up": "Registrar",
"Some_field_is_invalid_or_empty": "Algum campo está inválido ou vazio",
"Sorting_by": "Ordenando por {{key}}",
"Sound": "Som da notificação",
"Star_room": "Favoritar sala",
"Star": "Favorito",
@ -502,7 +495,6 @@
"unarchive": "desarquivar",
"UNARCHIVE": "DESARQUIVAR",
"Unblock_user": "Desbloquear usuário",
"Unfavorite": "Remover dos Favoritos",
"Unfollowed_thread": "Parou de seguir tópico",
"Unmute": "Permitir que o usuário fale",
"unmuted": "permitiu que o usuário fale",
@ -673,6 +665,13 @@
"Deleted_The_Team_Successfully": "Time deletado com sucesso",
"Deleted_The_Room_Successfully": "Sala deletada com sucesso",
"Convert_to_Channel": "Converter para um Canal",
"Display": "Display",
"Avatars": "Avatars",
"Sort_by": "Ordenar por",
"Group_by": "Agrupar por",
"Types": "Tipos",
"Expanded": "Estendido",
"Condensed": "Condensado",
"Canned_Responses": "Respostas Predefinidas",
"No_match_found": "Nenhum resultado encontrado",
"Check_canned_responses": "Verifique nas respostas predefinidas",

View File

@ -81,7 +81,6 @@
"error-you-are-last-owner": "Você é o último proprietário. Por favor, defina novo proprietário antes de sair da sala.",
"error-status-not-allowed": "O estado invisível está desactivado",
"Actions": "Acções",
"activity": "actividade",
"Activity": "Actividade",
"Add_Reaction": "Adicionar Reacção",
"Add_Server": "Adicionar Servidor",
@ -232,7 +231,6 @@
"Everyone_can_access_this_team": "Todos podem aceder a esta equipa",
"Error_uploading": "Erro ao fazer o envio",
"Expiration_Days": "Validade (Dias)",
"Favorite": "Favorito",
"Favorites": "Favoritos",
"Files": "Ficheiros",
"File_description": "Descrição do ficheiro",
@ -249,9 +247,6 @@
"Forward_to_user": "Reencaminhar para o utilizador",
"Full_table": "Clique para ver a tabela completa",
"Generate_New_Link": "Gerar Novo Link",
"Group_by_favorites": "Agrupar por favoritos",
"Group_by_type": "Agrupar por tipo",
"Hide": "Esconder",
"Has_joined_the_channel": "entrou no canal",
"Has_joined_the_conversation": "entrou na conversa",
"Has_left_the_channel": "saiu do canal",
@ -333,7 +328,6 @@
"N_people_reacted": "{{n}} pessoas reagiram",
"N_users": "{{n}} utilizadores",
"N_channels": "{{n}} canais",
"name": "nome",
"Name": "Nome",
"Navigation_history": "Histórico de navegação",
"Never": "Nunca",
@ -411,7 +405,6 @@
"Reactions_are_disabled": "Reacções desactivadas",
"Reactions_are_enabled": "Reacções activadas",
"Reactions": "Reacções",
"Read": "Ler",
"Read_External_Permission_Message": "Rocket.Chat precisa acessar fotos, média e arquivos em seu dispositivo",
"Read_External_Permission": "Permissão de leitura da média",
"Read_Only_Channel": "Canal só de leitura",
@ -458,7 +451,6 @@
"Sign_in_your_server": "Entre no seu servidor",
"Sign_Up": "Inscreva-se",
"Some_field_is_invalid_or_empty": "Algum campo é inválido ou está vazio",
"Sorting_by": "Ordenar por {{key}}",
"Star_room": "Marcar como favorito",
"Star": "Dar estrela",
"Starred_Messages": "Mensagens com estrela",

View File

@ -81,7 +81,6 @@
"error-you-are-last-owner": "Вы последний владелец. Пожалуйста, назначьте нового владельца, прежде чем покинуть чат.",
"error-status-not-allowed": "Статус Невидимый отключён",
"Actions": "Действия",
"activity": "активности",
"Activity": "По активности",
"Add_Reaction": "Добавить реакцию",
"Add_Server": "Добавить сервер",
@ -232,7 +231,6 @@
"Everyone_can_access_this_team": "Каждый может получить доступ к этой Команде",
"Error_uploading": "Ошибка загрузки",
"Expiration_Days": "Срок действия (Дни)",
"Favorite": "Избранное",
"Favorites": "Избранные",
"Files": "Файлы",
"File_description": "Описание файла",
@ -249,9 +247,6 @@
"Forward_to_user": "Перенаправить пользователю",
"Full_table": "Нажмите, чтобы увидеть полную таблицу",
"Generate_New_Link": "Сгенерировать Новую Ссылку",
"Group_by_favorites": "По избранным",
"Group_by_type": "По типу",
"Hide": "Скрыть",
"Has_joined_the_channel": "присоединился к каналу",
"Has_joined_the_conversation": "присоединился к беседе",
"Has_left_the_channel": "покинул канал",
@ -334,7 +329,6 @@
"N_people_reacted": "отреагировало {{n}} человек",
"N_users": "{{n}} пользователи",
"N_channels": "{{n}} каналов",
"name": "имя",
"Name": "Имя",
"Navigation_history": "История навигации",
"Never": "Никогда",
@ -412,7 +406,6 @@
"Reactions_are_disabled": "Реакции отключены",
"Reactions_are_enabled": "Реакции активированы",
"Reactions": "Реакции",
"Read": "Читать",
"Read_External_Permission_Message": "Rocket.Chat необходим доступ к фотографиям, медиа и другим файлам на вашем устройстве",
"Read_External_Permission": "Разрешение на Чтение Медиа",
"Read_Only_Channel": "Канал только для чтения",
@ -507,7 +500,6 @@
"Sign_in_your_server": "Войдите на ваш сервер",
"Sign_Up": "Регистрация",
"Some_field_is_invalid_or_empty": "Некоторые поля недопустимы или пусты",
"Sorting_by": "Сортировка по {{key}}",
"Sound": "Звук",
"Star_room": "В избранное",
"Star": "Отметить",
@ -546,7 +538,6 @@
"unarchive": "разархивировать",
"UNARCHIVE": "РАЗАРХИВИРОВАТЬ",
"Unblock_user": "Разблокировать пользователя",
"Unfavorite": "Удалить из избранного",
"Unfollowed_thread": "Не следить",
"Unmute": "Отменить заглушивание",
"unmuted": "Заглушивание отменено",

View File

@ -79,7 +79,6 @@
"error-user-registration-secret": "Kullanıcı kaydına yalnızca Gizli URL aracılığıyla izin verilir!",
"error-you-are-last-owner": "Son sahibi sizsiniz. Lütfen odadan ayrılmadan önce yeni bir sahip belirleyin.",
"Actions": "İşlemler",
"activity": "etkinlik",
"Activity": "Etkinlik",
"Add_Reaction": "Tepki ekle",
"Add_Server": "Sunucu ekle",
@ -227,7 +226,6 @@
"Everyone_can_access_this_channel": "Bu kanala herkes erişebilir",
"Error_uploading": "Yükleme hatası",
"Expiration_Days": "Geçerlilik Süresi (Gün)",
"Favorite": "Favori",
"Favorites": "Favoriler",
"Files": "Dosyalar",
"File_description": "Dosya açıklaması",
@ -244,9 +242,6 @@
"Forward_to_user": "Kullanıcıya İlet",
"Full_table": "Tam tabloyu görmek için tıklayın",
"Generate_New_Link": "Yeni Bağlantı Oluştur",
"Group_by_favorites": "Favorilere göre grupla",
"Group_by_type": "Türe göre grupla",
"Hide": "Gizle",
"Has_joined_the_channel": "kanala katıldı",
"Has_joined_the_conversation": "sohbete katıldı",
"Has_left_the_channel": "kanaldan ayrıldı",
@ -327,7 +322,6 @@
"My_servers": "Sunucularım",
"N_people_reacted": "{{n}} kişi tepki verdi",
"N_users": "{{n}} kullanıcı",
"name": "isim",
"Name": "İsim",
"Navigation_history": "Gezinti geçmişi",
"Never": "Asla",
@ -405,7 +399,6 @@
"Reactions_are_disabled": "Tepkiler devre dışı bırakıldı",
"Reactions_are_enabled": "Tepkiler etkinleştirildi",
"Reactions": "Tepkiler",
"Read": "Oku",
"Read_External_Permission_Message": "Rocket.Chat'in cihazınızdaki fotoğraflara, medyaya ve dosyalara erişmesi gerekiyor",
"Read_External_Permission": "Medya Okuma İzni ",
"Read_Only_Channel": "Yazma Kısıtlı Kanal",
@ -498,7 +491,6 @@
"Sign_in_your_server": "Sunucunuzda oturum açın",
"Sign_Up": "Kaydol",
"Some_field_is_invalid_or_empty": "Bazı alanlar geçersiz veya boş",
"Sorting_by": "{{key}} göre sıralanıyor",
"Sound": "Ses",
"Star_room": "Odayı Yıldızla",
"Star": "Yıldızla",
@ -537,7 +529,6 @@
"unarchive": "arşivden çıkar",
"UNARCHIVE": "ARŞİVDEN ÇIKAR",
"Unblock_user": "Kullanıcının engelini kaldır",
"Unfavorite": "Favorilerden Çıkar",
"Unfollowed_thread": "Takip edilmeyen başlık",
"Unmute": "Sesi Aç",
"unmuted": "Sesi Açıldı",

View File

@ -79,7 +79,6 @@
"error-user-registration-secret": "只能透过加密网址进行用戶注册",
"error-you-are-last-owner": "您是最后的拥有者。请删除此人之前设置一个新的拥有者。",
"Actions": "操作",
"activity": "活动时间",
"Activity": "按活动时间排列",
"Add_Reaction": "增加表情貼",
"Add_Server": "創建服务器",
@ -227,7 +226,6 @@
"Everyone_can_access_this_channel": "每个人都可以访问此频道",
"Error_uploading": "错误上传",
"Expiration_Days": "到期 (日)",
"Favorite": "收藏",
"Favorites": "收藏",
"Files": "文件",
"File_description": "文件描述",
@ -244,9 +242,6 @@
"Forward_to_user": "转发给用戶",
"Full_table": "点击以查看完整表格",
"Generate_New_Link": "产生新的链接",
"Group_by_favorites": "收藏优先",
"Group_by_type": "以类型分组",
"Hide": "隐藏",
"Has_joined_the_channel": "已加入频道",
"Has_joined_the_conversation": "已经加入此对话",
"Has_left_the_channel": "已离开频道",
@ -324,7 +319,6 @@
"My_servers": "我的服务器",
"N_people_reacted": "{{n}} 人回复",
"N_users": "{{n}} 位用户",
"name": "名称",
"Name": "名称",
"Navigation_history": "浏览历史记录",
"Never": "从不",
@ -402,7 +396,6 @@
"Reactions_are_disabled": "表情貼被禁用",
"Reactions_are_enabled": "表情貼被启用",
"Reactions": "表情貼",
"Read": "读取",
"Read_External_Permission_Message": "Rocket.Chat 需要存取您装置上的相片、多媒体及文件",
"Read_External_Permission": "读取媒体权限",
"Read_Only_Channel": "只读频道",
@ -496,7 +489,6 @@
"Sign_in_your_server": "登录你的服务器",
"Sign_Up": "注册",
"Some_field_is_invalid_or_empty": "某些字段无效或为空",
"Sorting_by": "按{{key}}排序",
"Sound": "声音",
"Star_room": "将聊天室标记",
"Star": "标记",
@ -535,7 +527,6 @@
"unarchive": "取消封存",
"UNARCHIVE": "取消封存",
"Unblock_user": "解除屏蔽",
"Unfavorite": "取消收藏",
"Unfollowed_thread": "取消追踪讨论",
"Unmute": "取消静音",
"unmuted": "静音状态",

View File

@ -79,7 +79,6 @@
"error-user-registration-secret": "只能透過加密網址進行使用者註冊",
"error-you-are-last-owner": "您是最後的擁有者。請刪除此人之前設置一個新的擁有者。",
"Actions": "操作",
"activity": "活動時間",
"Activity": "以活動時間排序",
"Add_Reaction": "增加表情貼",
"Add_Server": "新增伺服器",
@ -227,7 +226,6 @@
"Everyone_can_access_this_channel": "所有人皆可存取此頻道",
"Error_uploading": "錯誤上傳",
"Expiration_Days": "到期 (日)",
"Favorite": "我的最愛",
"Favorites": "我的最愛",
"Files": "檔案",
"File_description": "檔案描述",
@ -244,9 +242,6 @@
"Forward_to_user": "轉發給使用者",
"Full_table": "點擊以查看完整表格",
"Generate_New_Link": "產生新的連結",
"Group_by_favorites": "我的最愛優先",
"Group_by_type": "以類型分組",
"Hide": "隱藏",
"Has_joined_the_channel": "已加入頻道",
"Has_joined_the_conversation": "已經加入此對話",
"Has_left_the_channel": "已離開頻道",
@ -325,7 +320,6 @@
"My_servers": "我的伺服器",
"N_people_reacted": "{{n}} 人回复",
"N_users": "{{n}} 位使用者",
"name": "名稱",
"Name": "名稱",
"Navigation_history": "瀏覽歷史記錄",
"Never": "從不",
@ -403,7 +397,6 @@
"Reactions_are_disabled": "表情貼被禁用",
"Reactions_are_enabled": "表情貼被啟用",
"Reactions": "表情貼",
"Read": "讀取",
"Read_External_Permission_Message": "Rocket.Chat 需要存取您裝置上的相片、多媒體及檔案",
"Read_External_Permission": "讀取媒體權限",
"Read_Only_Channel": "唯讀頻道",
@ -497,7 +490,6 @@
"Sign_in_your_server": "登錄你的伺服器",
"Sign_Up": "註冊",
"Some_field_is_invalid_or_empty": "某些字段無效或為空",
"Sorting_by": "以{{key}}排序",
"Sound": "聲音",
"Star_room": "標記聊天室",
"Star": "標記",
@ -536,7 +528,6 @@
"unarchive": "取消封存",
"UNARCHIVE": "取消封存",
"Unblock_user": "解除封鎖",
"Unfavorite": "取消最愛",
"Unfollowed_thread": "取消追蹤討論",
"Unmute": "取消靜音",
"unmuted": "靜音狀態",

View File

@ -1,11 +1,12 @@
import React from 'react';
import { Animated, Text, View } from 'react-native';
import { Animated, View } from 'react-native';
import { RectButton } from 'react-native-gesture-handler';
import I18n, { isRTL } from '../../i18n';
import styles, { ACTION_WIDTH, LONG_SWIPE } from './styles';
import { isRTL } from '../../i18n';
import { CustomIcon } from '../../lib/Icons';
import { themes } from '../../constants/colors';
import { DISPLAY_MODE_CONDENSED } from '../../constants/constantDisplayMode';
import styles, { ACTION_WIDTH, LONG_SWIPE, ROW_HEIGHT_CONDENSED } from './styles';
interface ILeftActions {
theme: string;
@ -13,6 +14,7 @@ interface ILeftActions {
isRead: boolean;
width: number;
onToggleReadPress(): void;
displayMode: string;
}
interface IRightActions {
@ -22,11 +24,14 @@ interface IRightActions {
width: number;
toggleFav(): void;
onHidePress(): void;
displayMode: string;
}
const reverse = new Animated.Value(isRTL() ? -1 : 1);
const CONDENSED_ICON_SIZE = 24;
const EXPANDED_ICON_SIZE = 28;
export const LeftActions = React.memo(({ theme, transX, isRead, width, onToggleReadPress }: ILeftActions) => {
export const LeftActions = React.memo(({ theme, transX, isRead, width, onToggleReadPress, displayMode }: ILeftActions) => {
const translateX = Animated.multiply(
transX.interpolate({
inputRange: [0, ACTION_WIDTH],
@ -34,6 +39,10 @@ export const LeftActions = React.memo(({ theme, transX, isRead, width, onToggleR
}),
reverse
);
const isCondensed = displayMode === DISPLAY_MODE_CONDENSED;
const viewHeight = isCondensed ? { height: ROW_HEIGHT_CONDENSED } : null;
return (
<View style={[styles.actionsContainer, styles.actionLeftContainer]} pointerEvents='box-none'>
<Animated.View
@ -44,14 +53,16 @@ export const LeftActions = React.memo(({ theme, transX, isRead, width, onToggleR
width,
transform: [{ translateX }],
backgroundColor: themes[theme].tintColor
}
},
viewHeight
]}>
<View style={styles.actionLeftButtonContainer}>
<View style={[styles.actionLeftButtonContainer, viewHeight]}>
<RectButton style={styles.actionButton} onPress={onToggleReadPress}>
<>
<CustomIcon size={20} name={isRead ? 'flag' : 'check'} color='white' />
<Text style={[styles.actionText, { color: themes[theme].buttonText }]}>{I18n.t(isRead ? 'Unread' : 'Read')}</Text>
</>
<CustomIcon
size={isCondensed ? CONDENSED_ICON_SIZE : EXPANDED_ICON_SIZE}
name={isRead ? 'flag' : 'check'}
color={themes[theme].buttonText}
/>
</RectButton>
</View>
</Animated.View>
@ -59,7 +70,8 @@ export const LeftActions = React.memo(({ theme, transX, isRead, width, onToggleR
);
});
export const RightActions = React.memo(({ transX, favorite, width, toggleFav, onHidePress, theme }: IRightActions) => {
export const RightActions = React.memo(
({ transX, favorite, width, toggleFav, onHidePress, theme, displayMode }: IRightActions) => {
const translateXFav = Animated.multiply(
transX.interpolate({
inputRange: [-width / 2, -ACTION_WIDTH * 2, 0],
@ -74,16 +86,12 @@ export const RightActions = React.memo(({ transX, favorite, width, toggleFav, on
}),
reverse
);
const isCondensed = displayMode === DISPLAY_MODE_CONDENSED;
const viewHeight = isCondensed ? { height: ROW_HEIGHT_CONDENSED } : null;
return (
<View
style={{
position: 'absolute',
left: 0,
right: 0,
height: 75,
flexDirection: 'row'
}}
pointerEvents='box-none'>
<View style={[styles.actionsLeftContainer, viewHeight]} pointerEvents='box-none'>
<Animated.View
style={[
styles.actionRightButtonContainer,
@ -91,15 +99,15 @@ export const RightActions = React.memo(({ transX, favorite, width, toggleFav, on
width,
transform: [{ translateX: translateXFav }],
backgroundColor: themes[theme].hideBackground
}
},
viewHeight
]}>
<RectButton style={[styles.actionButton, { backgroundColor: themes[theme].favoriteBackground }]} onPress={toggleFav}>
<>
<CustomIcon size={20} name={favorite ? 'star-filled' : 'star'} color={themes[theme].buttonText} />
<Text style={[styles.actionText, { color: themes[theme].buttonText }]}>
{I18n.t(favorite ? 'Unfavorite' : 'Favorite')}
</Text>
</>
<CustomIcon
size={isCondensed ? CONDENSED_ICON_SIZE : EXPANDED_ICON_SIZE}
name={favorite ? 'star-filled' : 'star'}
color={themes[theme].buttonText}
/>
</RectButton>
</Animated.View>
<Animated.View
@ -108,15 +116,18 @@ export const RightActions = React.memo(({ transX, favorite, width, toggleFav, on
{
width,
transform: [{ translateX: translateXHide }]
}
},
isCondensed && { height: ROW_HEIGHT_CONDENSED }
]}>
<RectButton style={[styles.actionButton, { backgroundColor: themes[theme].hideBackground }]} onPress={onHidePress}>
<>
<CustomIcon size={20} name='unread-on-top-disabled' color={themes[theme].buttonText} />
<Text style={[styles.actionText, { color: themes[theme].buttonText }]}>{I18n.t('Hide')}</Text>
</>
<CustomIcon
size={isCondensed ? CONDENSED_ICON_SIZE : EXPANDED_ICON_SIZE}
name='unread-on-top-disabled'
color={themes[theme].buttonText}
/>
</RectButton>
</Animated.View>
</View>
);
});
}
);

View File

@ -0,0 +1,63 @@
import React from 'react';
import { View } from 'react-native';
import PropTypes from 'prop-types';
import Avatar from '../../containers/Avatar';
import { DISPLAY_MODE_CONDENSED, DISPLAY_MODE_EXPANDED } from '../../constants/constantDisplayMode';
import TypeIcon from './TypeIcon';
import styles from './styles';
const IconOrAvatar = ({
avatar,
type,
rid,
showAvatar,
prid,
status,
isGroupChat,
teamMain,
showLastMessage,
theme,
displayMode
}) => {
if (showAvatar) {
return (
<Avatar text={avatar} size={displayMode === DISPLAY_MODE_CONDENSED ? 36 : 48} type={type} style={styles.avatar} rid={rid} />
);
}
if (displayMode === DISPLAY_MODE_EXPANDED && showLastMessage) {
return (
<View style={styles.typeIcon}>
<TypeIcon
type={type}
prid={prid}
status={status}
isGroupChat={isGroupChat}
theme={theme}
teamMain={teamMain}
size={24}
style={{ marginRight: 12 }}
/>
</View>
);
}
return null;
};
IconOrAvatar.propTypes = {
avatar: PropTypes.string,
type: PropTypes.string,
theme: PropTypes.string,
rid: PropTypes.string,
showAvatar: PropTypes.bool,
displayMode: PropTypes.string,
prid: PropTypes.string,
status: PropTypes.string,
isGroupChat: PropTypes.bool,
teamMain: PropTypes.bool,
showLastMessage: PropTypes.bool
};
export default IconOrAvatar;

View File

@ -80,6 +80,7 @@ const LastMessage = React.memo(
numberOfLines={2}
preview
theme={theme}
testID='room-item-last-message'
/>
),
arePropsEqual

View File

@ -11,6 +11,7 @@ import UpdatedAt from './UpdatedAt';
import Touchable from './Touchable';
import Tag from './Tag';
import I18n from '../../i18n';
import { DISPLAY_MODE_EXPANDED } from '../../constants/constantDisplayMode';
interface IRoomItem {
rid: string;
@ -57,6 +58,8 @@ interface IRoomItem {
hideChannel(): void;
autoJoin: boolean;
size?: number;
showAvatar: boolean;
displayMode: string;
}
const RoomItem = ({
@ -95,7 +98,9 @@ const RoomItem = ({
toggleRead,
hideChannel,
teamMain,
autoJoin
autoJoin,
showAvatar,
displayMode
}: IRoomItem) => (
<Touchable
onPress={onPress}
@ -111,12 +116,28 @@ const RoomItem = ({
type={type}
theme={theme}
isFocused={isFocused}
swipeEnabled={swipeEnabled}>
<Wrapper accessibilityLabel={accessibilityLabel} avatar={avatar} avatarSize={avatarSize} type={type} theme={theme} rid={rid}>
{showLastMessage ? (
swipeEnabled={swipeEnabled}
displayMode={displayMode}>
<Wrapper
accessibilityLabel={accessibilityLabel}
avatar={avatar}
avatarSize={avatarSize}
type={type}
theme={theme}
rid={rid}
prid={prid}
status={status}
isGroupChat={isGroupChat}
teamMain={teamMain}
displayMode={displayMode}
showAvatar={showAvatar}
showLastMessage={showLastMessage}>
{showLastMessage && displayMode === DISPLAY_MODE_EXPANDED ? (
<>
<View style={styles.titleContainer}>
{showAvatar ? (
<TypeIcon type={type} prid={prid} status={status} isGroupChat={isGroupChat} theme={theme} teamMain={teamMain} />
) : null}
<Title name={name} theme={theme} hideUnreadStatus={hideUnreadStatus} alert={alert} />
{autoJoin ? <Tag testID='auto-join-tag' name={I18n.t('Auto-join')} /> : null}
<UpdatedAt date={date} theme={theme} hideUnreadStatus={hideUnreadStatus} alert={alert} />
@ -143,9 +164,20 @@ const RoomItem = ({
</>
) : (
<View style={[styles.titleContainer, styles.flex]}>
<TypeIcon type={type} prid={prid} status={status} isGroupChat={isGroupChat} theme={theme} teamMain={teamMain} />
<TypeIcon
type={type}
prid={prid}
status={status}
isGroupChat={isGroupChat}
theme={theme}
teamMain={teamMain}
size={22}
style={{ marginRight: 8 }}
/>
<Title name={name} theme={theme} hideUnreadStatus={hideUnreadStatus} alert={alert} />
{autoJoin ? <Tag name={I18n.t('Auto-join')} /> : null}
<View style={styles.wrapUpdatedAndBadge}>
<UpdatedAt date={date} theme={theme} hideUnreadStatus={hideUnreadStatus} alert={alert} />
<UnreadBadge
unread={unread}
userMentions={userMentions}
@ -155,6 +187,7 @@ const RoomItem = ({
tunreadGroup={tunreadGroup}
/>
</View>
</View>
)}
</Wrapper>
</Touchable>

View File

@ -24,6 +24,7 @@ interface ITouchableProps {
theme: string;
isFocused: boolean;
swipeEnabled: boolean;
displayMode: string;
}
class Touchable extends React.Component<ITouchableProps, any> {
@ -227,7 +228,7 @@ class Touchable extends React.Component<ITouchableProps, any> {
};
render() {
const { testID, isRead, width, favorite, children, theme, isFocused, swipeEnabled } = this.props;
const { testID, isRead, width, favorite, children, theme, isFocused, swipeEnabled, displayMode } = this.props;
return (
<LongPressGestureHandler onHandlerStateChange={this.onLongPressHandlerStateChange}>
@ -244,6 +245,7 @@ class Touchable extends React.Component<ITouchableProps, any> {
width={width}
onToggleReadPress={this.onToggleReadPress}
theme={theme}
displayMode={displayMode}
/>
<RightActions
transX={this.transXReverse}
@ -252,6 +254,7 @@ class Touchable extends React.Component<ITouchableProps, any> {
toggleFav={this.toggleFav}
onHidePress={this.onHidePress}
theme={theme}
displayMode={displayMode}
/>
<Animated.View
style={{

View File

@ -9,10 +9,19 @@ interface ITypeIcon {
isGroupChat: boolean;
teamMain: boolean;
theme?: string;
size?: number;
style?: object;
}
const TypeIcon = React.memo(({ type, prid, status, isGroupChat, teamMain }: ITypeIcon) => (
<RoomTypeIcon type={prid ? 'discussion' : type} isGroupChat={isGroupChat} status={status} teamMain={teamMain} />
const TypeIcon = React.memo(({ type, prid, status, isGroupChat, teamMain, size, style }: ITypeIcon) => (
<RoomTypeIcon
type={prid ? 'discussion' : type}
isGroupChat={isGroupChat}
status={status}
teamMain={teamMain}
size={size}
style={style}
/>
));
export default TypeIcon;

View File

@ -1,9 +1,10 @@
import React from 'react';
import { View } from 'react-native';
import styles from './styles';
import { themes } from '../../constants/colors';
import Avatar from '../../containers/Avatar';
import { DISPLAY_MODE_CONDENSED } from '../../constants/constantDisplayMode';
import IconOrAvatar from './IconOrAvatar';
import styles from './styles';
interface IWrapper {
accessibilityLabel: string;
@ -13,17 +14,27 @@ interface IWrapper {
theme: string;
rid: string;
children: JSX.Element;
displayMode: string;
prid: string;
showLastMessage: boolean;
status: string;
isGroupChat: boolean;
teamMain: boolean;
showAvatar: boolean;
}
const Wrapper = ({ accessibilityLabel, avatar, avatarSize, type, theme, rid, children }: IWrapper) => (
<View style={styles.container} accessibilityLabel={accessibilityLabel}>
<Avatar text={avatar} size={avatarSize} type={type} style={styles.avatar} rid={rid} />
const Wrapper = ({ accessibilityLabel, theme, children, displayMode, ...props }: IWrapper) => (
<View
style={[styles.container, displayMode === DISPLAY_MODE_CONDENSED && styles.containerCondensed]}
accessibilityLabel={accessibilityLabel}>
<IconOrAvatar theme={theme} displayMode={displayMode} {...props} />
<View
style={[
styles.centerContainer,
{
borderColor: themes[theme].separatorColor
}
},
displayMode === DISPLAY_MODE_CONDENSED && styles.condensedPaddingVertical
]}>
{children}
</View>

View File

@ -2,12 +2,11 @@ import React from 'react';
import { connect } from 'react-redux';
import I18n from '../../i18n';
import { ROW_HEIGHT } from './styles';
import { ROW_HEIGHT, ROW_HEIGHT_CONDENSED } from './styles';
import { formatDate } from '../../utils/room';
import RoomItem from './RoomItem';
export { ROW_HEIGHT };
export { ROW_HEIGHT, ROW_HEIGHT_CONDENSED };
interface IRoomItemContainerProps {
item: any;
showLastMessage: boolean;
@ -32,9 +31,22 @@ interface IRoomItemContainerProps {
getIsRead: Function;
swipeEnabled: boolean;
autoJoin: boolean;
showAvatar: boolean;
displayMode: string;
}
const attrs = ['width', 'status', 'connected', 'theme', 'isFocused', 'forceUpdate', 'showLastMessage', 'autoJoin'];
const attrs = [
'width',
'status',
'connected',
'theme',
'isFocused',
'forceUpdate',
'showLastMessage',
'autoJoin',
'showAvatar',
'displayMode'
];
class RoomItemContainer extends React.Component<IRoomItemContainerProps, any> {
private mounted: boolean;
@ -137,7 +149,9 @@ class RoomItemContainer extends React.Component<IRoomItemContainerProps, any> {
username,
useRealName,
swipeEnabled,
autoJoin
autoJoin,
showAvatar,
displayMode
} = this.props;
const name = getRoomTitle(item);
const testID = `rooms-list-view-item-${name}`;
@ -200,6 +214,8 @@ class RoomItemContainer extends React.Component<IRoomItemContainerProps, any> {
swipeEnabled={swipeEnabled}
teamMain={item.teamMain}
autoJoin={autoJoin}
showAvatar={showAvatar}
displayMode={displayMode}
/>
);
}

View File

@ -3,6 +3,7 @@ import { PixelRatio, StyleSheet } from 'react-native';
import sharedStyles from '../../views/Styles';
export const ROW_HEIGHT = 75 * PixelRatio.getFontScale();
export const ROW_HEIGHT_CONDENSED = 60 * PixelRatio.getFontScale();
export const ACTION_WIDTH = 80;
export const SMALL_SWIPE = ACTION_WIDTH / 2;
export const LONG_SWIPE = ACTION_WIDTH * 3;
@ -17,6 +18,12 @@ export default StyleSheet.create<any>({
paddingLeft: 14,
height: ROW_HEIGHT
},
containerCondensed: {
height: ROW_HEIGHT_CONDENSED
},
condensedPaddingVertical: {
paddingVertical: 20
},
centerContainer: {
flex: 1,
paddingVertical: 10,
@ -37,6 +44,9 @@ export default StyleSheet.create<any>({
flexDirection: 'row',
alignItems: 'flex-start'
},
wrapUpdatedAndBadge: {
alignItems: 'flex-end'
},
titleContainer: {
width: '100%',
flexDirection: 'row',
@ -72,11 +82,12 @@ export default StyleSheet.create<any>({
right: 0,
height: ROW_HEIGHT
},
actionText: {
fontSize: 15,
justifyContent: 'center',
marginTop: 4,
...sharedStyles.textSemibold
actionsLeftContainer: {
flexDirection: 'row',
position: 'absolute',
left: 0,
right: 0,
height: ROW_HEIGHT
},
actionLeftButtonContainer: {
position: 'absolute',
@ -107,5 +118,9 @@ export default StyleSheet.create<any>({
fontSize: 13,
paddingHorizontal: 4,
...sharedStyles.textSemibold
},
typeIcon: {
height: ROW_HEIGHT,
justifyContent: 'center'
}
});

View File

@ -8,7 +8,6 @@ const initialState = {
searchText: '',
showServerDropdown: false,
closeServerDropdown: false,
showSortDropdown: false,
showSearchHeader: false
};
@ -56,16 +55,6 @@ export default function login(state = initialState, action) {
...state,
showServerDropdown: !state.showServerDropdown
};
case types.ROOMS.CLOSE_SORT_DROPDOWN:
return {
...state,
closeSortDropdown: !state.closeSortDropdown
};
case types.ROOMS.TOGGLE_SORT_DROPDOWN:
return {
...state,
showSortDropdown: !state.showSortDropdown
};
case types.ROOMS.OPEN_SEARCH_HEADER:
return {
...state,

View File

@ -1,10 +1,13 @@
import { SORT_PREFERENCES } from '../actions/actionsTypes';
import { DISPLAY_MODE_EXPANDED } from '../constants/constantDisplayMode';
const initialState = {
sortBy: 'activity',
groupByType: false,
showFavorites: false,
showUnread: false
showUnread: false,
showAvatar: true,
displayMode: DISPLAY_MODE_EXPANDED
};
export default (state = initialState, action) => {

View File

@ -38,6 +38,9 @@ import ProfileView from '../views/ProfileView';
import UserPreferencesView from '../views/UserPreferencesView';
import UserNotificationPrefView from '../views/UserNotificationPreferencesView';
// Display Preferences View
import DisplayPrefsView from '../views/DisplayPrefsView';
// Settings Stack
import SettingsView from '../views/SettingsView';
import SecurityPrivacyView from '../views/SecurityPrivacyView';
@ -220,6 +223,18 @@ const AdminPanelStackNavigator = () => {
);
};
// DisplayPreferenceNavigator
const DisplayPrefStack = createStackNavigator();
const DisplayPrefStackNavigator = () => {
const { theme } = React.useContext(ThemeContext);
return (
<DisplayPrefStack.Navigator screenOptions={{ ...defaultHeader, ...themedHeader(theme), ...StackAnimation }}>
<DisplayPrefStack.Screen name='DisplayPrefsView' component={DisplayPrefsView} />
</DisplayPrefStack.Navigator>
);
};
// DrawerNavigator
const Drawer = createDrawerNavigator();
const DrawerNavigator = () => {
@ -236,6 +251,7 @@ const DrawerNavigator = () => {
<Drawer.Screen name='ProfileStackNavigator' component={ProfileStackNavigator} />
<Drawer.Screen name='SettingsStackNavigator' component={SettingsStackNavigator} />
<Drawer.Screen name='AdminPanelStackNavigator' component={AdminPanelStackNavigator} />
<Drawer.Screen name='DisplayPrefStackNavigator' component={DisplayPrefStackNavigator} />
</Drawer.Navigator>
);
};

View File

@ -33,6 +33,7 @@ import TeamChannelsView from '../../views/TeamChannelsView';
import MarkdownTableView from '../../views/MarkdownTableView';
import ReadReceiptsView from '../../views/ReadReceiptView';
import ProfileView from '../../views/ProfileView';
import DisplayPrefsView from '../../views/DisplayPrefsView';
import SettingsView from '../../views/SettingsView';
import LanguageView from '../../views/LanguageView';
import ThemeView from '../../views/ThemeView';
@ -204,6 +205,7 @@ const ModalStackNavigator = React.memo(({ navigation }) => {
component={ProfileView}
options={props => ProfileView.navigationOptions({ ...props, isMasterDetail: true })}
/>
<ModalStack.Screen name='DisplayPrefsView' component={DisplayPrefsView} />
<ModalStack.Screen
name='AdminPanelView'
component={AdminPanelView}

View File

@ -66,15 +66,18 @@ export default {
RL_TOGGLE_READ_F: 'rl_toggle_read_f',
RL_HIDE_CHANNEL: 'rl_hide_channel',
RL_HIDE_CHANNEL_F: 'rl_hide_channel_f',
RL_TOGGLE_SORT_DROPDOWN: 'rl_toggle_sort_dropdown',
RL_SORT_CHANNELS_BY_NAME: 'rl_sort_channels_by_name',
RL_SORT_CHANNELS_BY_ACTIVITY: 'rl_sort_channels_by_activity',
RL_SORT_CHANNELS_F: 'rl_sort_channels_f',
RL_GROUP_CHANNELS_BY_TYPE: 'rl_group_channels_by_type',
RL_GROUP_CHANNELS_BY_FAVORITE: 'rl_group_channels_by_favorite',
RL_GROUP_CHANNELS_BY_UNREAD: 'rl_group_channels_by_unread',
RL_CREATE_NEW_WORKSPACE: 'rl_create_new_workspace',
// DISPLAY PREFERENCES VIEW
DP_SORT_CHANNELS_BY_NAME: 'dp_sort_channels_by_name',
DP_SORT_CHANNELS_BY_ACTIVITY: 'dp_sort_channels_by_activity',
DP_GROUP_CHANNELS_BY_TYPE: 'dp_group_channels_by_type',
DP_GROUP_CHANNELS_BY_FAVORITE: 'dp_group_channels_by_favorite',
DP_GROUP_CHANNELS_BY_UNREAD: 'dp_group_channels_by_unread',
DP_TOGGLE_AVATAR: 'dp_toggle_avatar',
DP_DISPLAY_EXPANDED: 'dp_display_expanded',
DP_DISPLAY_CONDENSED: 'dp_display_condensed',
// QUEUE LIST VIEW
QL_GO_ROOM: 'ql_go_room',

View File

@ -0,0 +1,192 @@
import React, { useEffect } from 'react';
import PropTypes from 'prop-types';
import { Switch } from 'react-native';
import { RadioButton } from 'react-native-ui-lib';
import { useDispatch, useSelector } from 'react-redux';
import { setPreference } from '../actions/sortPreferences';
import RocketChat from '../lib/rocketchat';
import StatusBar from '../containers/StatusBar';
import I18n from '../i18n';
import * as List from '../containers/List';
import { useTheme } from '../theme';
import { themes } from '../constants/colors';
import * as HeaderButton from '../containers/HeaderButton';
import SafeAreaView from '../containers/SafeAreaView';
import { ICON_SIZE } from '../containers/List/constants';
import log, { events, logEvent } from '../utils/log';
import { DISPLAY_MODE_CONDENSED, DISPLAY_MODE_EXPANDED } from '../constants/constantDisplayMode';
const DisplayPrefsView = props => {
const { theme } = useTheme();
const { sortBy, groupByType, showFavorites, showUnread, showAvatar, displayMode } = useSelector(state => state.sortPreferences);
const dispatch = useDispatch();
useEffect(() => {
const { navigation, isMasterDetail } = props;
navigation.setOptions({
title: I18n.t('Display'),
headerLeft: () =>
isMasterDetail ? (
<HeaderButton.CloseModal navigation={navigation} testID='display-view-close' />
) : (
<HeaderButton.Drawer navigation={navigation} testID='display-view-drawer' />
)
});
}, []);
const setSortPreference = async param => {
try {
dispatch(setPreference(param));
await RocketChat.saveSortPreference(param);
} catch (e) {
log(e);
}
};
const sortByName = async () => {
logEvent(events.DP_SORT_CHANNELS_BY_NAME);
await setSortPreference({ sortBy: 'alphabetical' });
};
const sortByActivity = async () => {
logEvent(events.DP_SORT_CHANNELS_BY_ACTIVITY);
await setSortPreference({ sortBy: 'activity' });
};
const toggleGroupByType = async () => {
logEvent(events.DP_GROUP_CHANNELS_BY_TYPE);
await setSortPreference({ groupByType: !groupByType });
};
const toggleGroupByFavorites = async () => {
logEvent(events.DP_GROUP_CHANNELS_BY_FAVORITE);
await setSortPreference({ showFavorites: !showFavorites });
};
const toggleUnread = async () => {
logEvent(events.DP_GROUP_CHANNELS_BY_UNREAD);
await setSortPreference({ showUnread: !showUnread });
};
const toggleAvatar = async () => {
logEvent(events.DP_TOGGLE_AVATAR);
await setSortPreference({ showAvatar: !showAvatar });
};
const displayExpanded = async () => {
logEvent(events.DP_DISPLAY_EXPANDED);
await setSortPreference({ displayMode: DISPLAY_MODE_EXPANDED });
};
const displayCondensed = async () => {
logEvent(events.DP_DISPLAY_CONDENSED);
await setSortPreference({ displayMode: DISPLAY_MODE_CONDENSED });
};
const renderCheckBox = value => (
<List.Icon name={value ? 'checkbox-checked' : 'checkbox-unchecked'} color={value ? themes[theme].actionTintColor : null} />
);
const renderAvatarSwitch = value => (
<Switch value={value} onValueChange={() => toggleAvatar()} testID='display-pref-view-avatar-switch' />
);
const renderRadio = value => (
<RadioButton
selected={!!value}
color={value ? themes[theme].actionTintColor : themes[theme].auxiliaryText}
size={ICON_SIZE}
/>
);
return (
<SafeAreaView>
<StatusBar />
<List.Container testID='display-view-list'>
<List.Section title='Display'>
<List.Separator />
<List.Item
left={() => <List.Icon name='view-extended' />}
title='Expanded'
testID='display-pref-view-expanded'
right={() => renderRadio(displayMode === DISPLAY_MODE_EXPANDED)}
onPress={displayExpanded}
/>
<List.Separator />
<List.Item
left={() => <List.Icon name='view-medium' />}
title='Condensed'
testID='display-pref-view-condensed'
right={() => renderRadio(displayMode === DISPLAY_MODE_CONDENSED)}
onPress={displayCondensed}
/>
<List.Separator />
<List.Item
left={() => <List.Icon name='avatar' />}
title='Avatars'
testID='display-pref-view-avatars'
right={() => renderAvatarSwitch(showAvatar)}
/>
<List.Separator />
</List.Section>
<List.Section title='Sort_by'>
<List.Separator />
<List.Item
title='Activity'
testID='display-pref-view-activity'
left={() => <List.Icon name='clock' />}
onPress={sortByActivity}
right={() => renderRadio(sortBy === 'activity')}
/>
<List.Separator />
<List.Item
title='Name'
testID='display-pref-view-name'
left={() => <List.Icon name='sort-az' />}
onPress={sortByName}
right={() => renderRadio(sortBy === 'alphabetical')}
/>
<List.Separator />
</List.Section>
<List.Section title='Group_by'>
<List.Separator />
<List.Item
title='Unread_on_top'
testID='display-pref-view-unread'
left={() => <List.Icon name='flag' />}
onPress={toggleUnread}
right={() => renderCheckBox(showUnread)}
/>
<List.Separator />
<List.Item
title='Favorites'
testID='display-pref-view-favorites'
left={() => <List.Icon name='star' />}
onPress={toggleGroupByFavorites}
right={() => renderCheckBox(showFavorites)}
/>
<List.Separator />
<List.Item
title='Types'
testID='display-pref-view-types'
left={() => <List.Icon name='group-by-type' />}
onPress={toggleGroupByType}
right={() => renderCheckBox(groupByType)}
/>
<List.Separator />
</List.Section>
</List.Container>
</SafeAreaView>
);
};
DisplayPrefsView.propTypes = {
navigation: PropTypes.object,
isMasterDetail: PropTypes.bool
};
export default DisplayPrefsView;

View File

@ -2,12 +2,7 @@ import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import {
closeServerDropdown,
closeSortDropdown,
setSearch as setSearchAction,
toggleServerDropdown
} from '../../../actions/rooms';
import { toggleServerDropdown, closeServerDropdown, setSearch as setSearchAction } from '../../../actions/rooms';
import { withTheme } from '../../../theme';
import EventEmitter from '../../../utils/events';
import { KEY_COMMAND, handleCommandOpenServerDropdown } from '../../../commands';
@ -18,7 +13,6 @@ import Header from './Header';
class RoomsListHeaderView extends PureComponent {
static propTypes = {
showServerDropdown: PropTypes.bool,
showSortDropdown: PropTypes.bool,
showSearchHeader: PropTypes.bool,
serverName: PropTypes.string,
connecting: PropTypes.bool,
@ -28,7 +22,6 @@ class RoomsListHeaderView extends PureComponent {
server: PropTypes.string,
open: PropTypes.func,
close: PropTypes.func,
closeSort: PropTypes.func,
setSearch: PropTypes.func
};
@ -58,14 +51,9 @@ class RoomsListHeaderView extends PureComponent {
onPress = () => {
logEvent(events.RL_TOGGLE_SERVER_DROPDOWN);
const { showServerDropdown, showSortDropdown, close, open, closeSort } = this.props;
const { showServerDropdown, close, open } = this.props;
if (showServerDropdown) {
close();
} else if (showSortDropdown) {
closeSort();
setTimeout(() => {
open();
}, 300);
} else {
open();
}
@ -93,7 +81,6 @@ class RoomsListHeaderView extends PureComponent {
const mapStateToProps = state => ({
showServerDropdown: state.rooms.showServerDropdown,
showSortDropdown: state.rooms.showSortDropdown,
showSearchHeader: state.rooms.showSearchHeader,
connecting: state.meteor.connecting || state.server.loading,
connected: state.meteor.connected,
@ -105,7 +92,6 @@ const mapStateToProps = state => ({
const mapDispatchtoProps = dispatch => ({
close: () => dispatch(closeServerDropdown()),
open: () => dispatch(toggleServerDropdown()),
closeSort: () => dispatch(closeSortDropdown()),
setSearch: searchText => dispatch(setSearchAction(searchText))
});

View File

@ -2,16 +2,13 @@ import React from 'react';
import PropTypes from 'prop-types';
import { withTheme } from '../../../theme';
import I18n from '../../../i18n';
import * as List from '../../../containers/List';
import { E2E_BANNER_TYPE } from '../../../lib/encryption/constants';
import { themes } from '../../../constants/colors';
import OmnichannelStatus from '../../../ee/omnichannel/containers/OmnichannelStatus';
const ListHeader = React.memo(
({ searching, sortBy, toggleSort, goEncryption, goQueue, queueSize, inquiryEnabled, encryptionBanner, user, theme }) => {
const sortTitle = I18n.t('Sorting_by', { key: I18n.t(sortBy === 'alphabetical' ? 'name' : 'activity') });
({ searching, goEncryption, goQueue, queueSize, inquiryEnabled, encryptionBanner, user, theme }) => {
if (searching) {
return null;
}
@ -36,13 +33,6 @@ const ListHeader = React.memo(
<List.Separator />
</>
) : null}
<List.Item
title={sortTitle}
left={() => <List.Icon name='sort' />}
color={themes[theme].auxiliaryText}
onPress={toggleSort}
translateTitle={false}
/>
<List.Separator />
<OmnichannelStatus
searching={searching}
@ -58,8 +48,6 @@ const ListHeader = React.memo(
ListHeader.propTypes = {
searching: PropTypes.bool,
sortBy: PropTypes.string,
toggleSort: PropTypes.func,
goEncryption: PropTypes.func,
goQueue: PropTypes.func,
queueSize: PropTypes.number,

View File

@ -1,207 +0,0 @@
import React, { PureComponent } from 'react';
import { Animated, Easing, TouchableWithoutFeedback } from 'react-native';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { withSafeAreaInsets } from 'react-native-safe-area-context';
import styles from '../styles';
import * as List from '../../../containers/List';
import RocketChat from '../../../lib/rocketchat';
import { setPreference } from '../../../actions/sortPreferences';
import log, { events, logEvent } from '../../../utils/log';
import I18n from '../../../i18n';
import { withTheme } from '../../../theme';
import { themes } from '../../../constants/colors';
import { headerHeight } from '../../../containers/Header';
const ANIMATION_DURATION = 200;
class Sort extends PureComponent {
static propTypes = {
closeSortDropdown: PropTypes.bool,
close: PropTypes.func,
sortBy: PropTypes.string,
groupByType: PropTypes.bool,
showFavorites: PropTypes.bool,
showUnread: PropTypes.bool,
isMasterDetail: PropTypes.bool,
theme: PropTypes.string,
insets: PropTypes.object,
setSortPreference: PropTypes.func
};
constructor(props) {
super(props);
this.animatedValue = new Animated.Value(0);
}
componentDidMount() {
Animated.timing(this.animatedValue, {
toValue: 1,
duration: ANIMATION_DURATION,
easing: Easing.inOut(Easing.quad),
useNativeDriver: true
}).start();
}
componentDidUpdate(prevProps) {
const { closeSortDropdown } = this.props;
if (prevProps.closeSortDropdown !== closeSortDropdown) {
this.close();
}
}
setSortPreference = param => {
const { setSortPreference } = this.props;
try {
setSortPreference(param);
RocketChat.saveSortPreference(param);
} catch (e) {
logEvent(events.RL_SORT_CHANNELS_F);
log(e);
}
};
sortByName = () => {
logEvent(events.RL_SORT_CHANNELS_BY_NAME);
this.setSortPreference({ sortBy: 'alphabetical' });
this.close();
};
sortByActivity = () => {
logEvent(events.RL_SORT_CHANNELS_BY_ACTIVITY);
this.setSortPreference({ sortBy: 'activity' });
this.close();
};
toggleGroupByType = () => {
logEvent(events.RL_GROUP_CHANNELS_BY_TYPE);
const { groupByType } = this.props;
this.setSortPreference({ groupByType: !groupByType });
};
toggleGroupByFavorites = () => {
logEvent(events.RL_GROUP_CHANNELS_BY_FAVORITE);
const { showFavorites } = this.props;
this.setSortPreference({ showFavorites: !showFavorites });
};
toggleUnread = () => {
logEvent(events.RL_GROUP_CHANNELS_BY_UNREAD);
const { showUnread } = this.props;
this.setSortPreference({ showUnread: !showUnread });
};
close = () => {
const { close } = this.props;
Animated.timing(this.animatedValue, {
toValue: 0,
duration: ANIMATION_DURATION,
easing: Easing.inOut(Easing.quad),
useNativeDriver: true
}).start(() => close());
};
renderCheck = () => {
const { theme } = this.props;
return <List.Icon name='check' color={themes[theme].tintColor} />;
};
render() {
const { isMasterDetail, insets } = this.props;
const statusBarHeight = insets?.top ?? 0;
const heightDestination = isMasterDetail ? headerHeight + statusBarHeight : 0;
const translateY = this.animatedValue.interpolate({
inputRange: [0, 1],
outputRange: [-326, heightDestination]
});
const { sortBy, groupByType, showFavorites, showUnread, theme } = this.props;
const backdropOpacity = this.animatedValue.interpolate({
inputRange: [0, 1],
outputRange: [0, themes[theme].backdropOpacity]
});
return (
<>
<TouchableWithoutFeedback onPress={this.close}>
<Animated.View
style={[
styles.backdrop,
{
backgroundColor: themes[theme].backdropColor,
opacity: backdropOpacity,
top: heightDestination
}
]}
/>
</TouchableWithoutFeedback>
<Animated.View
style={[
styles.dropdownContainer,
{
transform: [{ translateY }],
backgroundColor: themes[theme].backgroundColor,
borderColor: themes[theme].separatorColor
}
]}>
<List.Item
title={I18n.t('Sorting_by', { key: I18n.t(sortBy === 'alphabetical' ? 'name' : 'activity') })}
left={() => <List.Icon name='sort' />}
color={themes[theme].auxiliaryText}
onPress={this.close}
translateTitle={false}
/>
<List.Separator />
<List.Item
title='Alphabetical'
left={() => <List.Icon name='sort-az' />}
color={themes[theme].auxiliaryText}
onPress={this.sortByName}
right={() => (sortBy === 'alphabetical' ? this.renderCheck() : null)}
/>
<List.Item
title='Activity'
left={() => <List.Icon name='clock' />}
color={themes[theme].auxiliaryText}
onPress={this.sortByActivity}
right={() => (sortBy === 'activity' ? this.renderCheck() : null)}
/>
<List.Separator />
<List.Item
title='Group_by_type'
left={() => <List.Icon name='group-by-type' />}
color={themes[theme].auxiliaryText}
onPress={this.toggleGroupByType}
right={() => (groupByType ? this.renderCheck() : null)}
/>
<List.Item
title='Group_by_favorites'
left={() => <List.Icon name='star' />}
color={themes[theme].auxiliaryText}
onPress={this.toggleGroupByFavorites}
right={() => (showFavorites ? this.renderCheck() : null)}
/>
<List.Item
title='Unread_on_top'
left={() => <List.Icon name='unread-on-top-disabled' />}
color={themes[theme].auxiliaryText}
onPress={this.toggleUnread}
right={() => (showUnread ? this.renderCheck() : null)}
/>
</Animated.View>
</>
);
}
}
const mapStateToProps = state => ({
closeSortDropdown: state.rooms.closeSortDropdown,
isMasterDetail: state.app.isMasterDetail
});
const mapDispatchToProps = dispatch => ({
setSortPreference: preference => dispatch(setPreference(preference))
});
export default connect(mapStateToProps, mapDispatchToProps)(withSafeAreaInsets(withTheme(Sort)));

View File

@ -9,15 +9,14 @@ import { withSafeAreaInsets } from 'react-native-safe-area-context';
import database from '../../lib/database';
import RocketChat from '../../lib/rocketchat';
import RoomItem, { ROW_HEIGHT } from '../../presentation/RoomItem';
import log, { events, logEvent } from '../../utils/log';
import RoomItem, { ROW_HEIGHT, ROW_HEIGHT_CONDENSED } from '../../presentation/RoomItem';
import log, { logEvent, events } from '../../utils/log';
import I18n from '../../i18n';
import {
closeSearchHeader as closeSearchHeaderAction,
closeServerDropdown as closeServerDropdownAction,
openSearchHeader as openSearchHeaderAction,
roomsRequest as roomsRequestAction,
toggleSortDropdown as toggleSortDropdownAction
roomsRequest as roomsRequestAction
} from '../../actions/rooms';
import { appStart as appStartAction, ROOT_OUTSIDE } from '../../actions/app';
import debounce from '../../utils/debounce';
@ -50,11 +49,11 @@ import { showConfirmationAlert, showErrorAlert } from '../../utils/info';
import { E2E_BANNER_TYPE } from '../../lib/encryption/constants';
import { getInquiryQueueSelector } from '../../ee/omnichannel/selectors/inquiry';
import { changeLivechatStatus, isOmnichannelStatusAvailable } from '../../ee/omnichannel/lib';
import { DISPLAY_MODE_CONDENSED } from '../../constants/constantDisplayMode';
import styles from './styles';
import ServerDropdown from './ServerDropdown';
import ListHeader from './ListHeader';
import RoomsListHeaderView from './Header';
import ServerDropdown from './ServerDropdown';
import SortDropdown from './SortDropdown';
import styles from './styles';
const INITIAL_NUM_TO_RENDER = isTablet ? 20 : 12;
const CHATS_HEADER = 'Chats';
@ -77,11 +76,6 @@ const shouldUpdateProps = [
'searchText',
'loadingServer',
'showServerDropdown',
'showSortDropdown',
'sortBy',
'groupByType',
'showFavorites',
'showUnread',
'useRealName',
'StoreLastMessage',
'theme',
@ -96,9 +90,14 @@ const shouldUpdateProps = [
'createPrivateChannelPermission',
'createDiscussionPermission'
];
const getItemLayout = (data, index) => ({
length: ROW_HEIGHT,
offset: ROW_HEIGHT * index,
const sortPreferencesShouldUpdate = ['sortBy', 'groupByType', 'showFavorites', 'showUnread'];
const displayPropsShouldUpdate = ['showAvatar', 'displayMode'];
const getItemLayout = (data, index, height) => ({
length: height,
offset: height * index,
index
});
const keyExtractor = item => item.rid;
@ -118,7 +117,6 @@ class RoomsListView extends React.Component {
changingServer: PropTypes.bool,
loadingServer: PropTypes.bool,
showServerDropdown: PropTypes.bool,
showSortDropdown: PropTypes.bool,
sortBy: PropTypes.string,
groupByType: PropTypes.bool,
showFavorites: PropTypes.bool,
@ -126,7 +124,6 @@ class RoomsListView extends React.Component {
refreshing: PropTypes.bool,
StoreLastMessage: PropTypes.bool,
theme: PropTypes.string,
toggleSortDropdown: PropTypes.func,
openSearchHeader: PropTypes.func,
closeSearchHeader: PropTypes.func,
appStart: PropTypes.func,
@ -140,6 +137,8 @@ class RoomsListView extends React.Component {
queueSize: PropTypes.number,
inquiryEnabled: PropTypes.bool,
encryptionBanner: PropTypes.string,
showAvatar: PropTypes.bool,
displayMode: PropTypes.string,
createTeamPermission: PropTypes.array,
createDirectMessagePermission: PropTypes.array,
createPublicChannelPermission: PropTypes.array,
@ -180,6 +179,11 @@ class RoomsListView extends React.Component {
this.unsubscribeFocus = navigation.addListener('focus', () => {
Orientation.unlockAllOrientations();
this.animated = true;
// Check if there were changes with sort preference, then call getSubscription to remount the list
if (this.sortPreferencesChanged) {
this.getSubscriptions();
this.sortPreferencesChanged = false;
}
// Check if there were changes while not focused (it's set on sCU)
if (this.shouldUpdate) {
this.forceUpdate();
@ -222,6 +226,20 @@ class RoomsListView extends React.Component {
return true;
}
// check if some display props are changed to force update when focus this view again
// eslint-disable-next-line react/destructuring-assignment
const displayUpdated = displayPropsShouldUpdate.some(key => nextProps[key] !== this.props[key]);
if (displayUpdated) {
this.shouldUpdate = true;
}
// check if some sort preferences are changed to getSubscription() when focus this view again
// eslint-disable-next-line react/destructuring-assignment
const sortPreferencesUpdate = sortPreferencesShouldUpdate.some(key => nextProps[key] !== this.props[key]);
if (sortPreferencesUpdate) {
this.sortPreferencesChanged = true;
}
// Compare changes only once
const chatsNotEqual = !dequal(nextState.chatsUpdate, chatsUpdate);
@ -285,7 +303,9 @@ class RoomsListView extends React.Component {
createPublicChannelPermission,
createPrivateChannelPermission,
createDirectMessagePermission,
createDiscussionPermission
createDiscussionPermission,
showAvatar,
displayMode
} = this.props;
const { item } = this.state;
@ -294,7 +314,9 @@ class RoomsListView extends React.Component {
prevProps.sortBy === sortBy &&
prevProps.groupByType === groupByType &&
prevProps.showFavorites === showFavorites &&
prevProps.showUnread === showUnread
prevProps.showUnread === showUnread &&
prevProps.showAvatar === showAvatar &&
prevProps.displayMode === displayMode
)
) {
this.getSubscriptions();
@ -616,16 +638,6 @@ class RoomsListView extends React.Component {
}
};
toggleSort = () => {
logEvent(events.RL_TOGGLE_SORT_DROPDOWN);
const { toggleSortDropdown } = this.props;
this.scrollToTop();
setTimeout(() => {
toggleSortDropdown();
}, 100);
};
toggleFav = async (rid, favorite) => {
logEvent(favorite ? events.RL_UNFAVORITE_CHANNEL : events.RL_FAVORITE_CHANNEL);
try {
@ -874,12 +886,10 @@ class RoomsListView extends React.Component {
renderListHeader = () => {
const { searching } = this.state;
const { sortBy, queueSize, inquiryEnabled, encryptionBanner, user } = this.props;
const { queueSize, inquiryEnabled, encryptionBanner, user } = this.props;
return (
<ListHeader
searching={searching}
sortBy={sortBy}
toggleSort={this.toggleSort}
goEncryption={this.goEncryption}
goQueue={this.goQueue}
queueSize={queueSize}
@ -913,7 +923,9 @@ class RoomsListView extends React.Component {
useRealName,
theme,
isMasterDetail,
width
width,
showAvatar,
displayMode
} = this.props;
const id = this.getUidDirectMessage(item);
@ -938,6 +950,8 @@ class RoomsListView extends React.Component {
getIsRead={this.isRead}
visitor={item.visitor}
isFocused={currentItem?.rid === item.rid}
showAvatar={showAvatar}
displayMode={displayMode}
/>
);
};
@ -953,7 +967,9 @@ class RoomsListView extends React.Component {
renderScroll = () => {
const { loading, chats, search, searching } = this.state;
const { theme, refreshing } = this.props;
const { theme, refreshing, displayMode } = this.props;
const height = displayMode === DISPLAY_MODE_CONDENSED ? ROW_HEIGHT_CONDENSED : ROW_HEIGHT;
if (loading) {
return <ActivityIndicator theme={theme} />;
@ -968,7 +984,7 @@ class RoomsListView extends React.Component {
style={[styles.list, { backgroundColor: themes[theme].backgroundColor }]}
renderItem={this.renderItem}
ListHeaderComponent={this.renderListHeader}
getItemLayout={getItemLayout}
getItemLayout={(data, index) => getItemLayout(data, index, height)}
removeClippedSubviews={isIOS}
keyboardShouldPersistTaps='always'
initialNumToRender={INITIAL_NUM_TO_RENDER}
@ -984,23 +1000,13 @@ class RoomsListView extends React.Component {
render = () => {
console.count(`${this.constructor.name}.render calls`);
const { sortBy, groupByType, showFavorites, showUnread, showServerDropdown, showSortDropdown, theme, navigation } =
this.props;
const { showServerDropdown, theme, navigation } = this.props;
return (
<SafeAreaView testID='rooms-list-view' style={{ backgroundColor: themes[theme].backgroundColor }}>
<StatusBar />
{this.renderHeader()}
{this.renderScroll()}
{showSortDropdown ? (
<SortDropdown
close={this.toggleSort}
sortBy={sortBy}
groupByType={groupByType}
showFavorites={showFavorites}
showUnread={showUnread}
/>
) : null}
{showServerDropdown ? <ServerDropdown navigation={navigation} /> : null}
</SafeAreaView>
);
@ -1015,7 +1021,6 @@ const mapStateToProps = state => ({
searchText: state.rooms.searchText,
loadingServer: state.server.loading,
showServerDropdown: state.rooms.showServerDropdown,
showSortDropdown: state.rooms.showSortDropdown,
refreshing: state.rooms.refreshing,
sortBy: state.sortPreferences.sortBy,
groupByType: state.sortPreferences.groupByType,
@ -1027,6 +1032,8 @@ const mapStateToProps = state => ({
queueSize: getInquiryQueueSelector(state).length,
inquiryEnabled: state.inquiry.enabled,
encryptionBanner: state.encryption.banner,
showAvatar: state.sortPreferences.showAvatar,
displayMode: state.sortPreferences.displayMode,
createTeamPermission: state.permissions['create-team'],
createDirectMessagePermission: state.permissions['create-d'],
createPublicChannelPermission: state.permissions['create-c'],
@ -1035,7 +1042,6 @@ const mapStateToProps = state => ({
});
const mapDispatchToProps = dispatch => ({
toggleSortDropdown: () => dispatch(toggleSortDropdownAction()),
openSearchHeader: () => dispatch(openSearchHeaderAction()),
closeSearchHeader: () => dispatch(closeSearchHeaderAction()),
roomsRequest: params => dispatch(roomsRequestAction(params)),

View File

@ -185,6 +185,8 @@ class SettingsView extends React.Component {
<List.Separator />
</List.Section>
<List.Section>
<List.Separator />
<List.Item title='Display' onPress={() => this.navigateToScreen('DisplayPrefsView')} showActionIndicator />
<List.Separator />
<List.Item
title='Profile'

View File

@ -193,6 +193,13 @@ class Sidebar extends Component {
testID='sidebar-profile'
current={this.currentItemKey === 'ProfileStackNavigator'}
/>
<SidebarItem
text={I18n.t('Display')}
left={<CustomIcon name='sort' size={20} color={themes[theme].titleText} />}
onPress={() => this.sidebarNavigate('DisplayPrefStackNavigator')}
testID='sidebar-display'
current={this.currentItemKey === 'DisplayPrefStackNavigator'}
/>
<SidebarItem
text={I18n.t('Settings')}
left={<CustomIcon name='administration' size={20} color={themes[theme].titleText} />}

View File

@ -61,7 +61,9 @@ class TeamChannelsView extends React.Component {
deleteCPermission: PropTypes.array,
deletePPermission: PropTypes.array,
showActionSheet: PropTypes.func,
deleteRoom: PropTypes.func
deleteRoom: PropTypes.func,
showAvatar: PropTypes.bool,
displayMode: PropTypes.string
};
constructor(props) {
@ -463,7 +465,7 @@ class TeamChannelsView extends React.Component {
};
renderItem = ({ item }) => {
const { StoreLastMessage, useRealName, theme, width } = this.props;
const { StoreLastMessage, useRealName, theme, width, showAvatar, displayMode } = this.props;
return (
<RoomItem
item={item}
@ -478,6 +480,8 @@ class TeamChannelsView extends React.Component {
getRoomAvatar={this.getRoomAvatar}
swipeEnabled={false}
autoJoin={item.teamDefault}
showAvatar={showAvatar}
displayMode={displayMode}
/>
);
};
@ -540,7 +544,9 @@ const mapStateToProps = state => ({
editTeamChannelPermission: state.permissions[PERMISSION_EDIT_TEAM_CHANNEL],
removeTeamChannelPermission: state.permissions[PERMISSION_REMOVE_TEAM_CHANNEL],
deleteCPermission: state.permissions[PERMISSION_DELETE_C],
deletePPermission: state.permissions[PERMISSION_DELETE_P]
deletePPermission: state.permissions[PERMISSION_DELETE_P],
showAvatar: state.sortPreferences.showAvatar,
displayMode: state.sortPreferences.displayMode
});
const mapDispatchToProps = dispatch => ({

View File

@ -0,0 +1,96 @@
const { login, navigateToLogin } = require('../../helpers/app');
const data = require('../../data');
const goToDisplayPref = async () => {
await expect(element(by.id('rooms-list-view-sidebar'))).toBeVisible();
await element(by.id('rooms-list-view-sidebar')).tap();
await expect(element(by.id('sidebar-display'))).toBeVisible();
await element(by.id('sidebar-display')).tap();
};
const goToRoomList = async () => {
await expect(element(by.id('display-view-drawer'))).toBeVisible();
await element(by.id('display-view-drawer')).tap();
await expect(element(by.id('sidebar-chats'))).toBeVisible();
await element(by.id('sidebar-chats')).tap();
};
describe('Rooms list screen', () => {
before(async () => {
await device.launchApp({ permissions: { notifications: 'YES' }, newInstance: true, delete: true });
await navigateToLogin();
await login(data.users.regular.username, data.users.regular.password);
});
describe('Render', () => {
it('should have rooms list screen', async () => {
await expect(element(by.id('rooms-list-view'))).toBeVisible();
});
it('should have room item', async () => {
await expect(element(by.id('rooms-list-view-item-general'))).toExist();
});
// Render - Header
describe('Header', () => {
it('should have create channel button', async () => {
await expect(element(by.id('rooms-list-view-create-channel'))).toBeVisible();
});
it('should have sidebar button', async () => {
await expect(element(by.id('rooms-list-view-sidebar'))).toBeVisible();
});
});
describe('DisplayPrefView', () => {
it('should go to Display Preferences', async () => {
await goToDisplayPref();
});
it('should have Displays button, expanded, condensed, avatars', async () => {
await expect(element(by.id('display-pref-view-expanded'))).toBeVisible();
await expect(element(by.id('display-pref-view-condensed'))).toBeVisible();
await expect(element(by.id('display-pref-view-avatars'))).toBeVisible();
});
it('should have Sort By button', async () => {
await expect(element(by.id('display-pref-view-activity'))).toBeVisible();
await expect(element(by.id('display-pref-view-name'))).toBeVisible();
});
it('should have Group by button', async () => {
await expect(element(by.id('display-pref-view-unread'))).toBeVisible();
await expect(element(by.id('display-pref-view-favorites'))).toBeVisible();
await expect(element(by.id('display-pref-view-types'))).toBeVisible();
});
});
describe('Change display', () => {
it('should appear the last message in RoomList when is Expanded', async () => {
await element(by.id('display-pref-view-expanded')).tap();
await goToRoomList();
await expect(element(by.id('room-item-last-message')).atIndex(0)).toBeVisible();
});
it('should not appear the last message in RoomList when is Condensed', async () => {
await goToDisplayPref();
await element(by.id('display-pref-view-condensed')).tap();
await goToRoomList();
await expect(element(by.id('room-item-last-message'))).not.toBeVisible();
});
});
describe('Change the avatar visible', () => {
it('should have avatar as default in room list', async () => {
await expect(element(by.id('avatar')).atIndex(0)).toExist();
});
it('should hide the avatar', async () => {
await goToDisplayPref();
await expect(element(by.id('display-pref-view-avatar-switch'))).toBeVisible();
await element(by.id('display-pref-view-avatar-switch')).tap();
await goToRoomList();
await expect(element(by.id('avatar'))).not.toBeVisible();
});
});
});
});

View File

@ -7,6 +7,7 @@ import { Provider } from 'react-redux';
import { themes } from '../../app/constants/colors';
import RoomItemComponent from '../../app/presentation/RoomItem/RoomItem';
import { longText } from '../utils';
import { DISPLAY_MODE_CONDENSED, DISPLAY_MODE_EXPANDED } from '../../app/constants/constantDisplayMode';
import { store } from './index';
const baseUrl = 'https://open.rocket.chat';
@ -30,6 +31,8 @@ const RoomItem = props => (
baseUrl={baseUrl}
width={width}
theme={_theme}
showAvatar
displayMode={DISPLAY_MODE_EXPANDED}
{...updatedAt}
{...props}
/>
@ -126,3 +129,57 @@ stories.add('Last Message', () => (
<RoomItem showLastMessage alert tunread={[1]} lastMessage={lastMessage} />
</>
));
stories.add('Condensed Room Item', () => (
<>
<RoomItem showLastMessage alert tunread={[1]} lastMessage={lastMessage} displayMode={DISPLAY_MODE_CONDENSED} />
<RoomItem showLastMessage alert name='unread' unread={1000} displayMode={DISPLAY_MODE_CONDENSED} />
<RoomItem type='c' displayMode={DISPLAY_MODE_CONDENSED} autoJoin />
</>
));
stories.add('Condensed Room Item without Avatar', () => (
<>
<RoomItem
showLastMessage
alert
tunread={[1]}
lastMessage={lastMessage}
displayMode={DISPLAY_MODE_CONDENSED}
showAvatar={false}
/>
<RoomItem type='p' displayMode={DISPLAY_MODE_CONDENSED} showAvatar={false} />
<RoomItem name={longText} autoJoin displayMode={DISPLAY_MODE_CONDENSED} showAvatar={false} />
</>
));
stories.add('Expanded Room Item without Avatar', () => (
<>
<RoomItem
showLastMessage
alert
tunread={[1]}
lastMessage={lastMessage}
displayMode={DISPLAY_MODE_EXPANDED}
showAvatar={false}
/>
<RoomItem
status='online'
showLastMessage
alert
tunread={[1]}
lastMessage={lastMessage}
displayMode={DISPLAY_MODE_EXPANDED}
showAvatar={false}
/>
<RoomItem
status='online'
showLastMessage
alert
lastMessage={lastMessage}
displayMode={DISPLAY_MODE_EXPANDED}
showAvatar={false}
/>
</>
));