linter and lint fixes

This commit is contained in:
Mike Schwörer 2024-05-25 21:36:05 +02:00
parent 7e347a70c2
commit 72be45feb4
Signed by: Mikescher
GPG Key ID: D3C7172E0A70F8CF
15 changed files with 256 additions and 158 deletions

View File

@ -4,6 +4,8 @@ run:
dart run build_runner build dart run build_runner build
flutter run flutter run
test:
dart analyze
gen: gen:
dart run build_runner build dart run build_runner build

View File

@ -1,29 +1,117 @@
# This file configures the analyzer, which statically analyzes Dart code to
# check for errors, warnings, and lints.
#
# The issues identified by the analyzer are surfaced in the UI of Dart-enabled
# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
# invoked from the command line by running `flutter analyze`.
# The following line activates a set of recommended lints for Flutter apps, include:
# packages, and plugins designed to encourage good coding practices. - package:lints/recommended.yaml
include: package:flutter_lints/flutter.yaml - package:flutter_lints/flutter.yaml
linter: linter:
# The lint rules applied to this project can be customized in the
# section below to disable rules from the `package:flutter_lints/flutter.yaml`
# included above or to enable additional rules. A list of all available lints
# and their documentation is published at https://dart.dev/lints.
#
# Instead of disabling a lint rule for the entire project in the
# section below, it can also be suppressed for a single line of code
# or a specific dart file by using the `// ignore: name_of_lint` and
# `// ignore_for_file: name_of_lint` syntax on the line or in the file
# producing the lint.
rules: rules:
# avoid_print: false # Uncomment to disable the `avoid_print` rule always_use_package_imports: true,
# prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule avoid_empty_else: true,
prefer_relative_imports: true, avoid_returning_null_for_future: true,
avoid_type_to_string: true,
avoid_types_as_parameter_names: true,
avoid_web_libraries_in_flutter: true,
collection_methods_unrelated_type: true,
discarded_futures: true,
empty_statements: true,
hash_and_equals: true,
implicit_reopen: true,
invalid_case_patterns: true,
invariant_booleans: true,
no_duplicate_case_values: true,
no_logic_in_create_state: true,
no_self_assignments: true,
no_wildcard_variable_uses: true,
prefer_void_to_null: true,
unnecessary_statements: true,
valid_regexps: true,
always_declare_return_types: true,
always_put_control_body_on_new_line: true,
always_specify_types: true,
annotate_overrides: true,
annotate_redeclares: true,
avoid_annotating_with_dynamic: true,
avoid_function_literals_in_foreach_calls: true,
avoid_init_to_null: true,
avoid_null_checks_in_equality_operators: true,
avoid_renaming_method_parameters: true,
avoid_return_types_on_setters: true,
avoid_returning_null: true,
avoid_returning_null_for_void: true,
avoid_returning_this: true,
avoid_shadowing_type_parameters: true,
avoid_single_cascade_in_expression_statements: true,
avoid_unnecessary_containers: true,
avoid_unused_constructor_parameters: true,
avoid_void_async: true,
await_only_futures: true,
camel_case_extensions: true,
camel_case_types: true,
cast_nullable_to_non_nullable: true,
constant_identifier_names: true,
empty_catches: true,
eol_at_end_of_file: true,
exhaustive_cases: true,
file_names: true,
no_literal_bool_comparisons: true,
null_check_on_nullable_type_parameter: true,
null_closures: true,
overridden_fields: true,
prefer_adjacent_string_concatenation: true,
prefer_collection_literals: true,
prefer_conditional_assignment: true,
prefer_const_constructors: true,
prefer_const_constructors_in_immutables: true,
prefer_const_declarations: true,
prefer_const_literals_to_create_immutables: true,
prefer_contains: true,
prefer_final_fields: true,
prefer_for_elements_to_map_fromIterable: true,
prefer_function_declarations_over_variables: true,
prefer_generic_function_type_aliases: true,
prefer_if_null_operators: true,
prefer_initializing_formals: true,
prefer_inlined_adds: true,
prefer_interpolation_to_compose_strings: true,
prefer_is_empty: true,
prefer_is_not_empty: true,
prefer_is_not_operator: true,
prefer_iterable_whereType: true,
prefer_null_aware_operators: true,
prefer_spread_collections: true,
prefer_typing_uninitialized_variables: true,
provide_deprecation_message: true,
recursive_getters: true,
sized_box_for_whitespace: true,
type_init_formals: true,
type_literal_in_constant_pattern: true,
unnecessary_const: true,
unnecessary_constructor_name: true,
unnecessary_getters_setters: true,
unnecessary_late: true,
unnecessary_new: true,
unnecessary_null_aware_assignments: true,
unnecessary_null_in_if_null_operators: true,
unnecessary_nullable_for_final_variable_declarations: true,
unnecessary_overrides: true,
unnecessary_string_escapes: true,
unnecessary_string_interpolations: true,
unnecessary_this: true,
unnecessary_to_list_in_spreads: true,
use_full_hex_values_for_flutter_colors: true,
use_function_type_syntax_for_parameters: true,
use_rethrow_when_possible: true,
use_string_in_part_of_directives: true,
use_super_parameters: true,
void_checks: true,
depend_on_referenced_packages: true,
package_names: true,
secure_pubspec_urls: true,
# Additional information about this file can be found at analyzer:
# https://dart.dev/guides/language/analysis-options language:
strict-casts: true
strict-inference: true
strict-raw-types: true

