aboutsummaryrefslogtreecommitdiff
path: root/lib/widgets
diff options
context:
space:
mode:
Diffstat (limited to 'lib/widgets')
-rw-r--r--lib/widgets/custom_drawer_widget.dart129
-rw-r--r--lib/widgets/error_widgets.dart97
-rw-r--r--lib/widgets/page_route_transitions.dart65
-rw-r--r--lib/widgets/recipe_card_widget.dart178
-rw-r--r--lib/widgets/recipe_search_delegate.dart112
-rw-r--r--lib/widgets/toastbar_widget.dart27
-rw-r--r--lib/widgets/utility_icon_row_widget.dart187
7 files changed, 795 insertions, 0 deletions
diff --git a/lib/widgets/custom_drawer_widget.dart b/lib/widgets/custom_drawer_widget.dart
new file mode 100644
index 0000000..3fd8c2e
--- /dev/null
+++ b/lib/widgets/custom_drawer_widget.dart
@@ -0,0 +1,129 @@
+import 'package:flutter/material.dart';
+
+import 'package:kulinar_app/constants.dart';
+import 'package:kulinar_app/views/info_view.dart';
+import 'package:kulinar_app/views/main_view.dart';
+import 'package:kulinar_app/views/vote_view.dart';
+import 'package:kulinar_app/views/week_view.dart';
+import 'package:kulinar_app/views/shoplist_view.dart';
+import 'package:kulinar_app/views/settings_view.dart';
+import 'package:kulinar_app/views/favorites_view.dart';
+import 'package:kulinar_app/models/data/settings_data_class.dart';
+import 'package:kulinar_app/widgets/page_route_transitions.dart';
+
+import 'package:flutter_gen/gen_l10n/app_localizations.dart';
+
+class CustomDrawer extends StatefulWidget {
+ CustomDrawer({Key? key, required this.initalIndex}) : super(key: key);
+
+ final int initalIndex;
+
+ @override
+ _CustomDrawerState createState() => _CustomDrawerState();
+}
+
+class _CustomDrawerState extends State<CustomDrawer> {
+ int? _index;
+
+ @override
+ void initState() {
+ super.initState();
+ _index = widget.initalIndex;
+ }
+
+ @override
+ void dispose() {
+ super.dispose();
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return Drawer(
+ child: Column(
+ children: [
+ Expanded(
+ child: Column(
+ children: [
+ _buildDrawerHeader(),
+ _buildDrawerItem(0, Icons.receipt_rounded, AppLocalizations.of(context)!.category1, () {
+ _navigateTo(MainView(), 0);
+ }),
+ _buildDrawerItem(1, Icons.favorite_rounded, AppLocalizations.of(context)!.category4, () {
+ _navigateTo(FavoritesView(), 1);
+ }),
+ _buildDrawerItem(2, Icons.calendar_today_rounded, AppLocalizations.of(context)!.category5, () {
+ _navigateTo(WeekView(), 2);
+ }),
+ _buildDrawerItem(3, Icons.how_to_vote_rounded, AppLocalizations.of(context)!.category6, () {
+ _navigateTo(VoteView(), 3);
+ }),
+ _buildDrawerItem(4, Icons.shopping_cart_rounded, AppLocalizations.of(context)!.category7, () {
+ _navigateTo(ShoplistView(), 4);
+ }),
+ ],
+ ),
+ ),
+ _buildDrawerItem(5, Icons.settings_rounded, AppLocalizations.of(context)!.category8, () {
+ _navigateTo(SettingsView(), 5);
+ }),
+ _buildDrawerItem(6, Icons.info_rounded, AppLocalizations.of(context)!.category9, () {
+ _navigateTo(InfoView(), 6);
+ }),
+ ],
+ ),
+ );
+ }
+
+ Widget _buildDrawerHeader() {
+ return SizedBox(
+ width: double.infinity,
+ child: DrawerHeader(
+ margin: EdgeInsets.zero,
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.center,
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ Padding(
+ padding: const EdgeInsets.only(bottom: 12.0),
+ child: Icon(
+ Icons.restaurant_menu_rounded,
+ color: cIconColor,
+ size: 100.0,
+ ),
+ ),
+ ],
+ ),
+ decoration: BoxDecoration(color: cPrimaryColor),
+ ),
+ );
+ }
+
+ Widget _buildDrawerItem(int index, IconData icon, String title, Function callback) {
+ Color color = cPassiveDrawerColor;
+
+ if (index == _index) {
+ color = cPrimaryColor;
+ }
+
+ if ((index == 2 || index == 3) && SettingsData.settings["serverURL"] == "") return Container();
+
+ return ListTile(
+ leading: Icon(icon, color: color),
+ title: Text(title, style: cDrawerTextStyle.copyWith(color: color)),
+ onTap: () {
+ callback();
+ },
+ );
+ }
+
+ void _navigateTo(Widget route, int index) async {
+ _index = index;
+
+ Navigator.pop(context);
+
+ await Navigator.pushReplacement(
+ context,
+ FadeRoute(child: route),
+ );
+ }
+}
diff --git a/lib/widgets/error_widgets.dart b/lib/widgets/error_widgets.dart
new file mode 100644
index 0000000..52ac0bb
--- /dev/null
+++ b/lib/widgets/error_widgets.dart
@@ -0,0 +1,97 @@
+import 'package:flutter/material.dart';
+
+import 'package:kulinar_app/constants.dart';
+
+import 'package:flutter_gen/gen_l10n/app_localizations.dart';
+
+class NoContentError extends StatelessWidget {
+ const NoContentError({Key? key}) : super(key: key);
+
+ @override
+ Widget build(BuildContext context) {
+ return Container(
+ width: double.infinity,
+ child: Column(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ Icon(
+ Icons.sentiment_dissatisfied_rounded,
+ size: 100,
+ ),
+ Padding(
+ padding: const EdgeInsets.only(top: 20.0),
+ child: Text(AppLocalizations.of(context)!.noContentError, style: cZeroContentStyle),
+ ),
+ ],
+ ),
+ );
+ }
+}
+
+class NetworkContentError extends StatelessWidget {
+ const NetworkContentError({Key? key, required this.refreshCallback}) : super(key: key);
+
+ final Function refreshCallback;
+
+ @override
+ Widget build(BuildContext context) {
+ return Container(
+ width: double.infinity,
+ child: Padding(
+ padding: const EdgeInsets.all(50.0),
+ child: Column(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ Icon(
+ Icons.signal_wifi_off_rounded,
+ size: 100,
+ ),
+ Padding(
+ padding: const EdgeInsets.only(top: 20.0),
+ child: Text(AppLocalizations.of(context)!.noNetworkError, textAlign: TextAlign.center, style: cZeroContentStyle),
+ ),
+ Padding(
+ padding: const EdgeInsets.only(top: 20.0),
+ child: ElevatedButton(
+ child: Padding(
+ padding: const EdgeInsets.only(left: 50.0, right: 50.0),
+ child: Text(AppLocalizations.of(context)!.retry, style: cSubTitleStyle),
+ ),
+ onPressed: () {
+ refreshCallback();
+ },
+ ),
+ ),
+ ],
+ ),
+ ),
+ );
+ }
+}
+
+class UnknownError extends StatelessWidget {
+ const UnknownError({Key? key}) : super(key: key);
+
+ @override
+ Widget build(BuildContext context) {
+ return Container(
+ width: double.infinity,
+ child: Padding(
+ padding: const EdgeInsets.all(50.0),
+ child: Column(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ Icon(
+ Icons.warning_amber_rounded,
+ size: 100,
+ ),
+ Padding(
+ padding: const EdgeInsets.only(top: 20.0),
+ child: Text(AppLocalizations.of(context)!.unknownError, textAlign: TextAlign.center, style: cZeroContentStyle),
+ ),
+ ],
+ ),
+ ),
+ );
+ }
+}
diff --git a/lib/widgets/page_route_transitions.dart b/lib/widgets/page_route_transitions.dart
new file mode 100644
index 0000000..8491555
--- /dev/null
+++ b/lib/widgets/page_route_transitions.dart
@@ -0,0 +1,65 @@
+import 'package:flutter/material.dart';
+
+class SlideFromLeftRoute extends PageRouteBuilder {
+ final Widget child;
+
+ SlideFromLeftRoute({required this.child})
+ : super(
+ transitionDuration: Duration(milliseconds: 300),
+ pageBuilder: (BuildContext _, Animation<double> __, Animation<double> ___) => child,
+ transitionsBuilder: (BuildContext _, Animation<double> animation, Animation<double> __, Widget child) => SlideTransition(
+ position: Tween<Offset>(
+ begin: Offset(-1, 0),
+ end: Offset.zero,
+ ).animate(CurvedAnimation(parent: animation, curve: Interval(0.00, 1.00, curve: Curves.ease))),
+ child: child,
+ ),
+ );
+}
+
+class SlideFromRightRoute extends PageRouteBuilder {
+ final Widget child;
+
+ SlideFromRightRoute({required this.child})
+ : super(
+ transitionDuration: Duration(milliseconds: 300),
+ pageBuilder: (BuildContext _, Animation<double> __, Animation<double> ___) => child,
+ transitionsBuilder: (BuildContext _, Animation<double> animation, Animation<double> __, Widget child) => SlideTransition(
+ position: Tween<Offset>(
+ begin: Offset(1, 0),
+ end: Offset.zero,
+ ).animate(CurvedAnimation(parent: animation, curve: Interval(0.00, 1.00, curve: Curves.ease))),
+ child: child,
+ ),
+ );
+}
+
+class SlideFromBottomRoute extends PageRouteBuilder {
+ final Widget child;
+
+ SlideFromBottomRoute({required this.child})
+ : super(
+ transitionDuration: Duration(milliseconds: 300),
+ pageBuilder: (BuildContext _, Animation<double> __, Animation<double> ___) => child,
+ transitionsBuilder: (BuildContext _, Animation<double> animation, Animation<double> __, Widget child) => SlideTransition(
+ position: Tween<Offset>(
+ begin: Offset(0, 1),
+ end: Offset.zero,
+ ).animate(CurvedAnimation(parent: animation, curve: Interval(0.00, 1.00, curve: Curves.ease))),
+ child: child,
+ ),
+ );
+}
+
+class FadeRoute extends PageRouteBuilder {
+ final Widget child;
+
+ FadeRoute({required this.child})
+ : super(
+ transitionDuration: Duration(milliseconds: 300),
+ pageBuilder: (BuildContext _, Animation<double> animation, Animation<double> __) => FadeTransition(
+ opacity: animation,
+ child: child,
+ ),
+ );
+}
diff --git a/lib/widgets/recipe_card_widget.dart b/lib/widgets/recipe_card_widget.dart
new file mode 100644
index 0000000..d96b004
--- /dev/null
+++ b/lib/widgets/recipe_card_widget.dart
@@ -0,0 +1,178 @@
+import 'dart:io';
+
+import 'package:flutter/material.dart';
+
+import 'package:kulinar_app/constants.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';
+
+class RecipeCard extends StatefulWidget {
+ const RecipeCard({Key? key, this.remote = false, this.inSearch = false, required this.recipe, this.redrawCallback, this.showToastCallback}) : super(key: key);
+
+ final bool remote;
+ final bool inSearch;
+ final Recipe recipe;
+ final Function? redrawCallback;
+ final Function? showToastCallback;
+
+ @override
+ _RecipeCardState createState() => _RecipeCardState();
+}
+
+class _RecipeCardState extends State<RecipeCard> {
+ @override
+ void dispose() {
+ super.dispose();
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return GestureDetector(
+ onTap: _recipeCardPressed,
+ child: Padding(
+ padding: const EdgeInsets.only(top: 5.0, right: 5.0, left: 5.0),
+ child: Card(
+ elevation: 30.0,
+ child: Padding(
+ padding: const EdgeInsets.all(10.0),
+ child: Column(
+ children: [
+ _RecipeInfo(recipe: widget.recipe),
+ _buildImage(),
+ ],
+ ),
+ ),
+ ),
+ ),
+ );
+ }
+
+ Future<void> _recipeCardPressed() async {
+ await Navigator.push(
+ context,
+ SlideFromBottomRoute(
+ child: RecipeView(
+ remote: widget.remote,
+ readonly: true,
+ recipe: widget.recipe,
+ redrawCallback: widget.redrawCallback,
+ showToastCallback: widget.showToastCallback,
+ ),
+ ),
+ );
+
+ try {
+ if (!mounted || widget.redrawCallback == null) return;
+
+ widget.redrawCallback!();
+ } catch (e) {
+ print(e);
+ }
+ }
+
+ Widget _buildImage() {
+ if (widget.recipe.image == null) return Container();
+ if (SettingsData.settings["showPhotos"] == "3") return Container();
+ if (SettingsData.settings["showPhotos"] == "1" && !widget.inSearch) return Container();
+ if (SettingsData.settings["showPhotos"] == "2" && widget.inSearch) return Container();
+
+ return Padding(
+ padding: const EdgeInsets.only(top: 10.0),
+ child: Container(
+ height: 200.0,
+ decoration: BoxDecoration(
+ borderRadius: BorderRadius.circular(5.0),
+ image: DecorationImage(
+ image: FileImage(
+ File(widget.recipe.image!),
+ ),
+ fit: BoxFit.cover,
+ ),
+ ),
+ ),
+ );
+ }
+}
+
+class _RecipeInfo extends StatefulWidget {
+ _RecipeInfo({Key? key, required this.recipe}) : super(key: key);
+
+ final Recipe recipe;
+
+ @override
+ __RecipeInfoState createState() => __RecipeInfoState();
+}
+
+class __RecipeInfoState extends State<_RecipeInfo> {
+ @override
+ Widget build(BuildContext context) {
+ return Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ _buildRecipeInfo(),
+ _buildFavortiteIcon(),
+ ],
+ );
+ }
+
+ List<Widget> _buildRating(int rating) {
+ List<Widget> _result = [];
+
+ if (rating == 0) return _result;
+
+ for (int i = 0; i < 5; i++) {
+ _result.add(rating >= 1 ? Icon(Icons.star_rounded) : Icon(Icons.star_border_rounded));
+ rating--;
+ }
+
+ return _result;
+ }
+
+ Widget _buildRecipeInfo() {
+ return Expanded(
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Padding(
+ padding: const EdgeInsets.all(2.0),
+ child: Text(
+ widget.recipe.title!,
+ style: cRecipeTextStyle,
+ overflow: TextOverflow.ellipsis,
+ ),
+ ),
+ Padding(
+ padding: const EdgeInsets.only(bottom: 2.0, left: 2.0),
+ child: Text(
+ widget.recipe.description!,
+ style: cRecipeDescriptionStyle,
+ overflow: TextOverflow.ellipsis,
+ maxLines: 1,
+ ),
+ ),
+ Padding(
+ padding: const EdgeInsets.only(bottom: 2.0),
+ child: Row(
+ children: widget.recipe.rating != null ? _buildRating(widget.recipe.rating) : [],
+ ),
+ ),
+ ],
+ ),
+ );
+ }
+
+ Widget _buildFavortiteIcon() {
+ return IconButton(
+ icon: widget.recipe.favorite ? Icon(Icons.favorite_rounded, color: Colors.red) : Icon(Icons.favorite_border_rounded),
+ onPressed: () {
+ widget.recipe.toggleFavorite();
+ RecipeData.save();
+
+ setState(() {});
+ },
+ );
+ }
+}
diff --git a/lib/widgets/recipe_search_delegate.dart b/lib/widgets/recipe_search_delegate.dart
new file mode 100644
index 0000000..1cb02e7
--- /dev/null
+++ b/lib/widgets/recipe_search_delegate.dart
@@ -0,0 +1,112 @@
+import 'package:flutter/material.dart';
+
+import 'package:kulinar_app/constants.dart';
+import 'package:kulinar_app/models/recipe_class.dart';
+import 'package:kulinar_app/widgets/recipe_card_widget.dart';
+import 'package:kulinar_app/models/data/recipe_data_class.dart';
+
+class RecipeSearch extends SearchDelegate {
+ @override
+ List<Widget> buildActions(BuildContext context) {
+ return [
+ IconButton(
+ icon: Icon(Icons.clear),
+ onPressed: () {
+ query = "";
+ },
+ ),
+ ];
+ }
+
+ @override
+ Widget buildLeading(BuildContext context) {
+ return IconButton(
+ icon: Icon(Icons.arrow_back, color: cIconColor),
+ onPressed: () {
+ close(context, null);
+ },
+ );
+ }
+
+ @override
+ Widget buildResults(BuildContext context) {
+ List<Recipe> _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]),
+ );
+ }
+
+ @override
+ Widget buildSuggestions(BuildContext context) {
+ List<Recipe> _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]),
+ );
+ }
+
+ @override
+ ThemeData appBarTheme(BuildContext context) {
+ return Theme.of(context).copyWith(
+ textTheme: TextTheme(
+ headline6: cSearchTextStyle,
+ ),
+ );
+ }
+}
+
+class FavoriteRecipeSearch extends SearchDelegate {
+ @override
+ List<Widget> buildActions(BuildContext context) {
+ return [
+ IconButton(
+ icon: Icon(Icons.clear),
+ onPressed: () {
+ query = "";
+ },
+ ),
+ ];
+ }
+
+ @override
+ Widget buildLeading(BuildContext context) {
+ return IconButton(
+ icon: Icon(Icons.arrow_back, color: cIconColor),
+ onPressed: () {
+ close(context, null);
+ },
+ );
+ }
+
+ @override
+ Widget buildResults(BuildContext context) {
+ List<Recipe> _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]),
+ );
+ }
+
+ @override
+ Widget buildSuggestions(BuildContext context) {
+ List<Recipe> _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]),
+ );
+ }
+
+ @override
+ ThemeData appBarTheme(BuildContext context) {
+ return Theme.of(context).copyWith(
+ textTheme: TextTheme(
+ headline6: cSearchTextStyle,
+ ),
+ );
+ }
+}
diff --git a/lib/widgets/toastbar_widget.dart b/lib/widgets/toastbar_widget.dart
new file mode 100644
index 0000000..760ce2e
--- /dev/null
+++ b/lib/widgets/toastbar_widget.dart
@@ -0,0 +1,27 @@
+import 'package:flutter/material.dart';
+
+class ToastBar {
+ static Future<void> showToastBar(BuildContext context, String content, {bool error = false, String? actionLabel, Function? actionCallback}) async {
+ SnackBar snackBar = SnackBar(
+ action: actionLabel != ""
+ ? SnackBarAction(
+ label: actionLabel!,
+ onPressed: () {
+ if (actionCallback != null) actionCallback();
+ },
+ textColor: Theme.of(context).colorScheme.secondary)
+ : null,
+ backgroundColor: error == true ? Colors.red : Colors.grey[900],
+ behavior: SnackBarBehavior.floating,
+ duration: Duration(seconds: 5),
+ elevation: 5.0,
+ content: Text(
+ content,
+ style: TextStyle(color: Colors.white),
+ overflow: TextOverflow.ellipsis,
+ ),
+ );
+
+ ScaffoldMessenger.of(context).showSnackBar(snackBar);
+ }
+}
diff --git a/lib/widgets/utility_icon_row_widget.dart b/lib/widgets/utility_icon_row_widget.dart
new file mode 100644
index 0000000..3d45d15
--- /dev/null
+++ b/lib/widgets/utility_icon_row_widget.dart
@@ -0,0 +1,187 @@
+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';
+
+class UtilityIconRow extends StatefulWidget {
+ const UtilityIconRow({
+ Key? key,
+ this.remote = false,
+ required this.readonly,
+ required this.unsavedRecipe,
+ required this.pickImageCallback,
+ required this.removeImageCallback,
+ required this.removeRecipeCallback,
+ required this.downloadRecipeCallback,
+ required this.isEditingAllowedCallback,
+ required this.cacheUnsavedRecipeCallback,
+ }) : super(key: key);
+
+ final bool remote;
+ final bool readonly;
+ final Recipe unsavedRecipe;
+ final Function pickImageCallback;
+ final Function removeImageCallback;
+ final Function removeRecipeCallback;
+ final Function downloadRecipeCallback;
+ final Function isEditingAllowedCallback;
+ final Function cacheUnsavedRecipeCallback;
+
+ @override
+ _UtilityIconRowState createState() => _UtilityIconRowState();
+}
+
+class _UtilityIconRowState extends State<UtilityIconRow> {
+ bool _isInputSourceCamera = SettingsData.settings["photoSource"] == "0" ? true : false;
+
+ @override
+ Widget build(BuildContext context) {
+ return Padding(
+ padding: const EdgeInsets.only(top: 10.0),
+ child: Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ Padding(
+ padding: const EdgeInsets.all(0), // EdgeInsets.only(left: 4.0),
+ child: _buildButtonAddImage(),
+ ),
+ Row(
+ mainAxisAlignment: MainAxisAlignment.end,
+ children: [
+ _buildIconRating(context),
+ _buildIconFavorite(),
+ // _buildIconCalculate(),
+ // _buildIconShare(),
+ // _buildIconImportExport(context),
+ ],
+ ),
+ ],
+ ),
+ );
+ }
+
+ IconButton _buildButtonAddImage() {
+ Icon _pickImageIcon;
+ Icon _removeImageIcon;
+ bool _recipeHasImage = widget.unsavedRecipe.image == null;
+
+ if (_isInputSourceCamera) {
+ _pickImageIcon = Icon(Icons.add_a_photo_rounded);
+ _removeImageIcon = Icon(Icons.no_photography_rounded);
+ } else {
+ _pickImageIcon = Icon(Icons.add_photo_alternate_rounded);
+ _removeImageIcon = Icon(Icons.image_not_supported_rounded);
+ }
+
+ void _onPress() {
+ if (_recipeHasImage) {
+ widget.pickImageCallback();
+ } else {
+ widget.removeImageCallback();
+ }
+ }
+
+ return IconButton(
+ icon: _recipeHasImage ? _pickImageIcon : _removeImageIcon,
+ onPressed: _onPress,
+ );
+ }
+
+ Widget _buildIconRating(BuildContext context) {
+ void _onPress() {
+ widget.unsavedRecipe.updateRating();
+ widget.cacheUnsavedRecipeCallback();
+ RecipeData.save();
+
+ setState(() {});
+ }
+
+ return Row(
+ children: [
+ Padding(
+ padding: const EdgeInsets.only(top: 2.0),
+ child: Text(widget.unsavedRecipe.rating.toString(), style: cDefaultTextStyle),
+ ),
+ IconButton(
+ iconSize: 28.0,
+ icon: Icon(Icons.star_border_rounded),
+ onPressed: !widget.remote ? _onPress : null,
+ ),
+ ],
+ );
+ }
+
+ Widget _buildIconFavorite() {
+ Icon icon = Icon(Icons.favorite_border_rounded);
+ Color color = Colors.black;
+
+ if (widget.unsavedRecipe.favorite) {
+ icon = Icon(Icons.favorite_rounded);
+ color = Colors.red;
+ }
+
+ void _onPress() {
+ widget.unsavedRecipe.toggleFavorite();
+ widget.cacheUnsavedRecipeCallback();
+ RecipeData.save();
+
+ setState(() {});
+ }
+
+ return IconButton(
+ icon: icon,
+ color: color,
+ onPressed: !widget.remote ? _onPress : null,
+ );
+ }
+
+ /* todo: IMPLEMENT RICH TEXT https://stackoverflow.com/questions/41557139/how-do-i-bold-or-format-a-piece-of-text-within-a-paragraph
+ // todo: Implement recalculations (portions, measurement system)
+ Widget _buildIconCalculate() {
+ return IconButton(
+ icon: Icon(Icons.calculate_rounded),
+ onPressed: null,
+ );
+ }
+ */
+
+/* Widget _buildIconShare() {
+ return IconButton(
+ icon: Icon(Icons.share),
+ onPressed: widget.readonly && !widget.remote ? _shareData : null,
+ );
+ } */
+
+ /*
+ IF REMOTE:
+ DOWNLOAD
+
+ IF REMOTE AND LOCAL:
+ GO TO LOCAL
+
+ IF LOCAL:
+ UPLOAD
+ Widget _buildIconImportExport(BuildContext context) {
+ if (widget.unsavedRecipe.isListed(remote: true)) {
+ if (widget.unsavedRecipe.isListed()) {
+ return IconButton(
+ icon: Icon(Icons.get_app),
+ onPressed: !widget.isEditingAllowedCallback() ? () => widget.downloadRecipeCallback(context, widget.unsavedRecipe) : null,
+ );
+ } else {
+ return IconButton(
+ icon: Icon(Icons.arrow_back),
+ onPressed: !widget.isEditingAllowedCallback() ? () => widget.downloadRecipeCallback(context, widget.unsavedRecipe) : null,
+ );
+ }
+ } else {
+ return IconButton(
+ icon: Icon(Icons.publish),
+ onPressed: !widget.isEditingAllowedCallback() ? () => _uploadRecipe(context) : null,
+ );
+ }
+ }
+ */
+}