From 049d68639fc246356dcd79bb64d7229965bb0235 Mon Sep 17 00:00:00 2001 From: mathru Date: Sun, 23 Oct 2022 22:35:04 +0900 Subject: [PATCH] feat: Mounting Completed --- .../katana_listenables/example/lib/main.dart | 78 ++---- .../katana_listenables/example/pubspec.lock | 28 +-- .../example/test/widget_test.dart | 2 +- .../lib/common/base_class.dart | 232 ++++++++++++------ .../lib/katana_listenables_builder.dart | 1 - .../lib/src/config.dart | 10 +- .../lib/value/class_value.dart | 22 ++ .../lib/value/parameter_value.dart | 6 + 8 files changed, 225 insertions(+), 154 deletions(-) diff --git a/packages/katana_listenables/example/lib/main.dart b/packages/katana_listenables/example/lib/main.dart index 3afbc470c..1e60e871f 100644 --- a/packages/katana_listenables/example/lib/main.dart +++ b/packages/katana_listenables/example/lib/main.dart @@ -1,38 +1,17 @@ import 'dart:math'; +import 'package:katana_listenables_annotation/katana_listenables_annotation.dart'; + import 'package:flutter/material.dart'; part 'main.listenable.dart'; -class Test with _$Test { - factory Test({ +@listenables +class ListenableValue with _$ListenableValue { + factory ListenableValue({ required TextEditingController name, ValueNotifier value, - }) = _Test; -} - -class _Test with ChangeNotifier implements Test { - _Test({required this.name, this.value}) { - if (name is Listenable) { - name?.addListener(notifyListeners); - } - if (value is Listenable) { - value?.addListener(notifyListeners); - } - } - final TextEditingController name; - final ValueNotifier? value; - - @override - void dispose() { - super.dispose(); - if (name is Listenable) { - name?.removeListener(notifyListeners); - } - if (value is Listenable) { - value?.removeListener(notifyListeners); - } - } + }) = _ListenableValue; } void main() { @@ -44,38 +23,31 @@ class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { - return LocalizeScope( - localize: l, - builder: (context, localize) { - return MaterialApp( - locale: localize.locale, - localizationsDelegates: localize.delegates(), - supportedLocales: localize.supportedLocales(), - localeResolutionCallback: localize.localeResolutionCallback(), - home: TestPage(), - title: "Flutter Demo", - theme: ThemeData( - primarySwatch: Colors.blue, - ), - ); - }, + return MaterialApp( + home: const ListenablePage(), + title: "Flutter Demo", + theme: ThemeData( + primarySwatch: Colors.blue, + ), ); } } -class TestPage extends StatefulWidget { +class ListenablePage extends StatefulWidget { + const ListenablePage({super.key}); + @override - State createState() => TestPageState(); + State createState() => ListenablePageState(); } -class TestPageState extends State { - final test = Test( - name: TextEditingController(text: "ccc"), +class ListenablePageState extends State { + final listenable = ListenableValue( + name: TextEditingController(text: "before click"), ); @override void initState() { super.initState(); - test.addListener(() { + listenable.addListener(() { setState(() {}); }); } @@ -83,19 +55,19 @@ class TestPageState extends State { @override Widget build(BuildContext context) { return Scaffold( - appBar: AppBar(title: Text(l().appTitle)), + appBar: AppBar(title: const Text("Flutter Demo")), body: ListView( children: [ ListTile( - title: Text(test.name.text), + title: Text(listenable.name.text), onTap: () { - test.name.text = "aaa"; + listenable.name.text = "after click"; }, ), ListTile( - title: Text(test.value?.value ?? ""), + title: Text(listenable.value?.value ?? ""), onTap: () { - test.value?.value = Random().rangeInt(0, 100).toString(); + listenable.value?.value = Random().nextInt(100).toString(); }, ) ], diff --git a/packages/katana_listenables/example/pubspec.lock b/packages/katana_listenables/example/pubspec.lock index b0f24a953..1661fd5bd 100644 --- a/packages/katana_listenables/example/pubspec.lock +++ b/packages/katana_listenables/example/pubspec.lock @@ -148,13 +148,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "3.0.2" - csv: - dependency: transitive - description: - name: csv - url: "https://pub.dartlang.org" - source: hosted - version: "5.0.1" cupertino_icons: dependency: "direct main" description: @@ -209,11 +202,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.0.1" - flutter_localizations: - dependency: transitive - description: flutter - source: sdk - version: "0.0.0" flutter_test: dependency: "direct dev" description: flutter @@ -296,27 +284,27 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.15.6" - katana_localization: + katana_listenables: dependency: "direct main" description: path: ".." relative: true source: path - version: "1.1.5" - katana_localization_annotation: + version: "1.0.0" + katana_listenables_annotation: dependency: "direct overridden" description: - path: "../../katana_localization_annotation" + path: "../../katana_listenables_annotation" relative: true source: path - version: "1.1.3" - katana_localization_builder: + version: "1.0.0" + katana_listenables_builder: dependency: "direct dev" description: - path: "../../katana_localization_builder" + path: "../../katana_listenables_builder" relative: true source: path - version: "1.1.5" + version: "1.0.0" lints: dependency: transitive description: diff --git a/packages/katana_listenables/example/test/widget_test.dart b/packages/katana_listenables/example/test/widget_test.dart index 6c0ba6a07..6053263f8 100644 --- a/packages/katana_listenables/example/test/widget_test.dart +++ b/packages/katana_listenables/example/test/widget_test.dart @@ -8,6 +8,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:katana_localization_example/main.dart'; +import 'package:katana_listenables_example/main.dart'; void main() {} diff --git a/packages/katana_listenables_builder/lib/common/base_class.dart b/packages/katana_listenables_builder/lib/common/base_class.dart index 7911c69f6..335416c7b 100644 --- a/packages/katana_listenables_builder/lib/common/base_class.dart +++ b/packages/katana_listenables_builder/lib/common/base_class.dart @@ -15,113 +15,197 @@ List baseClass( (c) => c ..name = "_\$${model.name}" ..abstract = true - ..extend = const Reference("AppLocalizeBase") + ..implements.addAll([ + const Reference("ChangeListener"), + ]) ..methods.addAll([ + ...model.parameters.map((param) { + return Method( + (m) => m + ..name = param.name + ..returns = Reference( + "${param.type.toString().trimStringRight("?")}${param.required ? "" : "?"}", + ), + ); + }), Method( (m) => m - ..name = "delegates" + ..name = "addListener" ..annotations.addAll([const Reference("override")]) - ..returns = const Reference("List") - ..optionalParameters.addAll([ + ..returns = const Reference("void") + ..lambda = true + ..requiredParameters.addAll([ Parameter( (p) => p - ..name = "delegates" - ..type = const Reference("List") - ..defaultTo = - const Code("GlobalMaterialLocalizations.delegates"), + ..name = "listener" + ..type = const Reference("VoidCallback"), ) ]) - ..body = Code( - "return [const _\$${model.name}Delegate(), ...delegates,];", - ), + ..body = const Code("throw UnimplementedError()"), ), Method( (m) => m - ..name = "supportedLocales" + ..name = "removeListener" ..annotations.addAll([const Reference("override")]) - ..returns = const Reference("List") - ..body = Code( - "return _\$${model.name.toCamelCase()}Localizations.keys.toList();", - ), - ), - Method( - (m) => m - ..name = "call" - ..returns = Reference("_\$${model.name}$_kBaseName") - ..optionalParameters.addAll([ + ..returns = const Reference("void") + ..lambda = true + ..requiredParameters.addAll([ Parameter( (p) => p - ..name = "context" - ..type = const Reference("BuildContext?"), + ..name = "listener" + ..type = const Reference("VoidCallback"), ) ]) - ..body = Code( - "final l = context != null ? Localizations.localeOf(context) : locale;if (_\$${model.name.toCamelCase()}Localizations.containsKey(l)) {return _\$${model.name.toCamelCase()}Localizations[l]!;} else {return _\$${model.name.toCamelCase()}Localizations.values.first;}", - ), - ) - ]), - ), - Class( - (c) => c - ..name = "_\$${model.name}Delegate" - ..extend = - Reference("LocalizationsDelegate<_\$${model.name}$_kBaseName>") - ..constructors.addAll([ - Constructor((c) => c..constant = true), - ]) - ..methods.addAll([ + ..body = const Code("throw UnimplementedError()"), + ), Method( (m) => m - ..name = "isSupported" + ..name = "notifyListeners" ..annotations.addAll([const Reference("override")]) - ..returns = const Reference("bool") + ..returns = const Reference("void") ..lambda = true - ..requiredParameters.addAll([ - Parameter( - (p) => p - ..name = "locale" - ..type = const Reference("Locale"), - ) - ]) - ..body = Code( - "_\$${model.name.toCamelCase()}Localizations.containsKey(locale)", - ), + ..body = const Code("throw UnimplementedError()"), ), Method( (m) => m - ..name = "load" + ..name = "dispose" ..annotations.addAll([const Reference("override")]) - ..returns = Reference("Future<_\$${model.name}$_kBaseName>") + ..returns = const Reference("void") ..lambda = true - ..requiredParameters.addAll([ - Parameter( - (p) => p - ..name = "locale" - ..type = const Reference("Locale"), - ) - ]) - ..body = Code( - "SynchronousFuture(_\$${model.name.toCamelCase()}Localizations[locale] ?? _\$${model.name.toCamelCase()}Localizations.values.first)", - ), + ..body = const Code("throw UnimplementedError()"), ), Method( (m) => m - ..name = "shouldReload" + ..name = "hasListeners" + ..type = MethodType.getter ..annotations.addAll([const Reference("override")]) ..returns = const Reference("bool") ..lambda = true - ..requiredParameters.addAll([ - Parameter( - (p) => p - ..name = "old" - ..type = Reference( - "LocalizationsDelegate<_\$${model.name}$_kBaseName>", - ), - ) - ]) - ..body = const Code("false"), + ..body = const Code("throw UnimplementedError()"), ), ]), ), + if (model.existUnderbarConstructor) ...[ + Class( + (c) => c + ..name = "_${model.name}" + ..extend = Reference(model.name) + ..mixins.addAll([ + const Reference("ChangeListener"), + ]) + ..constructors.addAll([ + Constructor( + (c) => c + ..optionalParameters.addAll([ + ...model.parameters.map((param) { + return Parameter( + (p) => p + ..name = param.name + ..toThis = true + ..required = param.required, + ); + }), + ]) + ..initializers.addAll([const Code("super._()")]) + ..body = Code( + model.parameters + .map( + (e) => + "if(${e.name} is Listenable){${e.name}${e.required ? "" : "?"}.addListener(_handledOnUpdate);}", + ) + .join("\n"), + ), + ), + ]) + ..fields.addAll([ + ...model.parameters.map((param) { + return Field( + (f) => f + ..name = param.name + ..modifier = FieldModifier.final$ + ..type = Reference( + "${param.type.toString().trimStringRight("?")}${param.required ? "" : "?"}", + ), + ); + }) + ]) + ..methods.addAll([ + Method( + (m) => m + ..name = "dispose" + ..annotations.addAll([const Reference("override")]) + ..returns = const Reference("void") + ..body = Code( + "super.dispose(); ${model.parameters.map((e) => "if(${e.name} is Listenable){${e.name}${e.required ? "" : "?"}.removeListener(_handledOnUpdate);}").join("\n")}", + ), + ), + ]), + ), + ] else ...[ + Class( + (c) => c + ..name = "_${model.name}" + ..mixins.addAll([ + const Reference("ChangeListener"), + ]) + ..implements.addAll([ + Reference(model.name), + ]) + ..constructors.addAll([ + Constructor( + (c) => c + ..optionalParameters.addAll([ + ...model.parameters.map((param) { + return Parameter( + (p) => p + ..name = param.name + ..toThis = true + ..required = param.required, + ); + }), + ]) + ..body = Code( + model.parameters + .map( + (e) => + "if(${e.name} is Listenable){${e.name}${e.required ? "" : "?"}.addListener(_handledOnUpdate);}", + ) + .join("\n"), + ), + ), + ]) + ..fields.addAll([ + ...model.parameters.map((param) { + return Field( + (f) => f + ..name = param.name + ..modifier = FieldModifier.final$ + ..type = Reference( + "${param.type.toString().trimStringRight("?")}${param.required ? "" : "?"}", + ), + ); + }) + ]) + ..methods.addAll([ + Method( + (m) => m + ..name = "dispose" + ..annotations.addAll([const Reference("override")]) + ..returns = const Reference("void") + ..body = Code( + "super.dispose(); ${model.parameters.map((e) => "if(${e.name} is Listenable){${e.name}${e.required ? "" : "?"}.removeListener(_handledOnUpdate);}").join("\n")}", + ), + ), + Method( + (m) => m + ..name = "_handledOnUpdate" + ..returns = const Reference("void") + ..body = const Code( + "notifyListeners();", + ), + ), + ]), + ), + ], ]; } diff --git a/packages/katana_listenables_builder/lib/katana_listenables_builder.dart b/packages/katana_listenables_builder/lib/katana_listenables_builder.dart index eec13b48f..7438fc4b3 100644 --- a/packages/katana_listenables_builder/lib/katana_listenables_builder.dart +++ b/packages/katana_listenables_builder/lib/katana_listenables_builder.dart @@ -10,7 +10,6 @@ library katana_listenables_builder; import 'dart:async'; -import 'package:analyzer/dart/constant/value.dart'; import 'package:analyzer/dart/element/element.dart'; import 'package:analyzer/dart/element/type.dart'; import 'package:build/build.dart'; diff --git a/packages/katana_listenables_builder/lib/src/config.dart b/packages/katana_listenables_builder/lib/src/config.dart index f10d0c5ff..25ac4b5fc 100644 --- a/packages/katana_listenables_builder/lib/src/config.dart +++ b/packages/katana_listenables_builder/lib/src/config.dart @@ -1,9 +1,9 @@ part of katana_listenables_builder; final _ignoreWords = [ - "in", - "new", - "class", - "set", - "get", + "dispose", + "addListener", + "removeListener", + "hasListeners", + "notifyListeners", ]; diff --git a/packages/katana_listenables_builder/lib/value/class_value.dart b/packages/katana_listenables_builder/lib/value/class_value.dart index 181ab1306..2a7d5e4a2 100644 --- a/packages/katana_listenables_builder/lib/value/class_value.dart +++ b/packages/katana_listenables_builder/lib/value/class_value.dart @@ -20,9 +20,21 @@ class ClassValue { final contstuctor = element.constructors.firstWhere((e) { return e.name.isEmpty; }); + existUnderbarConstructor = element.constructors.any((e) { + return e.name == "_" && !e.isFactory; + }); parameters = contstuctor.parameters.where((e) => e.name != "key").map((e) { return ParamaterValue(e); }).toList(); + existMethodOrField = + element.methods.isNotEmpty || element.fields.isNotEmpty; + if (existMethodOrField && !existUnderbarConstructor) { + throw InvalidGenerationSourceError( + "To define a method or field in a class, add the following constructor.\n\n" + "`$name._();`", + element: element, + ); + } } /// Class Element. @@ -40,6 +52,16 @@ class ClassValue { /// クラスのパラメーター。 late final List parameters; + /// Check if there is a _constructor_. + /// + /// _のコンストラクターがあるかどうかのチェック。 + late final bool existUnderbarConstructor; + + /// True if the method or field is present. + /// + /// メソッドやフィールドがある場合true. + late final bool existMethodOrField; + @override String toString() { return "$name(${parameters.map((e) => e.toString()).join(", ")})"; diff --git a/packages/katana_listenables_builder/lib/value/parameter_value.dart b/packages/katana_listenables_builder/lib/value/parameter_value.dart index 2b104138f..4e986b353 100644 --- a/packages/katana_listenables_builder/lib/value/parameter_value.dart +++ b/packages/katana_listenables_builder/lib/value/parameter_value.dart @@ -23,6 +23,7 @@ class ParamaterValue { ); } type = element.type; + required = element.isRequired; } /// Parameter Element. @@ -40,6 +41,11 @@ class ParamaterValue { /// パラメーターの名前。 late final String name; + /// True if Required. + /// + /// Requiredな場合true. + late final bool required; + @override String toString() { return "$name($type)";