1
0
mirror of https://github.com/flutter/samples.git synced 2026-04-04 18:51:05 +00:00

Some linting_tool updates and cleanup (#1279)

This commit is contained in:
Parker Lougheed
2022-05-22 23:48:16 -05:00
committed by GitHub
parent 50863c5b63
commit d6296157f4
24 changed files with 187 additions and 196 deletions

View File

@@ -12,12 +12,10 @@ bool isDisplayLarge(BuildContext context) =>
/// Returns boolean value whether the window is considered medium size.
/// Used to build adaptive and responsive layouts.
bool isDisplayMedium(BuildContext context) {
return getWindowType(context) == AdaptiveWindowType.medium;
}
bool isDisplayMedium(BuildContext context) =>
getWindowType(context) == AdaptiveWindowType.medium;
/// Returns boolean value whether the window is considered small size.
/// Used to build adaptive and responsive layouts.
bool isDisplaySmall(BuildContext context) {
return getWindowType(context) <= AdaptiveWindowType.small;
}
bool isDisplaySmall(BuildContext context) =>
getWindowType(context) <= AdaptiveWindowType.small;

View File

@@ -10,7 +10,7 @@ import 'package:linting_tool/model/rule.dart';
import 'package:window_size/window_size.dart';
Future<void> main() async {
/// Initiliaze Hive DB.
/// Initialize Hive DB.
await Hive.initFlutter();
/// Register adapters for [Rule] and [RulesProfile]

View File

@@ -11,7 +11,7 @@ import 'package:linting_tool/model/rule.dart';
class EditingController extends ChangeNotifier {
bool _isEditing;
EditingController({bool? isEditing}) : _isEditing = isEditing ?? false;
EditingController({bool isEditing = false}) : _isEditing = isEditing;
bool get isEditing => _isEditing;
@@ -21,9 +21,9 @@ class EditingController extends ChangeNotifier {
notifyListeners();
}
final List<Rule> _selectedRules = [];
final Set<Rule> _selectedRules = {};
List<Rule> get selectedRules => _selectedRules;
Set<Rule> get selectedRules => _selectedRules;
void selectRule(Rule rule) {
_selectedRules.add(rule);
@@ -37,12 +37,10 @@ class EditingController extends ChangeNotifier {
Future deleteSelected(
RulesProfile profile, ProfilesStore profilesStore) async {
var rules = profile.rules;
for (var rule in _selectedRules) {
rules.remove(rule);
}
final rules = profile.rules;
rules.removeWhere((rule) => _selectedRules.contains(rule));
RulesProfile newProfile = RulesProfile(name: profile.name, rules: rules);
final newProfile = RulesProfile(name: profile.name, rules: rules);
await profilesStore.updateProfile(profile, newProfile);

View File

@@ -20,11 +20,12 @@ import 'package:yaml/yaml.dart';
const _boxName = 'rules_profile';
class ProfilesStore extends ChangeNotifier {
late final Repository repository;
ProfilesStore(http.Client httpClient) {
repository = Repository(httpClient);
final Repository repository;
ProfilesStore(http.Client httpClient) : repository = Repository(httpClient) {
fetchSavedProfiles();
}
bool _isLoading = true;
bool get isLoading => _isLoading;
@@ -41,8 +42,7 @@ class ProfilesStore extends ChangeNotifier {
if (!_isLoading) _isLoading = true;
notifyListeners();
try {
var profiles = await HiveService.getBoxes<RulesProfile>(_boxName);
_savedProfiles = profiles;
_savedProfiles = await HiveService.getBoxes<RulesProfile>(_boxName);
} on Exception catch (e) {
log(e.toString());
}
@@ -64,12 +64,16 @@ class ProfilesStore extends ChangeNotifier {
// TODO(abd99): Consider refactoring to LinkedHashSet/SplayTreeSet to avoid
// duplication automatically.
// ref: https://github.com/flutter/samples/pull/870#discussion_r685666792
var rules = profile.rules;
if (!rules.contains(rule)) {
rules.add(rule);
final rules = profile.rules;
// If rule is already in profile, skip updating profile
if (rules.contains(rule)) {
return;
}
RulesProfile newProfile = RulesProfile(name: profile.name, rules: rules);
rules.add(rule);
final newProfile = RulesProfile(name: profile.name, rules: rules);
await HiveService.updateBox<RulesProfile>(profile, newProfile, _boxName);
@@ -88,7 +92,7 @@ class ProfilesStore extends ChangeNotifier {
}
Future<void> removeRuleFromProfile(RulesProfile profile, Rule rule) async {
var newProfile =
final newProfile =
RulesProfile(name: profile.name, rules: profile.rules..remove(rule));
await updateProfile(profile, newProfile);
}
@@ -111,10 +115,10 @@ class ProfilesStore extends ChangeNotifier {
var resultSaved = false;
try {
var templateFileData = await repository.getTemplateFile();
final templateFileData = await repository.getTemplateFile();
/// Fetch formatted data to create new YamlFile.
String newYamlFile =
final newYamlFile =
_prepareYamlFile(profile, templateFileData, rulesStyle);
resultSaved = await _saveFileToDisk(newYamlFile);
@@ -136,7 +140,7 @@ class ProfilesStore extends ChangeNotifier {
const name = 'analysis_options.yaml';
/// Get file path using file picker.
var savePath = await file_selector.getSavePath(
final savePath = await file_selector.getSavePath(
suggestedName: name,
);
@@ -149,25 +153,21 @@ class ProfilesStore extends ChangeNotifier {
return true;
}
var errorMessage = 'File path not found.';
const errorMessage = 'File path not found.';
_error = errorMessage;
throw Exception(errorMessage);
}
String _prepareYamlFile(
RulesProfile profile, YamlMap templateFile, RulesStyle rulesStyle) {
var rules = profile.rules.map((e) => e.name).toList();
final rules = profile.rules.map((e) => e.name);
var rulesData =
final rulesData =
json.decode(json.encode(templateFile)) as Map<String, dynamic>;
/// Add rules to existing template according to formatting style.
if (rulesStyle == RulesStyle.booleanMap) {
var rulesMap = Map.fromEntries(
rules.map(
(e) => MapEntry(e, true),
),
);
final rulesMap = <String, bool>{for (final rule in rules) rule: true};
rulesData.update('linter', (dynamic value) => {'rules': rulesMap});
} else {
rulesData.update('linter', (dynamic value) => {'rules': rules});

View File

@@ -41,5 +41,5 @@ class Rule extends Equatable {
Map<String, dynamic> toJson() => _$RuleToJson(this);
@override
List<Object?> get props => [name];
List<Object> get props => [name];
}

View File

@@ -62,19 +62,17 @@ class RuleAdapter extends TypeAdapter<Rule> {
// JsonSerializableGenerator
// **************************************************************************
Rule _$RuleFromJson(Map<String, dynamic> json) {
return Rule(
name: json['name'] as String,
description: json['description'] as String,
group: json['group'] as String,
maturity: json['maturity'] as String,
incompatible: (json['incompatible'] as List<dynamic>)
.map((e) => e as String)
.toList(),
sets: (json['sets'] as List<dynamic>).map((e) => e as String).toList(),
details: json['details'] as String,
);
}
Rule _$RuleFromJson(Map<String, dynamic> json) => Rule(
name: json['name'] as String,
description: json['description'] as String,
group: json['group'] as String,
maturity: json['maturity'] as String,
incompatible: (json['incompatible'] as List<dynamic>)
.map((e) => e as String)
.toList(),
sets: (json['sets'] as List<dynamic>).map((e) => e as String).toList(),
details: json['details'] as String,
);
Map<String, dynamic> _$RuleToJson(Rule instance) => <String, dynamic>{
'name': instance.name,

View File

@@ -13,12 +13,12 @@ import 'package:linting_tool/repository/repository.dart';
/// Manages fetching rules from the web.
class RuleStore extends ChangeNotifier {
late final Repository repository;
final Repository repository;
RuleStore(http.Client httpClient) {
repository = Repository(httpClient);
RuleStore(http.Client httpClient) : repository = Repository(httpClient) {
fetchRules();
}
bool _isLoading = true;
bool get isLoading => _isLoading;
@@ -32,32 +32,31 @@ class RuleStore extends ChangeNotifier {
String? get error => _error;
List<RulesProfile> get defaultProfiles {
List<RulesProfile> defaultProfiles = [];
if (isLoading || rules.isEmpty) {
return const [];
}
var rulesWithDefaultSets =
rules.where((rule) => rule.sets.isNotEmpty).toList();
final Map<String, RulesProfile> setsToProfiles = {};
for (final rule in rulesWithDefaultSets) {
for (final rule in rules) {
for (final setName in rule.sets) {
var profileIndex =
defaultProfiles.indexWhere((profile) => profile.name == setName);
if (profileIndex >= 0) {
defaultProfiles[profileIndex].rules.add(rule);
final profile = setsToProfiles[setName];
if (profile == null) {
setsToProfiles[setName] = RulesProfile(name: setName, rules: [rule]);
} else {
defaultProfiles.add(RulesProfile(name: setName, rules: [rule]));
profile.rules.add(rule);
}
}
}
return defaultProfiles;
return setsToProfiles.values.toList(growable: false);
}
Future<void> fetchRules() async {
if (!_isLoading) _isLoading = true;
notifyListeners();
try {
var rules = await repository.getRulesList();
_rules = rules;
_rules = await repository.getRulesList();
} on SocketException catch (e) {
log(e.toString());
_error = 'Check internet connection.';

View File

@@ -20,8 +20,8 @@ class DefaultLintsPage extends StatelessWidget {
return const CircularProgressIndicator.adaptive();
}
if (rulesStore.defaultProfiles.isNotEmpty) {
var defaultSets = rulesStore.defaultProfiles;
final defaultSets = rulesStore.defaultProfiles;
if (defaultSets.isNotEmpty) {
final isDesktop = isDisplayLarge(context);
final isTablet = isDisplayMedium(context);
final startPadding = isTablet
@@ -45,7 +45,7 @@ class DefaultLintsPage extends StatelessWidget {
cacheExtent: 5,
itemCount: defaultSets.length,
itemBuilder: (context, index) {
var profile = rulesStore.defaultProfiles[index];
final profile = defaultSets[index];
return ListTile(
title: Text(
profile.name,

View File

@@ -20,7 +20,7 @@ class DefaultRulesPage extends StatelessWidget {
Widget build(BuildContext context) {
final isDesktop = isDisplayLarge(context);
final isTablet = isDisplayMedium(context);
var textTheme = Theme.of(context).textTheme;
final textTheme = Theme.of(context).textTheme;
final startPadding = isTablet
? 60.0
: isDesktop

View File

@@ -19,38 +19,36 @@ class HomePage extends StatelessWidget {
return const CircularProgressIndicator.adaptive();
}
if (!rulesStore.isLoading) {
if (rulesStore.rules.isNotEmpty) {
final isDesktop = isDisplayLarge(context);
final isTablet = isDisplayMedium(context);
final startPadding = isTablet
? 60.0
: isDesktop
? 120.0
: 16.0;
final endPadding = isTablet
? 60.0
: isDesktop
? 120.0
: 16.0;
if (rulesStore.rules.isNotEmpty) {
final isDesktop = isDisplayLarge(context);
final isTablet = isDisplayMedium(context);
final startPadding = isTablet
? 60.0
: isDesktop
? 120.0
: 16.0;
final endPadding = isTablet
? 60.0
: isDesktop
? 120.0
: 16.0;
return ListView.separated(
padding: EdgeInsetsDirectional.only(
start: startPadding,
end: endPadding,
top: isDesktop ? 28 : 16,
bottom: isDesktop ? kToolbarHeight : 16,
),
itemCount: rulesStore.rules.length,
cacheExtent: 5,
itemBuilder: (context, index) {
return LintExpansionTile(
rule: rulesStore.rules[index],
);
},
separatorBuilder: (context, index) => const SizedBox(height: 4),
);
}
return ListView.separated(
padding: EdgeInsetsDirectional.only(
start: startPadding,
end: endPadding,
top: isDesktop ? 28 : 16,
bottom: isDesktop ? kToolbarHeight : 16,
),
itemCount: rulesStore.rules.length,
cacheExtent: 5,
itemBuilder: (context, index) {
return LintExpansionTile(
rule: rulesStore.rules[index],
);
},
separatorBuilder: (context, index) => const SizedBox(height: 4),
);
}
return Column(

View File

@@ -23,7 +23,7 @@ class RulesPage extends StatelessWidget {
Widget build(BuildContext context) {
final isDesktop = isDisplayLarge(context);
final isTablet = isDisplayMedium(context);
var textTheme = Theme.of(context).textTheme;
final textTheme = Theme.of(context).textTheme;
final startPadding = isTablet
? 60.0
: isDesktop
@@ -85,7 +85,7 @@ class RulesPage extends StatelessWidget {
itemCount: profile.rules.length,
cacheExtent: 5,
itemBuilder: (context, index) {
/// Show righ-click context menu to delete rule.
/// Show right-click context menu to delete rule.
return ContextMenuRegion(
contextMenu: GenericContextMenu(
buttonConfigs: [

View File

@@ -8,8 +8,10 @@ import 'package:linting_tool/model/rule.dart';
import 'package:yaml/yaml.dart';
class APIProvider {
final _baseURL = 'https://dart-lang.github.io/linter';
static const String _baseURL = 'https://dart-lang.github.io/linter';
final http.Client httpClient;
APIProvider(this.httpClient);
Future<List<Rule>> getRulesList() async {
@@ -17,11 +19,10 @@ class APIProvider {
await httpClient.get(Uri.parse('$_baseURL//lints/machine/rules.json'));
if (response.statusCode == 200) {
List<Rule> rulesList = [];
final data = json.decode(response.body) as List;
for (var item in data) {
rulesList.add(Rule.fromJson(item as Map<String, dynamic>));
}
final rulesList = [
for (final item in data) Rule.fromJson(item as Map<String, dynamic>)
];
return rulesList;
} else {
throw Exception('Failed to load rules');

View File

@@ -10,7 +10,7 @@ class HiveService {
boxName,
);
List<T> existingProducts = await getBoxes(boxName);
final List<T> existingProducts = await getBoxes(boxName);
if (!existingProducts.contains(item)) {
await openBox.add(item);
@@ -24,9 +24,9 @@ class HiveService {
boxName,
);
List<T> existingProducts = await getBoxes(boxName);
final Set<T> existingProducts = Set.unmodifiable(await getBoxes(boxName));
for (var item in items) {
for (final item in items) {
if (!existingProducts.contains(item)) {
await openBox.add(item);
}
@@ -38,9 +38,9 @@ class HiveService {
boxName,
);
List<T> boxes = await getBoxes(boxName);
final List<T> boxes = await getBoxes(boxName);
for (var box in boxes) {
for (final box in boxes) {
if (box == item) {
await openBox.deleteAt(boxes.indexOf(item));
}
@@ -52,9 +52,9 @@ class HiveService {
boxName,
);
List<T> boxes = await getBoxes(boxName);
final List<T> boxes = await getBoxes(boxName);
for (var box in boxes) {
for (final box in boxes) {
if (box == item) {
await openBox.putAt(boxes.indexOf(item), newItem);
}
@@ -62,15 +62,13 @@ class HiveService {
}
static Future<List<T>> getBoxes<T>(String boxName, [String? query]) async {
List<T> boxList = [];
final openBox = await Hive.openLazyBox<T>(boxName);
int length = openBox.length;
final length = openBox.length;
for (int i = 0; i < length; i++) {
boxList.add(await openBox.getAt(i) as T);
}
final boxList = <T>[
for (int i = 0; i < length; i++) await openBox.getAt(i) as T
];
return boxList;
}

View File

@@ -8,11 +8,9 @@ import 'package:linting_tool/repository/api_provider.dart';
import 'package:yaml/yaml.dart';
class Repository {
late final APIProvider _apiProvider;
final APIProvider _apiProvider;
Repository(http.Client httpClient) {
_apiProvider = APIProvider(httpClient);
}
Repository(http.Client httpClient) : _apiProvider = APIProvider(httpClient);
Future<List<Rule>> getRulesList() => _apiProvider.getRulesList();

View File

@@ -7,7 +7,7 @@ import 'package:flutter_markdown/flutter_markdown.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:linting_tool/theme/colors.dart';
class AppTheme {
abstract class AppTheme {
static ThemeData buildReplyLightTheme(BuildContext context) {
final base = ThemeData.light();
return base.copyWith(

View File

@@ -4,7 +4,7 @@
import 'package:flutter/material.dart';
class AppColors {
abstract class AppColors {
static const Color white50 = Color(0xFFFFFFFF);
static const Color black800 = Color(0xFF121212);

View File

@@ -46,7 +46,7 @@ class _AdaptiveNavState extends State<AdaptiveNav> {
),
];
final trailing = <String, IconData>{
const trailing = <String, IconData>{
'About': Icons.info_outline,
};
@@ -62,25 +62,25 @@ class _NavView extends StatefulWidget {
const _NavView({
required this.extended,
required this.destinations,
this.trailing,
this.trailing = const {},
});
final bool extended;
final List<_Destination> destinations;
final Map<String, IconData>? trailing;
final Map<String, IconData> trailing;
@override
_NavViewState createState() => _NavViewState();
}
class _NavViewState extends State<_NavView> {
late ValueNotifier<bool?> _isExtended;
late final ValueNotifier<bool> _isExtended;
var _selectedIndex = 0;
@override
void initState() {
super.initState();
_isExtended = ValueNotifier<bool?>(widget.extended);
_isExtended = ValueNotifier<bool>(widget.extended);
}
void _onDestinationSelected(int index) {
@@ -91,7 +91,7 @@ class _NavViewState extends State<_NavView> {
@override
Widget build(BuildContext context) {
var textTheme = Theme.of(context).textTheme;
final textTheme = Theme.of(context).textTheme;
return Scaffold(
appBar: AppBar(
title: Text(
@@ -115,7 +115,7 @@ class _NavViewState extends State<_NavView> {
minHeight: constraints.maxHeight,
),
child: IntrinsicHeight(
child: ValueListenableBuilder<bool?>(
child: ValueListenableBuilder<bool>(
valueListenable: _isExtended,
builder: (context, value, child) {
var isSmallDisplay = isDisplaySmall(context);
@@ -130,13 +130,13 @@ class _NavViewState extends State<_NavView> {
label: Text(destination.textLabel),
),
],
extended: _isExtended.value! && !isSmallDisplay,
extended: _isExtended.value && !isSmallDisplay,
labelType: NavigationRailLabelType.none,
leading: _NavigationRailHeader(
extended: _isExtended,
),
trailing: _NavigationRailTrailingSection(
trailingDestinations: widget.trailing!,
trailingDestinations: widget.trailing,
),
selectedIndex: _selectedIndex,
onDestinationSelected: _onDestinationSelected,

View File

@@ -13,6 +13,7 @@ import 'package:provider/provider.dart';
class LintExpansionTile extends StatefulWidget {
final Rule rule;
const LintExpansionTile({
required this.rule,
super.key,
@@ -24,10 +25,11 @@ class LintExpansionTile extends StatefulWidget {
class _LintExpansionTileState extends State<LintExpansionTile> {
var isExpanded = false;
@override
Widget build(BuildContext context) {
var theme = Theme.of(context);
var textTheme = theme.textTheme;
final theme = Theme.of(context);
final textTheme = theme.textTheme;
final rule = widget.rule;
final incompatibleString =
rule.incompatible.isNotEmpty ? rule.incompatible.join(', ') : 'none';
@@ -287,8 +289,8 @@ class ExistingProfileDialog extends StatefulWidget {
class _ExistingProfileDialogState extends State<ExistingProfileDialog> {
@override
Widget build(BuildContext context) {
var profilesStore = Provider.of<ProfilesStore>(context);
var savedProfiles = profilesStore.savedProfiles;
final profilesStore = Provider.of<ProfilesStore>(context);
final savedProfiles = profilesStore.savedProfiles;
return AlertDialog(
title: const Text('Select a lint profile'),
content: Column(

View File

@@ -12,6 +12,7 @@ import 'package:provider/provider.dart';
class SavedRuleTile extends StatefulWidget {
final Rule rule;
const SavedRuleTile({
required this.rule,
super.key,
@@ -27,8 +28,8 @@ class _SavedRuleTileState extends State<SavedRuleTile> {
@override
Widget build(BuildContext context) {
var theme = Theme.of(context);
var textTheme = theme.textTheme;
final theme = Theme.of(context);
final textTheme = theme.textTheme;
final rule = widget.rule;
final incompatibleString =
rule.incompatible.isNotEmpty ? rule.incompatible.join(', ') : 'none';