mirror of
https://github.com/flutter/samples.git
synced 2025-11-08 13:58:47 +00:00
[linting_tool] Implement exporting profiles (#869)
This commit is contained in:
committed by
GitHub
parent
a46327ef80
commit
9986fe2f2c
@@ -11,6 +11,8 @@ import 'package:linting_tool/routes.dart' as routes;
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
|
||||
final client = http.Client();
|
||||
|
||||
class LintingTool extends StatefulWidget {
|
||||
const LintingTool({Key? key}) : super(key: key);
|
||||
|
||||
@@ -26,10 +28,10 @@ class _LintingToolState extends State<LintingTool> {
|
||||
return MultiProvider(
|
||||
providers: [
|
||||
ChangeNotifierProvider<RuleStore>(
|
||||
create: (context) => RuleStore(http.Client()),
|
||||
create: (context) => RuleStore(client),
|
||||
),
|
||||
ChangeNotifierProvider<ProfilesStore>(
|
||||
create: (context) => ProfilesStore(),
|
||||
create: (context) => ProfilesStore(client),
|
||||
),
|
||||
],
|
||||
child: MaterialApp(
|
||||
|
||||
@@ -2,16 +2,26 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'dart:convert';
|
||||
import 'dart:developer';
|
||||
import 'dart:io';
|
||||
import 'dart:typed_data';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:json2yaml/json2yaml.dart';
|
||||
import 'package:linting_tool/model/profile.dart';
|
||||
import 'package:linting_tool/model/rule.dart';
|
||||
import 'package:linting_tool/repository/hive_service.dart';
|
||||
import 'package:linting_tool/repository/repository.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:file_selector/file_selector.dart' as file_selector;
|
||||
import 'package:yaml/yaml.dart';
|
||||
|
||||
const _boxName = 'rules_profile';
|
||||
|
||||
class ProfilesStore extends ChangeNotifier {
|
||||
ProfilesStore() {
|
||||
late final Repository repository;
|
||||
ProfilesStore(http.Client httpClient) {
|
||||
repository = Repository(httpClient);
|
||||
fetchSavedProfiles();
|
||||
}
|
||||
bool _isLoading = true;
|
||||
@@ -66,4 +76,84 @@ class ProfilesStore extends ChangeNotifier {
|
||||
await fetchSavedProfiles();
|
||||
});
|
||||
}
|
||||
|
||||
Future<bool> exportProfileFile(
|
||||
RulesProfile profile, {
|
||||
RulesStyle rulesStyle = RulesStyle.booleanMap,
|
||||
}) async {
|
||||
_isLoading = true;
|
||||
notifyListeners();
|
||||
|
||||
var resultSaved = false;
|
||||
|
||||
try {
|
||||
var templateFileData = await repository.getTemplateFile();
|
||||
|
||||
String newYamlFile =
|
||||
_prepareYamlFile(profile, templateFileData, rulesStyle);
|
||||
|
||||
resultSaved = await _saveFileToDisk(newYamlFile);
|
||||
} on SocketException catch (e) {
|
||||
log(e.toString());
|
||||
_error = 'Check internet connection.';
|
||||
resultSaved = false;
|
||||
} on Exception catch (e) {
|
||||
log(e.toString());
|
||||
}
|
||||
|
||||
_isLoading = false;
|
||||
notifyListeners();
|
||||
|
||||
return resultSaved;
|
||||
}
|
||||
|
||||
Future<bool> _saveFileToDisk(String newYamlFile) async {
|
||||
const name = 'analysis_options.yaml';
|
||||
|
||||
/// Get file path using file picker.
|
||||
var savePath = await file_selector.getSavePath(
|
||||
suggestedName: name,
|
||||
);
|
||||
|
||||
final data = Uint8List.fromList(newYamlFile.codeUnits);
|
||||
final file = file_selector.XFile.fromData(data, name: name);
|
||||
|
||||
/// Save file to disk if path was provided.
|
||||
if (savePath != null) {
|
||||
file.saveTo(savePath);
|
||||
return true;
|
||||
}
|
||||
|
||||
var 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();
|
||||
|
||||
var 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),
|
||||
),
|
||||
);
|
||||
rulesData.update('linter', (dynamic value) => {'rules': rulesMap});
|
||||
} else {
|
||||
rulesData.update('linter', (dynamic value) => {'rules': rules});
|
||||
}
|
||||
|
||||
return json2yaml(rulesData, yamlStyle: YamlStyle.pubspecYaml);
|
||||
}
|
||||
}
|
||||
|
||||
/// Formatting style for rules.
|
||||
enum RulesStyle {
|
||||
list,
|
||||
booleanMap,
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ class SavedLintsPage extends StatelessWidget {
|
||||
),
|
||||
itemCount: profilesStore.savedProfiles.length,
|
||||
cacheExtent: 5,
|
||||
itemBuilder: (context, index) {
|
||||
itemBuilder: (itemBuilderContext, index) {
|
||||
var profile = profilesStore.savedProfiles[index];
|
||||
return ListTile(
|
||||
title: Text(
|
||||
@@ -74,10 +74,21 @@ class SavedLintsPage extends StatelessWidget {
|
||||
),
|
||||
PopupMenuButton<String>(
|
||||
icon: const Icon(Icons.more_vert),
|
||||
onSelected: (value) {
|
||||
onSelected: (value) async {
|
||||
switch (value) {
|
||||
case 'Export file':
|
||||
// TODO(abd99): Implement exporting files.
|
||||
// TODO(abd99): Add option to select formatting style.
|
||||
|
||||
var saved = await profilesStore
|
||||
.exportProfileFile(profile);
|
||||
|
||||
if (!saved) {
|
||||
_showSnackBar(
|
||||
context,
|
||||
profilesStore.error ?? 'Failed to save file.',
|
||||
);
|
||||
}
|
||||
|
||||
break;
|
||||
case 'Delete':
|
||||
profilesStore.deleteProfile(profile);
|
||||
@@ -123,4 +134,12 @@ class SavedLintsPage extends StatelessWidget {
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
void _showSnackBar(BuildContext context, String data) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text(data),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
import 'dart:convert';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:linting_tool/model/rule.dart';
|
||||
import 'package:yaml/yaml.dart';
|
||||
|
||||
class APIProvider {
|
||||
final _baseURL = 'https://dart-lang.github.io/linter';
|
||||
@@ -12,7 +13,7 @@ class APIProvider {
|
||||
APIProvider(this.httpClient);
|
||||
|
||||
Future<List<Rule>> getRulesList() async {
|
||||
http.Response response =
|
||||
final response =
|
||||
await httpClient.get(Uri.parse('$_baseURL//lints/machine/rules.json'));
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
@@ -26,4 +27,14 @@ class APIProvider {
|
||||
throw Exception('Failed to load rules');
|
||||
}
|
||||
}
|
||||
|
||||
Future<YamlMap> getTemplateFile() async {
|
||||
final response = await httpClient.get(Uri.parse(
|
||||
'https://raw.githubusercontent.com/flutter/flutter/master/packages/flutter_tools/templates/app_shared/analysis_options.yaml.tmpl'));
|
||||
if (response.statusCode == 200) {
|
||||
return loadYaml(response.body) as YamlMap;
|
||||
} else {
|
||||
throw Exception('Failed to load template file');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
import 'package:linting_tool/model/rule.dart';
|
||||
import 'package:linting_tool/repository/api_provider.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:yaml/yaml.dart';
|
||||
|
||||
class Repository {
|
||||
late final APIProvider _apiProvider;
|
||||
@@ -14,4 +15,6 @@ class Repository {
|
||||
}
|
||||
|
||||
Future<List<Rule>> getRulesList() => _apiProvider.getRulesList();
|
||||
|
||||
Future<YamlMap> getTemplateFile() => _apiProvider.getTemplateFile();
|
||||
}
|
||||
|
||||
@@ -4,6 +4,10 @@
|
||||
|
||||
#include "generated_plugin_registrant.h"
|
||||
|
||||
#include <file_selector_linux/file_selector_plugin.h>
|
||||
|
||||
void fl_register_plugins(FlPluginRegistry* registry) {
|
||||
g_autoptr(FlPluginRegistrar) file_selector_linux_registrar =
|
||||
fl_plugin_registry_get_registrar_for_plugin(registry, "FileSelectorPlugin");
|
||||
file_selector_plugin_register_with_registrar(file_selector_linux_registrar);
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#
|
||||
|
||||
list(APPEND FLUTTER_PLUGIN_LIST
|
||||
file_selector_linux
|
||||
)
|
||||
|
||||
set(PLUGIN_BUNDLED_LIBRARIES)
|
||||
|
||||
@@ -5,8 +5,10 @@
|
||||
import FlutterMacOS
|
||||
import Foundation
|
||||
|
||||
import file_selector_macos
|
||||
import path_provider_macos
|
||||
|
||||
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
||||
FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin"))
|
||||
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
|
||||
}
|
||||
|
||||
@@ -1,19 +1,25 @@
|
||||
PODS:
|
||||
- file_selector_macos (0.0.1):
|
||||
- FlutterMacOS
|
||||
- FlutterMacOS (1.0.0)
|
||||
- path_provider_macos (0.0.1):
|
||||
- FlutterMacOS
|
||||
|
||||
DEPENDENCIES:
|
||||
- file_selector_macos (from `Flutter/ephemeral/.symlinks/plugins/file_selector_macos/macos`)
|
||||
- FlutterMacOS (from `Flutter/ephemeral`)
|
||||
- path_provider_macos (from `Flutter/ephemeral/.symlinks/plugins/path_provider_macos/macos`)
|
||||
|
||||
EXTERNAL SOURCES:
|
||||
file_selector_macos:
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/file_selector_macos/macos
|
||||
FlutterMacOS:
|
||||
:path: Flutter/ephemeral
|
||||
path_provider_macos:
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/path_provider_macos/macos
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
file_selector_macos: ff6dc948d4ddd34e8602a1f60b7d0b4cc6051a47
|
||||
FlutterMacOS: 57701585bf7de1b3fc2bb61f6378d73bbdea8424
|
||||
path_provider_macos: a0a3fd666cb7cd0448e936fb4abad4052961002b
|
||||
|
||||
|
||||
@@ -10,5 +10,7 @@
|
||||
<true/>
|
||||
<key>com.apple.security.network.server</key>
|
||||
<true/>
|
||||
<key>com.apple.security.files.user-selected.read-write</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
|
||||
@@ -8,5 +8,7 @@
|
||||
<true/>
|
||||
<key>com.apple.security.network.server</key>
|
||||
<true/>
|
||||
<key>com.apple.security.files.user-selected.read-write</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
|
||||
@@ -155,6 +155,13 @@ packages:
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.0.1"
|
||||
cross_file:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: cross_file
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.3.1+4"
|
||||
crypto:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -204,6 +211,48 @@ packages:
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "6.1.2"
|
||||
file_selector:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: file_selector
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.8.2"
|
||||
file_selector_linux:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: file_selector_linux
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.0.2+1"
|
||||
file_selector_macos:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: file_selector_macos
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.0.4+1"
|
||||
file_selector_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: file_selector_platform_interface
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.2"
|
||||
file_selector_web:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: file_selector_web
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.8.1+1"
|
||||
file_selector_windows:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: file_selector_windows
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.0.2+1"
|
||||
fixnum:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -235,6 +284,11 @@ packages:
|
||||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
flutter_web_plugins:
|
||||
dependency: transitive
|
||||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
frontend_server_client:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -319,6 +373,13 @@ packages:
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.6.3"
|
||||
json2yaml:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: json2yaml
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.0"
|
||||
json_annotation:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -626,7 +687,7 @@ packages:
|
||||
source: hosted
|
||||
version: "0.2.0"
|
||||
yaml:
|
||||
dependency: transitive
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: yaml
|
||||
url: "https://pub.dartlang.org"
|
||||
@@ -634,4 +695,4 @@ packages:
|
||||
version: "3.1.0"
|
||||
sdks:
|
||||
dart: ">=2.13.0 <3.0.0"
|
||||
flutter: ">=1.20.0"
|
||||
flutter: ">=2.0.0"
|
||||
|
||||
@@ -12,14 +12,21 @@ dependencies:
|
||||
adaptive_breakpoints: ^0.0.4
|
||||
cupertino_icons: ^1.0.2
|
||||
equatable: ^2.0.3
|
||||
file_selector: ^0.8.2
|
||||
file_selector_linux: ^0.0.2+1
|
||||
file_selector_macos: ^0.0.4+1
|
||||
file_selector_web: ^0.8.1+1
|
||||
file_selector_windows: ^0.0.2+1
|
||||
flutter_markdown: ^0.6.2
|
||||
google_fonts: ^2.1.0
|
||||
hive: ^2.0.4
|
||||
hive_flutter: ^1.1.0
|
||||
http: ^0.13.3
|
||||
json2yaml: ^2.0.0
|
||||
json_annotation: ^4.0.1
|
||||
mockito: ^5.0.13
|
||||
provider: ^5.0.0
|
||||
yaml: ^3.1.0
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
|
||||
@@ -38,7 +38,7 @@ class _TestApp extends StatelessWidget {
|
||||
create: (context) => RuleStore(_mockClient),
|
||||
),
|
||||
ChangeNotifierProvider<ProfilesStore>(
|
||||
create: (context) => ProfilesStore(),
|
||||
create: (context) => ProfilesStore(_mockClient),
|
||||
),
|
||||
],
|
||||
child: MaterialApp(
|
||||
|
||||
@@ -4,6 +4,9 @@
|
||||
|
||||
#include "generated_plugin_registrant.h"
|
||||
|
||||
#include <file_selector_windows/file_selector_plugin.h>
|
||||
|
||||
void RegisterPlugins(flutter::PluginRegistry* registry) {
|
||||
FileSelectorPluginRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("FileSelectorPlugin"));
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#
|
||||
|
||||
list(APPEND FLUTTER_PLUGIN_LIST
|
||||
file_selector_windows
|
||||
)
|
||||
|
||||
set(PLUGIN_BUNDLED_LIBRARIES)
|
||||
|
||||
Reference in New Issue
Block a user