Chat details redesign (#1010)
* replace chat details dropdown with chat details button * initial work on chat details design updates * added back space invite buttons, openning up invite search, removed references to room locking
This commit is contained in:
parent
22f33b0a85
commit
a44305a5af
17 changed files with 878 additions and 321 deletions
|
|
@ -4024,7 +4024,7 @@
|
|||
"conversationBotCustomZone_customSystemPromptPlaceholder": "Set custom system prompt",
|
||||
"conversationBotCustomZone_customSystemPromptEmptyError": "Missing custom system prompt",
|
||||
"conversationBotCustomZone_customTriggerReactionEnabledLabel": "Responds on ⏩ reaction",
|
||||
"botConfig": "Chat settings",
|
||||
"botConfig": "Bot and activity settings",
|
||||
"addConversationBotDialogTitleInvite": "Confirm inviting conversation bot",
|
||||
"addConversationBotButtonInvite": "Invite",
|
||||
"addConversationBotDialogInviteConfirmation": "Invite",
|
||||
|
|
@ -4500,5 +4500,11 @@
|
|||
"other": "Other",
|
||||
"botModeValidation": "Please select a chat mode",
|
||||
"clickBestOption": "Choose the best options to translate your message!",
|
||||
"unlockedLanguageTools": "You’ve unlocked the language tools for this message. Try them out by clicking below!"
|
||||
"unlockedLanguageTools": "You’ve unlocked the language tools for this message. Try them out by clicking below!",
|
||||
"botSettingsSubtitle": "Invite bot to moderate chat activity",
|
||||
"invitePeople": "Invite users",
|
||||
"invitePeopleChatSubtitle": "Invite users or admins to this chat",
|
||||
"invitePeopleSpaceSubtitle": "Invite users or admins to this space",
|
||||
"noCapacityLimit": "No capacity limit",
|
||||
"downloadGroupText": "Download group text"
|
||||
}
|
||||
|
|
@ -5004,9 +5004,286 @@
|
|||
"enterDiscussionTopic": "Introduzca un tema de debate",
|
||||
"selectBotChatMode": "Selecciona el modo de chat",
|
||||
"messageNotInTargetLang": "El mensaje no está en la lengua de llegada",
|
||||
"botConfig": "Configuración del chat",
|
||||
"chatCapacityNotSet": "Este chat no tiene límite de capacidad.",
|
||||
"spaceCapacityNotSet": "Este espacio no tiene límite de capacidad.",
|
||||
"chatExceedsCapacity": "Este chat supera su capacidad.",
|
||||
"spaceExceedsCapacity": "Este espacio supera su capacidad."
|
||||
}
|
||||
"spaceExceedsCapacity": "Este espacio supera su capacidad.",
|
||||
"botConfig": "Configuración de bots y actividades",
|
||||
"missingVoiceTitle": "La voz que falta",
|
||||
"grammarCopyPOSsconj": "Conjunción subordinante",
|
||||
"grammarCopyPOSnum": "Número",
|
||||
"grammarCopyPOSverb": "Verbo",
|
||||
"grammarCopyPOSaffix": "Coloque",
|
||||
"grammarCopyPOSpart": "Partículas",
|
||||
"grammarCopyPOSadj": "Adjetivo",
|
||||
"grammarCopyPOScconj": "Conjunción de coordinación",
|
||||
"grammarCopyPOSpunct": "Puntuación",
|
||||
"grammarCopyPOSadv": "Adverbio",
|
||||
"grammarCopyPOSaux": "Auxiliar",
|
||||
"grammarCopyPOSspace": "Espacio",
|
||||
"grammarCopyPOSsym": "Símbolo",
|
||||
"grammarCopyPOSdet": "Determinante",
|
||||
"grammarCopyPOSpron": "Pronombre",
|
||||
"grammarCopyPOSadp": "Adposición",
|
||||
"grammarCopyPOSpropn": "Nombre propio",
|
||||
"grammarCopyPOSnoun": "Sustantivo",
|
||||
"grammarCopyPOSintj": "Interjección",
|
||||
"grammarCopyPOSx": "Otros",
|
||||
"grammarCopyGENDERfem": "Femenino",
|
||||
"grammarCopyPERSON2": "Segunda persona",
|
||||
"grammarCopyMOODimp": "Imperativo",
|
||||
"grammarCopyPUNCTTYPEqest": "Pregunta",
|
||||
"grammarCopyASPECTperf": "Perfecto",
|
||||
"grammarCopyCASEaccnom": "Acusativo, Nominativo",
|
||||
"grammarCopyCASEobl": "Oblicuo",
|
||||
"grammarCopyVOICEact": "Activo",
|
||||
"grammarCopyPUNCTTYPEbrck": "Soporte",
|
||||
"grammarCopyNOUNTYPEart": "Artículo",
|
||||
"grammarCopyNUMBERsing": "Singular",
|
||||
"grammarCopyGENDERmasc": "Hombre",
|
||||
"grammarCopyVERBTYPEmod": "Modal",
|
||||
"grammarCopyADVTYPEadverbial": "Adverbial",
|
||||
"grammarCopyTENSEperi": "Perifrástico",
|
||||
"grammarCopyNUMFORMdigit": "Dígitos",
|
||||
"grammarCopyNOUNTYPEnot_proper": "No procede",
|
||||
"grammarCopyNUMTYPEcard": "Cardenal",
|
||||
"grammarCopyNOUNTYPEprop": "Adecuado",
|
||||
"grammarCopyPUNCTTYPEdash": "Dash",
|
||||
"grammarCopyPUNCTTYPEyes": "Sí",
|
||||
"grammarCopyPUNCTTYPEsemi": "Punto y coma",
|
||||
"grammarCopyPUNCTTYPEcomm": "Coma",
|
||||
"grammarCopyMOODcnd": "Condicional",
|
||||
"grammarCopyCASEacc": "Acusativo",
|
||||
"grammarCopyPARTTYPEpart": "Partitivo",
|
||||
"grammarCopyTENSEpast": "Anterior",
|
||||
"grammarCopyDEGREEsup": "Superlativo",
|
||||
"grammarCopyPUNCTTYPEcolo": "Colon",
|
||||
"grammarCopyPERSON3": "Tercera persona",
|
||||
"grammarCopyNUMBERplur": "Plural",
|
||||
"grammarCopyPRONTYPEnpr": "Nombre propio",
|
||||
"grammarCopyPRONTYPEinterrogative": "Preguntas",
|
||||
"grammarCopyPOLITEinfm": "Informal",
|
||||
"grammarCopyADVTYPEtim": "Tiempo",
|
||||
"grammarCopyPOLARITYneg": "Negativo",
|
||||
"grammarCopyNUMTYPEtot": "Total",
|
||||
"grammarCopyADVTYPEadnomial": "Adnominal",
|
||||
"grammarCopyASPECTprog": "Progresiva",
|
||||
"grammarCopyMOODsub": "Subjuntivo",
|
||||
"grammarCopyVERBFORMcomplementive": "Complementive",
|
||||
"grammarCopyCASEnom": "Nominativo",
|
||||
"grammarCopyTENSEfut": "Futuro",
|
||||
"grammarCopyCASEdat": "Dativo",
|
||||
"grammarCopyTENSEpres": "Presente",
|
||||
"grammarCopyGENDERneut": "Esterilizar",
|
||||
"grammarCopyPRONTYPErel": "Relativa",
|
||||
"grammarCopyVERBFORMfinalEnding": "Final",
|
||||
"grammarCopyPRONTYPEdem": "Demostrativo",
|
||||
"grammarCopyPREPCASEpre": "Preposicional",
|
||||
"grammarCopyVERBFORMfin": "Finito",
|
||||
"grammarCopyDEGREEpos": "Positivo",
|
||||
"grammarCopyPUNCTTYPEquot": "Presupuesto",
|
||||
"grammarCopyVERBFORMger": "Redondo",
|
||||
"grammarCopyVOICEpass": "Pasivo",
|
||||
"grammarCopyCASEgen": "Genitivo",
|
||||
"grammarCopyTENSEprs": "Presente",
|
||||
"grammarCopyDEFINITEdef": "Definitivo",
|
||||
"grammarCopyNUMTYPEord": "Ordinal",
|
||||
"grammarCopyCASEins": "Instrumental",
|
||||
"grammarCopyVERBFORMinf": "Infinitivo",
|
||||
"grammarCopyNUMFORMlong": "Largo",
|
||||
"grammarCopyCASEloc": "Locativo",
|
||||
"grammarCopyMOODind": "Indicativo",
|
||||
"grammarCopyDEGREEcmp": "Comparativa",
|
||||
"grammarCopyCASErelativeCase": "Relativa",
|
||||
"grammarCopyPUNCTTYPEexcl": "Exclamativo",
|
||||
"grammarCopyPERSON1": "En primera persona",
|
||||
"grammarCopyPUNCTSIDEini": "Inicial",
|
||||
"grammarCopyGENDERperson": "Persona",
|
||||
"grammarCopyFOREIGNyes": "Extranjero",
|
||||
"grammarCopyVOICEvoice": "Voz",
|
||||
"grammarCopyVERBTYPEverbType": "Verbo",
|
||||
"grammarCopyPOSSpass": "Posesivo",
|
||||
"grammarCopyPREPCASEprepCase": "Preposicional",
|
||||
"grammarCopyNUMTYPEnumType": "Numeral",
|
||||
"grammarCopyNOUNTYPEnounType": "Sustantivo",
|
||||
"grammarCopyREFLEXreflex": "Reflexivo",
|
||||
"grammarCopyPRONTYPEpronType": "Pronombre",
|
||||
"grammarCopyPUNCTSIDEpunctSide": "Puntuación Lado",
|
||||
"grammarCopyVERBFORMverbForm": "Verbo",
|
||||
"grammarCopyGENDERgender": "Género",
|
||||
"grammarCopyMOODmood": "Estado de ánimo",
|
||||
"grammarCopyASPECTaspect": "Aspecto",
|
||||
"grammarCopyPUNCTTYPEpunctType": "Puntuación",
|
||||
"grammarCopyTENSEtense": "Tense",
|
||||
"grammarCopyDEGREEdegree": "Titulación",
|
||||
"grammarCopyPOLITEpolite": "Cortesía",
|
||||
"grammarCopyADVTYPEadvType": "Adverbio",
|
||||
"grammarCopyNUMFORMnumber": "Número",
|
||||
"grammarCopyCONJTYPEconjType": "Conjunción",
|
||||
"grammarCopyPOLARITYpolarity": "Polaridad",
|
||||
"grammarCopyCASEcase": "Caso",
|
||||
"grammarCopyDEFINITEdefinite": "Definitividad",
|
||||
"grammarCopyNUMFORMnumForm": "Numeral",
|
||||
"grammarCopyPRONTYPEadn": "Adnominal",
|
||||
"grammarCopyVOCvoc": "Vocativo",
|
||||
"grammarCopyCMPLcmpl": "Complementizer",
|
||||
"grammarCopyADVadv": "Adverbial",
|
||||
"grammarCopyMOODjus": "Jussive",
|
||||
"grammarCopyGENDERcom": "Común",
|
||||
"grammarCopyREFLEXrflx": "Reflexivo",
|
||||
"grammarCopyPARTTYPEpar": "Partitivo",
|
||||
"grammarCopySPCspc": "Específico",
|
||||
"grammarCopyTENSEpqp": "Pluperfect",
|
||||
"grammarCopyREFLEXref": "Reflexivo",
|
||||
"grammarCopyPUNCTTYPEnshrt": "Corto",
|
||||
"grammarCopyNUMBERdual": "Doble",
|
||||
"grammarCopyNUMFORMlng": "Largo",
|
||||
"grammarCopyVOICEmid": "Medio",
|
||||
"grammarCopyINTRELintRel": "Interrogativo, relativo",
|
||||
"grammarCopyINTint": "Preguntas",
|
||||
"grammarCopyVOICEcaus": "Causa",
|
||||
"grammarCopyEVIDENTevident": "Evidencialidad",
|
||||
"grammarCopyNUMFORMnumberPsor": "Número del poseedor",
|
||||
"grammarCopyASPECThab": "Habitual",
|
||||
"grammarCopyCASEabl": "Ablativo",
|
||||
"grammarCopyCASEall": "Allative",
|
||||
"grammarCopyCASEess": "Essive",
|
||||
"grammarCopyCASEtra": "Translativo",
|
||||
"grammarCopyCASEequ": "Ecuativo",
|
||||
"grammarCopyCASEdis": "Distributivo",
|
||||
"grammarCopyCASEabs": "Absolutivo",
|
||||
"grammarCopyCASEerg": "Ergativa",
|
||||
"grammarCopyCASEcau": "Causal",
|
||||
"grammarCopyCASEben": "Benefactive",
|
||||
"grammarCopyCASEtem": "Temporal",
|
||||
"grammarCopyCONJTYPEcoord": "Coordinación",
|
||||
"grammarCopyDEFINITEcons": "Construir el Estado",
|
||||
"grammarCopyDEGREEabs": "Grado absoluto",
|
||||
"grammarCopyEVIDENTfh": "Evidencialidad de los hechos",
|
||||
"grammarCopyEVIDENTnfh": "Evidencialidad no factual",
|
||||
"grammarCopyMOODopt": "Optativo",
|
||||
"grammarCopyMOODadm": "Admirable",
|
||||
"grammarCopyMOODdes": "Desiderativo",
|
||||
"grammarCopyMOODnec": "Necesidades",
|
||||
"grammarCopyMOODpot": "Posible",
|
||||
"grammarCopyMOODprp": "Propositivo",
|
||||
"grammarCopyMOODqot": "Cita",
|
||||
"grammarCopyNUMFORMword": "Forma verbal",
|
||||
"grammarCopyNUMFORMroman": "Número romano",
|
||||
"grammarCopyNUMFORMletter": "Formulario de carta",
|
||||
"grammarCopyNUMTYPEmult": "Multiplicativo",
|
||||
"grammarCopyNUMTYPEfrac": "Fraccional",
|
||||
"grammarCopyNUMTYPEsets": "Establecer",
|
||||
"grammarCopyNUMTYPErange": "Gama",
|
||||
"grammarCopyNUMTYPEdist": "Distributivo",
|
||||
"grammarCopyNUMBERtri": "Ensayo",
|
||||
"grammarCopyNUMBERpauc": "Paucal",
|
||||
"grammarCopyNUMBERgrpa": "Gran Paucal",
|
||||
"grammarCopyNUMBERgrpl": "Mayor Plural",
|
||||
"grammarCopyNUMBERinv": "Inversa",
|
||||
"grammarCopyPERSON0": "Cero",
|
||||
"grammarCopyPERSON4": "Cuarto",
|
||||
"grammarCopyPOLITEform": "Formal",
|
||||
"grammarCopyPOLITEelev": "Elevado",
|
||||
"grammarCopyPOLITEhumb": "Humilde",
|
||||
"grammarCopyPRONTYPEemp": "Enfático",
|
||||
"grammarCopyPRONTYPEexc": "Exclamativo",
|
||||
"grammarCopyPRONTYPErcp": "Reciprocal",
|
||||
"grammarCopyPRONTYPEintRelPronType": "Interrogativo-Relativo",
|
||||
"grammarCopyTENSEaor": "aoristo",
|
||||
"grammarCopyTENSEeps": "Epistémica",
|
||||
"grammarCopyTENSEprosp": "Prospectiva",
|
||||
"grammarCopyVERBFORMpart": "Participio",
|
||||
"grammarCopyVERBFORMconv": "Converb",
|
||||
"grammarCopyVERBFORMvnoun": "Sustantivo verbal",
|
||||
"grammarCopyVOICEantip": "Antipasivo",
|
||||
"grammarCopyVOICEcauVoice": "Causa",
|
||||
"grammarCopyVOICedir": "Directo",
|
||||
"grammarCopyVOICEinvVoice": "Inversa",
|
||||
"grammarCopyVOICErcpVoice": "Reciprocal",
|
||||
"grammarCopyPOS": "Parte de la oración",
|
||||
"grammarCopyGENDER": "Género",
|
||||
"grammarCopyPERSON": "Persona",
|
||||
"grammarCopyMOOD": "Estado de ánimo",
|
||||
"grammarCopyPUNCTTYPE": "Tipo de puntuación",
|
||||
"grammarCopyASPECT": "Aspecto",
|
||||
"grammarCopyCASE": "Caso",
|
||||
"grammarCopyVOICE": "Voz",
|
||||
"grammarCopyNOUNTYPE": "Tipo de sustantivo",
|
||||
"grammarCopyVERBTYPE": "Tipo de verbo",
|
||||
"grammarCopyADVTYPE": "Tipo de adverbio",
|
||||
"grammarCopyNUMFORM": "Forma numérica",
|
||||
"grammarCopyNUMTYPE": "Tipo de número",
|
||||
"grammarCopyNUMBER": "Número",
|
||||
"grammarCopyDEFINITE": "Definitividad",
|
||||
"grammarCopyDEGREE": "Titulación",
|
||||
"grammarCopyEVIDENT": "Evidencialidad",
|
||||
"grammarCopyFOREIGN": "Extranjero",
|
||||
"grammarCopyPOLARITY": "Polaridad",
|
||||
"grammarCopyPOLITE": "Cortesía",
|
||||
"grammarCopyPREPCASE": "Caso preposicional",
|
||||
"grammarCopyPRONTYPE": "Tipo de pronombre",
|
||||
"grammarCopyPUNCTSIDE": "Puntuación Lado",
|
||||
"grammarCopyREFLEX": "Reflexivo",
|
||||
"grammarCopyTENSE": "Tense",
|
||||
"grammarCopyVERBFORM": "Forma verbal",
|
||||
"grammarCopyCONJTYPE": "Tipo de conjunción",
|
||||
"grammarCopySPC": "Especificidad",
|
||||
"grammarCopyPARTTYPE": "Tipo Partitivo",
|
||||
"grammarCopyINTREL": "Interrogativo-Relativo",
|
||||
"grammarCopyNUMFORMpsor": "Número del poseedor",
|
||||
"grammarCopyUNKNOWN": "Desconocido",
|
||||
"grammarCopyNUMBERPSOR": "Número del poseedor",
|
||||
"grammarCopyPOSS": "Posesivo",
|
||||
"grammarCopyASPECTimp": "Aspecto imperfectivo",
|
||||
"grammarCopyCASEvoc": "Vocativo",
|
||||
"grammarCopyCASEcom": "Comitative",
|
||||
"grammarCopyCASEpar": "Partitivo",
|
||||
"grammarCopyCASEadv": "Adverbial",
|
||||
"grammarCopyCASEref": "Referencial",
|
||||
"grammarCopyCASErel": "Relativa",
|
||||
"grammarCopyCASEsub": "Subesivo",
|
||||
"grammarCopyCASEsup": "Superessive",
|
||||
"grammarCopyCASEaccdat": "Acusativo-dativo",
|
||||
"grammarCopyCASEpre": "Preposicional",
|
||||
"grammarCopyCONJTYPEsub": "Subordinación",
|
||||
"grammarCopyCONJTYPEcmp": "Comparativa",
|
||||
"grammarCopyDEFINITEind": "Indefinido",
|
||||
"grammarCopyMOODint": "Modo interrogativo",
|
||||
"grammarCopyNOUNTYPEcomm": "Sustantivo común",
|
||||
"grammarCopyNUMBERPSORsing": "Singular del poseedor",
|
||||
"grammarCopyNUMBERPSORplur": "Plural del poseedor",
|
||||
"grammarCopyNUMBERPSORdual": "Doble del poseedor",
|
||||
"grammarCopyPOLARITYpos": "Polaridad positiva",
|
||||
"grammarCopyPOSSyes": "Posesivo",
|
||||
"grammarCopyPREPCASEnpr": "No preposicional",
|
||||
"grammarCopyPRONTYPEprs": "Personal",
|
||||
"grammarCopyPRONTYPEint": "Preguntas",
|
||||
"grammarCopyPRONTYPEtot": "Total",
|
||||
"grammarCopyPRONTYPEneg": "Negativo",
|
||||
"grammarCopyPRONTYPEart": "Artículo",
|
||||
"grammarCopyPRONTYPEind": "Indefinido",
|
||||
"grammarCopyPRONTYPEintrel": "Interrogativo-Relativo",
|
||||
"grammarCopyPUNCTSIDEfin": "Puntuación final",
|
||||
"grammarCopyPUNCTTYPEperi": "Periodo",
|
||||
"grammarCopyREFLEXyes": "Reflexivo",
|
||||
"grammarCopyTENSEimp": "Imperfect",
|
||||
"grammarCopyVERBFORMsup": "SuApine",
|
||||
"grammarCopyVERBFORMadn": "Adnominal",
|
||||
"grammarCopyVERBFORMlng": "Largo",
|
||||
"grammarCopyVERBTYPEcaus": "Verbo causativo",
|
||||
"grammarCopyVOICEcau": "Causa",
|
||||
"grammarCopyVOICEdir": "Directo",
|
||||
"grammarCopyVOICEinv": "Inversa",
|
||||
"grammarCopyVOICErcp": "Reciprocal",
|
||||
"other": "Otros",
|
||||
"botModeValidation": "Seleccione un modo de chat",
|
||||
"clickBestOption": "Elija las mejores opciones para traducir su mensaje",
|
||||
"unlockedLanguageTools": "Has desbloqueado las herramientas lingüísticas para este mensaje. Pruébalas haciendo clic a continuación.",
|
||||
"botSettingsSubtitle": "Invitar a un bot a moderar la actividad del chat",
|
||||
"invitePeople": "Invitar a usuarios",
|
||||
"invitePeopleChatSubtitle": "Invitar a usuarios o administradores a este chat",
|
||||
"invitePeopleSpaceSubtitle": "Invitar a usuarios o administradores a este espacio",
|
||||
"noCapacityLimit": "Sin límite de capacidad",
|
||||
"downloadGroupText": "Descargar texto del grupo"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,8 +6,6 @@ import 'package:fluffychat/pages/chat/seen_by_row.dart';
|
|||
import 'package:fluffychat/pages/chat/typing_indicators.dart';
|
||||
import 'package:fluffychat/pages/user_bottom_sheet/user_bottom_sheet.dart';
|
||||
import 'package:fluffychat/pangea/enum/instructions_enum.dart';
|
||||
import 'package:fluffychat/pangea/extensions/pangea_room_extension/pangea_room_extension.dart';
|
||||
import 'package:fluffychat/pangea/widgets/chat/locked_chat_message.dart';
|
||||
import 'package:fluffychat/utils/account_config.dart';
|
||||
import 'package:fluffychat/utils/adaptive_bottom_sheet.dart';
|
||||
import 'package:fluffychat/utils/matrix_sdk_extensions/filtered_timeline_extension.dart';
|
||||
|
|
@ -99,14 +97,6 @@ class ChatEventList extends StatelessWidget {
|
|||
);
|
||||
}
|
||||
|
||||
// #Pangea
|
||||
if (i == 1) {
|
||||
return (controller.room.isLocked) && !controller.room.isRoomAdmin
|
||||
? const LockedChatMessage()
|
||||
: const SizedBox.shrink();
|
||||
}
|
||||
// Pangea#
|
||||
|
||||
// Request history button or progress indicator:
|
||||
if (i == events.length + 1) {
|
||||
if (controller.timeline!.isRequestingHistory) {
|
||||
|
|
@ -158,10 +148,7 @@ class ChatEventList extends StatelessWidget {
|
|||
return const SizedBox(height: AppConfig.toolbarMaxHeight);
|
||||
// Pangea#
|
||||
}
|
||||
// #Pangea
|
||||
// i--;
|
||||
i = i - 2;
|
||||
// Pangea#
|
||||
i--;
|
||||
|
||||
final event = events[i];
|
||||
final animateIn = animateInEventIndex != null &&
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@ import 'package:fluffychat/pangea/widgets/chat/chat_floating_action_button.dart'
|
|||
import 'package:fluffychat/pangea/widgets/chat/chat_view_background.dart';
|
||||
import 'package:fluffychat/pangea/widgets/chat/input_bar_wrapper.dart';
|
||||
import 'package:fluffychat/utils/account_config.dart';
|
||||
import 'package:fluffychat/widgets/chat_settings_popup_menu.dart';
|
||||
import 'package:fluffychat/widgets/connection_status_header.dart';
|
||||
import 'package:fluffychat/widgets/matrix.dart';
|
||||
import 'package:fluffychat/widgets/mxc_image.dart';
|
||||
|
|
@ -117,9 +116,16 @@ class ChatView extends StatelessWidget {
|
|||
// #Pangea
|
||||
} else {
|
||||
return [
|
||||
ChatSettingsPopupMenu(
|
||||
controller.room,
|
||||
(!controller.room.isDirectChat && !controller.room.isArchived),
|
||||
IconButton(
|
||||
icon: const Icon(Icons.info_outline),
|
||||
tooltip: L10n.of(context)!.chatDetails,
|
||||
onPressed: () {
|
||||
if (GoRouterState.of(context).uri.path.endsWith('/details')) {
|
||||
context.go('/rooms/${controller.room.id}');
|
||||
} else {
|
||||
context.go('/rooms/${controller.room.id}/details');
|
||||
}
|
||||
},
|
||||
),
|
||||
];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import 'package:adaptive_dialog/adaptive_dialog.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:file_picker/file_picker.dart';
|
||||
import 'package:fluffychat/pages/chat_details/chat_details_view.dart';
|
||||
import 'package:fluffychat/pages/settings/settings.dart';
|
||||
import 'package:fluffychat/pangea/pages/chat_details/pangea_chat_details.dart';
|
||||
import 'package:fluffychat/pangea/pages/class_settings/p_class_widgets/class_description_button.dart';
|
||||
import 'package:fluffychat/pangea/utils/set_class_name.dart';
|
||||
import 'package:fluffychat/utils/platform_infos.dart';
|
||||
|
|
@ -199,7 +199,10 @@ class ChatDetailsController extends State<ChatDetails> {
|
|||
static const fixedWidth = 360.0;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => ChatDetailsView(this);
|
||||
// #Pangea
|
||||
Widget build(BuildContext context) => PangeaChatDetailsView(this);
|
||||
// Widget build(BuildContext context) => ChatDetailsView(this);
|
||||
// Pangea#
|
||||
|
||||
// #Pangea
|
||||
bool showEditNameIcon = false;
|
||||
|
|
@ -220,6 +223,29 @@ class ChatDetailsController extends State<ChatDetails> {
|
|||
if (mounted) setState(() {});
|
||||
}
|
||||
|
||||
Future<void> toggleMute() async {
|
||||
final client = Matrix.of(context).client;
|
||||
final Room? room = client.getRoomById(roomId!);
|
||||
if (room == null) return;
|
||||
await showFutureLoadingDialog(
|
||||
context: context,
|
||||
future: () async {
|
||||
await (room.pushRuleState == PushRuleState.notify
|
||||
? room.setPushRuleState(PushRuleState.mentionsOnly)
|
||||
: room.setPushRuleState(PushRuleState.notify));
|
||||
},
|
||||
);
|
||||
|
||||
// wait for push rule update in sync
|
||||
await client.onSync.stream.firstWhere(
|
||||
(sync) =>
|
||||
sync.accountData != null &&
|
||||
sync.accountData!.isNotEmpty &&
|
||||
sync.accountData!.any((e) => e.type == 'm.push_rules'),
|
||||
);
|
||||
if (mounted) setState(() {});
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
import 'package:adaptive_dialog/adaptive_dialog.dart';
|
||||
import 'package:fluffychat/config/app_config.dart';
|
||||
import 'package:fluffychat/pages/chat_details/chat_details.dart';
|
||||
import 'package:fluffychat/pages/chat_details/participant_list_item.dart';
|
||||
import 'package:fluffychat/pangea/extensions/pangea_room_extension/pangea_room_extension.dart';
|
||||
|
|
@ -8,13 +7,11 @@ import 'package:fluffychat/pangea/pages/class_settings/p_class_widgets/class_des
|
|||
import 'package:fluffychat/pangea/pages/class_settings/p_class_widgets/class_details_toggle_add_students_tile.dart';
|
||||
import 'package:fluffychat/pangea/pages/class_settings/p_class_widgets/class_invitation_buttons.dart';
|
||||
import 'package:fluffychat/pangea/pages/class_settings/p_class_widgets/room_capacity_button.dart';
|
||||
import 'package:fluffychat/pangea/utils/lock_room.dart';
|
||||
import 'package:fluffychat/pangea/widgets/chat/visibility_toggle.dart';
|
||||
import 'package:fluffychat/pangea/widgets/conversation_bot/conversation_bot_settings.dart';
|
||||
import 'package:fluffychat/utils/fluffy_share.dart';
|
||||
import 'package:fluffychat/utils/matrix_sdk_extensions/matrix_locals.dart';
|
||||
import 'package:fluffychat/widgets/avatar.dart';
|
||||
import 'package:fluffychat/widgets/chat_settings_popup_menu.dart';
|
||||
import 'package:fluffychat/widgets/layouts/max_width_body.dart';
|
||||
import 'package:fluffychat/widgets/matrix.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
|
@ -66,7 +63,7 @@ class ChatDetailsView extends StatelessWidget {
|
|||
leading: controller.widget.embeddedCloseButton ??
|
||||
const Center(child: BackButton()),
|
||||
elevation: theme.appBarTheme.elevation,
|
||||
actions: <Widget>[
|
||||
actions: const <Widget>[
|
||||
// #Pangea
|
||||
// if (room.canonicalAlias.isNotEmpty)
|
||||
// IconButton(
|
||||
|
|
@ -77,9 +74,9 @@ class ChatDetailsView extends StatelessWidget {
|
|||
// context,
|
||||
// ),
|
||||
// ),
|
||||
// if (controller.widget.embeddedCloseButton == null)
|
||||
// ChatSettingsPopupMenu(room, false),
|
||||
// Pangea#
|
||||
if (controller.widget.embeddedCloseButton == null)
|
||||
ChatSettingsPopupMenu(room, false),
|
||||
],
|
||||
// #Pangea
|
||||
title: ClassNameHeader(
|
||||
|
|
@ -460,44 +457,6 @@ class ChatDetailsView extends StatelessWidget {
|
|||
}
|
||||
},
|
||||
),
|
||||
if (room.isRoomAdmin && !room.isDirectChat)
|
||||
SwitchListTile.adaptive(
|
||||
activeColor: AppConfig.activeToggleColor,
|
||||
title: Text(
|
||||
room.isSpace
|
||||
? L10n.of(context)!.lockSpace
|
||||
: L10n.of(context)!.lockChat,
|
||||
style: TextStyle(
|
||||
color:
|
||||
Theme.of(context).colorScheme.secondary,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
secondary: CircleAvatar(
|
||||
backgroundColor:
|
||||
Theme.of(context).scaffoldBackgroundColor,
|
||||
foregroundColor: iconColor,
|
||||
child: Icon(
|
||||
room.isLocked
|
||||
? Icons.lock_outlined
|
||||
: Icons.no_encryption_outlined,
|
||||
),
|
||||
),
|
||||
value: room.isLocked,
|
||||
onChanged: (value) => showFutureLoadingDialog(
|
||||
context: context,
|
||||
future: () => value
|
||||
? lockRoom(
|
||||
room,
|
||||
Matrix.of(context).client,
|
||||
)
|
||||
: unlockRoom(
|
||||
room,
|
||||
Matrix.of(context).client,
|
||||
),
|
||||
),
|
||||
),
|
||||
const Divider(height: 1),
|
||||
// Pangea#
|
||||
ListTile(
|
||||
title: Text(
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
import 'package:adaptive_dialog/adaptive_dialog.dart';
|
||||
import 'package:fluffychat/config/app_config.dart';
|
||||
import 'package:fluffychat/pangea/extensions/pangea_room_extension/pangea_room_extension.dart';
|
||||
import 'package:fluffychat/pangea/utils/get_chat_list_item_subtitle.dart';
|
||||
import 'package:fluffychat/utils/matrix_sdk_extensions/matrix_locals.dart';
|
||||
import 'package:fluffychat/utils/room_status_extension.dart';
|
||||
|
|
@ -350,16 +349,6 @@ class ChatListItem extends StatelessWidget {
|
|||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
// #Pangea
|
||||
if (room.isLocked)
|
||||
const Padding(
|
||||
padding: EdgeInsets.only(right: 4.0),
|
||||
child: Icon(
|
||||
Icons.lock_outlined,
|
||||
size: 16,
|
||||
),
|
||||
),
|
||||
// Pangea#
|
||||
AnimatedContainer(
|
||||
duration: FluffyThemes.animationDuration,
|
||||
curve: FluffyThemes.animationCurve,
|
||||
|
|
|
|||
|
|
@ -3,8 +3,6 @@ import 'dart:async';
|
|||
import 'package:adaptive_dialog/adaptive_dialog.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:fluffychat/pages/invitation_selection/invitation_selection_view.dart';
|
||||
import 'package:fluffychat/pangea/constants/class_default_values.dart';
|
||||
import 'package:fluffychat/pangea/extensions/pangea_room_extension/pangea_room_extension.dart';
|
||||
import 'package:fluffychat/pangea/utils/bot_name.dart';
|
||||
import 'package:fluffychat/utils/matrix_sdk_extensions/matrix_locals.dart';
|
||||
import 'package:fluffychat/widgets/matrix.dart';
|
||||
|
|
@ -15,10 +13,6 @@ import 'package:matrix/matrix.dart';
|
|||
|
||||
import '../../utils/localized_exception_extension.dart';
|
||||
|
||||
//#Pangea
|
||||
enum InvitationSelectionMode { admin, member }
|
||||
//Pangea#
|
||||
|
||||
class InvitationSelection extends StatefulWidget {
|
||||
final String roomId;
|
||||
const InvitationSelection({
|
||||
|
|
@ -76,80 +70,72 @@ class InvitationSelectionController extends State<InvitationSelection> {
|
|||
}
|
||||
|
||||
//#Pangea
|
||||
// add all students (already local) from spaceParents who aren't already in room to eligibleStudents
|
||||
// use room.members to get all users in room
|
||||
bool _initialized = false;
|
||||
Future<List<User>> eligibleStudents(
|
||||
BuildContext context,
|
||||
String text,
|
||||
) async {
|
||||
if (!_initialized) {
|
||||
_initialized = true;
|
||||
await requestParentSpaceParticipants();
|
||||
}
|
||||
// // add all students (already local) from spaceParents who aren't already in room to eligibleStudents
|
||||
// // use room.members to get all users in room
|
||||
// bool _initialized = false;
|
||||
// Future<List<User>> eligibleStudents(
|
||||
// BuildContext context,
|
||||
// String text,
|
||||
// ) async {
|
||||
// if (!_initialized) {
|
||||
// _initialized = true;
|
||||
// await requestParentSpaceParticipants();
|
||||
// }
|
||||
|
||||
final eligibleStudents = <User>[];
|
||||
final spaceParents = room?.pangeaSpaceParents;
|
||||
if (spaceParents == null) return eligibleStudents;
|
||||
// final eligibleStudents = <User>[];
|
||||
// final spaceParents = room?.pangeaSpaceParents;
|
||||
// if (spaceParents == null) return eligibleStudents;
|
||||
|
||||
final userId = Matrix.of(context).client.userID;
|
||||
for (final Room space in spaceParents) {
|
||||
eligibleStudents.addAll(
|
||||
space.getParticipants().where(
|
||||
(spaceUser) =>
|
||||
spaceUser.id != BotName.byEnvironment &&
|
||||
spaceUser.id != "@support:staging.pangea.chat" &&
|
||||
spaceUser.id != userId &&
|
||||
(text.isEmpty ||
|
||||
(spaceUser.displayName
|
||||
?.toLowerCase()
|
||||
.contains(text.toLowerCase()) ??
|
||||
false) ||
|
||||
spaceUser.id.toLowerCase().contains(text.toLowerCase())),
|
||||
),
|
||||
);
|
||||
}
|
||||
return eligibleStudents;
|
||||
}
|
||||
// final userId = Matrix.of(context).client.userID;
|
||||
// for (final Room space in spaceParents) {
|
||||
// eligibleStudents.addAll(
|
||||
// space.getParticipants().where(
|
||||
// (spaceUser) =>
|
||||
// spaceUser.id != BotName.byEnvironment &&
|
||||
// spaceUser.id != "@support:staging.pangea.chat" &&
|
||||
// spaceUser.id != userId &&
|
||||
// (text.isEmpty ||
|
||||
// (spaceUser.displayName
|
||||
// ?.toLowerCase()
|
||||
// .contains(text.toLowerCase()) ??
|
||||
// false) ||
|
||||
// spaceUser.id.toLowerCase().contains(text.toLowerCase())),
|
||||
// ),
|
||||
// );
|
||||
// }
|
||||
// return eligibleStudents;
|
||||
// }
|
||||
|
||||
Future<SearchUserDirectoryResponse>
|
||||
eligibleStudentsAsSearchUserDirectoryResponse(
|
||||
BuildContext context,
|
||||
String text,
|
||||
) async {
|
||||
return SearchUserDirectoryResponse(
|
||||
results: (await eligibleStudents(context, text))
|
||||
.map(
|
||||
(e) => Profile(
|
||||
userId: e.id,
|
||||
avatarUrl: e.avatarUrl,
|
||||
displayName: e.displayName,
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
limited: false,
|
||||
);
|
||||
}
|
||||
// Future<SearchUserDirectoryResponse>
|
||||
// eligibleStudentsAsSearchUserDirectoryResponse(
|
||||
// BuildContext context,
|
||||
// String text,
|
||||
// ) async {
|
||||
// return SearchUserDirectoryResponse(
|
||||
// results: (await eligibleStudents(context, text))
|
||||
// .map(
|
||||
// (e) => Profile(
|
||||
// userId: e.id,
|
||||
// avatarUrl: e.avatarUrl,
|
||||
// displayName: e.displayName,
|
||||
// ),
|
||||
// )
|
||||
// .toList(),
|
||||
// limited: false,
|
||||
// );
|
||||
// }
|
||||
|
||||
List<User?> studentsInRoom(BuildContext context) =>
|
||||
room
|
||||
?.getParticipants()
|
||||
.where(
|
||||
(u) => [Membership.join, Membership.invite].contains(u.membership),
|
||||
)
|
||||
.toList() ??
|
||||
<User>[];
|
||||
// List<User?> studentsInRoom(BuildContext context) =>
|
||||
// room
|
||||
// ?.getParticipants()
|
||||
// .where(
|
||||
// (u) => [Membership.join, Membership.invite].contains(u.membership),
|
||||
// )
|
||||
// .toList() ??
|
||||
// <User>[];
|
||||
//Pangea#
|
||||
|
||||
// #Pangea
|
||||
// void inviteAction(BuildContext context, String id, String displayname) async {
|
||||
void inviteAction(
|
||||
BuildContext context,
|
||||
String id,
|
||||
String displayname, {
|
||||
InvitationSelectionMode? mode,
|
||||
}) async {
|
||||
// Pangea#
|
||||
void inviteAction(BuildContext context, String id, String displayname) async {
|
||||
final room = Matrix.of(context).client.getRoomById(roomId!)!;
|
||||
if (OkCancelResult.ok !=
|
||||
await showOkCancelAlertDialog(
|
||||
|
|
@ -168,16 +154,7 @@ class InvitationSelectionController extends State<InvitationSelection> {
|
|||
}
|
||||
final success = await showFutureLoadingDialog(
|
||||
context: context,
|
||||
//#Pangea
|
||||
// future: () => room.invite(id),
|
||||
future: () async {
|
||||
if (mode == InvitationSelectionMode.admin) {
|
||||
await inviteTeacherAction(room, id);
|
||||
} else {
|
||||
await room.invite(id);
|
||||
}
|
||||
},
|
||||
// Pangea#
|
||||
future: () => room.invite(id),
|
||||
);
|
||||
if (success.error == null) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
|
|
@ -191,13 +168,6 @@ class InvitationSelectionController extends State<InvitationSelection> {
|
|||
}
|
||||
}
|
||||
|
||||
// #Pangea
|
||||
Future<void> inviteTeacherAction(Room room, String id) async {
|
||||
await room.invite(id);
|
||||
await room.setPower(id, ClassDefaultValues.powerLevelOfAdmin);
|
||||
}
|
||||
// Pangea#
|
||||
|
||||
void searchUserWithCoolDown(String text) async {
|
||||
coolDown?.cancel();
|
||||
coolDown = Timer(
|
||||
|
|
@ -218,15 +188,7 @@ class InvitationSelectionController extends State<InvitationSelection> {
|
|||
final matrix = Matrix.of(context);
|
||||
SearchUserDirectoryResponse response;
|
||||
try {
|
||||
//#Pangea
|
||||
// response = await matrix.client.searchUserDirectory(text, limit: 10);
|
||||
response = await (mode == InvitationSelectionMode.admin
|
||||
? matrix.client.searchUserDirectory(text, limit: 10)
|
||||
: eligibleStudentsAsSearchUserDirectoryResponse(
|
||||
context,
|
||||
text,
|
||||
));
|
||||
//Pangea#
|
||||
response = await matrix.client.searchUserDirectory(text, limit: 10);
|
||||
} catch (e) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(content: Text((e).toLocalizedString(context))),
|
||||
|
|
@ -264,67 +226,6 @@ class InvitationSelectionController extends State<InvitationSelection> {
|
|||
});
|
||||
}
|
||||
|
||||
//#Pangea
|
||||
Room? _room;
|
||||
Room? get room => _room ??= Matrix.of(context).client.getRoomById(roomId!);
|
||||
|
||||
// request participants for all parent spaces
|
||||
Future<void> requestParentSpaceParticipants() async {
|
||||
final spaceParents = room?.pangeaSpaceParents;
|
||||
if (spaceParents != null) {
|
||||
await Future.wait([
|
||||
...spaceParents.map((r) async {
|
||||
await r.requestParticipants();
|
||||
}),
|
||||
room!.requestParticipants(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
InvitationSelectionMode mode = InvitationSelectionMode.member;
|
||||
|
||||
StreamSubscription<SyncUpdate>? _spaceSubscription;
|
||||
@override
|
||||
void initState() {
|
||||
Future.delayed(
|
||||
Duration.zero,
|
||||
() => setState(
|
||||
() => mode = room?.isSpace ?? false
|
||||
? InvitationSelectionMode.admin
|
||||
: InvitationSelectionMode.member,
|
||||
),
|
||||
);
|
||||
_spaceSubscription = Matrix.of(context)
|
||||
.client
|
||||
.onSync
|
||||
.stream
|
||||
.where(
|
||||
(event) =>
|
||||
event.rooms?.join?.keys.any(
|
||||
(ithRoomId) =>
|
||||
room?.pangeaSpaceParents
|
||||
.map((e) => e.id)
|
||||
.contains(ithRoomId) ??
|
||||
false,
|
||||
) ??
|
||||
false,
|
||||
)
|
||||
.listen(
|
||||
(SyncUpdate syncUpdate) async {
|
||||
await requestParentSpaceParticipants();
|
||||
setState(() {});
|
||||
},
|
||||
);
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_spaceSubscription?.cancel();
|
||||
super.dispose();
|
||||
}
|
||||
//Pangea#
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => InvitationSelectionView(this);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -64,9 +64,7 @@ class InvitationSelectionView extends StatelessWidget {
|
|||
fontWeight: FontWeight.normal,
|
||||
),
|
||||
// #Pangea
|
||||
hintText: controller.mode == InvitationSelectionMode.admin
|
||||
? L10n.of(context)!.inviteUsersFromPangea
|
||||
: L10n.of(context)!.inviteStudentByUserName,
|
||||
hintText: L10n.of(context)!.inviteStudentByUserName,
|
||||
// hintText: L10n.of(context)!.inviteContactToGroup(groupName),
|
||||
// Pangea#
|
||||
prefixIcon: controller.loading
|
||||
|
|
@ -93,18 +91,6 @@ class InvitationSelectionView extends StatelessWidget {
|
|||
builder: (context, snapshot) {
|
||||
final participants =
|
||||
room.getParticipants().map((user) => user.id).toSet();
|
||||
if (controller.mode != InvitationSelectionMode.admin &&
|
||||
room.spaceParents.isEmpty) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Center(
|
||||
child: Text(
|
||||
L10n.of(context)!.emptyInviteWarning,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
return controller.foundProfiles.isNotEmpty
|
||||
? ListView.builder(
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
|
|
@ -126,19 +112,11 @@ class InvitationSelectionView extends StatelessWidget {
|
|||
controller.foundProfiles[i].displayName ??
|
||||
controller.foundProfiles[i].userId.localpart ??
|
||||
L10n.of(context)!.user,
|
||||
// #Pangea
|
||||
mode: controller.mode,
|
||||
// Pangea#
|
||||
),
|
||||
),
|
||||
)
|
||||
: FutureBuilder<List<User>>(
|
||||
// #Pangea
|
||||
future: controller.mode == InvitationSelectionMode.admin
|
||||
? controller.getContacts(context)
|
||||
: controller.eligibleStudents(context, ""),
|
||||
// future: controller.getContacts(context),
|
||||
// Pangea#
|
||||
future: controller.getContacts(context),
|
||||
builder: (BuildContext context, snapshot) {
|
||||
if (!snapshot.hasData) {
|
||||
return const Center(
|
||||
|
|
@ -166,9 +144,6 @@ class InvitationSelectionView extends StatelessWidget {
|
|||
contacts[i].displayName ??
|
||||
contacts[i].id.localpart ??
|
||||
L10n.of(context)!.user,
|
||||
// #Pangea
|
||||
mode: controller.mode,
|
||||
// Pangea#
|
||||
),
|
||||
),
|
||||
);
|
||||
|
|
|
|||
|
|
@ -259,7 +259,7 @@ extension PangeaRoom on Room {
|
|||
|
||||
Future<bool> get isBotDM async => await _isBotDM;
|
||||
|
||||
bool get isLocked => _isLocked;
|
||||
// bool get isLocked => _isLocked;
|
||||
|
||||
bool isAnalyticsRoomOfUser(String userId) => _isAnalyticsRoomOfUser(userId);
|
||||
|
||||
|
|
|
|||
|
|
@ -58,24 +58,24 @@ extension RoomInformationRoomExtension on Room {
|
|||
|
||||
Future<bool> get _isBotDM async => botOptions?.mode == BotMode.directChat;
|
||||
|
||||
bool get _isLocked {
|
||||
if (isDirectChat) return false;
|
||||
if (!isSpace) {
|
||||
if (eventsDefaultPowerLevel == null) return false;
|
||||
return (eventsDefaultPowerLevel ?? 0) >=
|
||||
ClassDefaultValues.powerLevelOfAdmin;
|
||||
}
|
||||
for (final child in spaceChildren) {
|
||||
if (child.roomId == null) continue;
|
||||
final Room? room = client.getRoomById(child.roomId!);
|
||||
if (room == null || room.isAnalyticsRoom || room.isArchived) continue;
|
||||
if (!room._isLocked) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return (eventsDefaultPowerLevel ?? 0) >=
|
||||
ClassDefaultValues.powerLevelOfAdmin;
|
||||
}
|
||||
// bool get _isLocked {
|
||||
// if (isDirectChat) return false;
|
||||
// if (!isSpace) {
|
||||
// if (eventsDefaultPowerLevel == null) return false;
|
||||
// return (eventsDefaultPowerLevel ?? 0) >=
|
||||
// ClassDefaultValues.powerLevelOfAdmin;
|
||||
// }
|
||||
// for (final child in spaceChildren) {
|
||||
// if (child.roomId == null) continue;
|
||||
// final Room? room = client.getRoomById(child.roomId!);
|
||||
// if (room == null || room.isAnalyticsRoom || room.isArchived) continue;
|
||||
// if (!room._isLocked) {
|
||||
// return false;
|
||||
// }
|
||||
// }
|
||||
// return (eventsDefaultPowerLevel ?? 0) >=
|
||||
// ClassDefaultValues.powerLevelOfAdmin;
|
||||
// }
|
||||
|
||||
bool _isAnalyticsRoomOfUser(String userId) =>
|
||||
isAnalyticsRoom && isMadeByUser(userId);
|
||||
|
|
|
|||
431
lib/pangea/pages/chat_details/pangea_chat_details.dart
Normal file
431
lib/pangea/pages/chat_details/pangea_chat_details.dart
Normal file
|
|
@ -0,0 +1,431 @@
|
|||
import 'package:adaptive_dialog/adaptive_dialog.dart';
|
||||
import 'package:fluffychat/pages/chat_details/chat_details.dart';
|
||||
import 'package:fluffychat/pages/chat_details/participant_list_item.dart';
|
||||
import 'package:fluffychat/pangea/extensions/pangea_room_extension/pangea_room_extension.dart';
|
||||
import 'package:fluffychat/pangea/pages/class_settings/class_name_header.dart';
|
||||
import 'package:fluffychat/pangea/pages/class_settings/p_class_widgets/class_details_toggle_add_students_tile.dart';
|
||||
import 'package:fluffychat/pangea/pages/class_settings/p_class_widgets/room_capacity_button.dart';
|
||||
import 'package:fluffychat/pangea/utils/download_chat.dart';
|
||||
import 'package:fluffychat/pangea/widgets/chat/visibility_toggle.dart';
|
||||
import 'package:fluffychat/pangea/widgets/conversation_bot/conversation_bot_settings.dart';
|
||||
import 'package:fluffychat/utils/fluffy_share.dart';
|
||||
import 'package:fluffychat/utils/matrix_sdk_extensions/matrix_locals.dart';
|
||||
import 'package:fluffychat/widgets/avatar.dart';
|
||||
import 'package:fluffychat/widgets/layouts/max_width_body.dart';
|
||||
import 'package:fluffychat/widgets/matrix.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
||||
import 'package:future_loading_dialog/future_loading_dialog.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:matrix/matrix.dart';
|
||||
|
||||
class PangeaChatDetailsView extends StatelessWidget {
|
||||
final ChatDetailsController controller;
|
||||
|
||||
const PangeaChatDetailsView(this.controller, {super.key});
|
||||
|
||||
void _downloadChat(BuildContext context) async {
|
||||
if (controller.roomId == null) return;
|
||||
final Room? room =
|
||||
Matrix.of(context).client.getRoomById(controller.roomId!);
|
||||
if (room == null) return;
|
||||
|
||||
final type = await showConfirmationDialog(
|
||||
context: context,
|
||||
title: L10n.of(context)!.downloadGroupText,
|
||||
actions: [
|
||||
AlertDialogAction(
|
||||
key: DownloadType.csv,
|
||||
label: L10n.of(context)!.downloadCSVFile,
|
||||
),
|
||||
AlertDialogAction(
|
||||
key: DownloadType.txt,
|
||||
label: L10n.of(context)!.downloadTxtFile,
|
||||
),
|
||||
AlertDialogAction(
|
||||
key: DownloadType.xlsx,
|
||||
label: L10n.of(context)!.downloadXLSXFile,
|
||||
),
|
||||
],
|
||||
);
|
||||
if (type == null) return;
|
||||
downloadChat(room, type, context);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
|
||||
final room = Matrix.of(context).client.getRoomById(controller.roomId!);
|
||||
if (room == null || room.membership == Membership.leave) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text(L10n.of(context)!.oopsSomethingWentWrong),
|
||||
),
|
||||
body: Center(
|
||||
child: Text(L10n.of(context)!.youAreNoLongerParticipatingInThisChat),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
final bool isGroupChat = !room.isDirectChat && !room.isSpace;
|
||||
|
||||
return StreamBuilder(
|
||||
stream: room.client.onRoomState.stream
|
||||
.where((update) => update.roomId == room.id),
|
||||
builder: (context, snapshot) {
|
||||
var members = room.getParticipants().toList()
|
||||
..sort((b, a) => a.powerLevel.compareTo(b.powerLevel));
|
||||
members = members.take(10).toList();
|
||||
final actualMembersCount = (room.summary.mInvitedMemberCount ?? 0) +
|
||||
(room.summary.mJoinedMemberCount ?? 0);
|
||||
final canRequestMoreMembers = members.length < actualMembersCount;
|
||||
final iconColor = theme.textTheme.bodyLarge!.color;
|
||||
final displayname = room.getLocalizedDisplayname(
|
||||
MatrixLocals(L10n.of(context)!),
|
||||
);
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
leading: controller.widget.embeddedCloseButton ??
|
||||
const Center(child: BackButton()),
|
||||
elevation: theme.appBarTheme.elevation,
|
||||
title: ClassNameHeader(
|
||||
controller: controller,
|
||||
room: room,
|
||||
),
|
||||
backgroundColor: theme.appBarTheme.backgroundColor,
|
||||
),
|
||||
body: MaxWidthBody(
|
||||
child: ListView.builder(
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
shrinkWrap: true,
|
||||
itemCount: members.length + 1 + (canRequestMoreMembers ? 1 : 0),
|
||||
itemBuilder: (BuildContext context, int i) => i == 0
|
||||
? Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: <Widget>[
|
||||
Row(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(32.0),
|
||||
child: Stack(
|
||||
children: [
|
||||
Hero(
|
||||
tag:
|
||||
controller.widget.embeddedCloseButton !=
|
||||
null
|
||||
? 'embedded_content_banner'
|
||||
: 'content_banner',
|
||||
child: Avatar(
|
||||
mxContent: room.avatar,
|
||||
name: displayname,
|
||||
size: Avatar.defaultSize * 2.5,
|
||||
),
|
||||
),
|
||||
if (!room.isDirectChat &&
|
||||
room.canChangeStateEvent(
|
||||
EventTypes.RoomAvatar,
|
||||
))
|
||||
Positioned(
|
||||
bottom: 0,
|
||||
right: 0,
|
||||
child: FloatingActionButton.small(
|
||||
onPressed: controller.setAvatarAction,
|
||||
heroTag: null,
|
||||
child: const Icon(
|
||||
Icons.camera_alt_outlined,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
TextButton.icon(
|
||||
onPressed: () => room.isDirectChat
|
||||
? null
|
||||
: room.canChangeStateEvent(
|
||||
EventTypes.RoomName,
|
||||
)
|
||||
? controller.setDisplaynameAction()
|
||||
: FluffyShare.share(
|
||||
displayname,
|
||||
context,
|
||||
copyOnly: true,
|
||||
),
|
||||
icon: Icon(
|
||||
room.isDirectChat
|
||||
? Icons.chat_bubble_outline
|
||||
: room.canChangeStateEvent(
|
||||
EventTypes.RoomName,
|
||||
)
|
||||
? Icons.edit_outlined
|
||||
: Icons.copy_outlined,
|
||||
size: 16,
|
||||
),
|
||||
style: TextButton.styleFrom(
|
||||
foregroundColor:
|
||||
theme.colorScheme.onSurface,
|
||||
),
|
||||
label: Text(
|
||||
room.isDirectChat
|
||||
? L10n.of(context)!.directChat
|
||||
: displayname,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: const TextStyle(fontSize: 18),
|
||||
),
|
||||
),
|
||||
TextButton.icon(
|
||||
onPressed: () => room.isDirectChat
|
||||
? null
|
||||
: context.push(
|
||||
'/rooms/${controller.roomId}/details/members',
|
||||
),
|
||||
icon: const Icon(
|
||||
Icons.group_outlined,
|
||||
size: 14,
|
||||
),
|
||||
style: TextButton.styleFrom(
|
||||
foregroundColor:
|
||||
theme.colorScheme.secondary,
|
||||
),
|
||||
label: Text(
|
||||
L10n.of(context)!.countParticipants(
|
||||
actualMembersCount,
|
||||
),
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
Divider(color: theme.dividerColor, height: 1),
|
||||
if (isGroupChat && room.canInvite)
|
||||
ConversationBotSettings(
|
||||
key: controller.addConversationBotKey,
|
||||
room: room,
|
||||
),
|
||||
if (isGroupChat && room.canInvite)
|
||||
Divider(color: theme.dividerColor, height: 1),
|
||||
if (room.canInvite && !room.isDirectChat)
|
||||
ListTile(
|
||||
title: Text(
|
||||
L10n.of(context)!.inviteStudentByUserName,
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).colorScheme.secondary,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
leading: CircleAvatar(
|
||||
backgroundColor:
|
||||
Theme.of(context).scaffoldBackgroundColor,
|
||||
foregroundColor:
|
||||
Theme.of(context).textTheme.bodyLarge!.color,
|
||||
child: const Icon(
|
||||
Icons.person_add_outlined,
|
||||
),
|
||||
),
|
||||
onTap: () => context.go('/rooms/${room.id}/invite'),
|
||||
),
|
||||
if (room.canInvite && !room.isDirectChat)
|
||||
Divider(color: theme.dividerColor, height: 1),
|
||||
if (room.isSpace && room.isRoomAdmin)
|
||||
SpaceDetailsToggleAddStudentsTile(
|
||||
controller: controller,
|
||||
),
|
||||
if (room.isSpace && room.isRoomAdmin)
|
||||
Divider(color: theme.dividerColor, height: 1),
|
||||
if (isGroupChat && room.isRoomAdmin)
|
||||
ListTile(
|
||||
title: Text(
|
||||
L10n.of(context)!.editChatPermissions,
|
||||
style: TextStyle(
|
||||
color: theme.colorScheme.secondary,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
subtitle: Text(
|
||||
L10n.of(context)!.whoCanPerformWhichAction,
|
||||
),
|
||||
leading: CircleAvatar(
|
||||
backgroundColor: theme.scaffoldBackgroundColor,
|
||||
foregroundColor: iconColor,
|
||||
child: const Icon(
|
||||
Icons.manage_accounts_outlined,
|
||||
),
|
||||
),
|
||||
onTap: () => context.push(
|
||||
'/rooms/${room.id}/details/permissions',
|
||||
),
|
||||
),
|
||||
if (isGroupChat && room.isRoomAdmin)
|
||||
Divider(color: theme.dividerColor, height: 1),
|
||||
if (room.isRoomAdmin)
|
||||
VisibilityToggle(
|
||||
room: room,
|
||||
setVisibility: controller.setVisibility,
|
||||
iconColor: iconColor,
|
||||
),
|
||||
if (room.isRoomAdmin)
|
||||
Divider(color: theme.dividerColor, height: 1),
|
||||
RoomCapacityButton(
|
||||
room: room,
|
||||
controller: controller,
|
||||
),
|
||||
Divider(color: theme.dividerColor, height: 1),
|
||||
if (isGroupChat)
|
||||
ListTile(
|
||||
title: Text(
|
||||
L10n.of(context)!.downloadGroupText,
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).colorScheme.secondary,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
leading: CircleAvatar(
|
||||
backgroundColor:
|
||||
Theme.of(context).scaffoldBackgroundColor,
|
||||
foregroundColor: iconColor,
|
||||
child: const Icon(
|
||||
Icons.download_outlined,
|
||||
),
|
||||
),
|
||||
onTap: () => _downloadChat(context),
|
||||
),
|
||||
if (isGroupChat)
|
||||
Divider(color: theme.dividerColor, height: 1),
|
||||
if (isGroupChat)
|
||||
ListTile(
|
||||
title: Text(
|
||||
L10n.of(context)!.muteChat,
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).colorScheme.secondary,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
leading: CircleAvatar(
|
||||
backgroundColor:
|
||||
Theme.of(context).scaffoldBackgroundColor,
|
||||
foregroundColor: iconColor,
|
||||
child: Icon(
|
||||
room.pushRuleState == PushRuleState.notify
|
||||
? Icons.volume_up
|
||||
: Icons.volume_off,
|
||||
),
|
||||
),
|
||||
onTap: controller.toggleMute,
|
||||
),
|
||||
if (isGroupChat)
|
||||
Divider(color: theme.dividerColor, height: 1),
|
||||
ListTile(
|
||||
title: Text(
|
||||
L10n.of(context)!.leave,
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).colorScheme.secondary,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
leading: CircleAvatar(
|
||||
backgroundColor:
|
||||
Theme.of(context).scaffoldBackgroundColor,
|
||||
foregroundColor: iconColor,
|
||||
child: const Icon(
|
||||
Icons.logout_outlined,
|
||||
),
|
||||
),
|
||||
onTap: () async {
|
||||
var confirmed = OkCancelResult.ok;
|
||||
var shouldGo = false;
|
||||
// If user is only admin, room will be archived
|
||||
final onlyAdmin = await room.isOnlyAdmin();
|
||||
// archiveSpace has its own popup; only show if not space
|
||||
if (!room.isSpace) {
|
||||
confirmed = await showOkCancelAlertDialog(
|
||||
useRootNavigator: false,
|
||||
context: context,
|
||||
title: L10n.of(context)!.areYouSure,
|
||||
okLabel: L10n.of(context)!.ok,
|
||||
cancelLabel: L10n.of(context)!.cancel,
|
||||
message: onlyAdmin
|
||||
? L10n.of(context)!.onlyAdminDescription
|
||||
: L10n.of(context)!.leaveRoomDescription,
|
||||
);
|
||||
}
|
||||
if (confirmed == OkCancelResult.ok) {
|
||||
if (room.isSpace) {
|
||||
shouldGo = onlyAdmin
|
||||
? await room.archiveSpace(
|
||||
context,
|
||||
Matrix.of(context).client,
|
||||
onlyAdmin: true,
|
||||
)
|
||||
: await room.leaveSpace(
|
||||
context,
|
||||
Matrix.of(context).client,
|
||||
);
|
||||
} else {
|
||||
final success = await showFutureLoadingDialog(
|
||||
context: context,
|
||||
future: () async {
|
||||
onlyAdmin
|
||||
? await room.archive()
|
||||
: await room.leave();
|
||||
},
|
||||
);
|
||||
shouldGo = (success.error == null);
|
||||
}
|
||||
if (shouldGo) {
|
||||
context.go('/rooms');
|
||||
}
|
||||
}
|
||||
},
|
||||
),
|
||||
Divider(color: theme.dividerColor, height: 1),
|
||||
ListTile(
|
||||
title: Text(
|
||||
L10n.of(context)!.countParticipants(
|
||||
actualMembersCount.toString(),
|
||||
),
|
||||
style: TextStyle(
|
||||
color: theme.colorScheme.secondary,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
: i < members.length + 1
|
||||
? ParticipantListItem(members[i - 1])
|
||||
: ListTile(
|
||||
title: Text(
|
||||
L10n.of(context)!.loadCountMoreParticipants(
|
||||
(actualMembersCount - members.length).toString(),
|
||||
),
|
||||
),
|
||||
leading: CircleAvatar(
|
||||
backgroundColor: theme.scaffoldBackgroundColor,
|
||||
child: const Icon(
|
||||
Icons.group_outlined,
|
||||
color: Colors.grey,
|
||||
),
|
||||
),
|
||||
onTap: () => context.push(
|
||||
'/rooms/${controller.roomId!}/details/members',
|
||||
),
|
||||
trailing: const Icon(Icons.chevron_right_outlined),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
import 'package:fluffychat/pangea/pages/class_settings/p_class_widgets/class_invitation_buttons.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
||||
|
||||
import '../../../../pages/chat_details/chat_details.dart';
|
||||
|
|
@ -14,27 +14,33 @@ class SpaceDetailsToggleAddStudentsTile extends StatelessWidget {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ListTile(
|
||||
title: Text(
|
||||
L10n.of(context)!.addStudents,
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).colorScheme.secondary,
|
||||
fontWeight: FontWeight.bold,
|
||||
return Column(
|
||||
children: [
|
||||
ListTile(
|
||||
title: Text(
|
||||
L10n.of(context)!.addStudents,
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).colorScheme.secondary,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
leading: CircleAvatar(
|
||||
backgroundColor: Theme.of(context).scaffoldBackgroundColor,
|
||||
foregroundColor: Theme.of(context).textTheme.bodyLarge!.color,
|
||||
child: const Icon(
|
||||
Icons.add,
|
||||
),
|
||||
),
|
||||
trailing: Icon(
|
||||
controller.displayAddStudentOptions
|
||||
? Icons.keyboard_arrow_down_outlined
|
||||
: Icons.keyboard_arrow_right_outlined,
|
||||
),
|
||||
onTap: controller.toggleAddStudentOptions,
|
||||
),
|
||||
),
|
||||
leading: CircleAvatar(
|
||||
backgroundColor: Theme.of(context).scaffoldBackgroundColor,
|
||||
foregroundColor: Theme.of(context).textTheme.bodyLarge!.color,
|
||||
child: const Icon(
|
||||
Icons.add,
|
||||
),
|
||||
),
|
||||
trailing: Icon(
|
||||
controller.displayAddStudentOptions
|
||||
? Icons.keyboard_arrow_down_outlined
|
||||
: Icons.keyboard_arrow_right_outlined,
|
||||
),
|
||||
onTap: controller.toggleAddStudentOptions,
|
||||
if (controller.displayAddStudentOptions)
|
||||
ClassInvitationButtons(roomId: controller.roomId!),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -86,11 +86,9 @@ class RoomCapacityButtonState extends State<RoomCapacityButton> {
|
|||
foregroundColor: iconColor,
|
||||
child: const Icon(Icons.reduce_capacity),
|
||||
),
|
||||
subtitle: Text(
|
||||
trailing: Text(
|
||||
(capacity == null)
|
||||
? spaceMode
|
||||
? L10n.of(context)!.spaceCapacityNotSet
|
||||
: L10n.of(context)!.chatCapacityNotSet
|
||||
? L10n.of(context)!.noCapacityLimit
|
||||
: (nonAdmins != null)
|
||||
? '$nonAdmins/$capacity'
|
||||
: '$capacity',
|
||||
|
|
|
|||
|
|
@ -23,13 +23,12 @@ enum DownloadType { txt, csv, xlsx }
|
|||
Future<void> downloadChat(
|
||||
Room room,
|
||||
DownloadType type,
|
||||
Client client,
|
||||
BuildContext context,
|
||||
) async {
|
||||
List<PangeaMessageEvent> allPangeaMessages;
|
||||
|
||||
try {
|
||||
final List<Event> allEvents = await getAllEvents(room, client);
|
||||
final List<Event> allEvents = await getAllEvents(room);
|
||||
final TimelineChunk chunk = TimelineChunk(events: allEvents);
|
||||
final Timeline timeline = Timeline(
|
||||
room: room,
|
||||
|
|
@ -85,14 +84,14 @@ Future<void> downloadChat(
|
|||
}
|
||||
}
|
||||
|
||||
Future<List<Event>> getAllEvents(Room room, Client client) async {
|
||||
Future<List<Event>> getAllEvents(Room room) async {
|
||||
final GetRoomEventsResponse initalResp =
|
||||
await client.getRoomEvents(room.id, Direction.b);
|
||||
await room.client.getRoomEvents(room.id, Direction.b);
|
||||
if (initalResp.end == null) return [];
|
||||
String? nextStartToken = initalResp.end;
|
||||
List<MatrixEvent> allMatrixEvents = initalResp.chunk;
|
||||
while (nextStartToken != null) {
|
||||
final GetRoomEventsResponse resp = await client.getRoomEvents(
|
||||
final GetRoomEventsResponse resp = await room.client.getRoomEvents(
|
||||
room.id,
|
||||
Direction.b,
|
||||
from: nextStartToken,
|
||||
|
|
|
|||
|
|
@ -70,6 +70,7 @@ class ConversationBotSettingsState extends State<ConversationBotSettings> {
|
|||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
subtitle: Text(L10n.of(context)!.botSettingsSubtitle),
|
||||
leading: CircleAvatar(
|
||||
backgroundColor: Theme.of(context).scaffoldBackgroundColor,
|
||||
foregroundColor: Theme.of(context).textTheme.bodyLarge!.color,
|
||||
|
|
@ -78,7 +79,6 @@ class ConversationBotSettingsState extends State<ConversationBotSettings> {
|
|||
expression: BotExpression.idle,
|
||||
),
|
||||
),
|
||||
trailing: const Icon(Icons.settings),
|
||||
onTap: showBotOptionsDialog,
|
||||
),
|
||||
],
|
||||
|
|
|
|||
|
|
@ -123,7 +123,6 @@ class ChatSettingsPopupMenuState extends State<ChatSettingsPopupMenu> {
|
|||
future: () => downloadChat(
|
||||
widget.room,
|
||||
DownloadType.txt,
|
||||
Matrix.of(context).client,
|
||||
context,
|
||||
),
|
||||
);
|
||||
|
|
@ -134,7 +133,6 @@ class ChatSettingsPopupMenuState extends State<ChatSettingsPopupMenu> {
|
|||
future: () => downloadChat(
|
||||
widget.room,
|
||||
DownloadType.csv,
|
||||
Matrix.of(context).client,
|
||||
context,
|
||||
),
|
||||
);
|
||||
|
|
@ -145,7 +143,6 @@ class ChatSettingsPopupMenuState extends State<ChatSettingsPopupMenu> {
|
|||
future: () => downloadChat(
|
||||
widget.room,
|
||||
DownloadType.xlsx,
|
||||
Matrix.of(context).client,
|
||||
context,
|
||||
),
|
||||
);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue