feat: menu de contexto em bottom sheet, painel de anexos, perfil e feed do mural
- Salas (chat, canais, murais e salas de espacos) abrem bottom sheet com grid de acoes - Botao + da barra de digitacao abre painel de anexos em grid de 3 colunas que empurra a caixa de texto - Modal do perfil permite editar nome/status e ler QR code (mobile) - Alterar status atualiza localmente via extensao do SDK matrix - Mural pre-carrega historico para exibir todas as midias em dispositivos sem cache
This commit is contained in:
@@ -88,6 +88,7 @@ class _MuralChatViewState extends State<MuralChatView> {
|
||||
bool _descriptionExpanded = false;
|
||||
bool _loadingHistory = false;
|
||||
bool _historyEnded = false;
|
||||
bool _initialLoading = false;
|
||||
final ScrollController _scrollController = ScrollController();
|
||||
|
||||
@override
|
||||
@@ -125,7 +126,8 @@ class _MuralChatViewState extends State<MuralChatView> {
|
||||
} catch (e, s) {
|
||||
Logs().w('Failed to load more mural posts', e, s);
|
||||
} finally {
|
||||
if (timeline.events.length <= eventCountBefore) {
|
||||
if (!timeline.canRequestHistory ||
|
||||
timeline.events.length <= eventCountBefore) {
|
||||
_historyEnded = true;
|
||||
}
|
||||
_loadingHistory = false;
|
||||
@@ -133,6 +135,25 @@ class _MuralChatViewState extends State<MuralChatView> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Fetches older events from the server until enough media posts were
|
||||
/// loaded or the entire history was consumed. This makes the mural behave
|
||||
/// like a chat: after the initial sync only a handful of recent events are
|
||||
/// in the timeline which usually contain very few media posts (most events
|
||||
/// are thread comments), so we must actively fetch batches from the server
|
||||
/// until the feed is properly populated.
|
||||
Future<void> _fillInitialMedia() async {
|
||||
var attempts = 0;
|
||||
const maxAttempts = 20;
|
||||
const targetMediaCount = 30;
|
||||
while (mounted &&
|
||||
!_historyEnded &&
|
||||
_mediaEvents.length < targetMediaCount &&
|
||||
attempts < maxAttempts) {
|
||||
attempts++;
|
||||
await _loadMore();
|
||||
}
|
||||
}
|
||||
|
||||
void updateView() {
|
||||
if (!mounted) return;
|
||||
setState(() {});
|
||||
@@ -142,12 +163,16 @@ class _MuralChatViewState extends State<MuralChatView> {
|
||||
timeline?.cancelSubscriptions();
|
||||
_loadingHistory = false;
|
||||
_historyEnded = false;
|
||||
_initialLoading = true;
|
||||
timeline = await room.getTimeline(
|
||||
onUpdate: updateView,
|
||||
limit: Room.defaultHistoryCount * 3,
|
||||
);
|
||||
if (!mounted) return;
|
||||
setState(() {});
|
||||
await _fillInitialMedia();
|
||||
_initialLoading = false;
|
||||
if (mounted) setState(() {});
|
||||
}
|
||||
|
||||
Future<void> _sendFiles(List<XFile>? files) async {
|
||||
@@ -318,7 +343,9 @@ class _MuralChatViewState extends State<MuralChatView> {
|
||||
),
|
||||
const Divider(height: 1),
|
||||
Expanded(
|
||||
child: events.isEmpty
|
||||
child: _initialLoading
|
||||
? const Center(child: CircularProgressIndicator.adaptive())
|
||||
: events.isEmpty
|
||||
? Center(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(24),
|
||||
|
||||
Reference in New Issue
Block a user