mirror of
https://github.com/chenasraf/pantry-flutter.git
synced 2026-05-17 17:28:03 +00:00
feat: take photos directly from the photo board
This commit is contained in:
@@ -84,6 +84,8 @@
|
||||
</array>
|
||||
<key>ITSAppUsesNonExemptEncryption</key>
|
||||
<false/>
|
||||
<key>NSCameraUsageDescription</key>
|
||||
<string>Pantry needs access to the camera so you can take photos and upload them to your photo board.</string>
|
||||
<key>AppGroupId</key>
|
||||
<string>group.dev.casraf.pantry</string>
|
||||
<key>CFBundleURLTypes</key>
|
||||
|
||||
@@ -1103,9 +1103,30 @@ class PhotoBoardMessages {
|
||||
/// "$count"
|
||||
/// ```
|
||||
String photoCount(int count) => """$count""";
|
||||
AddMenuPhotoBoardMessages get addMenu => AddMenuPhotoBoardMessages(this);
|
||||
SortPhotoBoardMessages get sort => SortPhotoBoardMessages(this);
|
||||
}
|
||||
|
||||
class AddMenuPhotoBoardMessages {
|
||||
final PhotoBoardMessages _parent;
|
||||
const AddMenuPhotoBoardMessages(this._parent);
|
||||
|
||||
/// ```dart
|
||||
/// "Upload photos"
|
||||
/// ```
|
||||
String get upload => """Upload photos""";
|
||||
|
||||
/// ```dart
|
||||
/// "Take photo"
|
||||
/// ```
|
||||
String get camera => """Take photo""";
|
||||
|
||||
/// ```dart
|
||||
/// "New folder"
|
||||
/// ```
|
||||
String get newFolder => """New folder""";
|
||||
}
|
||||
|
||||
class SortPhotoBoardMessages {
|
||||
final PhotoBoardMessages _parent;
|
||||
const SortPhotoBoardMessages(this._parent);
|
||||
@@ -1625,6 +1646,9 @@ Please complete login in your browser.""",
|
||||
"""photoBoard.folderName""": """Folder name""",
|
||||
"""photoBoard.renameFolder""": """Rename folder""",
|
||||
"""photoBoard.caption""": """Caption""",
|
||||
"""photoBoard.addMenu.upload""": """Upload photos""",
|
||||
"""photoBoard.addMenu.camera""": """Take photo""",
|
||||
"""photoBoard.addMenu.newFolder""": """New folder""",
|
||||
"""photoBoard.sort.foldersFirst""": """Folders first""",
|
||||
"""photoBoard.sort.newestFirst""": """Newest first""",
|
||||
"""photoBoard.sort.oldestFirst""": """Oldest first""",
|
||||
|
||||
@@ -209,6 +209,10 @@ photoBoard:
|
||||
renameFolder: Rename folder
|
||||
caption: Caption
|
||||
photoCount(int count): "$count"
|
||||
addMenu:
|
||||
upload: Upload photos
|
||||
camera: Take photo
|
||||
newFolder: New folder
|
||||
sort:
|
||||
foldersFirst: Folders first
|
||||
newestFirst: Newest first
|
||||
|
||||
@@ -1114,9 +1114,30 @@ class PhotoBoardMessagesDe extends PhotoBoardMessages {
|
||||
/// "$count"
|
||||
/// ```
|
||||
String photoCount(int count) => """$count""";
|
||||
AddMenuPhotoBoardMessagesDe get addMenu => AddMenuPhotoBoardMessagesDe(this);
|
||||
SortPhotoBoardMessagesDe get sort => SortPhotoBoardMessagesDe(this);
|
||||
}
|
||||
|
||||
class AddMenuPhotoBoardMessagesDe extends AddMenuPhotoBoardMessages {
|
||||
final PhotoBoardMessagesDe _parent;
|
||||
const AddMenuPhotoBoardMessagesDe(this._parent) : super(_parent);
|
||||
|
||||
/// ```dart
|
||||
/// "Fotos hochladen"
|
||||
/// ```
|
||||
String get upload => """Fotos hochladen""";
|
||||
|
||||
/// ```dart
|
||||
/// "Foto aufnehmen"
|
||||
/// ```
|
||||
String get camera => """Foto aufnehmen""";
|
||||
|
||||
/// ```dart
|
||||
/// "Neuer Ordner"
|
||||
/// ```
|
||||
String get newFolder => """Neuer Ordner""";
|
||||
}
|
||||
|
||||
class SortPhotoBoardMessagesDe extends SortPhotoBoardMessages {
|
||||
final PhotoBoardMessagesDe _parent;
|
||||
const SortPhotoBoardMessagesDe(this._parent) : super(_parent);
|
||||
@@ -1649,6 +1670,9 @@ Bitte melde dich in deinem Browser an.""",
|
||||
"""photoBoard.folderName""": """Ordnername""",
|
||||
"""photoBoard.renameFolder""": """Ordner umbenennen""",
|
||||
"""photoBoard.caption""": """Beschriftung""",
|
||||
"""photoBoard.addMenu.upload""": """Fotos hochladen""",
|
||||
"""photoBoard.addMenu.camera""": """Foto aufnehmen""",
|
||||
"""photoBoard.addMenu.newFolder""": """Neuer Ordner""",
|
||||
"""photoBoard.sort.foldersFirst""": """Ordner zuerst""",
|
||||
"""photoBoard.sort.newestFirst""": """Neueste zuerst""",
|
||||
"""photoBoard.sort.oldestFirst""": """Älteste zuerst""",
|
||||
|
||||
@@ -209,6 +209,10 @@ photoBoard:
|
||||
renameFolder: Ordner umbenennen
|
||||
caption: Beschriftung
|
||||
photoCount(int count): "$count"
|
||||
addMenu:
|
||||
upload: Fotos hochladen
|
||||
camera: Foto aufnehmen
|
||||
newFolder: Neuer Ordner
|
||||
sort:
|
||||
foldersFirst: Ordner zuerst
|
||||
newestFirst: Neueste zuerst
|
||||
|
||||
@@ -1110,9 +1110,30 @@ class PhotoBoardMessagesEs extends PhotoBoardMessages {
|
||||
/// "$count"
|
||||
/// ```
|
||||
String photoCount(int count) => """$count""";
|
||||
AddMenuPhotoBoardMessagesEs get addMenu => AddMenuPhotoBoardMessagesEs(this);
|
||||
SortPhotoBoardMessagesEs get sort => SortPhotoBoardMessagesEs(this);
|
||||
}
|
||||
|
||||
class AddMenuPhotoBoardMessagesEs extends AddMenuPhotoBoardMessages {
|
||||
final PhotoBoardMessagesEs _parent;
|
||||
const AddMenuPhotoBoardMessagesEs(this._parent) : super(_parent);
|
||||
|
||||
/// ```dart
|
||||
/// "Subir fotos"
|
||||
/// ```
|
||||
String get upload => """Subir fotos""";
|
||||
|
||||
/// ```dart
|
||||
/// "Tomar foto"
|
||||
/// ```
|
||||
String get camera => """Tomar foto""";
|
||||
|
||||
/// ```dart
|
||||
/// "Nueva carpeta"
|
||||
/// ```
|
||||
String get newFolder => """Nueva carpeta""";
|
||||
}
|
||||
|
||||
class SortPhotoBoardMessagesEs extends SortPhotoBoardMessages {
|
||||
final PhotoBoardMessagesEs _parent;
|
||||
const SortPhotoBoardMessagesEs(this._parent) : super(_parent);
|
||||
@@ -1639,6 +1660,9 @@ Por favor, completa el inicio de sesión en tu navegador.""",
|
||||
"""photoBoard.folderName""": """Nombre de la carpeta""",
|
||||
"""photoBoard.renameFolder""": """Renombrar carpeta""",
|
||||
"""photoBoard.caption""": """Descripción""",
|
||||
"""photoBoard.addMenu.upload""": """Subir fotos""",
|
||||
"""photoBoard.addMenu.camera""": """Tomar foto""",
|
||||
"""photoBoard.addMenu.newFolder""": """Nueva carpeta""",
|
||||
"""photoBoard.sort.foldersFirst""": """Carpetas primero""",
|
||||
"""photoBoard.sort.newestFirst""": """Más recientes""",
|
||||
"""photoBoard.sort.oldestFirst""": """Más antiguos""",
|
||||
|
||||
@@ -209,6 +209,10 @@ photoBoard:
|
||||
renameFolder: Renombrar carpeta
|
||||
caption: "Descripción"
|
||||
photoCount(int count): "$count"
|
||||
addMenu:
|
||||
upload: Subir fotos
|
||||
camera: Tomar foto
|
||||
newFolder: Nueva carpeta
|
||||
sort:
|
||||
foldersFirst: Carpetas primero
|
||||
newestFirst: "Más recientes"
|
||||
|
||||
@@ -1113,9 +1113,30 @@ class PhotoBoardMessagesFr extends PhotoBoardMessages {
|
||||
/// "$count"
|
||||
/// ```
|
||||
String photoCount(int count) => """$count""";
|
||||
AddMenuPhotoBoardMessagesFr get addMenu => AddMenuPhotoBoardMessagesFr(this);
|
||||
SortPhotoBoardMessagesFr get sort => SortPhotoBoardMessagesFr(this);
|
||||
}
|
||||
|
||||
class AddMenuPhotoBoardMessagesFr extends AddMenuPhotoBoardMessages {
|
||||
final PhotoBoardMessagesFr _parent;
|
||||
const AddMenuPhotoBoardMessagesFr(this._parent) : super(_parent);
|
||||
|
||||
/// ```dart
|
||||
/// "Téléverser des photos"
|
||||
/// ```
|
||||
String get upload => """Téléverser des photos""";
|
||||
|
||||
/// ```dart
|
||||
/// "Prendre une photo"
|
||||
/// ```
|
||||
String get camera => """Prendre une photo""";
|
||||
|
||||
/// ```dart
|
||||
/// "Nouveau dossier"
|
||||
/// ```
|
||||
String get newFolder => """Nouveau dossier""";
|
||||
}
|
||||
|
||||
class SortPhotoBoardMessagesFr extends SortPhotoBoardMessages {
|
||||
final PhotoBoardMessagesFr _parent;
|
||||
const SortPhotoBoardMessagesFr(this._parent) : super(_parent);
|
||||
@@ -1647,6 +1668,9 @@ Veuillez terminer la connexion dans votre navigateur.""",
|
||||
"""photoBoard.folderName""": """Nom du dossier""",
|
||||
"""photoBoard.renameFolder""": """Renommer le dossier""",
|
||||
"""photoBoard.caption""": """Légende""",
|
||||
"""photoBoard.addMenu.upload""": """Téléverser des photos""",
|
||||
"""photoBoard.addMenu.camera""": """Prendre une photo""",
|
||||
"""photoBoard.addMenu.newFolder""": """Nouveau dossier""",
|
||||
"""photoBoard.sort.foldersFirst""": """Dossiers en premier""",
|
||||
"""photoBoard.sort.newestFirst""": """Plus récents""",
|
||||
"""photoBoard.sort.oldestFirst""": """Plus anciens""",
|
||||
|
||||
@@ -209,6 +209,10 @@ photoBoard:
|
||||
renameFolder: Renommer le dossier
|
||||
caption: "Légende"
|
||||
photoCount(int count): "$count"
|
||||
addMenu:
|
||||
upload: Téléverser des photos
|
||||
camera: Prendre une photo
|
||||
newFolder: Nouveau dossier
|
||||
sort:
|
||||
foldersFirst: Dossiers en premier
|
||||
newestFirst: "Plus récents"
|
||||
|
||||
@@ -1105,9 +1105,30 @@ class PhotoBoardMessagesHe extends PhotoBoardMessages {
|
||||
/// "$count"
|
||||
/// ```
|
||||
String photoCount(int count) => """$count""";
|
||||
AddMenuPhotoBoardMessagesHe get addMenu => AddMenuPhotoBoardMessagesHe(this);
|
||||
SortPhotoBoardMessagesHe get sort => SortPhotoBoardMessagesHe(this);
|
||||
}
|
||||
|
||||
class AddMenuPhotoBoardMessagesHe extends AddMenuPhotoBoardMessages {
|
||||
final PhotoBoardMessagesHe _parent;
|
||||
const AddMenuPhotoBoardMessagesHe(this._parent) : super(_parent);
|
||||
|
||||
/// ```dart
|
||||
/// "העלאת תמונות"
|
||||
/// ```
|
||||
String get upload => """העלאת תמונות""";
|
||||
|
||||
/// ```dart
|
||||
/// "צילום תמונה"
|
||||
/// ```
|
||||
String get camera => """צילום תמונה""";
|
||||
|
||||
/// ```dart
|
||||
/// "תיקייה חדשה"
|
||||
/// ```
|
||||
String get newFolder => """תיקייה חדשה""";
|
||||
}
|
||||
|
||||
class SortPhotoBoardMessagesHe extends SortPhotoBoardMessages {
|
||||
final PhotoBoardMessagesHe _parent;
|
||||
const SortPhotoBoardMessagesHe(this._parent) : super(_parent);
|
||||
@@ -1622,6 +1643,9 @@ Map<String, String> get messagesHeMap => {
|
||||
"""photoBoard.folderName""": """שם התיקייה""",
|
||||
"""photoBoard.renameFolder""": """שנה שם תיקייה""",
|
||||
"""photoBoard.caption""": """כיתוב""",
|
||||
"""photoBoard.addMenu.upload""": """העלאת תמונות""",
|
||||
"""photoBoard.addMenu.camera""": """צילום תמונה""",
|
||||
"""photoBoard.addMenu.newFolder""": """תיקייה חדשה""",
|
||||
"""photoBoard.sort.foldersFirst""": """תיקיות קודם""",
|
||||
"""photoBoard.sort.newestFirst""": """החדש ביותר""",
|
||||
"""photoBoard.sort.oldestFirst""": """הישן ביותר""",
|
||||
|
||||
@@ -209,6 +209,10 @@ photoBoard:
|
||||
renameFolder: שנה שם תיקייה
|
||||
caption: כיתוב
|
||||
photoCount(int count): "$count"
|
||||
addMenu:
|
||||
upload: העלאת תמונות
|
||||
camera: צילום תמונה
|
||||
newFolder: תיקייה חדשה
|
||||
sort:
|
||||
foldersFirst: תיקיות קודם
|
||||
newestFirst: החדש ביותר
|
||||
|
||||
@@ -96,11 +96,7 @@ class _PhotoBoardBody extends StatelessWidget {
|
||||
),
|
||||
],
|
||||
),
|
||||
PositionedDirectional(
|
||||
end: 16,
|
||||
bottom: 16,
|
||||
child: PhotoAddButton(controller: controller),
|
||||
),
|
||||
Positioned.fill(child: PhotoAddButton(controller: controller)),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
@@ -1,47 +1,80 @@
|
||||
import 'dart:math' as math;
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:image_picker/image_picker.dart';
|
||||
|
||||
import 'package:pantry/i18n.dart';
|
||||
import 'package:pantry/views/photos/photo_board_controller.dart';
|
||||
|
||||
class PhotoAddButton extends StatelessWidget {
|
||||
class PhotoAddButton extends StatefulWidget {
|
||||
final PhotoBoardController controller;
|
||||
|
||||
const PhotoAddButton({super.key, required this.controller});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
FloatingActionButton.small(
|
||||
heroTag: 'photo_folder',
|
||||
onPressed: () => _createFolder(context),
|
||||
child: const Icon(Icons.create_new_folder),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
FloatingActionButton(
|
||||
heroTag: 'photo_upload',
|
||||
onPressed: () => _pickPhotos(context),
|
||||
child: const Icon(Icons.add_photo_alternate),
|
||||
),
|
||||
],
|
||||
State<PhotoAddButton> createState() => _PhotoAddButtonState();
|
||||
}
|
||||
|
||||
class _PhotoAddButtonState extends State<PhotoAddButton>
|
||||
with SingleTickerProviderStateMixin {
|
||||
late final AnimationController _animController;
|
||||
bool _open = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_animController = AnimationController(
|
||||
vsync: this,
|
||||
duration: const Duration(milliseconds: 380),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _pickPhotos(BuildContext context) async {
|
||||
final picker = ImagePicker();
|
||||
final files = await picker.pickMultiImage();
|
||||
if (files.isNotEmpty) {
|
||||
controller.uploadPhotos(files);
|
||||
@override
|
||||
void dispose() {
|
||||
_animController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
void _toggle() {
|
||||
setState(() => _open = !_open);
|
||||
if (_open) {
|
||||
_animController.forward();
|
||||
} else {
|
||||
_animController.reverse();
|
||||
}
|
||||
}
|
||||
|
||||
void _createFolder(BuildContext context) {
|
||||
void _close() {
|
||||
if (!_open) return;
|
||||
setState(() => _open = false);
|
||||
_animController.reverse();
|
||||
}
|
||||
|
||||
Future<void> _pickPhotos() async {
|
||||
_close();
|
||||
final picker = ImagePicker();
|
||||
final files = await picker.pickMultiImage();
|
||||
if (files.isNotEmpty) {
|
||||
widget.controller.uploadPhotos(files);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _takePhoto() async {
|
||||
_close();
|
||||
final picker = ImagePicker();
|
||||
final file = await picker.pickImage(source: ImageSource.camera);
|
||||
if (file != null) {
|
||||
widget.controller.uploadPhotos([file]);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _createFolderDialog() async {
|
||||
_close();
|
||||
if (!mounted) return;
|
||||
final textController = TextEditingController();
|
||||
showDialog(
|
||||
final name = await showDialog<String>(
|
||||
context: context,
|
||||
builder: (ctx) => AlertDialog(
|
||||
builder: (dialogCtx) => AlertDialog(
|
||||
title: Text(m.photoBoard.newFolder),
|
||||
content: TextField(
|
||||
controller: textController,
|
||||
@@ -51,24 +84,211 @@ class PhotoAddButton extends StatelessWidget {
|
||||
labelText: m.photoBoard.folderName,
|
||||
border: const OutlineInputBorder(),
|
||||
),
|
||||
onSubmitted: (value) {
|
||||
final v = value.trim();
|
||||
if (v.isNotEmpty) Navigator.pop(dialogCtx, v);
|
||||
},
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.pop(ctx),
|
||||
onPressed: () => Navigator.pop(dialogCtx),
|
||||
child: Text(m.common.cancel),
|
||||
),
|
||||
FilledButton(
|
||||
onPressed: () {
|
||||
final name = textController.text.trim();
|
||||
if (name.isNotEmpty) {
|
||||
controller.createFolder(name);
|
||||
Navigator.pop(ctx);
|
||||
}
|
||||
final v = textController.text.trim();
|
||||
if (v.isNotEmpty) Navigator.pop(dialogCtx, v);
|
||||
},
|
||||
child: Text(m.common.save),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
if (name != null && name.isNotEmpty) {
|
||||
widget.controller.createFolder(name);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final actions = <_FabAction>[
|
||||
_FabAction(
|
||||
icon: Icons.add_photo_alternate,
|
||||
label: m.photoBoard.addMenu.upload,
|
||||
onTap: _pickPhotos,
|
||||
),
|
||||
_FabAction(
|
||||
icon: Icons.camera_alt,
|
||||
label: m.photoBoard.addMenu.camera,
|
||||
onTap: _takePhoto,
|
||||
),
|
||||
_FabAction(
|
||||
icon: Icons.create_new_folder,
|
||||
label: m.photoBoard.addMenu.newFolder,
|
||||
onTap: _createFolderDialog,
|
||||
),
|
||||
];
|
||||
|
||||
return PopScope(
|
||||
canPop: !_open,
|
||||
onPopInvokedWithResult: (didPop, _) {
|
||||
if (!didPop && _open) _close();
|
||||
},
|
||||
child: Stack(
|
||||
children: [
|
||||
Positioned.fill(
|
||||
child: IgnorePointer(
|
||||
ignoring: !_open,
|
||||
child: AnimatedOpacity(
|
||||
opacity: _open ? 1 : 0,
|
||||
duration: const Duration(milliseconds: 180),
|
||||
child: GestureDetector(
|
||||
behavior: HitTestBehavior.opaque,
|
||||
onTap: _close,
|
||||
child: const ColoredBox(color: Color(0x66000000)),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
PositionedDirectional(
|
||||
end: 16,
|
||||
bottom: 16,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
children: [
|
||||
for (var i = 0; i < actions.length; i++)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(bottom: 12),
|
||||
child: _AnimatedAction(
|
||||
action: actions[i],
|
||||
controller: _animController,
|
||||
index: actions.length - 1 - i,
|
||||
total: actions.length,
|
||||
),
|
||||
),
|
||||
_buildMainFab(),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildMainFab() {
|
||||
return FloatingActionButton(
|
||||
heroTag: 'photo_add_menu_main',
|
||||
onPressed: _toggle,
|
||||
child: AnimatedBuilder(
|
||||
animation: _animController,
|
||||
builder: (ctx, _) {
|
||||
return Transform.rotate(
|
||||
angle: _animController.value * (math.pi * 3 / 4),
|
||||
child: const Icon(Icons.add),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _FabAction {
|
||||
final IconData icon;
|
||||
final String label;
|
||||
final VoidCallback onTap;
|
||||
|
||||
const _FabAction({
|
||||
required this.icon,
|
||||
required this.label,
|
||||
required this.onTap,
|
||||
});
|
||||
}
|
||||
|
||||
class _AnimatedAction extends StatelessWidget {
|
||||
final _FabAction action;
|
||||
final AnimationController controller;
|
||||
final int index;
|
||||
final int total;
|
||||
|
||||
const _AnimatedAction({
|
||||
required this.action,
|
||||
required this.controller,
|
||||
required this.index,
|
||||
required this.total,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final start = (index / total) * 0.4;
|
||||
final end = math.min(1.0, start + 0.7);
|
||||
final anim = CurvedAnimation(
|
||||
parent: controller,
|
||||
curve: Interval(start, end, curve: Curves.easeOutCubic),
|
||||
reverseCurve: Interval(start, end, curve: Curves.easeInCubic),
|
||||
);
|
||||
return AnimatedBuilder(
|
||||
animation: anim,
|
||||
builder: (ctx, child) {
|
||||
final v = anim.value.clamp(0.0, 1.0);
|
||||
if (v == 0) return const SizedBox.shrink();
|
||||
return Opacity(
|
||||
opacity: v,
|
||||
child: Transform.translate(
|
||||
offset: Offset(0, (1 - v) * 16),
|
||||
child: child,
|
||||
),
|
||||
);
|
||||
},
|
||||
child: _ActionRow(action: action),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _ActionRow extends StatelessWidget {
|
||||
final _FabAction action;
|
||||
const _ActionRow({required this.action});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final scheme = Theme.of(context).colorScheme;
|
||||
return Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Material(
|
||||
color: scheme.surfaceContainerHighest,
|
||||
elevation: 2,
|
||||
shape: const StadiumBorder(),
|
||||
child: InkWell(
|
||||
customBorder: const StadiumBorder(),
|
||||
onTap: action.onTap,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 8),
|
||||
child: Text(
|
||||
action.label,
|
||||
style: Theme.of(context).textTheme.bodyMedium,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
Material(
|
||||
color: scheme.secondaryContainer,
|
||||
elevation: 4,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(14),
|
||||
),
|
||||
child: InkWell(
|
||||
borderRadius: BorderRadius.circular(14),
|
||||
onTap: action.onTap,
|
||||
child: SizedBox(
|
||||
width: 48,
|
||||
height: 48,
|
||||
child: Icon(action.icon, color: scheme.onSecondaryContainer),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user