mirror of
https://github.com/immich-app/immich
synced 2025-11-07 17:27:20 +00:00
Implemented bottom app bar with control buttons for asset's operation (#15)
This commit is contained in:
parent
b04e69fd66
commit
f578ca6d47
11 changed files with 252 additions and 55 deletions
75
mobile/lib/modules/home/ui/control_bottom_app_bar.dart
Normal file
75
mobile/lib/modules/home/ui/control_bottom_app_bar.dart
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:immich_mobile/modules/home/ui/delete_diaglog.dart';
|
||||
|
||||
class ControlBottomAppBar extends StatelessWidget {
|
||||
const ControlBottomAppBar({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Positioned(
|
||||
bottom: 0,
|
||||
left: 0,
|
||||
child: Container(
|
||||
width: MediaQuery.of(context).size.width,
|
||||
height: MediaQuery.of(context).size.height * 0.15,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: const BorderRadius.only(topLeft: Radius.circular(15), topRight: Radius.circular(15)),
|
||||
color: Colors.grey[300]?.withOpacity(0.98),
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 20),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
ControlBoxButton(
|
||||
iconData: Icons.delete_forever_rounded,
|
||||
label: "Delete",
|
||||
onPressed: () {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return const DeleteDialog();
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class ControlBoxButton extends StatelessWidget {
|
||||
const ControlBoxButton({Key? key, required this.label, required this.iconData, required this.onPressed})
|
||||
: super(key: key);
|
||||
|
||||
final String label;
|
||||
final IconData iconData;
|
||||
final Function onPressed;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SizedBox(
|
||||
width: 60,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
onPressed();
|
||||
},
|
||||
icon: Icon(iconData, size: 30),
|
||||
),
|
||||
Text(label)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -24,6 +24,31 @@ class DailyTitleText extends ConsumerWidget {
|
|||
var selectedDateGroup = ref.watch(homePageStateProvider).selectedDateGroup;
|
||||
var selectedItems = ref.watch(homePageStateProvider).selectedItems;
|
||||
|
||||
void _handleTitleIconClick() {
|
||||
if (isMultiSelectEnable &&
|
||||
selectedDateGroup.contains(dateText) &&
|
||||
selectedDateGroup.length == 1 &&
|
||||
selectedItems.length <= assetGroup.length) {
|
||||
// Multi select is active - click again on the icon while it is the only active group -> disable multi select
|
||||
ref.watch(homePageStateProvider.notifier).disableMultiSelect();
|
||||
} else if (isMultiSelectEnable &&
|
||||
selectedDateGroup.contains(dateText) &&
|
||||
selectedItems.length != assetGroup.length) {
|
||||
// Multi select is active - click again on the icon while it is not the only active group -> remove that group from selected group/items
|
||||
ref.watch(homePageStateProvider.notifier).removeSelectedDateGroup(dateText);
|
||||
ref.watch(homePageStateProvider.notifier).removeMultipleSelectedItem(assetGroup);
|
||||
} else if (isMultiSelectEnable && selectedDateGroup.contains(dateText) && selectedDateGroup.length > 1) {
|
||||
ref.watch(homePageStateProvider.notifier).removeSelectedDateGroup(dateText);
|
||||
ref.watch(homePageStateProvider.notifier).removeMultipleSelectedItem(assetGroup);
|
||||
} else if (isMultiSelectEnable && !selectedDateGroup.contains(dateText)) {
|
||||
ref.watch(homePageStateProvider.notifier).addSelectedDateGroup(dateText);
|
||||
ref.watch(homePageStateProvider.notifier).addMultipleSelectedItems(assetGroup);
|
||||
} else {
|
||||
ref.watch(homePageStateProvider.notifier).enableMultiSelect(assetGroup.toSet());
|
||||
ref.watch(homePageStateProvider.notifier).addSelectedDateGroup(dateText);
|
||||
}
|
||||
}
|
||||
|
||||
return SliverToBoxAdapter(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(top: 29.0, bottom: 29.0, left: 12.0, right: 12.0),
|
||||
|
|
@ -39,33 +64,16 @@ class DailyTitleText extends ConsumerWidget {
|
|||
),
|
||||
const Spacer(),
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
if (isMultiSelectEnable &&
|
||||
selectedDateGroup.contains(dateText) &&
|
||||
selectedDateGroup.length == 1 &&
|
||||
selectedItems.length == assetGroup.length) {
|
||||
ref.watch(homePageStateProvider.notifier).disableMultiSelect();
|
||||
} else if (isMultiSelectEnable &&
|
||||
selectedDateGroup.contains(dateText) &&
|
||||
selectedItems.length != assetGroup.length) {
|
||||
ref.watch(homePageStateProvider.notifier).removeSelectedDateGroup(dateText);
|
||||
ref.watch(homePageStateProvider.notifier).removeMultipleSelectedItem(assetGroup);
|
||||
} else if (isMultiSelectEnable &&
|
||||
selectedDateGroup.contains(dateText) &&
|
||||
selectedDateGroup.length > 1) {
|
||||
ref.watch(homePageStateProvider.notifier).removeSelectedDateGroup(dateText);
|
||||
ref.watch(homePageStateProvider.notifier).removeMultipleSelectedItem(assetGroup);
|
||||
} else if (isMultiSelectEnable && !selectedDateGroup.contains(dateText)) {
|
||||
ref.watch(homePageStateProvider.notifier).addSelectedDateGroup(dateText);
|
||||
ref.watch(homePageStateProvider.notifier).addMultipleSelectedItems(assetGroup);
|
||||
} else {
|
||||
ref.watch(homePageStateProvider.notifier).enableMultiSelect(assetGroup.toSet());
|
||||
ref.watch(homePageStateProvider.notifier).addSelectedDateGroup(dateText);
|
||||
}
|
||||
},
|
||||
onTap: _handleTitleIconClick,
|
||||
child: isMultiSelectEnable && selectedDateGroup.contains(dateText)
|
||||
? const Icon(Icons.check_circle_rounded)
|
||||
: const Icon(Icons.check_circle_outline_rounded),
|
||||
? Icon(
|
||||
Icons.check_circle_rounded,
|
||||
color: Theme.of(context).primaryColor,
|
||||
)
|
||||
: const Icon(
|
||||
Icons.check_circle_outline_rounded,
|
||||
color: Colors.grey,
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
|
|
|
|||
33
mobile/lib/modules/home/ui/delete_diaglog.dart
Normal file
33
mobile/lib/modules/home/ui/delete_diaglog.dart
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
class DeleteDialog extends StatelessWidget {
|
||||
const DeleteDialog({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AlertDialog(
|
||||
backgroundColor: Colors.grey[200],
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
|
||||
title: const Text("Delete Permanently"),
|
||||
content: const Text("These items will be permanently deleted from Immich and from your device"),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
child: const Text(
|
||||
"Cancel",
|
||||
style: TextStyle(color: Colors.blueGrey),
|
||||
),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () {},
|
||||
child: Text(
|
||||
"Delete",
|
||||
style: TextStyle(color: Colors.red[400]),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
47
mobile/lib/modules/home/ui/disable_multi_select_button.dart
Normal file
47
mobile/lib/modules/home/ui/disable_multi_select_button.dart
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:immich_mobile/modules/home/providers/home_page_state.provider.dart';
|
||||
|
||||
class DisableMultiSelectButton extends ConsumerWidget {
|
||||
const DisableMultiSelectButton({
|
||||
Key? key,
|
||||
required this.onPressed,
|
||||
required this.selectedItemCount,
|
||||
}) : super(key: key);
|
||||
|
||||
final Function onPressed;
|
||||
final int selectedItemCount;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
return Positioned(
|
||||
top: 0,
|
||||
left: 0,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(left: 16.0, top: 46),
|
||||
child: Material(
|
||||
elevation: 20,
|
||||
borderRadius: BorderRadius.circular(35),
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(35),
|
||||
color: Colors.grey[100],
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 4.0),
|
||||
child: TextButton.icon(
|
||||
onPressed: () {
|
||||
onPressed();
|
||||
},
|
||||
icon: const Icon(Icons.close_rounded),
|
||||
label: Text(
|
||||
selectedItemCount.toString(),
|
||||
style: const TextStyle(fontWeight: FontWeight.w600, fontSize: 18),
|
||||
)),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -57,8 +57,8 @@ class ProfileDrawer extends ConsumerWidget {
|
|||
bool res = await ref.read(authenticationProvider.notifier).logout();
|
||||
|
||||
if (res) {
|
||||
ref.watch(assetProvider.notifier).clearAllAsset();
|
||||
AutoRouter.of(context).popUntilRoot();
|
||||
ref.read(assetProvider.notifier).clearAllAsset();
|
||||
}
|
||||
},
|
||||
)
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@ class ThumbnailImage extends HookConsumerWidget {
|
|||
} else if (isMultiSelectEnable && !selectedAsset.contains(asset)) {
|
||||
ref.watch(homePageStateProvider.notifier).addSingleSelectedItem(asset);
|
||||
} else {
|
||||
print(asset.id);
|
||||
if (asset.type == 'IMAGE') {
|
||||
AutoRouter.of(context).push(
|
||||
ImageViewerRoute(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue