part of '../space_admin_dialog.dart'; class _PermissionsTab extends ConsumerStatefulWidget { final Room space; const _PermissionsTab({required this.space}); @override ConsumerState<_PermissionsTab> createState() => _PermissionsTabState(); } class _PermissionsTabState extends ConsumerState<_PermissionsTab> { bool _saving = false; String? _status; // Current power level values (loaded from room state) late Map _levels; static const _defaults = { 'events_default': 0, 'state_default': 50, 'invite': 0, 'kick': 50, 'ban': 50, 'redact': 50, }; static const _labels = { 'events_default': 'Nachrichten senden', 'state_default': 'Raum-Einstellungen ändern', 'invite': 'Mitglieder einladen', 'kick': 'Mitglieder kicken', 'ban': 'Mitglieder bannen', 'redact': 'Nachrichten löschen', }; @override void initState() { super.initState(); _load(); } void _load() { final content = widget.space .getState(EventTypes.RoomPowerLevels) ?.content ?? {}; _levels = { for (final key in _defaults.keys) key: (content[key] as int?) ?? _defaults[key]!, }; } Future _save() async { setState(() { _saving = true; _status = null; }); try { // Server-Stand holen und nur die geänderten Schlüssel mergen — der // lokale Cache kann unvollständig sein und würde users/events wipen. await updatePowerLevelsSafely(widget.space, (content) { for (final entry in _levels.entries) { content[entry.key] = entry.value; } }); setState(() => _status = 'Gespeichert'); } catch (e) { final msg = e is MatrixException ? '${e.errcode}: ${e.errorMessage}' : e.toString().split('\n').first; setState(() => _status = 'Fehler: $msg'); } finally { setState(() => _saving = false); } } @override Widget build(BuildContext context) { final pt = PyramidTheme.of(context); final ownPower = widget.space.ownPowerLevel; final canEdit = ownPower >= _kPowerAdmin; return SingleChildScrollView( padding: const EdgeInsets.all(20), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('Mindestberechtigungen', style: TextStyle( color: pt.fgDim, fontSize: 11, fontWeight: FontWeight.w700, letterSpacing: 0.8)), const SizedBox(height: 4), Text( 'Lege fest, welche Stufe ein Mitglied mindestens haben muss, um diese Aktion auszuführen.', style: TextStyle(color: pt.fgDim, fontSize: 12)), const SizedBox(height: 16), ...(_labels.entries.map((e) => _PermissionRow( label: e.value, value: _levels[e.key]!, enabled: canEdit, pt: pt, onChanged: (v) => setState(() => _levels[e.key] = v), ))), if (canEdit) ...[ const SizedBox(height: 20), if (_status != null) Padding( padding: const EdgeInsets.only(bottom: 8), child: Text(_status!, style: TextStyle( color: _status!.startsWith('F') ? const Color(0xFFED4245) : const Color(0xFF57F287), fontSize: 12)), ), SizedBox( width: double.infinity, child: FilledButton( onPressed: _saving ? null : _save, style: FilledButton.styleFrom( backgroundColor: pt.accent, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(pt.rBase)), ), child: _saving ? SizedBox( width: 18, height: 18, child: CircularProgressIndicator( strokeWidth: 2, color: pt.bg0)) : const Text('Speichern', style: TextStyle( color: Colors.white, fontWeight: FontWeight.w600)), ), ), ], ], ), ); } } class _PermissionRow extends StatelessWidget { final String label; final int value; final bool enabled; final PyramidTheme pt; final ValueChanged onChanged; const _PermissionRow({ required this.label, required this.value, required this.enabled, required this.pt, required this.onChanged, }); @override Widget build(BuildContext context) { return Padding( padding: const EdgeInsets.only(bottom: 12), child: Row( children: [ Expanded( child: Text(label, style: TextStyle( color: pt.fg, fontSize: 13, fontWeight: FontWeight.w500)), ), if (enabled) DropdownButton( value: value, dropdownColor: pt.bg2, underline: const SizedBox.shrink(), style: TextStyle(color: pt.fg, fontSize: 13), items: const [ DropdownMenuItem(value: 0, child: Text('Mitglied (0)')), DropdownMenuItem(value: 50, child: Text('Moderator (50)')), DropdownMenuItem(value: 100, child: Text('Admin (100)')), ], onChanged: (v) => v != null ? onChanged(v) : null, ) else Container( padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4), decoration: BoxDecoration( color: _powerColor(value, pt).withAlpha(30), borderRadius: BorderRadius.circular(6), ), child: Text(_powerLabel(value), style: TextStyle( color: _powerColor(value, pt), fontSize: 12, fontWeight: FontWeight.w600)), ), ], ), ); } }