View File

@ -74,7 +74,7 @@ class APIClient {
if (responseStatusCode != 200) { if (responseStatusCode != 200) {
try { try {
final apierr = APIError.fromJson(jsonDecode(responseBody)); final apierr = APIError.fromJson(jsonDecode(responseBody) as Map<String, dynamic>);
RequestLog.addRequestAPIError(name, t0, method, uri, req.body, req.headers, responseStatusCode, responseBody, responseHeaders, apierr); RequestLog.addRequestAPIError(name, t0, method, uri, req.body, req.headers, responseStatusCode, responseBody, responseHeaders, apierr);
showPlatformToast(child: Text('Request "${name}" is fehlgeschlagen'), context: ToastProvider.context); showPlatformToast(child: Text('Request "${name}" is fehlgeschlagen'), context: ToastProvider.context);
@ -90,7 +90,7 @@ class APIClient {
final data = jsonDecode(responseBody); final data = jsonDecode(responseBody);
if (fn != null) { if (fn != null) {
final result = fn(data); final result = fn(data as Map<String, dynamic>);
RequestLog.addRequestSuccess(name, t0, method, uri, req.body, req.headers, responseStatusCode, responseBody, responseHeaders); RequestLog.addRequestSuccess(name, t0, method, uri, req.body, req.headers, responseStatusCode, responseBody, responseHeaders);
return result; return result;
} else { } else {
@ -137,7 +137,7 @@ class APIClient {
method: 'GET', method: 'GET',
relURL: 'users/${auth.userId}/channels', relURL: 'users/${auth.userId}/channels',
query: {'selector': sel.apiKey}, query: {'selector': sel.apiKey},
fn: (json) => ChannelWithSubscription.fromJsonArray(json['channels']), fn: (json) => ChannelWithSubscription.fromJsonArray(json['channels'] as List<dynamic>),
auth: auth, auth: auth,
); );
} }

View File

@ -39,7 +39,7 @@ class SCNAppBar extends StatelessWidget implements PreferredSizeWidget {
icon: const Icon(FontAwesomeIcons.solidSpiderBlackWidow), icon: const Icon(FontAwesomeIcons.solidSpiderBlackWidow),
tooltip: 'Debug', tooltip: 'Debug',
onPressed: () { onPressed: () {
Navigator.push(context, MaterialPageRoute(builder: (context) => DebugMainPage())); Navigator.push(context, MaterialPageRoute<DebugMainPage>(builder: (context) => DebugMainPage()));
}, },
), ),
if (!showDebug) SizedBox.square(dimension: 40), if (!showDebug) SizedBox.square(dimension: 40),

View File

@ -13,10 +13,10 @@ class APIError {
factory APIError.fromJson(Map<String, dynamic> json) { factory APIError.fromJson(Map<String, dynamic> json) {
return APIError( return APIError(
success: json['success'], success: json['success'] as String,
error: json['error'], error: json['error'] as String,
errhighlight: json['errhighlight'], errhighlight: json['errhighlight'] as String,
message: json['message'], message: json['message'] as String,
); );
} }
} }

View File

@ -25,15 +25,15 @@ class Channel {
factory Channel.fromJson(Map<String, dynamic> json) { factory Channel.fromJson(Map<String, dynamic> json) {
return Channel( return Channel(
channelID: json['channel_id'], channelID: json['channel_id'] as String,
ownerUserID: json['owner_user_id'], ownerUserID: json['owner_user_id'] as String,
internalName: json['internal_name'], internalName: json['internal_name'] as String,
displayName: json['display_name'], displayName: json['display_name'] as String,
descriptionName: json['description_name'], descriptionName: json['description_name'] as String?,
subscribeKey: json['subscribe_key'], subscribeKey: json['subscribe_key'] as String?,
timestampCreated: json['timestamp_created'], timestampCreated: json['timestamp_created'] as String,
timestampLastSent: json['timestamp_lastsent'], timestampLastSent: json['timestamp_lastsent'] as String?,
messagesSent: json['messages_sent'], messagesSent: json['messages_sent'] as int,
); );
} }
} }
@ -56,20 +56,20 @@ class ChannelWithSubscription extends Channel {
factory ChannelWithSubscription.fromJson(Map<String, dynamic> json) { factory ChannelWithSubscription.fromJson(Map<String, dynamic> json) {
return ChannelWithSubscription( return ChannelWithSubscription(
channelID: json['channel_id'], channelID: json['channel_id'] as String,
ownerUserID: json['owner_user_id'], ownerUserID: json['owner_user_id'] as String,
internalName: json['internal_name'], internalName: json['internal_name'] as String,
displayName: json['display_name'], displayName: json['display_name'] as String,
descriptionName: json['description_name'], descriptionName: json['description_name'] as String?,
subscribeKey: json['subscribe_key'], subscribeKey: json['subscribe_key'] as String?,
timestampCreated: json['timestamp_created'], timestampCreated: json['timestamp_created'] as String,
timestampLastSent: json['timestamp_lastsent'], timestampLastSent: json['timestamp_lastsent'] as String?,
messagesSent: json['messages_sent'], messagesSent: json['messages_sent'] as int,
subscription: Subscription.fromJson(json['subscription']), subscription: Subscription.fromJson(json['subscription'] as Map<String, dynamic>),
); );
} }
static List<ChannelWithSubscription> fromJsonArray(List<dynamic> jsonArr) { static List<ChannelWithSubscription> fromJsonArray(List<dynamic> jsonArr) {
return jsonArr.map<ChannelWithSubscription>((e) => ChannelWithSubscription.fromJson(e)).toList(); return jsonArr.map<ChannelWithSubscription>((e) => ChannelWithSubscription.fromJson(e as Map<String, dynamic>)).toList();
} }
} }

View File

@ -31,26 +31,26 @@ class Message {
factory Message.fromJson(Map<String, dynamic> json) { factory Message.fromJson(Map<String, dynamic> json) {
return Message( return Message(
messageID: json['message_id'], messageID: json['message_id'] as String,
senderUserID: json['sender_user_id'], senderUserID: json['sender_user_id'] as String,
channelInternalName: json['channel_internal_name'], channelInternalName: json['channel_internal_name'] as String,
channelID: json['channel_id'], channelID: json['channel_id'] as String,
senderName: json['sender_name'], senderName: json['sender_name'] as String,
senderIP: json['sender_ip'], senderIP: json['sender_ip'] as String,
timestamp: json['timestamp'], timestamp: json['timestamp'] as String,
title: json['title'], title: json['title'] as String,
content: json['content'], content: json['content'] as String,
priority: json['priority'], priority: json['priority'] as int,
userMessageID: json['usr_message_id'], userMessageID: json['usr_message_id'] as String,
usedKeyID: json['used_key_id'], usedKeyID: json['used_key_id'] as String,
trimmed: json['trimmed'], trimmed: json['trimmed'] as bool,
); );
} }
static fromPaginatedJsonArray(Map<String, dynamic> data, String keyMessages, String keyToken) { static (String, List<Message>) fromPaginatedJsonArray(Map<String, dynamic> data, String keyMessages, String keyToken) {
final npt = data[keyToken] as String; final npt = data[keyToken] as String;
final messages = (data[keyMessages] as List<dynamic>).map<Message>((e) => Message.fromJson(e)).toList(); final messages = (data[keyMessages] as List<dynamic>).map<Message>((e) => Message.fromJson(e as Map<String, dynamic>)).toList();
return (npt, messages); return (npt, messages);
} }

View File

@ -19,13 +19,13 @@ class Subscription {
factory Subscription.fromJson(Map<String, dynamic> json) { factory Subscription.fromJson(Map<String, dynamic> json) {
return Subscription( return Subscription(
subscriptionID: json['subscription_id'], subscriptionID: json['subscription_id'] as String,
subscriberUserID: json['subscriber_user_id'], subscriberUserID: json['subscriber_user_id'] as String,
channelOwnerUserID: json['channel_owner_user_id'], channelOwnerUserID: json['channel_owner_user_id'] as String,
channelID: json['channel_id'], channelID: json['channel_id'] as String,
channelInternalName: json['channel_internal_name'], channelInternalName: json['channel_internal_name'] as String,
timestampCreated: json['timestamp_created'], timestampCreated: json['timestamp_created'] as String,
confirmed: json['confirmed'], confirmed: json['confirmed'] as bool,
); );
} }
} }

View File

@ -41,24 +41,24 @@ class User {
factory User.fromJson(Map<String, dynamic> json) { factory User.fromJson(Map<String, dynamic> json) {
return User( return User(
userID: json['user_id'], userID: json['user_id'] as String,
username: json['username'], username: json['username'] as String?,
timestampCreated: json['timestamp_created'], timestampCreated: json['timestamp_created'] as String,
timestampLastRead: json['timestamp_lastread'], timestampLastRead: json['timestamp_lastread'] as String?,
timestampLastSent: json['timestamp_lastsent'], timestampLastSent: json['timestamp_lastsent'] as String?,
messagesSent: json['messages_sent'], messagesSent: json['messages_sent'] as int,
quotaUsed: json['quota_used'], quotaUsed: json['quota_used'] as int,
quotaRemaining: json['quota_remaining'], quotaRemaining: json['quota_remaining'] as int,
quotaPerDay: json['quota_max'], quotaPerDay: json['quota_max'] as int,
isPro: json['is_pro'], isPro: json['is_pro'] as bool,
defaultChannel: json['default_channel'], defaultChannel: json['default_channel'] as String,
maxBodySize: json['max_body_size'], maxBodySize: json['max_body_size'] as int,
maxTitleLength: json['max_title_length'], maxTitleLength: json['max_title_length'] as int,
defaultPriority: json['default_priority'], defaultPriority: json['default_priority'] as int,
maxChannelNameLength: json['max_channel_name_length'], maxChannelNameLength: json['max_channel_name_length'] as int,
maxChannelDescriptionLength: json['max_channel_description_length'], maxChannelDescriptionLength: json['max_channel_description_length'] as int,
maxSenderNameLength: json['max_sender_name_length'], maxSenderNameLength: json['max_sender_name_length'] as int,
maxUserMessageIDLength: json['max_user_message_id_length'], maxUserMessageIDLength: json['max_user_message_id_length'] as int,
); );
} }
} }

View File

@ -25,62 +25,9 @@ class _DebugRequestsPageState extends State<DebugRequestsPage> {
itemBuilder: (context, listIndex) { itemBuilder: (context, listIndex) {
final req = requestsBox.getAt(requestsBox.length - listIndex - 1)!; final req = requestsBox.getAt(requestsBox.length - listIndex - 1)!;
if (req.type == 'SUCCESS') { if (req.type == 'SUCCESS') {
return Padding( return buildItemSuccess(context, req);
padding: const EdgeInsets.symmetric(horizontal: 0, vertical: 2.0),
child: GestureDetector(
onTap: () => Navigator.push(context, MaterialPageRoute(builder: (context) => DebugRequestViewPage(request: req))),
child: ListTile(
title: Row(
children: [
SizedBox(
width: 120,
child: Text(_dateFormat.format(req.timestampStart), style: TextStyle(fontSize: 12)),
),
Expanded(
child: Text(req.name, style: TextStyle(fontWeight: FontWeight.bold)),
),
SizedBox(width: 2),
Text('${req.timestampEnd.difference(req.timestampStart).inMilliseconds}ms', style: TextStyle(fontSize: 12)),
],
),
subtitle: Text(req.type),
),
),
);
} else { } else {
return Padding( return buildItemError(context, req);
padding: const EdgeInsets.symmetric(horizontal: 0, vertical: 2.0),
child: GestureDetector(
onTap: () => Navigator.push(context, MaterialPageRoute(builder: (context) => DebugRequestViewPage(request: req))),
child: ListTile(
tileColor: Theme.of(context).colorScheme.errorContainer,
textColor: Theme.of(context).colorScheme.onErrorContainer,
title: Row(
children: [
SizedBox(
width: 120,
child: Text(_dateFormat.format(req.timestampStart), style: TextStyle(fontSize: 12)),
),
Expanded(
child: Text(req.name, style: TextStyle(fontWeight: FontWeight.bold)),
),
SizedBox(width: 2),
Text('${req.timestampEnd.difference(req.timestampStart).inMilliseconds}ms', style: TextStyle(fontSize: 12)),
],
),
subtitle: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(req.type),
Text(
req.error,
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
],
)),
),
);
} }
}, },
); );
@ -88,4 +35,65 @@ class _DebugRequestsPageState extends State<DebugRequestsPage> {
), ),
); );
} }
Padding buildItemError(BuildContext context, SCNRequest req) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 0, vertical: 2.0),
child: GestureDetector(
onTap: () => Navigator.push(context, MaterialPageRoute<DebugRequestViewPage>(builder: (context) => DebugRequestViewPage(request: req))),
child: ListTile(
tileColor: Theme.of(context).colorScheme.errorContainer,
textColor: Theme.of(context).colorScheme.onErrorContainer,
title: Row(
children: [
SizedBox(
width: 120,
child: Text(_dateFormat.format(req.timestampStart), style: TextStyle(fontSize: 12)),
),
Expanded(
child: Text(req.name, style: TextStyle(fontWeight: FontWeight.bold)),
),
SizedBox(width: 2),
Text('${req.timestampEnd.difference(req.timestampStart).inMilliseconds}ms', style: TextStyle(fontSize: 12)),
],
),
subtitle: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(req.type),
Text(
req.error,
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
],
)),
),
);
}
Padding buildItemSuccess(BuildContext context, SCNRequest req) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 0, vertical: 2.0),
child: GestureDetector(
onTap: () => Navigator.push(context, MaterialPageRoute<DebugRequestViewPage>(builder: (context) => DebugRequestViewPage(request: req))),
child: ListTile(
title: Row(
children: [
SizedBox(
width: 120,
child: Text(_dateFormat.format(req.timestampStart), style: TextStyle(fontSize: 12)),
),
Expanded(
child: Text(req.name, style: TextStyle(fontWeight: FontWeight.bold)),
),
SizedBox(width: 2),
Text('${req.timestampEnd.difference(req.timestampStart).inMilliseconds}ms', style: TextStyle(fontSize: 12)),
],
),
subtitle: Text(req.type),
),
),
);
}
} }

