Merge branch 'main' of gitlab.com:famedly/fluffychat into main

This commit is contained in:
Christian Pauly 2021-04-14 13:40:19 +02:00
commit ebbfb395df
35 changed files with 224 additions and 99 deletions

View File

@ -4,6 +4,9 @@ linter:
rules: rules:
- camel_case_types - camel_case_types
- avoid_print - avoid_print
- constant_identifier_names
- prefer_final_locals
- prefer_final_in_for_each
analyzer: analyzer:
errors: errors:

View File

@ -7,24 +7,24 @@ import 'app_config.dart';
abstract class FluffyThemes { abstract class FluffyThemes {
static const double columnWidth = 360.0; static const double columnWidth = 360.0;
static const fallback_text_style = static const fallbackTextStyle =
TextStyle(fontFamily: 'NotoSans', fontFamilyFallback: ['NotoEmoji']); TextStyle(fontFamily: 'NotoSans', fontFamilyFallback: ['NotoEmoji']);
static var fallback_text_theme = PlatformInfos.isDesktop static var fallback_text_theme = PlatformInfos.isDesktop
? TextTheme( ? TextTheme(
bodyText1: fallback_text_style, bodyText1: fallbackTextStyle,
bodyText2: fallback_text_style, bodyText2: fallbackTextStyle,
button: fallback_text_style, button: fallbackTextStyle,
caption: fallback_text_style, caption: fallbackTextStyle,
overline: fallback_text_style, overline: fallbackTextStyle,
headline1: fallback_text_style, headline1: fallbackTextStyle,
headline2: fallback_text_style, headline2: fallbackTextStyle,
headline3: fallback_text_style, headline3: fallbackTextStyle,
headline4: fallback_text_style, headline4: fallbackTextStyle,
headline5: fallback_text_style, headline5: fallbackTextStyle,
headline6: fallback_text_style, headline6: fallbackTextStyle,
subtitle1: fallback_text_style, subtitle1: fallbackTextStyle,
subtitle2: fallback_text_style) subtitle2: fallbackTextStyle)
: TextTheme(); : TextTheme();
static ThemeData light = ThemeData( static ThemeData light = ThemeData(

View File

@ -28,16 +28,16 @@ class InvitationSelectionController extends State<InvitationSelection> {
Timer coolDown; Timer coolDown;
Future<List<User>> getContacts(BuildContext context) async { Future<List<User>> getContacts(BuildContext context) async {
var client = Matrix.of(context).client; final client = Matrix.of(context).client;
final room = client.getRoomById(widget.roomId); final room = client.getRoomById(widget.roomId);
var participants = await room.requestParticipants(); final participants = await room.requestParticipants();
participants.removeWhere( participants.removeWhere(
(u) => ![Membership.join, Membership.invite].contains(u.membership), (u) => ![Membership.join, Membership.invite].contains(u.membership),
); );
var contacts = <User>[]; final contacts = <User>[];
var userMap = <String, bool>{}; final userMap = <String, bool>{};
for (var i = 0; i < client.rooms.length; i++) { for (var i = 0; i < client.rooms.length; i++) {
var roomUsers = client.rooms[i].getParticipants(); final roomUsers = client.rooms[i].getParticipants();
for (var j = 0; j < roomUsers.length; j++) { for (var j = 0; j < roomUsers.length; j++) {
if (userMap[roomUsers[j].id] != true && if (userMap[roomUsers[j].id] != true &&

View File

@ -20,7 +20,7 @@ class SignUpController extends State<SignUp> {
MatrixFile avatar; MatrixFile avatar;
void setAvatarAction() async { void setAvatarAction() async {
var file = final file =
await FilePickerCross.importFromStorage(type: FileTypeCross.image); await FilePickerCross.importFromStorage(type: FileTypeCross.image);
if (file != null) { if (file != null) {
setState( setState(
@ -35,7 +35,7 @@ class SignUpController extends State<SignUp> {
void resetAvatarAction() => setState(() => avatar = null); void resetAvatarAction() => setState(() => avatar = null);
void signUpAction([_]) async { void signUpAction([_]) async {
var matrix = Matrix.of(context); final matrix = Matrix.of(context);
if (usernameController.text.isEmpty) { if (usernameController.text.isEmpty) {
setState(() => usernameError = L10n.of(context).pleaseChooseAUsername); setState(() => usernameError = L10n.of(context).pleaseChooseAUsername);
} else { } else {

View File

@ -29,7 +29,7 @@ class SignUpPasswordController extends State<SignUpPassword> {
void toggleShowPassword() => setState(() => showPassword = !showPassword); void toggleShowPassword() => setState(() => showPassword = !showPassword);
void signUpAction({AuthenticationData auth}) async { void signUpAction({AuthenticationData auth}) async {
var matrix = Matrix.of(context); final matrix = Matrix.of(context);
if (passwordController.text.isEmpty) { if (passwordController.text.isEmpty) {
setState(() => passwordError = L10n.of(context).pleaseEnterYourPassword); setState(() => passwordError = L10n.of(context).pleaseEnterYourPassword);
} else { } else {
@ -42,7 +42,7 @@ class SignUpPasswordController extends State<SignUpPassword> {
try { try {
setState(() => loading = true); setState(() => loading = true);
var waitForLogin = matrix.client.onLoginStateChanged.stream.first; final waitForLogin = matrix.client.onLoginStateChanged.stream.first;
await matrix.client.register( await matrix.client.register(
username: widget.username, username: widget.username,
password: passwordController.text, password: passwordController.text,

View File

@ -2304,5 +2304,15 @@
"@chats": { "@chats": {
"type": "text", "type": "text",
"placeholders": {} "placeholders": {}
},
"goToTheNewRoom": "Ir á nova sala",
"@goToTheNewRoom": {
"type": "text",
"placeholders": {}
},
"roomVersion": "Versión da sala",
"@roomVersion": {
"type": "text",
"placeholders": {}
} }
} }

View File

@ -2287,5 +2287,30 @@
"@tapOnDeviceToVerify": { "@tapOnDeviceToVerify": {
"type": "text", "type": "text",
"placeholders": {} "placeholders": {}
},
"goToTheNewRoom": "Vai nella nuova stanza",
"@goToTheNewRoom": {
"type": "text",
"placeholders": {}
},
"roomVersion": "Versione della stanza",
"@roomVersion": {
"type": "text",
"placeholders": {}
},
"publicGroups": "Gruppi pubblici",
"@publicGroups": {
"type": "text",
"placeholders": {}
},
"people": "Persone",
"@people": {
"type": "text",
"placeholders": {}
},
"chats": "Discussioni",
"@chats": {
"type": "text",
"placeholders": {}
} }
} }

View File

@ -2165,7 +2165,7 @@
"type": "text", "type": "text",
"placeholders": {} "placeholders": {}
}, },
"pleaseEnterSecurityKey": "Унесите свој сигурносни кључ", "pleaseEnterSecurityKey": "Унесите свој сигурносни кључ:",
"@pleaseEnterSecurityKey": { "@pleaseEnterSecurityKey": {
"type": "text", "type": "text",
"placeholders": {} "placeholders": {}
@ -2215,5 +2215,90 @@
"serverVersions": {}, "serverVersions": {},
"supportedVersions": {} "supportedVersions": {}
} }
},
"unlockChatBackup": "Откључај резерву ћаскања",
"@unlockChatBackup": {
"type": "text",
"placeholders": {}
},
"friends": "Пријатељи",
"@friends": {
"type": "text",
"placeholders": {}
},
"addNewFriend": "Додај новог пријатеља",
"@addNewFriend": {
"type": "text",
"placeholders": {}
},
"noEncryptionForPublicRooms": "Шифровање се може активирати након што соба престане да буде јавно доступна.",
"@noEncryptionForPublicRooms": {
"type": "text",
"placeholders": {}
},
"deviceVerifyDescription": "Шифровање је безбедно само када су сви уређаји верификовани.",
"@deviceVerifyDescription": {
"type": "text",
"placeholders": {}
},
"tapOnDeviceToVerify": "Тапните уређај да верификујете",
"@tapOnDeviceToVerify": {
"type": "text",
"placeholders": {}
},
"showPassword": "Прикажи лозинку",
"@showPassword": {
"type": "text",
"placeholders": {}
},
"addEmail": "Додај е-адресу",
"@addEmail": {
"type": "text",
"placeholders": {}
},
"zoomOut": "Умањи",
"@zoomOut": {
"type": "text",
"placeholders": {}
},
"zoomIn": "Увећај",
"@zoomIn": {
"type": "text",
"placeholders": {}
},
"blocked": "Блокиран",
"@blocked": {
"type": "text",
"placeholders": {}
},
"verified": "Верификовано",
"@verified": {
"type": "text",
"placeholders": {}
},
"goToTheNewRoom": "Иди у нову собу",
"@goToTheNewRoom": {
"type": "text",
"placeholders": {}
},
"roomVersion": "Верзија собе",
"@roomVersion": {
"type": "text",
"placeholders": {}
},
"publicGroups": "Јавне групе",
"@publicGroups": {
"type": "text",
"placeholders": {}
},
"people": "Људи",
"@people": {
"type": "text",
"placeholders": {}
},
"chats": "Ћаскања",
"@chats": {
"type": "text",
"placeholders": {}
} }
} }

View File

@ -300,13 +300,13 @@ class BackgroundPush {
} }
// initialise the plugin. app_icon needs to be a added as a drawable resource to the Android head project // initialise the plugin. app_icon needs to be a added as a drawable resource to the Android head project
var initializationSettingsAndroid = final initializationSettingsAndroid =
AndroidInitializationSettings('notifications_icon'); AndroidInitializationSettings('notifications_icon');
var initializationSettingsIOS = final initializationSettingsIOS =
IOSInitializationSettings(onDidReceiveLocalNotification: (i, a, b, c) { IOSInitializationSettings(onDidReceiveLocalNotification: (i, a, b, c) {
return null; return null;
}); });
var initializationSettings = InitializationSettings( final initializationSettings = InitializationSettings(
android: initializationSettingsAndroid, android: initializationSettingsAndroid,
iOS: initializationSettingsIOS, iOS: initializationSettingsIOS,
); );
@ -622,7 +622,7 @@ class BackgroundPush {
); );
// Show notification // Show notification
var androidPlatformChannelSpecifics = _getAndroidNotificationDetails( final androidPlatformChannelSpecifics = _getAndroidNotificationDetails(
styleInformation: MessagingStyleInformation( styleInformation: MessagingStyleInformation(
person, person,
conversationTitle: title, conversationTitle: title,
@ -636,8 +636,8 @@ class BackgroundPush {
), ),
ticker: l10n.newMessageInFluffyChat, ticker: l10n.newMessageInFluffyChat,
); );
var iOSPlatformChannelSpecifics = IOSNotificationDetails(); final iOSPlatformChannelSpecifics = IOSNotificationDetails();
var platformChannelSpecifics = NotificationDetails( final platformChannelSpecifics = NotificationDetails(
android: androidPlatformChannelSpecifics, android: androidPlatformChannelSpecifics,
iOS: iOSPlatformChannelSpecifics, iOS: iOSPlatformChannelSpecifics,
); );
@ -655,8 +655,8 @@ class BackgroundPush {
await setupLocalNotificationsPlugin(); await setupLocalNotificationsPlugin();
await loadLocale(); await loadLocale();
String eventId = data['event_id']; final String eventId = data['event_id'];
String roomId = data['room_id']; final String roomId = data['room_id'];
final unread = ((data['counts'] is String final unread = ((data['counts'] is String
? json.decode(data.tryGet<String>('counts', '{}')) ? json.decode(data.tryGet<String>('counts', '{}'))
: data.tryGet<Map<String, dynamic>>( : data.tryGet<Map<String, dynamic>>(
@ -668,9 +668,9 @@ class BackgroundPush {
} }
// Display notification // Display notification
var androidPlatformChannelSpecifics = _getAndroidNotificationDetails(); final androidPlatformChannelSpecifics = _getAndroidNotificationDetails();
var iOSPlatformChannelSpecifics = IOSNotificationDetails(); final iOSPlatformChannelSpecifics = IOSNotificationDetails();
var platformChannelSpecifics = NotificationDetails( final platformChannelSpecifics = NotificationDetails(
android: androidPlatformChannelSpecifics, android: androidPlatformChannelSpecifics,
iOS: iOSPlatformChannelSpecifics, iOS: iOSPlatformChannelSpecifics,
); );
@ -692,20 +692,20 @@ class BackgroundPush {
final thumbnail = width == null && height == null ? false : true; final thumbnail = width == null && height == null ? false : true;
final tempDirectory = (await getTemporaryDirectory()).path; final tempDirectory = (await getTemporaryDirectory()).path;
final prefix = thumbnail ? 'thumbnail' : ''; final prefix = thumbnail ? 'thumbnail' : '';
var file = final file =
File('$tempDirectory/${prefix}_${content.toString().split("/").last}'); File('$tempDirectory/${prefix}_${content.toString().split("/").last}');
if (!file.existsSync()) { if (!file.existsSync()) {
final url = thumbnail final url = thumbnail
? content.getThumbnail(client, width: width, height: height) ? content.getThumbnail(client, width: width, height: height)
: content.getDownloadLink(client); : content.getDownloadLink(client);
var request = await HttpClient().getUrl(Uri.parse(url)); final request = await HttpClient().getUrl(Uri.parse(url));
var response = await request.close(); final response = await request.close();
if (response.statusCode >= 300) { if (response.statusCode >= 300) {
// we are not in the 2xx range // we are not in the 2xx range
return null; return null;
} }
var bytes = await consolidateHttpClientResponseBytes(response); final bytes = await consolidateHttpClientResponseBytes(response);
await file.writeAsBytes(bytes); await file.writeAsBytes(bytes);
} }

View File

@ -44,13 +44,13 @@ extension DateTimeExtension on DateTime {
/// Returns [localizedTimeOfDay()] if the ChatTime is today, the name of the week /// Returns [localizedTimeOfDay()] if the ChatTime is today, the name of the week
/// day if the ChatTime is this week and a date string else. /// day if the ChatTime is this week and a date string else.
String localizedTimeShort(BuildContext context) { String localizedTimeShort(BuildContext context) {
var now = DateTime.now(); final now = DateTime.now();
var sameYear = now.year == year; final sameYear = now.year == year;
var sameDay = sameYear && now.month == month && now.day == day; final sameDay = sameYear && now.month == month && now.day == day;
var sameWeek = sameYear && final sameWeek = sameYear &&
!sameDay && !sameDay &&
now.millisecondsSinceEpoch - millisecondsSinceEpoch < now.millisecondsSinceEpoch - millisecondsSinceEpoch <
1000 * 60 * 60 * 24 * 7; 1000 * 60 * 60 * 24 * 7;
@ -86,11 +86,11 @@ extension DateTimeExtension on DateTime {
/// shows the date. /// shows the date.
/// TODO: Add localization /// TODO: Add localization
String localizedTime(BuildContext context) { String localizedTime(BuildContext context) {
var now = DateTime.now(); final now = DateTime.now();
var sameYear = now.year == year; final sameYear = now.year == year;
var sameDay = sameYear && now.month == month && now.day == day; final sameDay = sameYear && now.month == month && now.day == day;
if (sameDay) return localizedTimeOfDay(context); if (sameDay) return localizedTimeOfDay(context);
return L10n.of(context).dateAndTimeOfDay( return L10n.of(context).dateAndTimeOfDay(

View File

@ -15,7 +15,7 @@ extension MatrixFileExtension on MatrixFile {
if (kIsWeb) { if (kIsWeb) {
final fileName = name.split('/').last; final fileName = name.split('/').last;
final mimeType = mime(fileName); final mimeType = mime(fileName);
var element = html.document.createElement('a'); final element = html.document.createElement('a');
element.setAttribute( element.setAttribute(
'href', html.Url.createObjectUrlFromBlob(html.Blob([bytes]))); 'href', html.Url.createObjectUrlFromBlob(html.Blob([bytes])));
element.setAttribute('target', '_blank'); element.setAttribute('target', '_blank');

View File

@ -40,7 +40,7 @@ abstract class PlatformInfos {
} }
static void showDialog(BuildContext context) async { static void showDialog(BuildContext context) async {
var version = await PlatformInfos.getVersion(); final version = await PlatformInfos.getVersion();
showAboutDialog( showAboutDialog(
context: context, context: context,
useRootNavigator: false, useRootNavigator: false,

View File

@ -35,7 +35,7 @@ extension RoomStatusExtension on Room {
String getLocalizedTypingText(BuildContext context) { String getLocalizedTypingText(BuildContext context) {
var typingText = ''; var typingText = '';
var typingUsers = this.typingUsers; final typingUsers = this.typingUsers;
typingUsers.removeWhere((User u) => u.id == client.userID); typingUsers.removeWhere((User u) => u.id == client.userID);
if (AppConfig.hideTypingUsernames) { if (AppConfig.hideTypingUsernames) {

View File

@ -40,7 +40,7 @@ class UrlLauncher {
var roomId = room?.id; var roomId = room?.id;
// we make the servers a set and later on convert to a list, so that we can easily // we make the servers a set and later on convert to a list, so that we can easily
// deduplicate servers added via alias lookup and query parameter // deduplicate servers added via alias lookup and query parameter
var servers = <String>{}; final servers = <String>{};
if (room == null && roomIdOrAlias.sigil == '#') { if (room == null && roomIdOrAlias.sigil == '#') {
// we were unable to find the room locally...so resolve it // we were unable to find the room locally...so resolve it
final response = await showFutureLoadingDialog( final response = await showFutureLoadingDialog(

View File

@ -251,7 +251,7 @@ class _ChatState extends State<Chat> {
} }
void openCameraAction(BuildContext context) async { void openCameraAction(BuildContext context) async {
var file = await ImagePicker().getImage(source: ImageSource.camera); final file = await ImagePicker().getImage(source: ImageSource.camera);
if (file == null) return; if (file == null) return;
final bytes = await file.readAsBytes(); final bytes = await file.readAsBytes();
await showDialog( await showDialog(
@ -297,7 +297,7 @@ class _ChatState extends State<Chat> {
.getDisplayEvent(timeline) .getDisplayEvent(timeline)
.getLocalizedBody(MatrixLocals(L10n.of(context))); .getLocalizedBody(MatrixLocals(L10n.of(context)));
} }
for (var event in selectedEvents) { for (final event in selectedEvents) {
if (copyString.isNotEmpty) copyString += '\n\n'; if (copyString.isNotEmpty) copyString += '\n\n';
copyString += event.getDisplayEvent(timeline).getLocalizedBody( copyString += event.getDisplayEvent(timeline).getLocalizedBody(
MatrixLocals(L10n.of(context)), MatrixLocals(L10n.of(context)),
@ -356,7 +356,7 @@ class _ChatState extends State<Chat> {
} }
void redactEventsAction(BuildContext context) async { void redactEventsAction(BuildContext context) async {
var confirmed = await showOkCancelAlertDialog( final confirmed = await showOkCancelAlertDialog(
context: context, context: context,
title: L10n.of(context).messageWillBeRemovedWarning, title: L10n.of(context).messageWillBeRemovedWarning,
okLabel: L10n.of(context).remove, okLabel: L10n.of(context).remove,
@ -365,7 +365,7 @@ class _ChatState extends State<Chat> {
) == ) ==
OkCancelResult.ok; OkCancelResult.ok;
if (!confirmed) return; if (!confirmed) return;
for (var event in selectedEvents) { for (final event in selectedEvents) {
await showFutureLoadingDialog( await showFutureLoadingDialog(
context: context, context: context,
future: () => event.status > 0 ? event.redact() : event.remove()); future: () => event.status > 0 ? event.redact() : event.remove());
@ -374,7 +374,7 @@ class _ChatState extends State<Chat> {
} }
bool get canRedactSelectedEvents { bool get canRedactSelectedEvents {
for (var event in selectedEvents) { for (final event in selectedEvents) {
if (event.canRedact == false) return false; if (event.canRedact == false) return false;
} }
return true; return true;
@ -512,7 +512,7 @@ class _ChatState extends State<Chat> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
matrix = Matrix.of(context); matrix = Matrix.of(context);
var client = matrix.client; final client = matrix.client;
room ??= client.getRoomById(widget.id); room ??= client.getRoomById(widget.id);
if (room == null) { if (room == null) {
return Scaffold( return Scaffold(
@ -985,7 +985,7 @@ class _ChatState extends State<Chat> {
selectedEvents.length == 1)) { selectedEvents.length == 1)) {
return Container(); return Container();
} }
var emojis = List<String>.from(AppEmojis.emojis); final emojis = List<String>.from(AppEmojis.emojis);
final allReactionEvents = selectedEvents.first final allReactionEvents = selectedEvents.first
.aggregatedEvents( .aggregatedEvents(
timeline, RelationshipTypes.Reaction) timeline, RelationshipTypes.Reaction)

View File

@ -83,7 +83,7 @@ class _ChatDetailsState extends State<ChatDetails> {
final aliases = final aliases =
aliasEvent != null ? aliasEvent.content['aliases'] ?? [] : []; aliasEvent != null ? aliasEvent.content['aliases'] ?? [] : [];
if (aliases.indexWhere((s) => s == canonicalAlias) == -1) { if (aliases.indexWhere((s) => s == canonicalAlias) == -1) {
var newAliases = List<String>.from(aliases); final newAliases = List<String>.from(aliases);
newAliases.add(canonicalAlias); newAliases.add(canonicalAlias);
final response = await showFutureLoadingDialog( final response = await showFutureLoadingDialog(
context: context, context: context,

View File

@ -116,7 +116,7 @@ class _ChatEncryptionSettingsState extends State<ChatEncryptionSettings> {
onSelected: (action) => onSelected: (action) =>
onSelected(context, action, deviceKeys[i]), onSelected(context, action, deviceKeys[i]),
itemBuilder: (c) { itemBuilder: (c) {
var items = <PopupMenuEntry<String>>[]; final items = <PopupMenuEntry<String>>[];
if (room if (room
.client .client
.userDeviceKeys[deviceKeys[i].userId] .userDeviceKeys[deviceKeys[i].userId]
@ -166,7 +166,7 @@ class _ChatEncryptionSettingsState extends State<ChatEncryptionSettings> {
onSelected: (action) => onSelected: (action) =>
onSelected(context, action, deviceKeys[i]), onSelected(context, action, deviceKeys[i]),
itemBuilder: (c) { itemBuilder: (c) {
var items = <PopupMenuEntry<String>>[]; final items = <PopupMenuEntry<String>>[];
if (deviceKeys[i].blocked || if (deviceKeys[i].blocked ||
!deviceKeys[i].verified) { !deviceKeys[i].verified) {
items.add(PopupMenuItem( items.add(PopupMenuItem(

View File

@ -182,7 +182,7 @@ class _ChatListState extends State<ChatList> {
} }
Future<void> waitForFirstSync(BuildContext context) async { Future<void> waitForFirstSync(BuildContext context) async {
var client = Matrix.of(context).client; final client = Matrix.of(context).client;
if (client.prevBatch?.isEmpty ?? true) { if (client.prevBatch?.isEmpty ?? true) {
await client.onFirstSync.stream.first; await client.onFirstSync.stream.first;
} }
@ -371,7 +371,7 @@ class _ChatListState extends State<ChatList> {
future: waitForFirstSync(context), future: waitForFirstSync(context),
builder: (BuildContext context, snapshot) { builder: (BuildContext context, snapshot) {
if (snapshot.hasData) { if (snapshot.hasData) {
var rooms = List<Room>.from( final rooms = List<Room>.from(
Matrix.of(context).client.rooms); Matrix.of(context).client.rooms);
rooms.removeWhere((room) => room.lastEvent == null); rooms.removeWhere((room) => room.lastEvent == null);
if (rooms.isEmpty) { if (rooms.isEmpty) {

View File

@ -62,7 +62,7 @@ class InvitationSelectionView extends StatelessWidget {
child: CircularProgressIndicator(), child: CircularProgressIndicator(),
); );
} }
var contacts = snapshot.data; final contacts = snapshot.data;
return ListView.builder( return ListView.builder(
physics: NeverScrollableScrollPhysics(), physics: NeverScrollableScrollPhysics(),
shrinkWrap: true, shrinkWrap: true,

View File

@ -61,6 +61,7 @@ class _LogViewerState extends State<LogViewer> {
} }
class _AnsiParser { class _AnsiParser {
// ignore: constant_identifier_names
static const TEXT = 0, BRACKET = 1, CODE = 2; static const TEXT = 0, BRACKET = 1, CODE = 2;
final String text; final String text;
@ -73,12 +74,13 @@ class _AnsiParser {
spans = []; spans = [];
var state = TEXT; var state = TEXT;
StringBuffer buffer; StringBuffer buffer;
var text = StringBuffer(); final text = StringBuffer();
var code = 0; var code = 0;
List<int> codes; List<int> codes;
// ignore: prefer_final_locals
for (var i = 0, n = s.length; i < n; i++) { for (var i = 0, n = s.length; i < n; i++) {
var c = s[i]; final c = s[i];
switch (state) { switch (state) {
case TEXT: case TEXT:
@ -104,7 +106,7 @@ class _AnsiParser {
case CODE: case CODE:
buffer.write(c); buffer.write(c);
var codeUnit = c.codeUnitAt(0); final codeUnit = c.codeUnitAt(0);
if (codeUnit >= 48 && codeUnit <= 57) { if (codeUnit >= 48 && codeUnit <= 57) {
code = code * 10 + codeUnit - 48; code = code * 10 + codeUnit - 48;
continue; continue;

View File

@ -26,7 +26,7 @@ class _LoginState extends State<Login> {
bool showPassword = false; bool showPassword = false;
void login(BuildContext context) async { void login(BuildContext context) async {
var matrix = Matrix.of(context); final matrix = Matrix.of(context);
if (usernameController.text.isEmpty) { if (usernameController.text.isEmpty) {
setState(() => usernameError = L10n.of(context).pleaseEnterYourUsername); setState(() => usernameError = L10n.of(context).pleaseEnterYourUsername);
} else { } else {

View File

@ -121,7 +121,7 @@ class _NewPrivateChatState extends State<NewPrivateChat> {
return L10n.of(context).pleaseEnterAMatrixIdentifier; return L10n.of(context).pleaseEnterAMatrixIdentifier;
} }
final matrix = Matrix.of(context); final matrix = Matrix.of(context);
var mxid = '@' + controller.text.trim(); final mxid = '@' + controller.text.trim();
if (mxid == matrix.client.userID) { if (mxid == matrix.client.userID) {
return L10n.of(context).youCannotInviteYourself; return L10n.of(context).youCannotInviteYourself;
} }
@ -187,7 +187,7 @@ class _NewPrivateChatState extends State<NewPrivateChat> {
child: ListView.builder( child: ListView.builder(
itemCount: foundProfiles.length, itemCount: foundProfiles.length,
itemBuilder: (BuildContext context, int i) { itemBuilder: (BuildContext context, int i) {
var foundProfile = foundProfiles[i]; final foundProfile = foundProfiles[i];
return ListTile( return ListTile(
onTap: () { onTap: () {
setState(() { setState(() {

View File

@ -355,7 +355,7 @@ class _SearchViewState extends State<SearchView> {
? ListView.builder( ? ListView.builder(
itemCount: foundProfiles.length, itemCount: foundProfiles.length,
itemBuilder: (BuildContext context, int i) { itemBuilder: (BuildContext context, int i) {
var foundProfile = foundProfiles[i]; final foundProfile = foundProfiles[i];
return ListTile( return ListTile(
onTap: () async { onTap: () async {
final roomID = await showFutureLoadingDialog( final roomID = await showFutureLoadingDialog(

View File

@ -51,7 +51,7 @@ class _SettingsState extends State<Settings> {
OkCancelResult.cancel) { OkCancelResult.cancel) {
return; return;
} }
var matrix = Matrix.of(context); final matrix = Matrix.of(context);
await showFutureLoadingDialog( await showFutureLoadingDialog(
context: context, context: context,
future: () => matrix.client.logout(), future: () => matrix.client.logout(),
@ -146,7 +146,7 @@ class _SettingsState extends State<Settings> {
void setJitsiInstanceAction(BuildContext context) async { void setJitsiInstanceAction(BuildContext context) async {
const prefix = 'https://'; const prefix = 'https://';
var input = await showTextInputDialog( final input = await showTextInputDialog(
context: context, context: context,
title: L10n.of(context).editJitsiInstance, title: L10n.of(context).editJitsiInstance,
okLabel: L10n.of(context).ok, okLabel: L10n.of(context).ok,

View File

@ -38,9 +38,9 @@ class DevicesSettingsState extends State<DevicesSettings> {
useRootNavigator: false, useRootNavigator: false,
) == ) ==
OkCancelResult.cancel) return; OkCancelResult.cancel) return;
var matrix = Matrix.of(context); final matrix = Matrix.of(context);
var deviceIds = <String>[]; final deviceIds = <String>[];
for (var userDevice in devices) { for (final userDevice in devices) {
deviceIds.add(userDevice.deviceId); deviceIds.add(userDevice.deviceId);
} }
@ -150,10 +150,10 @@ class DevicesSettingsState extends State<DevicesSettings> {
if (!snapshot.hasData || this.devices == null) { if (!snapshot.hasData || this.devices == null) {
return Center(child: CircularProgressIndicator()); return Center(child: CircularProgressIndicator());
} }
Function isOwnDevice = (Device userDevice) => final Function isOwnDevice = (Device userDevice) =>
userDevice.deviceId == Matrix.of(context).client.deviceID; userDevice.deviceId == Matrix.of(context).client.deviceID;
final devices = List<Device>.from(this.devices); final devices = List<Device>.from(this.devices);
var thisDevice = final thisDevice =
devices.firstWhere(isOwnDevice, orElse: () => null); devices.firstWhere(isOwnDevice, orElse: () => null);
devices.removeWhere(isOwnDevice); devices.removeWhere(isOwnDevice);
devices.sort((a, b) => b.lastSeenTs.compareTo(a.lastSeenTs)); devices.sort((a, b) => b.lastSeenTs.compareTo(a.lastSeenTs));

View File

@ -137,7 +137,7 @@ class _EmotesSettingsState extends State<EmotesSettings> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
var client = Matrix.of(context).client; final client = Matrix.of(context).client;
if (emotes == null) { if (emotes == null) {
emotes = <_EmoteEntry>[]; emotes = <_EmoteEntry>[];
Map<String, dynamic> emoteSource; Map<String, dynamic> emoteSource;

View File

@ -27,10 +27,10 @@ class AudioPlayer extends StatefulWidget {
_AudioPlayerState createState() => _AudioPlayerState(); _AudioPlayerState createState() => _AudioPlayerState();
} }
enum AudioPlayerStatus { NOT_DOWNLOADED, DOWNLOADING, DOWNLOADED } enum AudioPlayerStatus { notDownloaded, downloading, downloaded }
class _AudioPlayerState extends State<AudioPlayer> { class _AudioPlayerState extends State<AudioPlayer> {
AudioPlayerStatus status = AudioPlayerStatus.NOT_DOWNLOADED; AudioPlayerStatus status = AudioPlayerStatus.notDownloaded;
final FlutterSoundPlayer flutterSound = FlutterSoundPlayer(); final FlutterSoundPlayer flutterSound = FlutterSoundPlayer();
@ -70,14 +70,14 @@ class _AudioPlayerState extends State<AudioPlayer> {
} }
Future<void> _downloadAction() async { Future<void> _downloadAction() async {
if (status != AudioPlayerStatus.NOT_DOWNLOADED) return; if (status != AudioPlayerStatus.notDownloaded) return;
setState(() => status = AudioPlayerStatus.DOWNLOADING); setState(() => status = AudioPlayerStatus.downloading);
try { try {
final matrixFile = final matrixFile =
await widget.event.downloadAndDecryptAttachmentCached(); await widget.event.downloadAndDecryptAttachmentCached();
setState(() { setState(() {
audioFile = matrixFile.bytes; audioFile = matrixFile.bytes;
status = AudioPlayerStatus.DOWNLOADED; status = AudioPlayerStatus.downloaded;
}); });
_playAction(); _playAction();
} catch (e, s) { } catch (e, s) {
@ -126,7 +126,7 @@ class _AudioPlayerState extends State<AudioPlayer> {
}); });
AudioPlayer.currentId = null; AudioPlayer.currentId = null;
} else if (e != null) { } else if (e != null) {
var txt = final txt =
'${e.position.inMinutes.toString().padLeft(2, '0')}:${(e.position.inSeconds % 60).toString().padLeft(2, '0')}'; '${e.position.inMinutes.toString().padLeft(2, '0')}:${(e.position.inSeconds % 60).toString().padLeft(2, '0')}';
setState(() { setState(() {
maxPosition = e.duration.inMilliseconds.toDouble(); maxPosition = e.duration.inMilliseconds.toDouble();
@ -158,7 +158,7 @@ class _AudioPlayerState extends State<AudioPlayer> {
children: <Widget>[ children: <Widget>[
Container( Container(
width: 30, width: 30,
child: status == AudioPlayerStatus.DOWNLOADING child: status == AudioPlayerStatus.downloading
? CircularProgressIndicator(strokeWidth: 2) ? CircularProgressIndicator(strokeWidth: 2)
: IconButton( : IconButton(
icon: Icon( icon: Icon(
@ -171,7 +171,7 @@ class _AudioPlayerState extends State<AudioPlayer> {
? L10n.of(context).audioPlayerPause ? L10n.of(context).audioPlayerPause
: L10n.of(context).audioPlayerPlay, : L10n.of(context).audioPlayerPlay,
onPressed: () { onPressed: () {
if (status == AudioPlayerStatus.DOWNLOADED) { if (status == AudioPlayerStatus.downloaded) {
_playAction(); _playAction();
} else { } else {
_downloadAction(); _downloadAction();
@ -184,7 +184,7 @@ class _AudioPlayerState extends State<AudioPlayer> {
value: currentPosition, value: currentPosition,
onChanged: (double position) => flutterSound onChanged: (double position) => flutterSound
.seekToPlayer(Duration(milliseconds: position.toInt())), .seekToPlayer(Duration(milliseconds: position.toInt())),
max: status == AudioPlayerStatus.DOWNLOADED ? maxPosition : 0, max: status == AudioPlayerStatus.downloaded ? maxPosition : 0,
min: 0, min: 0,
), ),
), ),

View File

@ -25,7 +25,7 @@ class Avatar extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
var thumbnail = mxContent?.getThumbnail( final thumbnail = mxContent?.getThumbnail(
client ?? Matrix.of(context).client, client ?? Matrix.of(context).client,
width: size * MediaQuery.of(context).devicePixelRatio, width: size * MediaQuery.of(context).devicePixelRatio,
height: size * MediaQuery.of(context).devicePixelRatio, height: size * MediaQuery.of(context).devicePixelRatio,

View File

@ -38,7 +38,7 @@ class _ChatSettingsPopupMenuState extends State<ChatSettingsPopupMenu> {
.listen( .listen(
(u) => setState(() => null), (u) => setState(() => null),
); );
var items = <PopupMenuEntry<String>>[ final items = <PopupMenuEntry<String>>[
widget.room.pushRuleState == PushRuleState.notify widget.room.pushRuleState == PushRuleState.notify
? PopupMenuItem<String>( ? PopupMenuItem<String>(
value: 'mute', value: 'mute',
@ -66,7 +66,7 @@ class _ChatSettingsPopupMenuState extends State<ChatSettingsPopupMenu> {
onSelected: (String choice) async { onSelected: (String choice) async {
switch (choice) { switch (choice) {
case 'leave': case 'leave':
var confirmed = await showOkCancelAlertDialog( final confirmed = await showOkCancelAlertDialog(
context: context, context: context,
useRootNavigator: false, useRootNavigator: false,
title: L10n.of(context).areYouSure, title: L10n.of(context).areYouSure,

View File

@ -248,7 +248,7 @@ class _KeyVerificationPageState extends State<KeyVerificationDialog> {
)); ));
break; break;
case KeyVerificationState.waitingSas: case KeyVerificationState.waitingSas:
var acceptText = widget.request.sasTypes.contains('emoji') final acceptText = widget.request.sasTypes.contains('emoji')
? L10n.of(context).waitingPartnerEmoji ? L10n.of(context).waitingPartnerEmoji
: L10n.of(context).waitingPartnerNumbers; : L10n.of(context).waitingPartnerNumbers;
body = Column( body = Column(

View File

@ -36,7 +36,7 @@ class _RecordingDialogState extends State<RecordingDialog> {
_recordedPath = '${tempDir.path}/recording${ext[codec.index]}'; _recordedPath = '${tempDir.path}/recording${ext[codec.index]}';
// delete any existing file // delete any existing file
var outputFile = File(_recordedPath); final outputFile = File(_recordedPath);
if (outputFile.existsSync()) { if (outputFile.existsSync()) {
await outputFile.delete(); await outputFile.delete();
} }

View File

@ -45,9 +45,9 @@ class Message extends StatelessWidget {
return StateMessage(event, unfold: unfold); return StateMessage(event, unfold: unfold);
} }
var client = Matrix.of(context).client; final client = Matrix.of(context).client;
final ownMessage = event.senderId == client.userID; final ownMessage = event.senderId == client.userID;
var alignment = ownMessage ? Alignment.topRight : Alignment.topLeft; final alignment = ownMessage ? Alignment.topRight : Alignment.topLeft;
var color = Theme.of(context).secondaryHeaderColor; var color = Theme.of(context).secondaryHeaderColor;
final sameSender = nextEvent != null && final sameSender = nextEvent != null &&
[EventTypes.Message, EventTypes.Sticker].contains(nextEvent.type) [EventTypes.Message, EventTypes.Sticker].contains(nextEvent.type)
@ -58,7 +58,7 @@ class Message extends StatelessWidget {
: Theme.of(context).brightness == Brightness.dark : Theme.of(context).brightness == Brightness.dark
? Colors.white ? Colors.white
: Colors.black; : Colors.black;
var rowMainAxisAlignment = final rowMainAxisAlignment =
ownMessage ? MainAxisAlignment.end : MainAxisAlignment.start; ownMessage ? MainAxisAlignment.end : MainAxisAlignment.start;
final displayEvent = event.getDisplayEvent(timeline); final displayEvent = event.getDisplayEvent(timeline);
@ -72,7 +72,7 @@ class Message extends StatelessWidget {
: Theme.of(context).primaryColor; : Theme.of(context).primaryColor;
} }
var rowChildren = <Widget>[ final rowChildren = <Widget>[
Expanded( Expanded(
child: Container( child: Container(
alignment: alignment, alignment: alignment,

View File

@ -12,7 +12,7 @@ class ParticipantListItem extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
var membershipBatch = <Membership, String>{ final membershipBatch = <Membership, String>{
Membership.join: '', Membership.join: '',
Membership.ban: L10n.of(context).banned, Membership.ban: L10n.of(context).banned,
Membership.invite: L10n.of(context).invited, Membership.invite: L10n.of(context).invited,

View File

@ -238,7 +238,7 @@ class MatrixState extends State<Matrix> with WidgetsBindingObserver {
Future<void> initConfig() async { Future<void> initConfig() async {
try { try {
var configJsonString = final configJsonString =
utf8.decode((await http.get('config.json')).bodyBytes); utf8.decode((await http.get('config.json')).bodyBytes);
final configJson = json.decode(configJsonString); final configJson = json.decode(configJsonString);
AppConfig.loadFromJson(configJson); AppConfig.loadFromJson(configJson);

View File

@ -90,7 +90,7 @@ class UserBottomSheet extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
final client = user.room.client; final client = user.room.client;
final presence = client.presences[user.id]; final presence = client.presences[user.id];
var items = <PopupMenuEntry<String>>[]; final items = <PopupMenuEntry<String>>[];
if (onMention != null) { if (onMention != null) {
items.add( items.add(