mirror of
https://github.com/flutter/samples.git
synced 2025-11-08 13:58:47 +00:00
[linting_tool] Implement saving rules to DB (#860)
This commit is contained in:
committed by
GitHub
parent
1818925286
commit
bbb8e342f1
@@ -3,6 +3,7 @@ include: package:flutter_lints/flutter.yaml
|
||||
analyzer:
|
||||
exclude:
|
||||
- lib/model/rule.g.dart
|
||||
- test/widget_test.mocks.dart
|
||||
strong-mode:
|
||||
implicit-casts: false
|
||||
implicit-dynamic: false
|
||||
|
||||
@@ -3,11 +3,13 @@
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:linting_tool/model/profiles_store.dart';
|
||||
import 'package:linting_tool/model/rules_store.dart';
|
||||
import 'package:linting_tool/theme/app_theme.dart';
|
||||
import 'package:linting_tool/widgets/adaptive_nav.dart';
|
||||
import 'package:linting_tool/routes.dart' as routes;
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
|
||||
class LintingTool extends StatefulWidget {
|
||||
const LintingTool({Key? key}) : super(key: key);
|
||||
@@ -21,8 +23,15 @@ class LintingTool extends StatefulWidget {
|
||||
class _LintingToolState extends State<LintingTool> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ChangeNotifierProvider<RuleStore>(
|
||||
create: (context) => RuleStore(),
|
||||
return MultiProvider(
|
||||
providers: [
|
||||
ChangeNotifierProvider<RuleStore>(
|
||||
create: (context) => RuleStore(http.Client()),
|
||||
),
|
||||
ChangeNotifierProvider<ProfilesStore>(
|
||||
create: (context) => ProfilesStore(),
|
||||
),
|
||||
],
|
||||
child: MaterialApp(
|
||||
title: 'Flutter Linting Tool',
|
||||
theme: AppTheme.buildReplyLightTheme(context),
|
||||
|
||||
@@ -3,8 +3,15 @@
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hive_flutter/hive_flutter.dart';
|
||||
import 'package:linting_tool/app.dart';
|
||||
import 'package:linting_tool/model/profile.dart';
|
||||
import 'package:linting_tool/model/rule.dart';
|
||||
|
||||
void main() {
|
||||
Future<void> main() async {
|
||||
await Hive.initFlutter();
|
||||
Hive.registerAdapter(RuleAdapter());
|
||||
Hive.registerAdapter(RulesProfileAdapter());
|
||||
await Hive.openLazyBox<RulesProfile>('rules_profile');
|
||||
runApp(const LintingTool());
|
||||
}
|
||||
|
||||
26
experimental/linting_tool/lib/model/profile.dart
Normal file
26
experimental/linting_tool/lib/model/profile.dart
Normal file
@@ -0,0 +1,26 @@
|
||||
// Copyright 2021 The Flutter team. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
import 'package:linting_tool/model/rule.dart';
|
||||
|
||||
part 'profile.g.dart';
|
||||
|
||||
@HiveType(typeId: 1)
|
||||
class RulesProfile extends Equatable {
|
||||
@HiveField(0)
|
||||
final String name;
|
||||
|
||||
@HiveField(1)
|
||||
final List<Rule> rules;
|
||||
|
||||
const RulesProfile({
|
||||
required this.name,
|
||||
required this.rules,
|
||||
});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [name];
|
||||
}
|
||||
44
experimental/linting_tool/lib/model/profile.g.dart
Normal file
44
experimental/linting_tool/lib/model/profile.g.dart
Normal file
@@ -0,0 +1,44 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'profile.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// TypeAdapterGenerator
|
||||
// **************************************************************************
|
||||
|
||||
class RulesProfileAdapter extends TypeAdapter<RulesProfile> {
|
||||
@override
|
||||
final int typeId = 1;
|
||||
|
||||
@override
|
||||
RulesProfile read(BinaryReader reader) {
|
||||
final numOfFields = reader.readByte();
|
||||
final fields = <int, dynamic>{
|
||||
for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(),
|
||||
};
|
||||
return RulesProfile(
|
||||
name: fields[0] as String,
|
||||
rules: (fields[1] as List).cast<Rule>(),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void write(BinaryWriter writer, RulesProfile obj) {
|
||||
writer
|
||||
..writeByte(2)
|
||||
..writeByte(0)
|
||||
..write(obj.name)
|
||||
..writeByte(1)
|
||||
..write(obj.rules);
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => typeId.hashCode;
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) =>
|
||||
identical(this, other) ||
|
||||
other is RulesProfileAdapter &&
|
||||
runtimeType == other.runtimeType &&
|
||||
typeId == other.typeId;
|
||||
}
|
||||
69
experimental/linting_tool/lib/model/profiles_store.dart
Normal file
69
experimental/linting_tool/lib/model/profiles_store.dart
Normal file
@@ -0,0 +1,69 @@
|
||||
// Copyright 2021 The Flutter team. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'dart:developer';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:linting_tool/model/profile.dart';
|
||||
import 'package:linting_tool/model/rule.dart';
|
||||
import 'package:linting_tool/repository/hive_service.dart';
|
||||
|
||||
const _boxName = 'rules_profile';
|
||||
|
||||
class ProfilesStore extends ChangeNotifier {
|
||||
ProfilesStore() {
|
||||
fetchSavedProfiles();
|
||||
}
|
||||
bool _isLoading = true;
|
||||
|
||||
bool get isLoading => _isLoading;
|
||||
|
||||
List<RulesProfile> _savedProfiles = [];
|
||||
|
||||
List<RulesProfile> get savedProfiles => _savedProfiles;
|
||||
|
||||
String? _error;
|
||||
|
||||
String? get error => _error;
|
||||
|
||||
Future<void> fetchSavedProfiles() async {
|
||||
if (!_isLoading) _isLoading = true;
|
||||
notifyListeners();
|
||||
try {
|
||||
var profiles = await HiveService.getBoxes<RulesProfile>(_boxName);
|
||||
_savedProfiles = profiles;
|
||||
} on Exception catch (e) {
|
||||
log(e.toString());
|
||||
}
|
||||
_isLoading = false;
|
||||
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
Future<void> addToNewProfile(RulesProfile profile) async {
|
||||
await HiveService.addBox<RulesProfile>(profile, _boxName);
|
||||
|
||||
await Future.delayed(const Duration(milliseconds: 100), () async {
|
||||
await fetchSavedProfiles();
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> addToExistingProfile(RulesProfile profile, Rule rule) async {
|
||||
RulesProfile newProfile =
|
||||
RulesProfile(name: profile.name, rules: profile.rules..add(rule));
|
||||
|
||||
await HiveService.updateBox<RulesProfile>(profile, newProfile, _boxName);
|
||||
|
||||
await Future.delayed(const Duration(milliseconds: 100), () async {
|
||||
await fetchSavedProfiles();
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> deleteProfile(RulesProfile profile) async {
|
||||
await HiveService.deleteBox<RulesProfile>(profile, _boxName);
|
||||
|
||||
await Future.delayed(const Duration(milliseconds: 100), () async {
|
||||
await fetchSavedProfiles();
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -3,18 +3,27 @@
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
|
||||
part 'rule.g.dart';
|
||||
|
||||
@JsonSerializable()
|
||||
@HiveType(typeId: 0)
|
||||
class Rule extends Equatable {
|
||||
@HiveField(0)
|
||||
final String name;
|
||||
@HiveField(1)
|
||||
final String description;
|
||||
@HiveField(2)
|
||||
final String group;
|
||||
@HiveField(3)
|
||||
final String maturity;
|
||||
@HiveField(4)
|
||||
final List<String> incompatible;
|
||||
@HiveField(5)
|
||||
final List<String> sets;
|
||||
@HiveField(6)
|
||||
final String details;
|
||||
|
||||
const Rule({
|
||||
|
||||
@@ -2,6 +2,62 @@
|
||||
|
||||
part of 'rule.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// TypeAdapterGenerator
|
||||
// **************************************************************************
|
||||
|
||||
class RuleAdapter extends TypeAdapter<Rule> {
|
||||
@override
|
||||
final int typeId = 0;
|
||||
|
||||
@override
|
||||
Rule read(BinaryReader reader) {
|
||||
final numOfFields = reader.readByte();
|
||||
final fields = <int, dynamic>{
|
||||
for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(),
|
||||
};
|
||||
return Rule(
|
||||
name: fields[0] as String,
|
||||
description: fields[1] as String,
|
||||
group: fields[2] as String,
|
||||
maturity: fields[3] as String,
|
||||
incompatible: (fields[4] as List).cast<String>(),
|
||||
sets: (fields[5] as List).cast<String>(),
|
||||
details: fields[6] as String,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void write(BinaryWriter writer, Rule obj) {
|
||||
writer
|
||||
..writeByte(7)
|
||||
..writeByte(0)
|
||||
..write(obj.name)
|
||||
..writeByte(1)
|
||||
..write(obj.description)
|
||||
..writeByte(2)
|
||||
..write(obj.group)
|
||||
..writeByte(3)
|
||||
..write(obj.maturity)
|
||||
..writeByte(4)
|
||||
..write(obj.incompatible)
|
||||
..writeByte(5)
|
||||
..write(obj.sets)
|
||||
..writeByte(6)
|
||||
..write(obj.details);
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => typeId.hashCode;
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) =>
|
||||
identical(this, other) ||
|
||||
other is RuleAdapter &&
|
||||
runtimeType == other.runtimeType &&
|
||||
typeId == other.typeId;
|
||||
}
|
||||
|
||||
// **************************************************************************
|
||||
// JsonSerializableGenerator
|
||||
// **************************************************************************
|
||||
|
||||
@@ -8,9 +8,13 @@ import 'dart:io';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:linting_tool/model/rule.dart';
|
||||
import 'package:linting_tool/repository/repository.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
|
||||
class RuleStore extends ChangeNotifier {
|
||||
RuleStore() {
|
||||
late final Repository repository;
|
||||
|
||||
RuleStore(http.Client httpClient) {
|
||||
repository = Repository(httpClient);
|
||||
fetchRules();
|
||||
}
|
||||
bool _isLoading = true;
|
||||
@@ -29,7 +33,7 @@ class RuleStore extends ChangeNotifier {
|
||||
if (!_isLoading) _isLoading = true;
|
||||
notifyListeners();
|
||||
try {
|
||||
var rules = await Repository().getRulesList();
|
||||
var rules = await repository.getRulesList();
|
||||
_rules = rules;
|
||||
} on SocketException catch (e) {
|
||||
log(e.toString());
|
||||
|
||||
74
experimental/linting_tool/lib/pages/rules_page.dart
Normal file
74
experimental/linting_tool/lib/pages/rules_page.dart
Normal file
@@ -0,0 +1,74 @@
|
||||
// Copyright 2021 The Flutter team. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:linting_tool/layout/adaptive.dart';
|
||||
import 'package:linting_tool/model/profile.dart';
|
||||
import 'package:linting_tool/widgets/saved_rule_tile.dart';
|
||||
|
||||
class RulesPage extends StatelessWidget {
|
||||
final RulesProfile profile;
|
||||
|
||||
const RulesPage({
|
||||
required this.profile,
|
||||
Key? key,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final isDesktop = isDisplayLarge(context);
|
||||
final isTablet = isDisplayMedium(context);
|
||||
var textTheme = Theme.of(context).textTheme;
|
||||
final startPadding = isTablet
|
||||
? 60.0
|
||||
: isDesktop
|
||||
? 120.0
|
||||
: 4.0;
|
||||
final endPadding = isTablet
|
||||
? 60.0
|
||||
: isDesktop
|
||||
? 120.0
|
||||
: 4.0;
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text(
|
||||
profile.name,
|
||||
style: textTheme.subtitle2!.copyWith(
|
||||
color: textTheme.bodyText1!.color,
|
||||
),
|
||||
),
|
||||
leading: Padding(
|
||||
padding: const EdgeInsets.only(left: 80.0),
|
||||
child: TextButton.icon(
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
icon: const Icon(Icons.arrow_back_ios_new),
|
||||
label: const Text('Back'),
|
||||
),
|
||||
),
|
||||
leadingWidth: 160.0,
|
||||
toolbarHeight: 38.0,
|
||||
backgroundColor: Colors.white,
|
||||
brightness: Brightness.light,
|
||||
),
|
||||
body: ListView.separated(
|
||||
padding: EdgeInsetsDirectional.only(
|
||||
start: startPadding,
|
||||
end: endPadding,
|
||||
top: isDesktop ? 28 : 0,
|
||||
bottom: isDesktop ? kToolbarHeight : 0,
|
||||
),
|
||||
itemCount: profile.rules.length,
|
||||
cacheExtent: 5,
|
||||
itemBuilder: (context, index) {
|
||||
return SavedRuleTile(
|
||||
rule: profile.rules[index],
|
||||
);
|
||||
},
|
||||
separatorBuilder: (context, index) => const SizedBox(height: 4),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -3,13 +3,124 @@
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:linting_tool/layout/adaptive.dart';
|
||||
import 'package:linting_tool/model/profiles_store.dart';
|
||||
import 'package:linting_tool/pages/rules_page.dart';
|
||||
import 'package:linting_tool/theme/colors.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
class SavedLintsPage extends StatelessWidget {
|
||||
const SavedLintsPage({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// TODO(abd99): Implement SavedLintsPage, showing a list of saved lint rules profiles.
|
||||
return const Text('Saved Profiles');
|
||||
return Consumer<ProfilesStore>(
|
||||
builder: (context, profilesStore, child) {
|
||||
if (profilesStore.isLoading) {
|
||||
return const CircularProgressIndicator.adaptive();
|
||||
}
|
||||
|
||||
if (!profilesStore.isLoading) {
|
||||
if (profilesStore.savedProfiles.isNotEmpty) {
|
||||
final isDesktop = isDisplayLarge(context);
|
||||
final isTablet = isDisplayMedium(context);
|
||||
final startPadding = isTablet
|
||||
? 60.0
|
||||
: isDesktop
|
||||
? 120.0
|
||||
: 4.0;
|
||||
final endPadding = isTablet
|
||||
? 60.0
|
||||
: isDesktop
|
||||
? 120.0
|
||||
: 4.0;
|
||||
|
||||
return ListView.separated(
|
||||
padding: EdgeInsetsDirectional.only(
|
||||
start: startPadding,
|
||||
end: endPadding,
|
||||
top: isDesktop ? 28 : 0,
|
||||
bottom: isDesktop ? kToolbarHeight : 0,
|
||||
),
|
||||
itemCount: profilesStore.savedProfiles.length,
|
||||
cacheExtent: 5,
|
||||
itemBuilder: (context, index) {
|
||||
var profile = profilesStore.savedProfiles[index];
|
||||
return ListTile(
|
||||
title: Text(
|
||||
profile.name,
|
||||
),
|
||||
tileColor: AppColors.white50,
|
||||
onTap: () {
|
||||
Navigator.push<void>(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => RulesPage(profile: profile),
|
||||
),
|
||||
);
|
||||
},
|
||||
trailing: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
IconButton(
|
||||
icon: const Icon(Icons.edit),
|
||||
onPressed: () {
|
||||
// TODO(abd99): Implement edit functionality.
|
||||
},
|
||||
),
|
||||
const SizedBox(
|
||||
width: 8.0,
|
||||
),
|
||||
PopupMenuButton<String>(
|
||||
icon: const Icon(Icons.more_vert),
|
||||
onSelected: (value) {
|
||||
switch (value) {
|
||||
case 'Export file':
|
||||
// TODO(abd99): Implement exporting files.
|
||||
break;
|
||||
case 'Delete':
|
||||
profilesStore.deleteProfile(profile);
|
||||
break;
|
||||
default:
|
||||
}
|
||||
},
|
||||
itemBuilder: (context) {
|
||||
return [
|
||||
const PopupMenuItem(
|
||||
child: Text('Export file'),
|
||||
value: 'Export file',
|
||||
),
|
||||
const PopupMenuItem(
|
||||
child: Text('Delete'),
|
||||
value: 'Delete',
|
||||
),
|
||||
];
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
separatorBuilder: (context, index) => const SizedBox(height: 4),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Text(profilesStore.error ?? 'No saved profiles found.'),
|
||||
const SizedBox(
|
||||
height: 16.0,
|
||||
),
|
||||
IconButton(
|
||||
onPressed: () => profilesStore.fetchSavedProfiles(),
|
||||
icon: const Icon(Icons.refresh),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,9 +8,12 @@ import 'package:linting_tool/model/rule.dart';
|
||||
|
||||
class APIProvider {
|
||||
final _baseURL = 'https://dart-lang.github.io/linter';
|
||||
final http.Client httpClient;
|
||||
APIProvider(this.httpClient);
|
||||
|
||||
Future<List<Rule>> getRulesList() async {
|
||||
http.Response response =
|
||||
await http.get(Uri.parse('$_baseURL//lints/machine/rules.json'));
|
||||
await httpClient.get(Uri.parse('$_baseURL//lints/machine/rules.json'));
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
List<Rule> rulesList = [];
|
||||
|
||||
77
experimental/linting_tool/lib/repository/hive_service.dart
Normal file
77
experimental/linting_tool/lib/repository/hive_service.dart
Normal file
@@ -0,0 +1,77 @@
|
||||
// Copyright 2021 The Flutter team. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'package:hive/hive.dart';
|
||||
|
||||
class HiveService {
|
||||
static Future<bool> addBox<T>(T item, String boxName) async {
|
||||
final openBox = await Hive.openLazyBox<T>(
|
||||
boxName,
|
||||
);
|
||||
|
||||
List<T> existingProducts = await getBoxes(boxName);
|
||||
|
||||
if (!existingProducts.contains(item)) {
|
||||
openBox.add(item);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static Future addBoxes<T>(List<T> items, String boxName) async {
|
||||
final openBox = await Hive.openLazyBox<T>(
|
||||
boxName,
|
||||
);
|
||||
|
||||
List<T> existingProducts = await getBoxes(boxName);
|
||||
|
||||
for (var item in items) {
|
||||
if (!existingProducts.contains(item)) {
|
||||
openBox.add(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static Future deleteBox<T>(T item, String boxName) async {
|
||||
final openBox = await Hive.openLazyBox<T>(
|
||||
boxName,
|
||||
);
|
||||
|
||||
List<T> boxes = await getBoxes(boxName);
|
||||
|
||||
for (var box in boxes) {
|
||||
if (box == item) {
|
||||
openBox.deleteAt(boxes.indexOf(item));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static Future updateBox<T>(T item, T newItem, String boxName) async {
|
||||
final openBox = await Hive.openLazyBox<T>(
|
||||
boxName,
|
||||
);
|
||||
|
||||
List<T> boxes = await getBoxes(boxName);
|
||||
|
||||
for (var box in boxes) {
|
||||
if (box == item) {
|
||||
openBox.putAt(boxes.indexOf(item), newItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
for (int i = 0; i < length; i++) {
|
||||
boxList.add(await openBox.getAt(i) as T);
|
||||
}
|
||||
|
||||
return boxList;
|
||||
}
|
||||
}
|
||||
@@ -4,9 +4,14 @@
|
||||
|
||||
import 'package:linting_tool/model/rule.dart';
|
||||
import 'package:linting_tool/repository/api_provider.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
|
||||
class Repository {
|
||||
final _apiProvider = APIProvider();
|
||||
late final APIProvider _apiProvider;
|
||||
|
||||
Repository(http.Client httpClient) {
|
||||
_apiProvider = APIProvider(httpClient);
|
||||
}
|
||||
|
||||
Future<List<Rule>> getRulesList() => _apiProvider.getRulesList();
|
||||
}
|
||||
|
||||
@@ -91,7 +91,19 @@ class _NavViewState extends State<_NavView> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var textTheme = Theme.of(context).textTheme;
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text(
|
||||
'Flutter Linting Tool',
|
||||
style: textTheme.subtitle2!.copyWith(
|
||||
color: textTheme.bodyText1!.color,
|
||||
),
|
||||
),
|
||||
toolbarHeight: 38.0,
|
||||
backgroundColor: Colors.white,
|
||||
brightness: Brightness.light,
|
||||
),
|
||||
body: Row(
|
||||
children: [
|
||||
LayoutBuilder(
|
||||
|
||||
@@ -4,9 +4,12 @@
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_markdown/flutter_markdown.dart';
|
||||
import 'package:linting_tool/model/profile.dart';
|
||||
import 'package:linting_tool/model/profiles_store.dart';
|
||||
import 'package:linting_tool/model/rule.dart';
|
||||
import 'package:linting_tool/theme/app_theme.dart';
|
||||
import 'package:linting_tool/theme/colors.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
class LintExpansionTile extends StatefulWidget {
|
||||
final Rule rule;
|
||||
@@ -127,8 +130,30 @@ class _LintExpansionTileState extends State<LintExpansionTile> {
|
||||
alignment: Alignment.centerRight,
|
||||
child: ElevatedButton(
|
||||
child: const Text('Add to profile'),
|
||||
onPressed: () {
|
||||
// TODO(abd99): Iplement adding to a profile.
|
||||
onPressed: () async {
|
||||
ProfileType? destinationProfileType =
|
||||
await showDialog<ProfileType>(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return const _ProfileTypeDialog();
|
||||
},
|
||||
);
|
||||
if (destinationProfileType == ProfileType.newProfile) {
|
||||
showDialog<String>(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return _NewProfileDialog(rule: rule);
|
||||
},
|
||||
);
|
||||
} else if (destinationProfileType ==
|
||||
ProfileType.existingProfile) {
|
||||
showDialog<String>(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return _ExistingProfileDialog(rule: rule);
|
||||
},
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
@@ -139,3 +164,145 @@ class _LintExpansionTileState extends State<LintExpansionTile> {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
enum ProfileType {
|
||||
newProfile,
|
||||
existingProfile,
|
||||
}
|
||||
|
||||
class _ProfileTypeDialog extends StatelessWidget {
|
||||
const _ProfileTypeDialog({
|
||||
Key? key,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AlertDialog(
|
||||
actionsPadding: const EdgeInsets.only(
|
||||
left: 16.0,
|
||||
right: 16.0,
|
||||
bottom: 16.0,
|
||||
),
|
||||
title: const Text('Select Profile Type'),
|
||||
actions: [
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
Navigator.pop(context, ProfileType.existingProfile);
|
||||
},
|
||||
child: const Text('Existing Profile'),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Navigator.pop(context, ProfileType.newProfile);
|
||||
},
|
||||
child: const Text('Create new profile'),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _NewProfileDialog extends StatelessWidget {
|
||||
final Rule rule;
|
||||
const _NewProfileDialog({
|
||||
required this.rule,
|
||||
Key? key,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
String name = '';
|
||||
final _formKey = GlobalKey<FormState>();
|
||||
|
||||
return AlertDialog(
|
||||
title: const Text('Create new lint profile'),
|
||||
content: Form(
|
||||
key: _formKey,
|
||||
autovalidateMode: AutovalidateMode.onUserInteraction,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Text('Profile Name'),
|
||||
TextFormField(
|
||||
onChanged: (value) {
|
||||
name = value;
|
||||
},
|
||||
validator: (value) {
|
||||
if (value == null || value.isEmpty) {
|
||||
return 'Name cannot be empty.';
|
||||
}
|
||||
return null;
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
actionsPadding: const EdgeInsets.all(16.0),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
child: const Text('Cancel'),
|
||||
),
|
||||
ElevatedButton(
|
||||
onPressed: () async {
|
||||
if (_formKey.currentState!.validate()) {
|
||||
var newProfile = RulesProfile(
|
||||
name: name,
|
||||
rules: [rule],
|
||||
);
|
||||
await Provider.of<ProfilesStore>(context, listen: false)
|
||||
.addToNewProfile(newProfile);
|
||||
Navigator.pop(context);
|
||||
}
|
||||
},
|
||||
child: const Text('Save'),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _ExistingProfileDialog extends StatelessWidget {
|
||||
const _ExistingProfileDialog({
|
||||
Key? key,
|
||||
required this.rule,
|
||||
}) : super(key: key);
|
||||
|
||||
final Rule rule;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var profilesStore = Provider.of<ProfilesStore>(context);
|
||||
var savedProfiles = profilesStore.savedProfiles;
|
||||
return AlertDialog(
|
||||
title: const Text('Select a lint profile'),
|
||||
content: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: List.generate(
|
||||
savedProfiles.length,
|
||||
(index) => ListTile(
|
||||
title: Text(savedProfiles[index].name),
|
||||
onTap: () async {
|
||||
await profilesStore.addToExistingProfile(
|
||||
savedProfiles[index], rule);
|
||||
Navigator.pop(context);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
actionsPadding: const EdgeInsets.all(16.0),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
child: const Text('Cancel'),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
132
experimental/linting_tool/lib/widgets/saved_rule_tile.dart
Normal file
132
experimental/linting_tool/lib/widgets/saved_rule_tile.dart
Normal file
@@ -0,0 +1,132 @@
|
||||
// Copyright 2021 The Flutter team. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_markdown/flutter_markdown.dart';
|
||||
import 'package:linting_tool/model/rule.dart';
|
||||
import 'package:linting_tool/theme/app_theme.dart';
|
||||
import 'package:linting_tool/theme/colors.dart';
|
||||
|
||||
class SavedRuleTile extends StatefulWidget {
|
||||
final Rule rule;
|
||||
const SavedRuleTile({
|
||||
required this.rule,
|
||||
Key? key,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
_SavedRuleTileState createState() => _SavedRuleTileState();
|
||||
}
|
||||
|
||||
class _SavedRuleTileState extends State<SavedRuleTile> {
|
||||
var isExpanded = false;
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var theme = Theme.of(context);
|
||||
var textTheme = theme.textTheme;
|
||||
final rule = widget.rule;
|
||||
final incompatibleString =
|
||||
rule.incompatible.isNotEmpty ? rule.incompatible.join(', ') : 'none';
|
||||
final setsString = rule.sets.isNotEmpty ? rule.sets.join(', ') : 'none';
|
||||
|
||||
// TODO(abd99): Add option to remove rule from profile.
|
||||
// TODO(abd99): Add right click functionality.
|
||||
return ExpansionTile(
|
||||
collapsedBackgroundColor: AppColors.white50,
|
||||
title: Text(
|
||||
rule.name,
|
||||
style: textTheme.subtitle1!.copyWith(
|
||||
fontWeight: FontWeight.w700,
|
||||
),
|
||||
),
|
||||
subtitle: Text(
|
||||
rule.description,
|
||||
style: textTheme.caption!,
|
||||
),
|
||||
initiallyExpanded: isExpanded,
|
||||
onExpansionChanged: (value) {
|
||||
setState(() {
|
||||
isExpanded = value;
|
||||
});
|
||||
},
|
||||
expandedAlignment: Alignment.centerLeft,
|
||||
childrenPadding: const EdgeInsets.symmetric(
|
||||
horizontal: 16.0,
|
||||
vertical: 8.0,
|
||||
),
|
||||
backgroundColor: AppColors.white50,
|
||||
maintainState: true,
|
||||
expandedCrossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text.rich(
|
||||
TextSpan(
|
||||
children: [
|
||||
TextSpan(
|
||||
text: 'Group:',
|
||||
style: textTheme.subtitle2,
|
||||
),
|
||||
TextSpan(
|
||||
text: ' ${rule.group}',
|
||||
),
|
||||
],
|
||||
),
|
||||
textAlign: TextAlign.left,
|
||||
),
|
||||
Text.rich(
|
||||
TextSpan(
|
||||
children: [
|
||||
TextSpan(
|
||||
text: 'Maturity:',
|
||||
style: textTheme.subtitle2,
|
||||
),
|
||||
TextSpan(
|
||||
text: ' ${rule.maturity}',
|
||||
),
|
||||
],
|
||||
),
|
||||
textAlign: TextAlign.left,
|
||||
),
|
||||
Text.rich(
|
||||
TextSpan(
|
||||
children: [
|
||||
TextSpan(
|
||||
text: 'Incompatible:',
|
||||
style: textTheme.subtitle2,
|
||||
),
|
||||
TextSpan(
|
||||
text: ' $incompatibleString',
|
||||
),
|
||||
],
|
||||
),
|
||||
textAlign: TextAlign.left,
|
||||
),
|
||||
Text.rich(
|
||||
TextSpan(
|
||||
children: [
|
||||
TextSpan(
|
||||
text: 'Sets:',
|
||||
style: textTheme.subtitle2,
|
||||
),
|
||||
TextSpan(
|
||||
text: ' $setsString',
|
||||
),
|
||||
],
|
||||
),
|
||||
textAlign: TextAlign.left,
|
||||
),
|
||||
const SizedBox(
|
||||
height: 16.0,
|
||||
),
|
||||
MarkdownBody(
|
||||
data: rule.details,
|
||||
selectable: true,
|
||||
styleSheet: AppTheme.buildMarkDownTheme(theme),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 16.0,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="14490.70" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="18122" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
|
||||
<dependencies>
|
||||
<deployment identifier="macosx"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="14490.70"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="18122"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
@@ -13,7 +13,7 @@
|
||||
</customObject>
|
||||
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
|
||||
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
|
||||
<customObject id="Voe-Tx-rLC" customClass="AppDelegate" customModule="Runner" customModuleProvider="target">
|
||||
<customObject id="Voe-Tx-rLC" customClass="AppDelegate" customModule="linting_tool" customModuleProvider="target">
|
||||
<connections>
|
||||
<outlet property="applicationMenu" destination="uQy-DD-JDr" id="XBo-yE-nKs"/>
|
||||
<outlet property="mainFlutterWindow" destination="QvC-M9-y7g" id="gIp-Ho-8D9"/>
|
||||
@@ -326,14 +326,15 @@
|
||||
</items>
|
||||
<point key="canvasLocation" x="142" y="-258"/>
|
||||
</menu>
|
||||
<window title="APP_NAME" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" animationBehavior="default" id="QvC-M9-y7g" customClass="MainFlutterWindow" customModule="Runner" customModuleProvider="target">
|
||||
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/>
|
||||
<window title="APP_NAME" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" animationBehavior="default" titlebarAppearsTransparent="YES" titleVisibility="hidden" id="QvC-M9-y7g" customClass="MainFlutterWindow" customModule="linting_tool" customModuleProvider="target">
|
||||
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES" fullSizeContentView="YES"/>
|
||||
<rect key="contentRect" x="335" y="390" width="800" height="600"/>
|
||||
<rect key="screenRect" x="0.0" y="0.0" width="2560" height="1577"/>
|
||||
<rect key="screenRect" x="0.0" y="0.0" width="1440" height="875"/>
|
||||
<view key="contentView" wantsLayer="YES" id="EiT-Mj-1SZ">
|
||||
<rect key="frame" x="0.0" y="0.0" width="800" height="600"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</view>
|
||||
<point key="canvasLocation" x="7" y="-655"/>
|
||||
</window>
|
||||
</objects>
|
||||
</document>
|
||||
|
||||
@@ -263,6 +263,27 @@ packages:
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.0"
|
||||
hive:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: hive
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.4"
|
||||
hive_flutter:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: hive_flutter
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.1.0"
|
||||
hive_generator:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: hive_generator
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.1.0"
|
||||
http:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -354,6 +375,13 @@ packages:
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.0.0"
|
||||
mockito:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: mockito
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "5.0.13"
|
||||
nested:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -492,6 +520,13 @@ packages:
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.0.3"
|
||||
source_helper:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: source_helper
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.2.0"
|
||||
source_span:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
||||
@@ -14,8 +14,11 @@ dependencies:
|
||||
equatable: ^2.0.3
|
||||
flutter_markdown: ^0.6.2
|
||||
google_fonts: ^2.1.0
|
||||
hive: ^2.0.4
|
||||
hive_flutter: ^1.1.0
|
||||
http: ^0.13.3
|
||||
json_annotation: ^4.0.1
|
||||
mockito: ^5.0.13
|
||||
provider: ^5.0.0
|
||||
|
||||
dev_dependencies:
|
||||
@@ -23,6 +26,7 @@ dev_dependencies:
|
||||
sdk: flutter
|
||||
build_runner: ^2.0.6
|
||||
flutter_lints: ^1.0.3
|
||||
hive_generator: ^1.1.0
|
||||
json_serializable: ^4.1.4
|
||||
|
||||
flutter:
|
||||
|
||||
@@ -1,20 +1,88 @@
|
||||
// This is a basic Flutter widget test.
|
||||
//
|
||||
// To perform an interaction with a widget in your test, use the WidgetTester
|
||||
// utility that Flutter provides. For example, you can send tap and scroll
|
||||
// gestures. You can also use WidgetTester to find child widgets in the widget
|
||||
// tree, read text, and verify that the values of widget properties are correct.
|
||||
// Copyright 2021 The Flutter team. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:hive_flutter/hive_flutter.dart';
|
||||
import 'package:linting_tool/app.dart';
|
||||
import 'package:linting_tool/model/profile.dart';
|
||||
import 'package:linting_tool/model/profiles_store.dart';
|
||||
import 'package:linting_tool/model/rule.dart';
|
||||
import 'package:linting_tool/model/rules_store.dart';
|
||||
import 'package:linting_tool/pages/default_lints_page.dart';
|
||||
import 'package:linting_tool/pages/home_page.dart';
|
||||
import 'package:linting_tool/pages/saved_lints_page.dart';
|
||||
import 'package:linting_tool/theme/app_theme.dart';
|
||||
import 'package:linting_tool/widgets/adaptive_nav.dart';
|
||||
import 'package:mockito/annotations.dart';
|
||||
import 'package:mockito/mockito.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'widget_test.mocks.dart';
|
||||
|
||||
late MockClient _mockClient;
|
||||
|
||||
class _TestApp extends StatelessWidget {
|
||||
const _TestApp({
|
||||
Key? key,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MultiProvider(
|
||||
providers: [
|
||||
ChangeNotifierProvider<RuleStore>(
|
||||
create: (context) => RuleStore(_mockClient),
|
||||
),
|
||||
ChangeNotifierProvider<ProfilesStore>(
|
||||
create: (context) => ProfilesStore(),
|
||||
),
|
||||
],
|
||||
child: MaterialApp(
|
||||
title: 'Flutter Linting Tool',
|
||||
initialRoute: LintingTool.homeRoute,
|
||||
theme: AppTheme.buildReplyLightTheme(context),
|
||||
onGenerateRoute: (settings) {
|
||||
switch (settings.name) {
|
||||
case LintingTool.homeRoute:
|
||||
return MaterialPageRoute<void>(
|
||||
builder: (context) => const AdaptiveNav(),
|
||||
settings: settings,
|
||||
);
|
||||
}
|
||||
return null;
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@GenerateMocks([http.Client])
|
||||
void main() {
|
||||
setUp(() async {
|
||||
final tempDir = await Directory.systemTemp.createTemp();
|
||||
Hive.init(tempDir.path);
|
||||
Hive.registerAdapter(RuleAdapter());
|
||||
Hive.registerAdapter(RulesProfileAdapter());
|
||||
await Hive.openLazyBox<RulesProfile>('rules_profile');
|
||||
_mockClient = MockClient();
|
||||
});
|
||||
testWidgets('NavigationRail smoke test', (tester) async {
|
||||
await tester.pumpWidget(const LintingTool());
|
||||
var responseBody =
|
||||
'''[{"name": "always_use_package_imports","description": "Avoid relative imports for files in `lib/`.","group": "errors","maturity": "stable","incompatible": [],"sets": [],"details": "*DO* avoid relative imports for files in `lib/`.\n\nWhen mixing relative and absolute imports it's possible to create confusion\nwhere the same member gets imported in two different ways. One way to avoid\nthat is to ensure you consistently use absolute imports for files withing the\n`lib/` directory.\n\nThis is the opposite of 'prefer_relative_imports'.\nMight be used with 'avoid_relative_lib_imports' to avoid relative imports of\nfiles within `lib/` directory outside of it. (for example `test/`)\n\n**GOOD:**\n\n```dart\nimport 'package:foo/bar.dart';\n\nimport 'package:foo/baz.dart';\n\nimport 'package:foo/src/baz.dart';\n...\n```\n\n**BAD:**\n\n```dart\nimport 'baz.dart';\n\nimport 'src/bag.dart'\n\nimport '../lib/baz.dart';\n\n...\n```\n\n"}]''';
|
||||
|
||||
when(_mockClient.get(Uri.parse(
|
||||
'https://dart-lang.github.io/linter//lints/machine/rules.json')))
|
||||
.thenAnswer(
|
||||
(_) async => http.Response(responseBody, 400),
|
||||
);
|
||||
|
||||
await tester.pumpWidget(const _TestApp());
|
||||
|
||||
expect(find.byType(HomePage), findsOneWidget);
|
||||
expect(find.byType(SavedLintsPage), findsNothing);
|
||||
await tester.tap(find.text('Saved Profiles'));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
107
experimental/linting_tool/test/widget_test.mocks.dart
Normal file
107
experimental/linting_tool/test/widget_test.mocks.dart
Normal file
@@ -0,0 +1,107 @@
|
||||
// Mocks generated by Mockito 5.0.13 from annotations
|
||||
// in linting_tool/test/widget_test.dart.
|
||||
// Do not manually edit this file.
|
||||
|
||||
import 'dart:async' as _i5;
|
||||
import 'dart:convert' as _i6;
|
||||
import 'dart:typed_data' as _i7;
|
||||
|
||||
import 'package:http/src/base_request.dart' as _i8;
|
||||
import 'package:http/src/client.dart' as _i4;
|
||||
import 'package:http/src/response.dart' as _i2;
|
||||
import 'package:http/src/streamed_response.dart' as _i3;
|
||||
import 'package:mockito/mockito.dart' as _i1;
|
||||
|
||||
// ignore_for_file: avoid_redundant_argument_values
|
||||
// ignore_for_file: avoid_setters_without_getters
|
||||
// ignore_for_file: comment_references
|
||||
// ignore_for_file: implementation_imports
|
||||
// ignore_for_file: invalid_use_of_visible_for_testing_member
|
||||
// ignore_for_file: prefer_const_constructors
|
||||
// ignore_for_file: unnecessary_parenthesis
|
||||
|
||||
class _FakeResponse extends _i1.Fake implements _i2.Response {}
|
||||
|
||||
class _FakeStreamedResponse extends _i1.Fake implements _i3.StreamedResponse {}
|
||||
|
||||
/// A class which mocks [Client].
|
||||
///
|
||||
/// See the documentation for Mockito's code generation for more information.
|
||||
class MockClient extends _i1.Mock implements _i4.Client {
|
||||
MockClient() {
|
||||
_i1.throwOnMissingStub(this);
|
||||
}
|
||||
|
||||
@override
|
||||
_i5.Future<_i2.Response> head(Uri? url, {Map<String, String>? headers}) =>
|
||||
(super.noSuchMethod(Invocation.method(#head, [url], {#headers: headers}),
|
||||
returnValue: Future<_i2.Response>.value(_FakeResponse()))
|
||||
as _i5.Future<_i2.Response>);
|
||||
@override
|
||||
_i5.Future<_i2.Response> get(Uri? url, {Map<String, String>? headers}) =>
|
||||
(super.noSuchMethod(Invocation.method(#get, [url], {#headers: headers}),
|
||||
returnValue: Future<_i2.Response>.value(_FakeResponse()))
|
||||
as _i5.Future<_i2.Response>);
|
||||
@override
|
||||
_i5.Future<_i2.Response> post(Uri? url,
|
||||
{Map<String, String>? headers,
|
||||
Object? body,
|
||||
_i6.Encoding? encoding}) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(#post, [url],
|
||||
{#headers: headers, #body: body, #encoding: encoding}),
|
||||
returnValue: Future<_i2.Response>.value(_FakeResponse()))
|
||||
as _i5.Future<_i2.Response>);
|
||||
@override
|
||||
_i5.Future<_i2.Response> put(Uri? url,
|
||||
{Map<String, String>? headers,
|
||||
Object? body,
|
||||
_i6.Encoding? encoding}) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(#put, [url],
|
||||
{#headers: headers, #body: body, #encoding: encoding}),
|
||||
returnValue: Future<_i2.Response>.value(_FakeResponse()))
|
||||
as _i5.Future<_i2.Response>);
|
||||
@override
|
||||
_i5.Future<_i2.Response> patch(Uri? url,
|
||||
{Map<String, String>? headers,
|
||||
Object? body,
|
||||
_i6.Encoding? encoding}) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(#patch, [url],
|
||||
{#headers: headers, #body: body, #encoding: encoding}),
|
||||
returnValue: Future<_i2.Response>.value(_FakeResponse()))
|
||||
as _i5.Future<_i2.Response>);
|
||||
@override
|
||||
_i5.Future<_i2.Response> delete(Uri? url,
|
||||
{Map<String, String>? headers,
|
||||
Object? body,
|
||||
_i6.Encoding? encoding}) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(#delete, [url],
|
||||
{#headers: headers, #body: body, #encoding: encoding}),
|
||||
returnValue: Future<_i2.Response>.value(_FakeResponse()))
|
||||
as _i5.Future<_i2.Response>);
|
||||
@override
|
||||
_i5.Future<String> read(Uri? url, {Map<String, String>? headers}) =>
|
||||
(super.noSuchMethod(Invocation.method(#read, [url], {#headers: headers}),
|
||||
returnValue: Future<String>.value('')) as _i5.Future<String>);
|
||||
@override
|
||||
_i5.Future<_i7.Uint8List> readBytes(Uri? url,
|
||||
{Map<String, String>? headers}) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(#readBytes, [url], {#headers: headers}),
|
||||
returnValue: Future<_i7.Uint8List>.value(_i7.Uint8List(0)))
|
||||
as _i5.Future<_i7.Uint8List>);
|
||||
@override
|
||||
_i5.Future<_i3.StreamedResponse> send(_i8.BaseRequest? request) =>
|
||||
(super.noSuchMethod(Invocation.method(#send, [request]),
|
||||
returnValue:
|
||||
Future<_i3.StreamedResponse>.value(_FakeStreamedResponse()))
|
||||
as _i5.Future<_i3.StreamedResponse>);
|
||||
@override
|
||||
void close() => super.noSuchMethod(Invocation.method(#close, []),
|
||||
returnValueForMissingStub: null);
|
||||
@override
|
||||
String toString() => super.toString();
|
||||
}
|
||||
Reference in New Issue
Block a user