View File

@ -48,7 +48,7 @@ class _MessageListPageState extends State<MessageListPage> {
try { try {
if (_channels == null) { if (_channels == null) {
final channels = await APIClient.getChannelList(acc.auth!, ChannelSelector.allAny); final channels = await APIClient.getChannelList(acc.auth!, ChannelSelector.allAny);
_channels = Map.fromIterable(channels, key: (e) => e.channelID); _channels = <String, ChannelWithSubscription>{for (var v in channels) v.channelID: v};
} }
final (npt, newItems) = await APIClient.getMessageList(acc.auth!, thisPageToken, _pageSize); final (npt, newItems) = await APIClient.getMessageList(acc.auth!, thisPageToken, _pageSize);
@ -76,7 +76,7 @@ class _MessageListPageState extends State<MessageListPage> {
message: item, message: item,
allChannels: _channels ?? {}, allChannels: _channels ?? {},
onPressed: () { onPressed: () {
Navigator.push(context, MaterialPageRoute(builder: (context) => MessageViewPage(message: item))); Navigator.push(context, MaterialPageRoute<MessageViewPage>(builder: (context) => MessageViewPage(message: item)));
}, },
), ),
), ),

View File

@ -145,7 +145,7 @@ class MessageListItem extends StatelessWidget {
); );
} }
processContent(String? v) { String processContent(String? v) {
if (v == null) { if (v == null) {
return ''; return '';
} }
@ -158,7 +158,7 @@ class MessageListItem extends StatelessWidget {
return lines.sublist(0, min(_lineCount, lines.length)).join("\n").trim(); return lines.sublist(0, min(_lineCount, lines.length)).join("\n").trim();
} }
processTitle(String? v) { String processTitle(String? v) {
if (v == null) { if (v == null) {
return ''; return '';
} }
@ -174,7 +174,7 @@ class MessageListItem extends StatelessWidget {
return allChannels[message.channelID]?.displayName ?? message.channelInternalName; return allChannels[message.channelID]?.displayName ?? message.channelInternalName;
} }
showChannel(Message message) { bool showChannel(Message message) {
return message.channelInternalName != 'main'; return message.channelInternalName != 'main';
} }
} }

