feat(recipes): add recipe visibility and sharing features
- Implemented functionality to set recipe visibility (public/private) with appropriate checks for user permissions. - Added ability to share recipes with other users, including validation for existing users and permissions. - Introduced new DTOs for setting visibility and sharing recipes. - Updated RecipesController and RecipesService to handle new endpoints for visibility and sharing. - Enhanced inventory preview to consider user permissions and shared recipes. - Updated front-end to support new sharing and visibility features, including UI changes for recipe detail and admin user management.
This commit is contained in:
@@ -6,6 +6,7 @@ import '../../../core/api/api_error_mapper.dart';
|
||||
import '../../../core/ui/async_state_views.dart';
|
||||
import '../data/recipe_providers.dart';
|
||||
import '../data/recipes_grid_provider.dart';
|
||||
import '../domain/recipe.dart';
|
||||
|
||||
class RecipesScreen extends ConsumerWidget {
|
||||
const RecipesScreen({super.key});
|
||||
@@ -47,21 +48,7 @@ class RecipesScreen extends ConsumerWidget {
|
||||
final recipe = recipes[index];
|
||||
return GestureDetector(
|
||||
onTap: () => context.push('/recipes/${recipe.id}'),
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(8.0),
|
||||
color: Colors.grey[200],
|
||||
image: recipe.imageUrl != null
|
||||
? DecorationImage(
|
||||
image: NetworkImage(recipe.imageUrl!),
|
||||
fit: BoxFit.cover,
|
||||
)
|
||||
: null,
|
||||
),
|
||||
child: recipe.imageUrl == null
|
||||
? const Center(child: Icon(Icons.restaurant, size: 32))
|
||||
: null,
|
||||
),
|
||||
child: _RecipeImageCard(recipe: recipe),
|
||||
);
|
||||
},
|
||||
);
|
||||
@@ -80,20 +67,11 @@ class RecipesScreen extends ConsumerWidget {
|
||||
children: [
|
||||
ClipRRect(
|
||||
borderRadius: BorderRadius.circular(6),
|
||||
child: recipe.imageUrl != null
|
||||
? Image.network(
|
||||
recipe.imageUrl!,
|
||||
width: 72,
|
||||
height: 72,
|
||||
fit: BoxFit.cover,
|
||||
)
|
||||
: Container(
|
||||
width: 72,
|
||||
height: 72,
|
||||
color: Colors.grey[200],
|
||||
child: const Icon(Icons.restaurant,
|
||||
size: 32),
|
||||
),
|
||||
child: SizedBox(
|
||||
width: 72,
|
||||
height: 72,
|
||||
child: _RecipeImageCard(recipe: recipe, compact: true),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
@@ -126,3 +104,57 @@ class RecipesScreen extends ConsumerWidget {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _RecipeImageCard extends StatelessWidget {
|
||||
final Recipe recipe;
|
||||
final bool compact;
|
||||
|
||||
const _RecipeImageCard({required this.recipe, this.compact = false});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final showStamp = recipe.isPublic == true &&
|
||||
recipe.ownerUsername != null &&
|
||||
recipe.ownerUsername.toString().isNotEmpty;
|
||||
final radius = compact ? 0.0 : 8.0;
|
||||
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(radius),
|
||||
color: Colors.grey[200],
|
||||
image: recipe.imageUrl != null
|
||||
? DecorationImage(
|
||||
image: NetworkImage(recipe.imageUrl!),
|
||||
fit: BoxFit.cover,
|
||||
)
|
||||
: null,
|
||||
),
|
||||
child: Stack(
|
||||
children: [
|
||||
if (recipe.imageUrl == null)
|
||||
const Center(child: Icon(Icons.restaurant, size: 32)),
|
||||
if (showStamp)
|
||||
Positioned(
|
||||
right: 4,
|
||||
bottom: 4,
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 5, vertical: 2),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.black.withOpacity(0.45),
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
child: Text(
|
||||
'@${recipe.ownerUsername}',
|
||||
style: TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: compact ? 8 : 10,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user