Skip to content

Commit

Permalink
Merge pull request #69 from greenfrogs/gf/draggable-intake-cards
Browse files Browse the repository at this point in the history
Add Draggable Intake Cards
  • Loading branch information
simonoppowa authored Apr 27, 2024
2 parents 4ac671b + b296129 commit 8e66448
Show file tree
Hide file tree
Showing 3 changed files with 229 additions and 92 deletions.
14 changes: 8 additions & 6 deletions lib/core/presentation/widgets/intake_card.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@ import 'package:opennutritracker/core/utils/locator.dart';

class IntakeCard extends StatelessWidget {
final IntakeEntity intake;
final Function(BuildContext, IntakeEntity) onItemLongPressed;
final Function(BuildContext, IntakeEntity)? onItemLongPressed;
final bool firstListElement;

const IntakeCard(
{required super.key,
required this.intake,
required this.onItemLongPressed,
this.onItemLongPressed,
required this.firstListElement});

@override
Expand All @@ -32,9 +32,9 @@ class IntakeCard extends StatelessWidget {
),
elevation: 1,
child: InkWell(
onLongPress: () {
onLongPressedItem(context);
},
onLongPress: onItemLongPressed != null
? () => onLongPressedItem(context)
: null,
child: Stack(
children: [
intake.meal.mainImageUrl != null
Expand Down Expand Up @@ -122,6 +122,8 @@ class IntakeCard extends StatelessWidget {
}

void onLongPressedItem(BuildContext context) {
onItemLongPressed(context, intake);
if (onItemLongPressed != null) {
onItemLongPressed!(context, intake);
}
}
}
154 changes: 103 additions & 51 deletions lib/features/home/home_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ class _HomePageState extends State<HomePage> with WidgetsBindingObserver {
final log = Logger('HomePage');

late HomeBloc _homeBloc;
bool _isDragging = false;

@override
void initState() {
Expand Down Expand Up @@ -111,57 +112,87 @@ class _HomePageState extends State<HomePage> with WidgetsBindingObserver {
if (showDisclaimerDialog) {
_showDisclaimerDialog(context);
}
return ListView(children: [
DashboardWidget(
totalKcalDaily: totalKcalDaily,
totalKcalLeft: totalKcalLeft,
totalKcalSupplied: totalKcalSupplied,
totalKcalBurned: totalKcalBurned,
totalCarbsIntake: totalCarbsIntake,
totalFatsIntake: totalFatsIntake,
totalProteinsIntake: totalProteinsIntake,
totalCarbsGoal: totalCarbsGoal,
totalFatsGoal: totalFatsGoal,
totalProteinsGoal: totalProteinsGoal,
),
ActivityVerticalList(
day: DateTime.now(),
title: S.of(context).activityLabel,
userActivityList: userActivities,
onItemLongPressedCallback: onActivityItemLongPressed,
),
IntakeVerticalList(
day: DateTime.now(),
title: S.of(context).breakfastLabel,
listIcon: IntakeTypeEntity.breakfast.getIconData(),
addMealType: AddMealType.breakfastType,
intakeList: breakfastIntakeList,
onItemLongPressedCallback: onIntakeItemLongPressed,
),
IntakeVerticalList(
day: DateTime.now(),
title: S.of(context).lunchLabel,
listIcon: IntakeTypeEntity.lunch.getIconData(),
addMealType: AddMealType.lunchType,
intakeList: lunchIntakeList,
onItemLongPressedCallback: onIntakeItemLongPressed,
),
IntakeVerticalList(
day: DateTime.now(),
title: S.of(context).dinnerLabel,
addMealType: AddMealType.dinnerType,
listIcon: IntakeTypeEntity.dinner.getIconData(),
intakeList: dinnerIntakeList,
onItemLongPressedCallback: onIntakeItemLongPressed,
),
IntakeVerticalList(
day: DateTime.now(),
title: S.of(context).snackLabel,
listIcon: IntakeTypeEntity.snack.getIconData(),
addMealType: AddMealType.snackType,
intakeList: snackIntakeList,
onItemLongPressedCallback: onIntakeItemLongPressed,
)
return Stack(children: [
ListView(children: [
DashboardWidget(
totalKcalDaily: totalKcalDaily,
totalKcalLeft: totalKcalLeft,
totalKcalSupplied: totalKcalSupplied,
totalKcalBurned: totalKcalBurned,
totalCarbsIntake: totalCarbsIntake,
totalFatsIntake: totalFatsIntake,
totalProteinsIntake: totalProteinsIntake,
totalCarbsGoal: totalCarbsGoal,
totalFatsGoal: totalFatsGoal,
totalProteinsGoal: totalProteinsGoal,
),
ActivityVerticalList(
day: DateTime.now(),
title: S.of(context).activityLabel,
userActivityList: userActivities,
onItemLongPressedCallback: onActivityItemLongPressed,
),
IntakeVerticalList(
day: DateTime.now(),
title: S.of(context).breakfastLabel,
listIcon: IntakeTypeEntity.breakfast.getIconData(),
addMealType: AddMealType.breakfastType,
intakeList: breakfastIntakeList,
onItemDragCallback: onIntakeItemDrag,
),
IntakeVerticalList(
day: DateTime.now(),
title: S.of(context).lunchLabel,
listIcon: IntakeTypeEntity.lunch.getIconData(),
addMealType: AddMealType.lunchType,
intakeList: lunchIntakeList,
onItemDragCallback: onIntakeItemDrag,
),
IntakeVerticalList(
day: DateTime.now(),
title: S.of(context).dinnerLabel,
addMealType: AddMealType.dinnerType,
listIcon: IntakeTypeEntity.dinner.getIconData(),
intakeList: dinnerIntakeList,
onItemDragCallback: onIntakeItemDrag,
),
IntakeVerticalList(
day: DateTime.now(),
title: S.of(context).snackLabel,
listIcon: IntakeTypeEntity.snack.getIconData(),
addMealType: AddMealType.snackType,
intakeList: snackIntakeList,
onItemDragCallback: onIntakeItemDrag,
),
const SizedBox(height: 48.0)
]),
Align(
alignment: Alignment.bottomCenter,
child: Visibility(
visible: _isDragging,
child: Container(
height: 70,
color: Theme.of(context).colorScheme.error.withOpacity(0.3),
child: DragTarget<IntakeEntity>(
onAcceptWithDetails: (data) {
_confirmDelete(context, data.data);
},
onLeave: (data) {
setState(() {
_isDragging = false;
});
},
builder: (context, candidateData, rejectedData) {
return const Center(
child: Icon(
Icons.delete_outline,
size: 36,
color: Colors.white,
),
);
},
),
)))
]);
}

Expand Down Expand Up @@ -195,6 +226,27 @@ class _HomePageState extends State<HomePage> with WidgetsBindingObserver {
}
}

void onIntakeItemDrag(bool isDragging) {
WidgetsBinding.instance.addPostFrameCallback((_) {
setState(() {
_isDragging = isDragging;
});
});
}

void _confirmDelete(BuildContext context, IntakeEntity intake) async {
bool? delete = await showDialog<bool>(
context: context, builder: (context) => const DeleteDialog());

if (delete == true) {
_homeBloc.deleteIntakeItem(intake);
_homeBloc.add(const LoadItemsEvent());
}
setState(() {
_isDragging = false;
});
}

/// Show disclaimer dialog after build method
void _showDisclaimerDialog(BuildContext context) async {
WidgetsBinding.instance.addPostFrameCallback((_) async {
Expand Down
Loading

0 comments on commit 8e66448

Please sign in to comment.