View File

@ -79,7 +79,7 @@ class _SendRootPageState extends State<SendRootPage> {
//... //...
} }
_buildQRCode(BuildContext context, UserAccount acc) { Widget _buildQRCode(BuildContext context, UserAccount acc) {
if (acc.auth == null) { if (acc.auth == null) {
return const Placeholder(); return const Placeholder();
} }

View File

@ -18,7 +18,7 @@ class Globals {
String platform = ''; String platform = '';
String hostname = ''; String hostname = '';
init() async { Future<void> init() async {
PackageInfo packageInfo = await PackageInfo.fromPlatform(); PackageInfo packageInfo = await PackageInfo.fromPlatform();
this.appName = packageInfo.appName; this.appName = packageInfo.appName;

View File

@ -38,7 +38,7 @@ class UserAccount extends ChangeNotifier {
notifyListeners(); notifyListeners();
} }
load() async { void load() async {
final prefs = await SharedPreferences.getInstance(); final prefs = await SharedPreferences.getInstance();
final uid = prefs.getString('auth.userid'); final uid = prefs.getString('auth.userid');
@ -51,7 +51,7 @@ class UserAccount extends ChangeNotifier {
} }
} }
save() async { Future<void> save() async {
final prefs = await SharedPreferences.getInstance(); final prefs = await SharedPreferences.getInstance();
if (_auth == null) { if (_auth == null) {
await prefs.remove('auth.userid'); await prefs.remove('auth.userid');
@ -62,9 +62,9 @@ class UserAccount extends ChangeNotifier {
} }
} }
loadUser(bool force) async { Future<User> loadUser(bool force) async {
if (!force && _user != null) { if (!force && _user != null) {
return _user; return _user!;
} }
if (_auth == null) { if (_auth == null) {