import 'package:famedlysdk/famedlysdk.dart'; import 'package:fluffychat/components/dialogs/simple_dialogs.dart'; import 'package:flutter/material.dart'; import '../utils/date_time_extension.dart'; import '../components/adaptive_page_layout.dart'; import '../components/matrix.dart'; import '../l10n/l10n.dart'; import 'chat_list.dart'; class DevicesSettingsView extends StatelessWidget { @override Widget build(BuildContext context) { return AdaptivePageLayout( primaryPage: FocusPage.SECOND, firstScaffold: ChatList(), secondScaffold: DevicesSettings(), ); } } class DevicesSettings extends StatefulWidget { @override DevicesSettingsState createState() => DevicesSettingsState(); } class DevicesSettingsState extends State { List devices; Future _loadUserDevices(BuildContext context) async { if (devices != null) return true; devices = await Matrix.of(context).client.requestUserDevices(); return true; } void reload() => setState(() => devices = null); void _removeDevicesAction( BuildContext context, List devices) async { if (await SimpleDialogs(context).askConfirmation() == false) return; var matrix = Matrix.of(context); var deviceIds = []; for (var userDevice in devices) { deviceIds.add(userDevice.deviceId); } final success = await SimpleDialogs(context) .tryRequestWithLoadingDialog(matrix.client.deleteDevices(deviceIds), onAdditionalAuth: (MatrixException exception) async { final password = await SimpleDialogs(context).enterText( titleText: L10n.of(context).pleaseEnterYourPassword, labelText: L10n.of(context).pleaseEnterYourPassword, hintText: '******', password: true); if (password == null) return; await matrix.client.deleteDevices(deviceIds, auth: matrix.getAuthByPassword(password, exception.session)); return; }); if (success != false) { reload(); } } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text(L10n.of(context).devices)), body: FutureBuilder( future: _loadUserDevices(context), builder: (BuildContext context, snapshot) { if (snapshot.hasError) { return Center( child: Column( mainAxisSize: MainAxisSize.min, children: [ Icon(Icons.error), Text(snapshot.error.toString()), ], ), ); } if (!snapshot.hasData || this.devices == null) { return Center(child: CircularProgressIndicator()); } Function isOwnDevice = (UserDevice userDevice) => userDevice.deviceId == Matrix.of(context).client.deviceID; final devices = List.from(this.devices); var thisDevice = devices.firstWhere(isOwnDevice, orElse: () => null); devices.removeWhere(isOwnDevice); devices.sort((a, b) => b.lastSeenTs.compareTo(a.lastSeenTs)); return Column( children: [ if (thisDevice != null) UserDeviceListItem( thisDevice, remove: (d) => _removeDevicesAction(context, [d]), ), Divider(height: 1), if (devices.isNotEmpty) ListTile( title: Text( L10n.of(context).removeAllOtherDevices, style: TextStyle(color: Colors.red), ), trailing: Icon(Icons.delete_outline), onTap: () => _removeDevicesAction(context, devices), ), Divider(height: 1), Expanded( child: devices.isEmpty ? Center( child: Icon( Icons.devices_other, size: 60, color: Theme.of(context).secondaryHeaderColor, ), ) : ListView.separated( separatorBuilder: (BuildContext context, int i) => Divider(height: 1), itemCount: devices.length, itemBuilder: (BuildContext context, int i) => UserDeviceListItem( devices[i], remove: (d) => _removeDevicesAction(context, [d]), ), ), ), ], ); }, ), ); } } class UserDeviceListItem extends StatelessWidget { final UserDevice userDevice; final Function remove; const UserDeviceListItem(this.userDevice, {this.remove, Key key}) : super(key: key); @override Widget build(BuildContext context) { return PopupMenuButton( onSelected: (String action) { if (action == 'remove' && remove != null) { remove(userDevice); } }, itemBuilder: (BuildContext context) => [ PopupMenuItem( value: 'remove', child: Text(L10n.of(context).removeDevice, style: TextStyle(color: Colors.red)), ), ], child: ListTile( contentPadding: EdgeInsets.all(16.0), title: Row( children: [ Expanded( child: Text( (userDevice.displayName?.isNotEmpty ?? false) ? userDevice.displayName : L10n.of(context).unknownDevice, maxLines: 1, overflow: TextOverflow.ellipsis, ), ), Text(userDevice.lastSeenTs.localizedTimeShort(context)), ], ), subtitle: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('${L10n.of(context).id}: ${userDevice.deviceId}'), Text('${L10n.of(context).lastSeenIp}: ${userDevice.lastSeenIp}'), ], ), ), ); } }