From 0570147b3104eb329207ff374541d9d6797fe427 Mon Sep 17 00:00:00 2001 From: davidpkj Date: Sat, 11 Mar 2023 17:54:46 +0100 Subject: Updated code to dart analysis recommendations --- lib/models/data/recipe_data_class.dart | 28 +-- lib/models/data/settings_data_class.dart | 6 +- lib/models/data/shoplist_data_class.dart | 6 +- lib/models/recipe_class.dart | 4 +- lib/util/file_handler.dart | 44 ++-- lib/util/notifications.dart | 4 +- lib/util/storage_handler.dart | 8 +- lib/views/favorites_view.dart | 10 +- lib/views/file_info.dart | 103 -------- lib/views/file_info_subview.dart | 103 ++++++++ lib/views/image_subview.dart | 37 +++ lib/views/image_view.dart | 37 --- lib/views/main_view.dart | 8 +- lib/views/recipe_subview.dart | 392 +++++++++++++++++++++++++++++++ lib/views/recipe_view.dart | 390 ------------------------------ lib/views/settings_view.dart | 37 +-- lib/views/shoplist_view.dart | 10 +- lib/views/week_view.dart | 4 +- lib/widgets/error_widgets.dart | 6 +- lib/widgets/recipe_card_widget.dart | 14 +- lib/widgets/recipe_search_delegate.dart | 28 +-- lib/widgets/utility_icon_row_widget.dart | 34 +-- 22 files changed, 642 insertions(+), 671 deletions(-) delete mode 100644 lib/views/file_info.dart create mode 100644 lib/views/file_info_subview.dart create mode 100644 lib/views/image_subview.dart delete mode 100644 lib/views/image_view.dart create mode 100644 lib/views/recipe_subview.dart delete mode 100644 lib/views/recipe_view.dart diff --git a/lib/models/data/recipe_data_class.dart b/lib/models/data/recipe_data_class.dart index 3193b7d..5dd092b 100644 --- a/lib/models/data/recipe_data_class.dart +++ b/lib/models/data/recipe_data_class.dart @@ -22,27 +22,27 @@ class RecipeData { } static String encode() { - List> _tempList = []; + List> tempList = []; - recipeList.forEach((element) { - Map _map = Map(); + for (Recipe recipe in recipeList) { + Map map = {}; - _map["title"] = element.title; - _map["description"] = element.description; - _map["favorite"] = element.favorite; - _map["rating"] = element.rating; - _map["image"] = element.image; + map["title"] = recipe.title; + map["description"] = recipe.description; + map["favorite"] = recipe.favorite; + map["rating"] = recipe.rating; + map["image"] = recipe.image; - _tempList.add(_map); - }); + tempList.add(map); + } - return jsonEncode(_tempList); + return jsonEncode(tempList); } static void decode(String data) { - final _result = jsonDecode(data); + final result = jsonDecode(data); - if (_result.isEmpty) return; + if (result.isEmpty) return; recipesIdentical(Recipe a, Recipe b) { if (a.title != b.title) return false; @@ -51,7 +51,7 @@ class RecipeData { return true; } - _result.forEach((item) { + result.forEach((item) { Recipe recipe = Recipe( title: item["title"], description: item["description"], diff --git a/lib/models/data/settings_data_class.dart b/lib/models/data/settings_data_class.dart index 5d3de60..c1c5b4d 100644 --- a/lib/models/data/settings_data_class.dart +++ b/lib/models/data/settings_data_class.dart @@ -22,11 +22,11 @@ class SettingsData { } static void decode(String data) { - final _result = jsonDecode(data); + final result = jsonDecode(data); - if (_result.isEmpty) return; + if (result.isEmpty) return; - _result.forEach((key, value) { + result.forEach((key, value) { settings[key] = value; }); diff --git a/lib/models/data/shoplist_data_class.dart b/lib/models/data/shoplist_data_class.dart index c8516c3..fb0a668 100644 --- a/lib/models/data/shoplist_data_class.dart +++ b/lib/models/data/shoplist_data_class.dart @@ -19,11 +19,11 @@ class ShoplistData { } static void decode(String data) { - final _result = jsonDecode(data); + final result = jsonDecode(data); - if (_result.isEmpty) return; + if (result.isEmpty) return; - _result.forEach((item) { + result.forEach((item) { shoplist.add(item); }); } diff --git a/lib/models/recipe_class.dart b/lib/models/recipe_class.dart index 7143547..1787495 100644 --- a/lib/models/recipe_class.dart +++ b/lib/models/recipe_class.dart @@ -17,9 +17,9 @@ class Recipe { Recipe({this.title, this.image, this.description, this.favorite = false, this.rating = 0}); bool isListed({bool remote = false}) { - List _list = remote ? RecipeData.remoteRecipeList : RecipeData.recipeList; + List list = remote ? RecipeData.remoteRecipeList : RecipeData.recipeList; - for (Recipe recipe in _list) { + for (Recipe recipe in list) { if (title == recipe.title && image == recipe.image && description == recipe.description) { return true; } diff --git a/lib/util/file_handler.dart b/lib/util/file_handler.dart index d6b909d..b230e35 100644 --- a/lib/util/file_handler.dart +++ b/lib/util/file_handler.dart @@ -27,13 +27,13 @@ class FileHandler { static Future serializeFile(BuildContext context, Map data) async { if (await Permission.storage.request().isGranted) { try { - final _directory = await ExternalPath.getExternalStoragePublicDirectory(ExternalPath.DIRECTORY_DOWNLOADS); - final _file = File("$_directory/Export-${DateTime.now().toUtc().toString().split(" ")[0]}.kulinar"); + final directory = await ExternalPath.getExternalStoragePublicDirectory(ExternalPath.DIRECTORY_DOWNLOADS); + final file = File("$directory/Export-${DateTime.now().toUtc().toString().split(" ")[0]}.kulinar"); - await _file.writeAsString(jsonEncode(await encodeDataAsMap(ExportType.full, data))); + await file.writeAsString(jsonEncode(await encodeDataAsMap(ExportType.full, data))); ToastBar.showToastBar(context, AppLocalizations.of(context)!.exportSuccess, actionLabel: ""); - Notifications.notify(AppLocalizations.of(context)!.exportSuccess, AppLocalizations.of(context)!.tapHint, _file.path); + Notifications.notify(AppLocalizations.of(context)!.exportSuccess, AppLocalizations.of(context)!.tapHint, file.path); } catch (e) { debugPrint("$e"); ToastBar.showToastBar(context, AppLocalizations.of(context)!.exportError, actionLabel: ""); @@ -43,31 +43,31 @@ class FileHandler { /// Deserializes the given `file` into the returned Map. Sends a confirmation Toast to the given `context` afterwards. static Future deserializeFile(BuildContext context, File file) async { - final dynamic _content = jsonDecode(await file.readAsString()); + final dynamic content = jsonDecode(await file.readAsString()); - SettingsData.decode(_content["settings"]); - RecipeData.decode(_content["recipes"]); + SettingsData.decode(content["settings"]); + RecipeData.decode(content["recipes"]); ToastBar.showToastBar(context, AppLocalizations.of(context)!.importSuccess, actionLabel: ""); } /// Parses a given possible deserializable `file` for useful information and returns a map of it. static Future> deserializeFileInformation(File file) async { - final Map _content = jsonDecode(await file.readAsString()); - Map _map = Map(); + final Map content = jsonDecode(await file.readAsString()); + Map map = {}; - _map["version"] = _content["version"]; - _map["type"] = _content["type"].split(".")[1]; - _map["size"] = "${await file.length()} Bytes"; + map["version"] = content["version"]; + map["type"] = content["type"].split(".")[1]; + map["size"] = "${await file.length()} Bytes"; - if (_content["type"] == ExportType.full.toString()) { - int a = jsonDecode(_content["recipes"]).length; - int b = jsonDecode(_content["settings"]).length; + if (content["type"] == ExportType.full.toString()) { + int a = jsonDecode(content["recipes"]).length; + int b = jsonDecode(content["settings"]).length; - _map["entries"] = (a + b).toString(); + map["entries"] = (a + b).toString(); } - return _map; + return map; } /// Opens the native file picker and returns the picked `.kulinar` file. @@ -90,14 +90,14 @@ class FileHandler { /// Encodes the given `data` together with some additional information into a serializable map. static Future> encodeDataAsMap(ExportType type, Map data) async { - Map _map = Map(); + Map map = {}; - _map["version"] = cVersion; - _map["type"] = type.toString(); + map["version"] = cVersion; + map["type"] = type.toString(); // TODO: IMPLEMENT: Base64 Images and image count on export - _map.addAll(data as Map); + map.addAll(data as Map); - return _map; + return map; } /// Decodes the given `map` into diff --git a/lib/util/notifications.dart b/lib/util/notifications.dart index c652600..533a97b 100644 --- a/lib/util/notifications.dart +++ b/lib/util/notifications.dart @@ -25,8 +25,8 @@ class Notifications { /// Launches the notification static Future notify(String title, String description, String payload) async { - const NotificationDetails _platformChannelSpecifics = NotificationDetails(android: _androidSpecifics); + const NotificationDetails platformChannelSpecifics = NotificationDetails(android: _androidSpecifics); - await flutterLocalNotificationsPlugin.show(0, title, description, _platformChannelSpecifics, payload: payload); + await flutterLocalNotificationsPlugin.show(0, title, description, platformChannelSpecifics, payload: payload); } } diff --git a/lib/util/storage_handler.dart b/lib/util/storage_handler.dart index fe27b93..d0897bd 100644 --- a/lib/util/storage_handler.dart +++ b/lib/util/storage_handler.dart @@ -4,17 +4,17 @@ import 'package:shared_preferences/shared_preferences.dart'; class StorageHandler { /// Stores the given `data` as a string with the `key`. static Future store(String key, String data) async { - final _prefs = await SharedPreferences.getInstance(); + final prefs = await SharedPreferences.getInstance(); - _prefs.setString(key, data); + prefs.setString(key, data); return data; } /// Fetches the string related to the given `key`. static Future fetch(String key) async { - final _prefs = await SharedPreferences.getInstance(); + final prefs = await SharedPreferences.getInstance(); - return _prefs.getString(key); + return prefs.getString(key); } } diff --git a/lib/views/favorites_view.dart b/lib/views/favorites_view.dart index 97f784c..d133b79 100644 --- a/lib/views/favorites_view.dart +++ b/lib/views/favorites_view.dart @@ -25,7 +25,7 @@ class FavoritesViewState extends State { return Scaffold( appBar: _buildAppBar(context), drawer: const CustomDrawer(initialIndex: 1), - body: Container( + body: SizedBox( width: double.infinity, child: Builder( builder: (BuildContext context) { @@ -66,14 +66,14 @@ class FavoritesViewState extends State { } Widget _buildListView() { - List _filteredRecipeList = RecipeData.recipeList.where((element) => element.favorite).toList(); + List filteredRecipeList = RecipeData.recipeList.where((element) => element.favorite).toList(); - if (_filteredRecipeList.isEmpty) return const NoContentError(); + if (filteredRecipeList.isEmpty) return const NoContentError(); return ListView.builder( - itemCount: _filteredRecipeList.length, + itemCount: filteredRecipeList.length, itemBuilder: (context, index) => RecipeCard( - recipe: _filteredRecipeList[index], + recipe: filteredRecipeList[index], redrawCallback: redrawFavoritesView, showToastCallback: showToastCallback, ), diff --git a/lib/views/file_info.dart b/lib/views/file_info.dart deleted file mode 100644 index 28c45f9..0000000 --- a/lib/views/file_info.dart +++ /dev/null @@ -1,103 +0,0 @@ -import 'dart:io'; - -import 'package:flutter/material.dart'; - -import 'package:kulinar_app/constants.dart'; -import 'package:kulinar_app/util/file_handler.dart'; -import 'package:kulinar_app/widgets/error_widgets.dart'; - -import 'package:flutter_gen/gen_l10n/app_localizations.dart'; - -class FileInfo extends StatefulWidget { - const FileInfo({Key? key, required this.filePath}) : super(key: key); - - final String filePath; - - @override - FileInfoState createState() => FileInfoState(); -} - -class FileInfoState extends State { - @override - Widget build(BuildContext context) { - final File _file = File(widget.filePath.split(":")[1]); - - return Scaffold( - appBar: AppBar(title: Text(AppLocalizations.of(context)!.category9)), - body: FutureBuilder( - future: FileHandler.deserializeFileInformation(_file), - builder: (BuildContext context, AsyncSnapshot> snapshot) { - if (snapshot.connectionState != ConnectionState.done) return const CircularProgressIndicator(); - if (snapshot.hasError || !snapshot.hasData) return const UnknownError(); - - return _buildFileInfoTable(_getSortedSnapshotData(snapshot), _file); - }, - ), - ); - } - - String _localizeInfoField(BuildContext context, String field) { - switch (field) { - case "type": - return AppLocalizations.of(context)!.infoField1; - case "version": - return AppLocalizations.of(context)!.infoField2; - case "size": - return AppLocalizations.of(context)!.infoField3; - case "entries": - return AppLocalizations.of(context)!.infoField4; - default: - return AppLocalizations.of(context)!.unknown; - } - } - - List _getSortedSnapshotData(AsyncSnapshot> snapshot) { - List _children = []; - - snapshot.data!.forEach((key, value) { - _children.add( - TableRow( - children: [ - Padding( - padding: const EdgeInsets.only(right: 4.0), - child: Text(_localizeInfoField(context, key), style: cTableKeyStyle, textAlign: TextAlign.right), - ), - Padding( - padding: const EdgeInsets.only(left: 4.0), - child: Text(value, style: cTableValueStyle), - ), - ], - ), - ); - }); - - return _children; - } - - Widget _buildFileInfoTable(List children, File file) { - return Padding( - padding: const EdgeInsets.only(top: 16.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Table( - columnWidths: const { - 0: FlexColumnWidth(), - 1: FlexColumnWidth(), - }, - children: children, - ), - Padding( - padding: const EdgeInsets.all(16.0), - child: ElevatedButton( - child: Text(AppLocalizations.of(context)!.option312, style: cOptionTextStyle.copyWith(color: cIconColor)), - onPressed: () { - FileHandler.deserializeFile(context, file); - }, - ), - ), - ], - ), - ); - } -} diff --git a/lib/views/file_info_subview.dart b/lib/views/file_info_subview.dart new file mode 100644 index 0000000..b9cd881 --- /dev/null +++ b/lib/views/file_info_subview.dart @@ -0,0 +1,103 @@ +import 'dart:io'; + +import 'package:flutter/material.dart'; + +import 'package:kulinar_app/constants.dart'; +import 'package:kulinar_app/util/file_handler.dart'; +import 'package:kulinar_app/widgets/error_widgets.dart'; + +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; + +class FileInfoSubview extends StatefulWidget { + const FileInfoSubview({Key? key, required this.filePath}) : super(key: key); + + final String filePath; + + @override + FileInfoSubviewState createState() => FileInfoSubviewState(); +} + +class FileInfoSubviewState extends State { + @override + Widget build(BuildContext context) { + final File file = File(widget.filePath.split(":")[1]); + + return Scaffold( + appBar: AppBar(title: Text(AppLocalizations.of(context)!.category9)), + body: FutureBuilder( + future: FileHandler.deserializeFileInformation(file), + builder: (BuildContext context, AsyncSnapshot> snapshot) { + if (snapshot.connectionState != ConnectionState.done) return const CircularProgressIndicator(); + if (snapshot.hasError || !snapshot.hasData) return const UnknownError(); + + return _buildFileInfoTable(_getSortedSnapshotData(snapshot), file); + }, + ), + ); + } + + String _localizeInfoField(BuildContext context, String field) { + switch (field) { + case "type": + return AppLocalizations.of(context)!.infoField1; + case "version": + return AppLocalizations.of(context)!.infoField2; + case "size": + return AppLocalizations.of(context)!.infoField3; + case "entries": + return AppLocalizations.of(context)!.infoField4; + default: + return AppLocalizations.of(context)!.unknown; + } + } + + List _getSortedSnapshotData(AsyncSnapshot> snapshot) { + List children = []; + + snapshot.data!.forEach((key, value) { + children.add( + TableRow( + children: [ + Padding( + padding: const EdgeInsets.only(right: 4.0), + child: Text(_localizeInfoField(context, key), style: cTableKeyStyle, textAlign: TextAlign.right), + ), + Padding( + padding: const EdgeInsets.only(left: 4.0), + child: Text(value, style: cTableValueStyle), + ), + ], + ), + ); + }); + + return children; + } + + Widget _buildFileInfoTable(List children, File file) { + return Padding( + padding: const EdgeInsets.only(top: 16.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Table( + columnWidths: const { + 0: FlexColumnWidth(), + 1: FlexColumnWidth(), + }, + children: children, + ), + Padding( + padding: const EdgeInsets.all(16.0), + child: ElevatedButton( + child: Text(AppLocalizations.of(context)!.option312, style: cOptionTextStyle.copyWith(color: cIconColor)), + onPressed: () { + FileHandler.deserializeFile(context, file); + }, + ), + ), + ], + ), + ); + } +} diff --git a/lib/views/image_subview.dart b/lib/views/image_subview.dart new file mode 100644 index 0000000..bc5ac49 --- /dev/null +++ b/lib/views/image_subview.dart @@ -0,0 +1,37 @@ +import 'dart:io'; + +import 'package:flutter/material.dart'; + +import 'package:kulinar_app/constants.dart'; + +class ImageSubview extends StatelessWidget { + const ImageSubview({Key? key, required this.image}) : super(key: key); + + final String image; + + @override + Widget build(BuildContext context) { + return InteractiveViewer( + child: Scaffold( + backgroundColor: _averageImageColor(image), + body: Center( + child: GestureDetector( + child: Hero( + tag: "image", + child: Image( + image: FileImage(File(image)), + ), + ), + onTap: () { + Navigator.pop(context); + }, + ), + ), + ), + ); + } + + Color _averageImageColor(String path) { + return cPrimaryColor; + } +} diff --git a/lib/views/image_view.dart b/lib/views/image_view.dart deleted file mode 100644 index 1363268..0000000 --- a/lib/views/image_view.dart +++ /dev/null @@ -1,37 +0,0 @@ -import 'dart:io'; - -import 'package:flutter/material.dart'; - -import 'package:kulinar_app/constants.dart'; - -class ImageView extends StatelessWidget { - const ImageView({Key? key, required this.image}) : super(key: key); - - final String image; - - @override - Widget build(BuildContext context) { - return InteractiveViewer( - child: Scaffold( - backgroundColor: _averageImageColor(image), - body: Center( - child: GestureDetector( - child: Hero( - tag: "image", - child: Image( - image: FileImage(File(image)), - ), - ), - onTap: () { - Navigator.pop(context); - }, - ), - ), - ), - ); - } - - Color _averageImageColor(String path) { - return cPrimaryColor; - } -} diff --git a/lib/views/main_view.dart b/lib/views/main_view.dart index 3db3e97..ae63538 100644 --- a/lib/views/main_view.dart +++ b/lib/views/main_view.dart @@ -2,11 +2,11 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:kulinar_app/constants.dart'; -import 'package:kulinar_app/views/file_info.dart'; -import 'package:kulinar_app/views/recipe_view.dart'; +import 'package:kulinar_app/views/recipe_subview.dart'; import 'package:kulinar_app/models/recipe_class.dart'; import 'package:kulinar_app/widgets/error_widgets.dart'; import 'package:kulinar_app/widgets/toastbar_widget.dart'; +import 'package:kulinar_app/views/file_info_subview.dart'; import 'package:kulinar_app/widgets/recipe_card_widget.dart'; import 'package:kulinar_app/widgets/custom_drawer_widget.dart'; import 'package:kulinar_app/models/data/recipe_data_class.dart'; @@ -76,7 +76,7 @@ class MainViewState extends State with SingleTickerProviderStateMixin, if (url != null) { setState(() { - Navigator.pushAndRemoveUntil(context, MaterialPageRoute(builder: (BuildContext context) => FileInfo(filePath: url)), (_) => false); + Navigator.pushAndRemoveUntil(context, MaterialPageRoute(builder: (BuildContext context) => FileInfoSubview(filePath: url)), (_) => false); }); } } @@ -91,7 +91,7 @@ class MainViewState extends State with SingleTickerProviderStateMixin, onPressed: () async { await Navigator.push( context, - SlideFromBottomRoute(child: const RecipeView()), + SlideFromBottomRoute(child: const RecipeSubview()), ); setState(() {}); diff --git a/lib/views/recipe_subview.dart b/lib/views/recipe_subview.dart new file mode 100644 index 0000000..9c7d91d --- /dev/null +++ b/lib/views/recipe_subview.dart @@ -0,0 +1,392 @@ +import 'dart:io'; + +import 'package:flutter/material.dart'; + +import 'package:kulinar_app/constants.dart'; +import 'package:kulinar_app/views/image_subview.dart'; +import 'package:kulinar_app/models/recipe_class.dart'; +import 'package:kulinar_app/widgets/toastbar_widget.dart'; +import 'package:kulinar_app/widgets/custom_markdown_style.dart'; +import 'package:kulinar_app/models/data/recipe_data_class.dart'; +import 'package:kulinar_app/widgets/page_route_transitions.dart'; +import 'package:kulinar_app/widgets/utility_icon_row_widget.dart'; +import 'package:kulinar_app/models/data/shoplist_data_class.dart'; +import 'package:kulinar_app/models/data/settings_data_class.dart'; + +import 'package:flutter_markdown/flutter_markdown.dart'; +import 'package:path_provider/path_provider.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:share_plus/share_plus.dart'; + +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; + +class RecipeSubview extends StatefulWidget { + const RecipeSubview({Key? key, this.remote = false, this.recipe, this.redrawCallback, this.showToastCallback}) : super(key: key); + + final bool remote; + final Recipe? recipe; + final Function? redrawCallback; + final Function? showToastCallback; + + @override + RecipeSubviewState createState() => RecipeSubviewState(); +} + +class RecipeSubviewState extends State { + final GlobalKey _formKey = GlobalKey(); + final GlobalKey _scaffoldKey = GlobalKey(); + final TextEditingController _controller1 = TextEditingController(); + final TextEditingController _controller2 = TextEditingController(); + final FocusNode _detailsTitleFocus = FocusNode(); + final FocusNode _detailsTextFocus = FocusNode(); + Recipe _unsavedRecipe = Recipe(); + bool _isEditModeEnabled = false; + Recipe? _removedRecipe; + + @override + Widget build(BuildContext context) { + // TODO: Refactor to easier code + if (widget.recipe != null && _unsavedRecipe.isDefault()) _unsavedRecipe = widget.recipe!; + + if (_unsavedRecipe.isDefault()) { + _controller1.clear(); + _controller2.clear(); + _isEditModeEnabled = true; + } else { + _controller1.text = _unsavedRecipe.title ?? ""; + _controller2.text = _unsavedRecipe.description ?? ""; + } + + return Scaffold( + key: _scaffoldKey, + appBar: _buildAppBar(context, _unsavedRecipe), + body: GestureDetector( + onTap: () { + _detailsTextFocus.requestFocus(); + _controller2.selection = TextSelection.fromPosition(TextPosition(offset: _controller2.text.length)); + }, + child: Form( + key: _formKey, + child: ListView( + children: [ + _buildUtilityRow(), + _buildTitleInput(), + _buildImage(), + _buildDescriptionInput(), + ], + ), + ), + ), + ); + } + + void _cacheUnsavedRecipe() { + _unsavedRecipe.title = _controller1.text; + _unsavedRecipe.description = _controller2.text; + } + + void _addRecipe({Recipe? passedRecipe}) { + if (passedRecipe != null) { + RecipeData.recipeList.add(passedRecipe); + RecipeData.save(); + return; + } + + if (!_formKey.currentState!.validate()) return; + + _unsavedRecipe.title = _controller1.text; + _unsavedRecipe.description = _controller2.text; + + if (_isEditModeEnabled) { + if (!RecipeData.recipeList.contains(_unsavedRecipe)) RecipeData.recipeList.add(_unsavedRecipe); + RecipeData.save(); + } + + _isEditModeEnabled = false; + + if (widget.recipe == null) { + Navigator.pop(context); + } else { + setState(() {}); + } + } + + void _removeRecipe(BuildContext _) { + Navigator.pop(context); + RecipeData.recipeList.remove(widget.recipe); + RecipeData.save(); + + _removedRecipe = widget.recipe; + + String content = AppLocalizations.of(context)!.removed; + String actionLabel = AppLocalizations.of(context)!.undo; + + if (widget.showToastCallback != null) { + widget.showToastCallback!(content, actionLabel, () { + _addRecipe(passedRecipe: _removedRecipe); + widget.redrawCallback!(); + }); + } + + setState(() {}); + } + + // TODO: This might introduce bugs later (sanitize); maybe use FileHandler? + void downloadRecipe(BuildContext context, Recipe recipe) async { + RecipeData.recipeList.add(recipe); + ToastBar.showToastBar(context, AppLocalizations.of(context)!.downloadSuccess); + + setState(() {}); + } + + void _pickImage() async { + XFile? pickedFile; + + if (SettingsData.settings["photoSource"] == "0") { + pickedFile = await ImagePicker().pickImage(source: ImageSource.camera); + } else { + pickedFile = await ImagePicker().pickImage(source: ImageSource.gallery); + } + + if (pickedFile != null) { + Directory directory = await getApplicationDocumentsDirectory(); + String name = DateTime.now().millisecondsSinceEpoch.toString(); + File file = File("${directory.path}/$name"); + + file.writeAsBytes(await pickedFile.readAsBytes()); + _unsavedRecipe.image = file.path; + + RecipeData.save(); + } + + setState(() {}); + } + + void _removeImage() async { + _unsavedRecipe.image = null; + await RecipeData.save(); + + setState(() {}); + } + + Widget _buildUtilityRow() { + if (widget.remote) { + return const SizedBox( + height: 10.0, + width: double.infinity, + ); + } else { + // _buildAppBarPhotoActions(recipe), + return UtilityIconRow( + remote: widget.remote, + isEditModeEnabled: _isEditModeEnabled, + unsavedRecipe: _unsavedRecipe, + pickImageCallback: _pickImage, + removeImageCallback: _removeImage, + removeRecipeCallback: _removeRecipe, + downloadRecipeCallback: downloadRecipe, + cacheUnsavedRecipeCallback: _cacheUnsavedRecipe, + ); + } + } + + Widget _buildTitleInput() { + return Padding( + padding: const EdgeInsets.only(right: 20.0, left: 20.0), + child: TextFormField( + controller: _controller1, + style: cRecipeTitleStyle, + cursorColor: cPrimaryColor, + enabled: _isEditModeEnabled, + focusNode: _detailsTitleFocus, + textInputAction: TextInputAction.next, + decoration: InputDecoration( + hintText: AppLocalizations.of(context)!.inputHint, + hintStyle: cInputHintStyle, + ), + onFieldSubmitted: (_) { + _detailsTitleFocus.unfocus(); + FocusScope.of(context).requestFocus(_detailsTextFocus); + }, + validator: (input) { + if (input == "" || input!.trim().isEmpty) return AppLocalizations.of(context)!.inputError; + + return null; + }, + ), + ); + } + + Widget _buildImage() { + if (_unsavedRecipe.image != null) { + return Padding( + padding: const EdgeInsets.only(top: 12.0, left: 20.0, right: 20.0), + child: GestureDetector( + child: ClipRRect( + borderRadius: BorderRadius.circular(10.0), + child: Hero( + tag: "image", + child: Image( + image: FileImage( + File(_unsavedRecipe.image!), + ), + ), + ), + ), + onTap: () { + Navigator.push( + context, + FadeRoute(child: ImageSubview(image: _unsavedRecipe.image!)), + ); + }, + ), + ); + } + + return Container(); + } + + Widget _buildDescriptionInput() { + return Padding( + padding: const EdgeInsets.all(18.0), + child: _isEditModeEnabled ? _buildInputDescription() : _buildMarkdownDescription(), + ); + } + + TextField _buildInputDescription() { + return TextField( + expands: true, + maxLines: null, + minLines: null, + decoration: null, + controller: _controller2, + cursorColor: cPrimaryColor, + focusNode: _detailsTextFocus, + style: cRecipeDescriptionStyle, + enableInteractiveSelection: true, + // TODO: only replace with code with same function + // ignore: deprecated_member_use + toolbarOptions: const ToolbarOptions( + copy: true, + cut: true, + paste: true, + selectAll: true, + ), + ); + } + + MarkdownBody _buildMarkdownDescription() { + return MarkdownBody( + styleSheet: CustomMarkdownStyle.sheet(), + data: _controller2.text, + selectable: true, + onTapLink: (text, href, title) => {}, + imageBuilder: (uri, title, alt) => Container(), + // styleSheet: CustomMarkdownStyle(), + ); + } + + void _shareData(BuildContext _) { + Share.share("${_unsavedRecipe.title}\n\n${_unsavedRecipe.description}", subject: _unsavedRecipe.title); + } + + void _addToShoppingList(BuildContext _) { + final ingredients = _unsavedRecipe.description!.split("\n")..retainWhere((element) => element.startsWith("- ")); + + if (ingredients.isEmpty) { + widget.showToastCallback!(AppLocalizations.of(context)!.ingredientsError, "", () {}); + return; + } + + for (String ingredient in ingredients) { + String item = ingredient.substring(2).trim(); + + if (!ShoplistData.shoplist.contains(item)) { + ShoplistData.shoplist.add(item); + } + } + + ShoplistData.save(); + + if (widget.showToastCallback != null) { + widget.showToastCallback!(AppLocalizations.of(context)!.ingredientsAdded, "", () {}); + } + } + + void _uploadRecipe(BuildContext context) async { + return; + } + + List _buildAppBarActions(BuildContext context, Recipe recipe) { + final actionList = [_shareData, _addToShoppingList, _uploadRecipe, _removeRecipe]; + + List localActions = [ + _buildAppBarCheckActions(), + PopupMenuButton( + onSelected: (int value) => actionList.elementAt(value)(context), + itemBuilder: (BuildContext context) => [ + PopupMenuItem(value: 0, child: Text(AppLocalizations.of(context)!.menu1)), + PopupMenuItem(value: 1, child: Text(AppLocalizations.of(context)!.menu2)), + PopupMenuItem(value: 2, child: Text(AppLocalizations.of(context)!.menu3)), + PopupMenuItem(value: 3, child: Text(AppLocalizations.of(context)!.menu4)), + ], + ), + ]; + + List remoteDownloadAction = [ + IconButton( + icon: const Icon(Icons.save_alt_rounded), + onPressed: () { + downloadRecipe(context, recipe); + }, + ), + ]; + + List remoteLookupAction = [ + const IconButton( + icon: Icon(Icons.menu_open_rounded), + onPressed: null, + ), + ]; + + if (widget.remote && RecipeData.recipeList.contains(recipe)) return remoteLookupAction; + if (widget.remote) return remoteDownloadAction; + + return localActions; + } + + PreferredSizeWidget _buildAppBar(BuildContext context, Recipe recipe) { + String title = AppLocalizations.of(context)!.mode1; + + if (_isEditModeEnabled) title = AppLocalizations.of(context)!.mode2; + + return AppBar( + title: Text(title), + leading: IconButton( + icon: const Icon(Icons.close), + onPressed: () { + Navigator.pop(context); + }, + ), + actions: _buildAppBarActions(context, recipe), + ); + } + + Widget _buildAppBarCheckActions() { + if (_isEditModeEnabled) { + return IconButton( + icon: const Icon(Icons.check), + onPressed: _addRecipe, + ); + } else { + return IconButton( + icon: const Icon(Icons.edit), + onPressed: () { + _isEditModeEnabled = true; + + setState(() {}); + }, + ); + } + } +} diff --git a/lib/views/recipe_view.dart b/lib/views/recipe_view.dart deleted file mode 100644 index 3aaa160..0000000 --- a/lib/views/recipe_view.dart +++ /dev/null @@ -1,390 +0,0 @@ -import 'dart:io'; - -import 'package:flutter/material.dart'; - -import 'package:kulinar_app/constants.dart'; -import 'package:kulinar_app/views/image_view.dart'; -import 'package:kulinar_app/models/recipe_class.dart'; -import 'package:kulinar_app/widgets/toastbar_widget.dart'; -import 'package:kulinar_app/widgets/custom_markdown_style.dart'; -import 'package:kulinar_app/models/data/recipe_data_class.dart'; -import 'package:kulinar_app/widgets/page_route_transitions.dart'; -import 'package:kulinar_app/widgets/utility_icon_row_widget.dart'; -import 'package:kulinar_app/models/data/shoplist_data_class.dart'; -import 'package:kulinar_app/models/data/settings_data_class.dart'; - -import 'package:flutter_markdown/flutter_markdown.dart'; -import 'package:path_provider/path_provider.dart'; -import 'package:image_picker/image_picker.dart'; -import 'package:share_plus/share_plus.dart'; - -import 'package:flutter_gen/gen_l10n/app_localizations.dart'; - -class RecipeView extends StatefulWidget { - const RecipeView({Key? key, this.remote = false, this.recipe, this.redrawCallback, this.showToastCallback}) : super(key: key); - - final bool remote; - final Recipe? recipe; - final Function? redrawCallback; - final Function? showToastCallback; - - @override - RecipeViewState createState() => RecipeViewState(); -} - -class RecipeViewState extends State { - final GlobalKey _formKey = GlobalKey(); - final GlobalKey _scaffoldKey = GlobalKey(); - final TextEditingController _controller1 = TextEditingController(); - final TextEditingController _controller2 = TextEditingController(); - final FocusNode _detailsTitleFocus = FocusNode(); - final FocusNode _detailsTextFocus = FocusNode(); - Recipe _unsavedRecipe = Recipe(); - bool _isEditModeEnabled = false; - Recipe? _removedRecipe; - - @override - Widget build(BuildContext context) { - // TODO: Refactor to easier code - if (widget.recipe != null && _unsavedRecipe.isDefault()) _unsavedRecipe = widget.recipe!; - - if (_unsavedRecipe.isDefault()) { - _controller1.clear(); - _controller2.clear(); - _isEditModeEnabled = true; - } else { - _controller1.text = _unsavedRecipe.title ?? ""; - _controller2.text = _unsavedRecipe.description ?? ""; - } - - return Scaffold( - key: _scaffoldKey, - appBar: _buildAppBar(context, _unsavedRecipe), - body: GestureDetector( - onTap: () { - _detailsTextFocus.requestFocus(); - _controller2.selection = TextSelection.fromPosition(TextPosition(offset: _controller2.text.length)); - }, - child: Form( - key: _formKey, - child: ListView( - children: [ - _buildUtilityRow(), - _buildTitleInput(), - _buildImage(), - _buildDescriptionInput(), - ], - ), - ), - ), - ); - } - - void _cacheUnsavedRecipe() { - _unsavedRecipe.title = _controller1.text; - _unsavedRecipe.description = _controller2.text; - } - - void _addRecipe({Recipe? passedRecipe}) { - if (passedRecipe != null) { - RecipeData.recipeList.add(passedRecipe); - RecipeData.save(); - return; - } - - if (!_formKey.currentState!.validate()) return; - - _unsavedRecipe.title = _controller1.text; - _unsavedRecipe.description = _controller2.text; - - if (_isEditModeEnabled) { - if (!RecipeData.recipeList.contains(_unsavedRecipe)) RecipeData.recipeList.add(_unsavedRecipe); - RecipeData.save(); - } - - _isEditModeEnabled = false; - - if (widget.recipe == null) { - Navigator.pop(context); - } else { - setState(() {}); - } - } - - void _removeRecipe(BuildContext _) { - Navigator.pop(context); - RecipeData.recipeList.remove(widget.recipe); - RecipeData.save(); - - _removedRecipe = widget.recipe; - - String _content = AppLocalizations.of(context)!.removed; - String _actionLabel = AppLocalizations.of(context)!.undo; - - if (widget.showToastCallback != null) { - widget.showToastCallback!(_content, _actionLabel, () { - _addRecipe(passedRecipe: _removedRecipe); - widget.redrawCallback!(); - }); - } - - setState(() {}); - } - - // TODO: This might introduce bugs later (sanitize); maybe use FileHandler? - void downloadRecipe(BuildContext context, Recipe recipe) async { - RecipeData.recipeList.add(recipe); - ToastBar.showToastBar(context, AppLocalizations.of(context)!.downloadSuccess); - - setState(() {}); - } - - void _pickImage() async { - XFile? _pickedFile; - - if (SettingsData.settings["photoSource"] == "0") { - _pickedFile = await ImagePicker().pickImage(source: ImageSource.camera); - } else { - _pickedFile = await ImagePicker().pickImage(source: ImageSource.gallery); - } - - if (_pickedFile != null) { - Directory _directory = await getApplicationDocumentsDirectory(); - String _name = DateTime.now().millisecondsSinceEpoch.toString(); - File _file = File("${_directory.path}/$_name"); - - _file.writeAsBytes(await _pickedFile.readAsBytes()); - _unsavedRecipe.image = _file.path; - - RecipeData.save(); - } - - setState(() {}); - } - - void _removeImage() async { - _unsavedRecipe.image = null; - await RecipeData.save(); - - setState(() {}); - } - - Widget _buildUtilityRow() { - if (widget.remote) { - return const SizedBox( - height: 10.0, - width: double.infinity, - ); - } else { - // _buildAppBarPhotoActions(recipe), - return UtilityIconRow( - remote: widget.remote, - isEditModeEnabled: _isEditModeEnabled, - unsavedRecipe: _unsavedRecipe, - pickImageCallback: _pickImage, - removeImageCallback: _removeImage, - removeRecipeCallback: _removeRecipe, - downloadRecipeCallback: downloadRecipe, - cacheUnsavedRecipeCallback: _cacheUnsavedRecipe, - ); - } - } - - Widget _buildTitleInput() { - return Padding( - padding: const EdgeInsets.only(right: 20.0, left: 20.0), - child: TextFormField( - controller: _controller1, - style: cRecipeTitleStyle, - cursorColor: cPrimaryColor, - enabled: _isEditModeEnabled, - focusNode: _detailsTitleFocus, - textInputAction: TextInputAction.next, - decoration: InputDecoration( - hintText: AppLocalizations.of(context)!.inputHint, - hintStyle: cInputHintStyle, - ), - onFieldSubmitted: (_) { - _detailsTitleFocus.unfocus(); - FocusScope.of(context).requestFocus(_detailsTextFocus); - }, - validator: (input) { - if (input == "" || input!.trim().isEmpty) return AppLocalizations.of(context)!.inputError; - - return null; - }, - ), - ); - } - - Widget _buildImage() { - if (_unsavedRecipe.image != null) { - return Padding( - padding: const EdgeInsets.only(top: 12.0, left: 20.0, right: 20.0), - child: GestureDetector( - child: ClipRRect( - borderRadius: BorderRadius.circular(10.0), - child: Hero( - tag: "image", - child: Image( - image: FileImage( - File(_unsavedRecipe.image!), - ), - ), - ), - ), - onTap: () { - Navigator.push( - context, - FadeRoute(child: ImageView(image: _unsavedRecipe.image!)), - ); - }, - ), - ); - } - - return Container(); - } - - Widget _buildDescriptionInput() { - return Padding( - padding: const EdgeInsets.all(18.0), - child: _isEditModeEnabled ? _buildInputDescription() : _buildMarkdownDescription(), - ); - } - - TextField _buildInputDescription() { - return TextField( - expands: true, - maxLines: null, - minLines: null, - decoration: null, - controller: _controller2, - cursorColor: cPrimaryColor, - focusNode: _detailsTextFocus, - style: cRecipeDescriptionStyle, - enableInteractiveSelection: true, - toolbarOptions: const ToolbarOptions( - copy: true, - cut: true, - paste: true, - selectAll: true, - ), - ); - } - - MarkdownBody _buildMarkdownDescription() { - return MarkdownBody( - styleSheet: CustomMarkdownStyle.sheet(), - data: _controller2.text, - selectable: true, - onTapLink: (text, href, title) => {}, - imageBuilder: (uri, title, alt) => Container(), - // styleSheet: CustomMarkdownStyle(), - ); - } - - void _shareData(BuildContext _) { - Share.share("${_unsavedRecipe.title}\n\n${_unsavedRecipe.description}", subject: _unsavedRecipe.title); - } - - void _addToShoppingList(BuildContext _) { - final _ingredients = _unsavedRecipe.description!.split("\n")..retainWhere((element) => element.startsWith("- ")); - - if (_ingredients.isEmpty) { - widget.showToastCallback!(AppLocalizations.of(context)!.ingredientsError, "", () {}); - return; - } - - for (String _ingredient in _ingredients) { - String _item = _ingredient.substring(2).trim(); - - if (!ShoplistData.shoplist.contains(_item)) { - ShoplistData.shoplist.add(_item); - } - } - - ShoplistData.save(); - - if (widget.showToastCallback != null) { - widget.showToastCallback!(AppLocalizations.of(context)!.ingredientsAdded, "", () {}); - } - } - - void _uploadRecipe(BuildContext context) async { - return; - } - - List _buildAppBarActions(BuildContext context, Recipe recipe) { - final _actionList = [_shareData, _addToShoppingList, _uploadRecipe, _removeRecipe]; - - List _localActions = [ - _buildAppBarCheckActions(), - PopupMenuButton( - onSelected: (int value) => _actionList.elementAt(value)(context), - itemBuilder: (BuildContext context) => [ - PopupMenuItem(value: 0, child: Text(AppLocalizations.of(context)!.menu1)), - PopupMenuItem(value: 1, child: Text(AppLocalizations.of(context)!.menu2)), - PopupMenuItem(value: 2, child: Text(AppLocalizations.of(context)!.menu3)), - PopupMenuItem(value: 3, child: Text(AppLocalizations.of(context)!.menu4)), - ], - ), - ]; - - List _remoteDownloadAction = [ - IconButton( - icon: const Icon(Icons.save_alt_rounded), - onPressed: () { - downloadRecipe(context, recipe); - }, - ), - ]; - - List _remoteLookupAction = [ - const IconButton( - icon: Icon(Icons.menu_open_rounded), - onPressed: null, - ), - ]; - - if (widget.remote && RecipeData.recipeList.contains(recipe)) return _remoteLookupAction; - if (widget.remote) return _remoteDownloadAction; - - return _localActions; - } - - PreferredSizeWidget _buildAppBar(BuildContext context, Recipe recipe) { - String _title = AppLocalizations.of(context)!.mode1; - - if (_isEditModeEnabled) _title = AppLocalizations.of(context)!.mode2; - - return AppBar( - title: Text(_title), - leading: IconButton( - icon: const Icon(Icons.close), - onPressed: () { - Navigator.pop(context); - }, - ), - actions: _buildAppBarActions(context, recipe), - ); - } - - Widget _buildAppBarCheckActions() { - if (_isEditModeEnabled) { - return IconButton( - icon: const Icon(Icons.check), - onPressed: _addRecipe, - ); - } else { - return IconButton( - icon: const Icon(Icons.edit), - onPressed: () { - _isEditModeEnabled = true; - - setState(() {}); - }, - ); - } - } -} diff --git a/lib/views/settings_view.dart b/lib/views/settings_view.dart index 7268acf..c4cd1ce 100644 --- a/lib/views/settings_view.dart +++ b/lib/views/settings_view.dart @@ -17,7 +17,6 @@ class SettingsView extends StatefulWidget { class SettingsViewState extends State { final TextEditingController _controller = TextEditingController(); - final FocusNode _focusNode = FocusNode(); @override void initState() { @@ -83,11 +82,11 @@ class SettingsViewState extends State { trailing: ElevatedButton( child: Text(AppLocalizations.of(context)!.option312, style: cOptionTextStyle.copyWith(color: cIconColor)), onPressed: () async { - final _file = await FileHandler.pickDeserializableFile(context); + final file = await FileHandler.pickDeserializableFile(context); - if (_file == null) return; + if (file == null) return; - await FileHandler.deserializeFile(context, _file); + await FileHandler.deserializeFile(context, file); setState(() {}); }, @@ -99,36 +98,6 @@ class SettingsViewState extends State { ); } - void _updateSettings(String? text) { - _focusNode.unfocus(); - - if (text != null) { - SettingsData.settings["serverURL"] = text; - SettingsData.save(); - } - } - -/* - // TODO: Use later in direct settings? - Widget _buildServerIPInput() { - if (MediaQuery.of(context).viewInsets.bottom == 0) _updateSettings(null); - - return Container( - width: 150.0, - child: TextFormField( - keyboardType: TextInputType.url, - controller: _controller, - style: cRecipeTextStyle, - focusNode: _focusNode, - cursorColor: cPrimaryColor, - onEditingComplete: () { - _updateSettings(_controller.text); - }, - ), - ); - } -*/ - Widget _buildPhotoSourceDropDownButton() { return DropdownButton( value: int.parse(SettingsData.settings["photoSource"]!), diff --git a/lib/views/shoplist_view.dart b/lib/views/shoplist_view.dart index 35332bc..638dc1b 100644 --- a/lib/views/shoplist_view.dart +++ b/lib/views/shoplist_view.dart @@ -70,11 +70,11 @@ class ShoplistViewState extends State { title: Text(ShoplistData.shoplist[index]), ), onDismissed: (_) { - String _content = AppLocalizations.of(context)!.removed; - String _actionLabel = AppLocalizations.of(context)!.undo; + String content = AppLocalizations.of(context)!.removed; + String actionLabel = AppLocalizations.of(context)!.undo; _removeItem(index); - ToastBar.showToastBar(context, _content, actionLabel: _actionLabel, actionCallback: () => _addItem(ShoplistData.removed.removeLast())); + ToastBar.showToastBar(context, content, actionLabel: actionLabel, actionCallback: () => _addItem(ShoplistData.removed.removeLast())); }, ), ); @@ -118,12 +118,12 @@ class ShoplistViewState extends State { focusNode: _focusNode, textInputAction: TextInputAction.done, onEditingComplete: () { - String _text = _controller.text.trim(); + String text = _controller.text.trim(); _closeInput(); _controller.clear(); - if (_text != "") _addItem(_text); + if (text != "") _addItem(text); }, ), ), diff --git a/lib/views/week_view.dart b/lib/views/week_view.dart index de6ebcf..53379b9 100644 --- a/lib/views/week_view.dart +++ b/lib/views/week_view.dart @@ -42,12 +42,12 @@ class WeekViewState extends State { } Future _getWeeklyRecipes() async { - Map _headers = {"Content-Type": "application/json; charset=UTF-8"}; + Map headers = {"Content-Type": "application/json; charset=UTF-8"}; try { return await Future.delayed(const Duration(milliseconds: 500), () { debugPrint("${SettingsData.settings['serverURL']}"); - return get(Uri.https(SettingsData.settings["serverURL"]!, "/weekly"), headers: _headers); + return get(Uri.https(SettingsData.settings["serverURL"]!, "/weekly"), headers: headers); }); } catch (e) { debugPrint("$e"); diff --git a/lib/widgets/error_widgets.dart b/lib/widgets/error_widgets.dart index e17e409..356a997 100644 --- a/lib/widgets/error_widgets.dart +++ b/lib/widgets/error_widgets.dart @@ -9,7 +9,7 @@ class NoContentError extends StatelessWidget { @override Widget build(BuildContext context) { - return Container( + return SizedBox( width: double.infinity, child: Column( mainAxisAlignment: MainAxisAlignment.center, @@ -35,7 +35,7 @@ class NetworkContentError extends StatelessWidget { @override Widget build(BuildContext context) { - return Container( + return SizedBox( width: double.infinity, child: Padding( padding: const EdgeInsets.all(50.0), @@ -74,7 +74,7 @@ class UnknownError extends StatelessWidget { @override Widget build(BuildContext context) { - return Container( + return SizedBox( width: double.infinity, child: Padding( padding: const EdgeInsets.all(50.0), diff --git a/lib/widgets/recipe_card_widget.dart b/lib/widgets/recipe_card_widget.dart index a3db5f7..fab88aa 100644 --- a/lib/widgets/recipe_card_widget.dart +++ b/lib/widgets/recipe_card_widget.dart @@ -3,11 +3,11 @@ import 'dart:io'; import 'package:flutter/material.dart'; import 'package:kulinar_app/constants.dart'; +import 'package:kulinar_app/models/recipe_class.dart'; import 'package:kulinar_app/models/data/recipe_data_class.dart'; import 'package:kulinar_app/models/data/settings_data_class.dart'; -import 'package:kulinar_app/views/recipe_view.dart'; -import 'package:kulinar_app/models/recipe_class.dart'; import 'package:kulinar_app/widgets/page_route_transitions.dart'; +import 'package:kulinar_app/views/recipe_subview.dart'; class RecipeCard extends StatefulWidget { const RecipeCard({Key? key, this.remote = false, this.inSearch = false, required this.recipe, this.redrawCallback, this.showToastCallback}) : super(key: key); @@ -54,7 +54,7 @@ class RecipeCardState extends State { await Navigator.push( context, SlideFromBottomRoute( - child: RecipeView( + child: RecipeSubview( remote: widget.remote, recipe: widget.recipe, redrawCallback: widget.redrawCallback, @@ -118,16 +118,16 @@ class _RecipeInfoState extends State<_RecipeInfo> { } List _buildRating(int rating) { - List _result = []; + List result = []; - if (rating == 0) return _result; + if (rating == 0) return result; for (int i = 0; i < 5; i++) { - _result.add(rating >= 1 ? const Icon(Icons.star_rounded) : const Icon(Icons.star_border_rounded)); + result.add(rating >= 1 ? const Icon(Icons.star_rounded) : const Icon(Icons.star_border_rounded)); rating--; } - return _result; + return result; } Widget _buildRecipeInfo() { diff --git a/lib/widgets/recipe_search_delegate.dart b/lib/widgets/recipe_search_delegate.dart index cd58b29..f260dc1 100644 --- a/lib/widgets/recipe_search_delegate.dart +++ b/lib/widgets/recipe_search_delegate.dart @@ -30,21 +30,21 @@ class RecipeSearch extends SearchDelegate { @override Widget buildResults(BuildContext context) { - List _filteredRecipeList = RecipeData.recipeList.where((element) => element.title!.toLowerCase().contains(query.toLowerCase())).toList(); + List filteredRecipeList = RecipeData.recipeList.where((element) => element.title!.toLowerCase().contains(query.toLowerCase())).toList(); return ListView.builder( - itemCount: _filteredRecipeList.length, - itemBuilder: (context, index) => RecipeCard(inSearch: true, recipe: _filteredRecipeList[index]), + itemCount: filteredRecipeList.length, + itemBuilder: (context, index) => RecipeCard(inSearch: true, recipe: filteredRecipeList[index]), ); } @override Widget buildSuggestions(BuildContext context) { - List _filteredRecipeList = RecipeData.recipeList.where((element) => element.title!.toLowerCase().contains(query.toLowerCase())).toList(); + List filteredRecipeList = RecipeData.recipeList.where((element) => element.title!.toLowerCase().contains(query.toLowerCase())).toList(); return ListView.builder( - itemCount: _filteredRecipeList.length, - itemBuilder: (context, index) => RecipeCard(inSearch: true, recipe: _filteredRecipeList[index]), + itemCount: filteredRecipeList.length, + itemBuilder: (context, index) => RecipeCard(inSearch: true, recipe: filteredRecipeList[index]), ); } @@ -52,7 +52,7 @@ class RecipeSearch extends SearchDelegate { ThemeData appBarTheme(BuildContext context) { return Theme.of(context).copyWith( textTheme: const TextTheme( - headline6: cSearchTextStyle, + titleLarge: cSearchTextStyle, ), ); } @@ -83,21 +83,21 @@ class FavoriteRecipeSearch extends SearchDelegate { @override Widget buildResults(BuildContext context) { - List _filteredRecipeList = RecipeData.recipeList.where((element) => element.title!.toLowerCase().contains(query.toLowerCase()) && element.favorite).toList(); + List filteredRecipeList = RecipeData.recipeList.where((element) => element.title!.toLowerCase().contains(query.toLowerCase()) && element.favorite).toList(); return ListView.builder( - itemCount: _filteredRecipeList.length, - itemBuilder: (context, index) => RecipeCard(inSearch: true, recipe: _filteredRecipeList[index]), + itemCount: filteredRecipeList.length, + itemBuilder: (context, index) => RecipeCard(inSearch: true, recipe: filteredRecipeList[index]), ); } @override Widget buildSuggestions(BuildContext context) { - List _filteredRecipeList = RecipeData.recipeList.where((element) => element.title!.toLowerCase().contains(query.toLowerCase()) && element.favorite).toList(); + List filteredRecipeList = RecipeData.recipeList.where((element) => element.title!.toLowerCase().contains(query.toLowerCase()) && element.favorite).toList(); return ListView.builder( - itemCount: _filteredRecipeList.length, - itemBuilder: (context, index) => RecipeCard(inSearch: true, recipe: _filteredRecipeList[index]), + itemCount: filteredRecipeList.length, + itemBuilder: (context, index) => RecipeCard(inSearch: true, recipe: filteredRecipeList[index]), ); } @@ -105,7 +105,7 @@ class FavoriteRecipeSearch extends SearchDelegate { ThemeData appBarTheme(BuildContext context) { return Theme.of(context).copyWith( textTheme: const TextTheme( - headline6: cSearchTextStyle, + titleLarge: cSearchTextStyle, ), ); } diff --git a/lib/widgets/utility_icon_row_widget.dart b/lib/widgets/utility_icon_row_widget.dart index 8270ab0..a09c733 100644 --- a/lib/widgets/utility_icon_row_widget.dart +++ b/lib/widgets/utility_icon_row_widget.dart @@ -1,9 +1,9 @@ import 'package:flutter/material.dart'; import 'package:kulinar_app/constants.dart'; -import 'package:kulinar_app/models/data/settings_data_class.dart'; import 'package:kulinar_app/models/recipe_class.dart'; import 'package:kulinar_app/models/data/recipe_data_class.dart'; +import 'package:kulinar_app/models/data/settings_data_class.dart'; class UtilityIconRow extends StatefulWidget { const UtilityIconRow({ @@ -32,7 +32,7 @@ class UtilityIconRow extends StatefulWidget { } class UtilityIconRowState extends State { - bool _isInputSourceCamera = SettingsData.settings["photoSource"] == "0" ? true : false; + final _isInputSourceCamera = SettingsData.settings["photoSource"] == "0" ? true : false; @override Widget build(BuildContext context) { @@ -64,20 +64,20 @@ class UtilityIconRowState extends State { } IconButton _buildButtonAddImage() { - Icon _pickImageIcon; - Icon _removeImageIcon; - bool _recipeHasImage = widget.unsavedRecipe.image == null; + Icon pickImageIcon; + Icon removeImageIcon; + bool recipeHasImage = widget.unsavedRecipe.image == null; if (_isInputSourceCamera) { - _pickImageIcon = const Icon(Icons.add_a_photo_rounded); - _removeImageIcon = const Icon(Icons.no_photography_rounded); + pickImageIcon = const Icon(Icons.add_a_photo_rounded); + removeImageIcon = const Icon(Icons.no_photography_rounded); } else { - _pickImageIcon = const Icon(Icons.add_photo_alternate_rounded); - _removeImageIcon = const Icon(Icons.image_not_supported_rounded); + pickImageIcon = const Icon(Icons.add_photo_alternate_rounded); + removeImageIcon = const Icon(Icons.image_not_supported_rounded); } - void _onPress() { - if (_recipeHasImage) { + void onPress() { + if (recipeHasImage) { widget.pickImageCallback(); } else { widget.removeImageCallback(); @@ -85,13 +85,13 @@ class UtilityIconRowState extends State { } return IconButton( - icon: _recipeHasImage ? _pickImageIcon : _removeImageIcon, - onPressed: widget.isEditModeEnabled ? null : _onPress, + icon: recipeHasImage ? pickImageIcon : removeImageIcon, + onPressed: widget.isEditModeEnabled ? null : onPress, ); } Widget _buildIconRating(BuildContext context) { - void _onPress() { + void onPress() { widget.unsavedRecipe.updateRating(); widget.cacheUnsavedRecipeCallback(); RecipeData.save(); @@ -108,7 +108,7 @@ class UtilityIconRowState extends State { IconButton( iconSize: 28.0, icon: const Icon(Icons.star_border_rounded), - onPressed: !widget.remote ? _onPress : null, + onPressed: !widget.remote ? onPress : null, ), ], ); @@ -123,7 +123,7 @@ class UtilityIconRowState extends State { color = Colors.red; } - void _onPress() { + void onPress() { widget.unsavedRecipe.toggleFavorite(); widget.cacheUnsavedRecipeCallback(); RecipeData.save(); @@ -134,7 +134,7 @@ class UtilityIconRowState extends State { return IconButton( icon: icon, color: color, - onPressed: !widget.remote ? _onPress : null, + onPressed: !widget.remote ? onPress : null, ); } -- cgit v1.2.3