feat(team_members): enhance Team Members Bottom Sheet with bucket details and edit functionality
This commit is contained in:
parent
219815dd27
commit
e624fb00a0
@ -1,9 +1,16 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:marco/helpers/widgets/my_text.dart';
|
import 'package:marco/helpers/widgets/my_text.dart';
|
||||||
import 'package:marco/helpers/widgets/avatar.dart';
|
import 'package:marco/helpers/widgets/avatar.dart';
|
||||||
|
import 'package:marco/model/directory/contact_bucket_list_model.dart';
|
||||||
|
|
||||||
class TeamMembersBottomSheet {
|
class TeamMembersBottomSheet {
|
||||||
static void show(BuildContext context, List<dynamic> members) {
|
static void show(
|
||||||
|
BuildContext context,
|
||||||
|
ContactBucket bucket,
|
||||||
|
List<dynamic> members, {
|
||||||
|
bool canEdit = false,
|
||||||
|
VoidCallback? onEdit,
|
||||||
|
}) {
|
||||||
showModalBottomSheet(
|
showModalBottomSheet(
|
||||||
context: context,
|
context: context,
|
||||||
isScrollControlled: true,
|
isScrollControlled: true,
|
||||||
@ -19,14 +26,13 @@ class TeamMembersBottomSheet {
|
|||||||
),
|
),
|
||||||
child: DraggableScrollableSheet(
|
child: DraggableScrollableSheet(
|
||||||
expand: false,
|
expand: false,
|
||||||
initialChildSize: 0.6,
|
initialChildSize: 0.7,
|
||||||
minChildSize: 0.4,
|
minChildSize: 0.5,
|
||||||
maxChildSize: 0.9,
|
maxChildSize: 0.95,
|
||||||
builder: (context, scrollController) {
|
builder: (context, scrollController) {
|
||||||
return Column(
|
return Column(
|
||||||
children: [
|
children: [
|
||||||
const SizedBox(height: 6),
|
const SizedBox(height: 6),
|
||||||
// Drag handle
|
|
||||||
Container(
|
Container(
|
||||||
width: 36,
|
width: 36,
|
||||||
height: 4,
|
height: 4,
|
||||||
@ -36,18 +42,170 @@ class TeamMembersBottomSheet {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 10),
|
const SizedBox(height: 10),
|
||||||
|
// Title at top center
|
||||||
|
MyText.titleMedium(
|
||||||
|
'Bucket Details',
|
||||||
|
fontWeight: 700,
|
||||||
|
),
|
||||||
|
|
||||||
|
const SizedBox(height: 12),
|
||||||
|
|
||||||
|
// Header with title and optional edit button
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: MyText.titleMedium(
|
||||||
|
bucket.name,
|
||||||
|
fontWeight: 700,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (canEdit)
|
||||||
|
IconButton(
|
||||||
|
onPressed: onEdit,
|
||||||
|
icon: const Icon(Icons.edit, color: Colors.red),
|
||||||
|
tooltip: 'Edit Bucket',
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
// Bucket info
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
MyText.titleMedium('Team Members', fontWeight: 700),
|
if (bucket.description.isNotEmpty)
|
||||||
const SizedBox(height: 6),
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(bottom: 6),
|
||||||
|
child: MyText.bodySmall(
|
||||||
|
bucket.description,
|
||||||
|
color: Colors.grey[700],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
const Icon(Icons.contacts_outlined,
|
||||||
|
size: 14, color: Colors.grey),
|
||||||
|
const SizedBox(width: 4),
|
||||||
|
MyText.labelSmall(
|
||||||
|
'${bucket.numberOfContacts} contact(s)',
|
||||||
|
fontWeight: 600,
|
||||||
|
color: Colors.red,
|
||||||
|
),
|
||||||
|
const SizedBox(width: 12),
|
||||||
|
const Icon(Icons.ios_share_outlined,
|
||||||
|
size: 14, color: Colors.grey),
|
||||||
|
const SizedBox(width: 4),
|
||||||
|
MyText.labelSmall(
|
||||||
|
'Shared with (${members.length})',
|
||||||
|
fontWeight: 600,
|
||||||
|
color: Colors.indigo,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
|
||||||
|
// Can edit indicator
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(top: 8),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
const Icon(Icons.edit_outlined,
|
||||||
|
size: 14, color: Colors.grey),
|
||||||
|
const SizedBox(width: 4),
|
||||||
|
MyText.labelSmall(
|
||||||
|
canEdit
|
||||||
|
? 'Can be edited by you'
|
||||||
|
: 'You don’t have edit access',
|
||||||
|
fontWeight: 600,
|
||||||
|
color: canEdit ? Colors.green : Colors.grey,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
const SizedBox(height: 10),
|
||||||
|
|
||||||
|
// Created by
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
CircleAvatar(
|
||||||
|
radius: 14,
|
||||||
|
backgroundColor: Colors.grey.shade300,
|
||||||
|
backgroundImage:
|
||||||
|
bucket.createdBy.photo != null &&
|
||||||
|
bucket.createdBy.photo!.isNotEmpty
|
||||||
|
? NetworkImage(bucket.createdBy.photo!)
|
||||||
|
: null,
|
||||||
|
child: bucket.createdBy.photo == null
|
||||||
|
? Text(
|
||||||
|
bucket.createdBy.firstName.isNotEmpty
|
||||||
|
? bucket.createdBy.firstName[0]
|
||||||
|
: '?',
|
||||||
|
style: const TextStyle(
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
fontSize: 12,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: null,
|
||||||
|
),
|
||||||
|
const SizedBox(width: 8),
|
||||||
|
Expanded(
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: MyText.labelSmall(
|
||||||
|
'${bucket.createdBy.firstName} ${bucket.createdBy.lastName}',
|
||||||
|
fontWeight: 600,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 6),
|
||||||
|
Container(
|
||||||
|
padding: const EdgeInsets.symmetric(
|
||||||
|
horizontal: 6, vertical: 2),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.red.shade50,
|
||||||
|
borderRadius:
|
||||||
|
BorderRadius.circular(4),
|
||||||
|
),
|
||||||
|
child: MyText.labelSmall(
|
||||||
|
"Owner",
|
||||||
|
fontWeight: 600,
|
||||||
|
color: Colors.red,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
MyText.bodySmall(
|
||||||
|
bucket.createdBy.jobRoleName,
|
||||||
|
color: Colors.grey[600],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
|
||||||
|
const SizedBox(height: 12),
|
||||||
const Divider(thickness: 1),
|
const Divider(thickness: 1),
|
||||||
|
const SizedBox(height: 6),
|
||||||
|
MyText.labelLarge(
|
||||||
|
'Shared with',
|
||||||
|
fontWeight: 700,
|
||||||
|
color: Colors.black,
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
const SizedBox(height: 4),
|
const SizedBox(height: 4),
|
||||||
|
|
||||||
|
// Members list
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||||
@ -63,7 +221,7 @@ class TeamMembersBottomSheet {
|
|||||||
controller: scrollController,
|
controller: scrollController,
|
||||||
itemCount: members.length,
|
itemCount: members.length,
|
||||||
separatorBuilder: (_, __) =>
|
separatorBuilder: (_, __) =>
|
||||||
const SizedBox(height: 4), // tighter spacing
|
const SizedBox(height: 4),
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
final member = members[index];
|
final member = members[index];
|
||||||
final firstName = member.firstName ?? '';
|
final firstName = member.firstName ?? '';
|
||||||
@ -75,7 +233,7 @@ class TeamMembersBottomSheet {
|
|||||||
leading: Avatar(
|
leading: Avatar(
|
||||||
firstName: firstName,
|
firstName: firstName,
|
||||||
lastName: lastName,
|
lastName: lastName,
|
||||||
size: 32, // smaller avatar
|
size: 32,
|
||||||
),
|
),
|
||||||
title: MyText.bodyMedium(
|
title: MyText.bodyMedium(
|
||||||
'${firstName.isNotEmpty ? firstName : 'Unnamed'} ${lastName.isNotEmpty ? lastName : ''}',
|
'${firstName.isNotEmpty ? firstName : 'Unnamed'} ${lastName.isNotEmpty ? lastName : ''}',
|
||||||
|
|||||||
@ -15,7 +15,6 @@ import 'package:marco/model/directory/create_bucket_bottom_sheet.dart';
|
|||||||
import 'package:marco/view/directory/contact_detail_screen.dart';
|
import 'package:marco/view/directory/contact_detail_screen.dart';
|
||||||
import 'package:marco/view/directory/manage_bucket_screen.dart';
|
import 'package:marco/view/directory/manage_bucket_screen.dart';
|
||||||
import 'package:marco/controller/permission_controller.dart';
|
import 'package:marco/controller/permission_controller.dart';
|
||||||
import 'package:marco/helpers/utils/permission_constants.dart';
|
|
||||||
|
|
||||||
class DirectoryView extends StatefulWidget {
|
class DirectoryView extends StatefulWidget {
|
||||||
@override
|
@override
|
||||||
@ -268,45 +267,41 @@ class _DirectoryViewState extends State<DirectoryView> {
|
|||||||
itemBuilder: (context) {
|
itemBuilder: (context) {
|
||||||
List<PopupMenuEntry<int>> menuItems = [];
|
List<PopupMenuEntry<int>> menuItems = [];
|
||||||
|
|
||||||
// Section: Actions
|
// Section: Actions (Always visible now)
|
||||||
if (permissionController
|
menuItems.add(
|
||||||
.hasPermission(Permissions.directoryAdmin) ||
|
const PopupMenuItem<int>(
|
||||||
permissionController
|
enabled: false,
|
||||||
.hasPermission(Permissions.directoryManager)) {
|
height: 30,
|
||||||
menuItems.add(
|
child: Text(
|
||||||
const PopupMenuItem<int>(
|
"Actions",
|
||||||
enabled: false,
|
style: TextStyle(
|
||||||
height: 30,
|
fontWeight: FontWeight.bold,
|
||||||
child: Text(
|
color: Colors.grey,
|
||||||
"Actions",
|
|
||||||
style: TextStyle(
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
color: Colors.grey),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
),
|
||||||
|
);
|
||||||
|
|
||||||
menuItems.add(
|
menuItems.add(
|
||||||
PopupMenuItem<int>(
|
PopupMenuItem<int>(
|
||||||
value: 1,
|
value: 1,
|
||||||
child: Row(
|
child: Row(
|
||||||
children: const [
|
children: const [
|
||||||
Icon(Icons.label_outline,
|
Icon(Icons.label_outline,
|
||||||
size: 20, color: Colors.black87),
|
size: 20, color: Colors.black87),
|
||||||
SizedBox(width: 10),
|
SizedBox(width: 10),
|
||||||
Expanded(child: Text("Manage Buckets")),
|
Expanded(child: Text("Manage Buckets")),
|
||||||
Icon(Icons.chevron_right,
|
Icon(Icons.chevron_right,
|
||||||
size: 20, color: Colors.red),
|
size: 20, color: Colors.red),
|
||||||
],
|
],
|
||||||
),
|
|
||||||
onTap: () {
|
|
||||||
Future.delayed(Duration.zero, () {
|
|
||||||
_handleManageBuckets();
|
|
||||||
});
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
);
|
onTap: () {
|
||||||
}
|
Future.delayed(Duration.zero, () {
|
||||||
|
_handleManageBuckets();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
// Section: Preferences
|
// Section: Preferences
|
||||||
menuItems.add(
|
menuItems.add(
|
||||||
@ -316,8 +311,9 @@ class _DirectoryViewState extends State<DirectoryView> {
|
|||||||
child: Text(
|
child: Text(
|
||||||
"Preferences",
|
"Preferences",
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
color: Colors.grey),
|
color: Colors.grey,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@ -109,8 +109,8 @@ class _ManageBucketsScreenState extends State<ManageBucketsScreen> {
|
|||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
contentPadding:
|
contentPadding:
|
||||||
const EdgeInsets.symmetric(horizontal: 12, vertical: 0),
|
const EdgeInsets.symmetric(horizontal: 12, vertical: 0),
|
||||||
prefixIcon: const Icon(Icons.search,
|
prefixIcon:
|
||||||
size: 18, color: Colors.grey),
|
const Icon(Icons.search, size: 18, color: Colors.grey),
|
||||||
suffixIcon: searchText.isNotEmpty
|
suffixIcon: searchText.isNotEmpty
|
||||||
? IconButton(
|
? IconButton(
|
||||||
icon: const Icon(Icons.close, color: Colors.grey),
|
icon: const Icon(Icons.close, color: Colors.grey),
|
||||||
@ -134,12 +134,11 @@ class _ManageBucketsScreenState extends State<ManageBucketsScreen> {
|
|||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Obx(() {
|
child: Obx(() {
|
||||||
final buckets = directoryController.contactBuckets.where((bucket) {
|
final buckets =
|
||||||
|
directoryController.contactBuckets.where((bucket) {
|
||||||
return bucket.name.toLowerCase().contains(searchText) ||
|
return bucket.name.toLowerCase().contains(searchText) ||
|
||||||
bucket.description.toLowerCase().contains(searchText) ||
|
bucket.description.toLowerCase().contains(searchText) ||
|
||||||
bucket.numberOfContacts
|
bucket.numberOfContacts.toString().contains(searchText);
|
||||||
.toString()
|
|
||||||
.contains(searchText);
|
|
||||||
}).toList();
|
}).toList();
|
||||||
|
|
||||||
if (directoryController.isLoading.value ||
|
if (directoryController.isLoading.value ||
|
||||||
@ -152,7 +151,8 @@ class _ManageBucketsScreenState extends State<ManageBucketsScreen> {
|
|||||||
child: Column(
|
child: Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
const Icon(Icons.folder_off, size: 48, color: Colors.grey),
|
const Icon(Icons.folder_off,
|
||||||
|
size: 48, color: Colors.grey),
|
||||||
MySpacing.height(12),
|
MySpacing.height(12),
|
||||||
MyText.bodyMedium("No buckets available.",
|
MyText.bodyMedium("No buckets available.",
|
||||||
fontWeight: 600, color: Colors.grey[700]),
|
fontWeight: 600, color: Colors.grey[700]),
|
||||||
@ -176,147 +176,128 @@ class _ManageBucketsScreenState extends State<ManageBucketsScreen> {
|
|||||||
.hasPermission(Permissions.directoryManager);
|
.hasPermission(Permissions.directoryManager);
|
||||||
final isExpanded = _expandedMap[bucket.id] ?? false;
|
final isExpanded = _expandedMap[bucket.id] ?? false;
|
||||||
|
|
||||||
return Row(
|
final matchedEmployees = manageBucketController.allEmployees
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
.where((emp) => bucket.employeeIds.contains(emp.id))
|
||||||
children: [
|
.toList();
|
||||||
const Padding(
|
|
||||||
padding: EdgeInsets.only(top: 4),
|
return GestureDetector(
|
||||||
child: Icon(Icons.label_outline,
|
onTap: () {
|
||||||
size: 26, color: Colors.indigo),
|
TeamMembersBottomSheet.show(
|
||||||
),
|
context,
|
||||||
MySpacing.width(12),
|
bucket,
|
||||||
Expanded(
|
matchedEmployees,
|
||||||
child: Column(
|
canEdit: canEdit,
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
onEdit: () {
|
||||||
children: [
|
print('Edit bucket: ${bucket.name}');
|
||||||
Row(
|
},
|
||||||
children: [
|
);
|
||||||
Expanded(
|
},
|
||||||
child: MyText.titleSmall(
|
child: Row(
|
||||||
bucket.name,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
fontWeight: 700,
|
children: [
|
||||||
overflow: TextOverflow.ellipsis,
|
const Padding(
|
||||||
|
padding: EdgeInsets.only(top: 4),
|
||||||
|
child: Icon(Icons.label_outline,
|
||||||
|
size: 26, color: Colors.indigo),
|
||||||
|
),
|
||||||
|
MySpacing.width(12),
|
||||||
|
Expanded(
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
MyText.titleSmall(
|
||||||
|
bucket.name,
|
||||||
|
fontWeight: 700,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
),
|
||||||
|
MySpacing.height(4),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
const Icon(Icons.contacts_outlined,
|
||||||
|
size: 14, color: Colors.grey),
|
||||||
|
MySpacing.width(4),
|
||||||
|
MyText.labelSmall(
|
||||||
|
'${bucket.numberOfContacts} contact(s)',
|
||||||
|
color: Colors.red,
|
||||||
|
fontWeight: 600,
|
||||||
),
|
),
|
||||||
),
|
MySpacing.width(12),
|
||||||
if (canEdit)
|
Row(
|
||||||
IconButton(
|
|
||||||
icon: const Icon(Icons.edit_outlined,
|
|
||||||
size: 20, color: Colors.red),
|
|
||||||
tooltip: 'View Members',
|
|
||||||
padding: EdgeInsets.zero,
|
|
||||||
constraints: const BoxConstraints(),
|
|
||||||
onPressed: () {
|
|
||||||
final matchedEmployees =
|
|
||||||
manageBucketController.allEmployees
|
|
||||||
.where((emp) =>
|
|
||||||
bucket.employeeIds
|
|
||||||
.contains(emp.id))
|
|
||||||
.toList();
|
|
||||||
TeamMembersBottomSheet.show(
|
|
||||||
context, matchedEmployees);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
MySpacing.height(4),
|
|
||||||
Row(
|
|
||||||
children: [
|
|
||||||
const Icon(Icons.contacts_outlined,
|
|
||||||
size: 14, color: Colors.grey),
|
|
||||||
MySpacing.width(4),
|
|
||||||
MyText.labelSmall(
|
|
||||||
'${bucket.numberOfContacts} contact(s)',
|
|
||||||
color: Colors.red,
|
|
||||||
fontWeight: 600,
|
|
||||||
),
|
|
||||||
MySpacing.width(12),
|
|
||||||
GestureDetector(
|
|
||||||
onTap: () {
|
|
||||||
final matchedEmployees =
|
|
||||||
manageBucketController.allEmployees
|
|
||||||
.where((emp) =>
|
|
||||||
bucket.employeeIds
|
|
||||||
.contains(emp.id))
|
|
||||||
.toList();
|
|
||||||
TeamMembersBottomSheet.show(
|
|
||||||
context, matchedEmployees);
|
|
||||||
},
|
|
||||||
child: Row(
|
|
||||||
children: [
|
children: [
|
||||||
const Icon(Icons.ios_share_outlined,
|
const Icon(Icons.ios_share_outlined,
|
||||||
size: 14, color: Colors.grey),
|
size: 14, color: Colors.grey),
|
||||||
MySpacing.width(4),
|
MySpacing.width(4),
|
||||||
MyText.labelSmall(
|
MyText.labelSmall(
|
||||||
'Shared with',
|
'Shared with (${matchedEmployees.length})',
|
||||||
color: Colors.indigo,
|
color: Colors.indigo,
|
||||||
fontWeight: 600,
|
fontWeight: 600,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
],
|
||||||
],
|
),
|
||||||
),
|
if (bucket.description.isNotEmpty)
|
||||||
if (bucket.description.isNotEmpty)
|
Padding(
|
||||||
Padding(
|
padding: const EdgeInsets.only(top: 4),
|
||||||
padding: const EdgeInsets.only(top: 4),
|
child: LayoutBuilder(
|
||||||
child: LayoutBuilder(
|
builder: (context, constraints) {
|
||||||
builder: (context, constraints) {
|
final span = TextSpan(
|
||||||
final span = TextSpan(
|
text: bucket.description,
|
||||||
text: bucket.description,
|
style: Theme.of(context)
|
||||||
style: Theme.of(context)
|
.textTheme
|
||||||
.textTheme
|
.bodySmall
|
||||||
.bodySmall
|
?.copyWith(color: Colors.grey[700]),
|
||||||
?.copyWith(color: Colors.grey[700]),
|
);
|
||||||
);
|
final tp = TextPainter(
|
||||||
final tp = TextPainter(
|
text: span,
|
||||||
text: span,
|
maxLines: 2,
|
||||||
maxLines: 2,
|
textDirection: TextDirection.ltr,
|
||||||
textDirection: TextDirection.ltr,
|
)..layout(maxWidth: constraints.maxWidth);
|
||||||
)..layout(maxWidth: constraints.maxWidth);
|
|
||||||
|
|
||||||
final hasOverflow = tp.didExceedMaxLines;
|
final hasOverflow = tp.didExceedMaxLines;
|
||||||
|
|
||||||
return Column(
|
return Column(
|
||||||
crossAxisAlignment:
|
crossAxisAlignment:
|
||||||
CrossAxisAlignment.start,
|
CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
MyText.bodySmall(
|
MyText.bodySmall(
|
||||||
bucket.description,
|
bucket.description,
|
||||||
color: Colors.grey[700],
|
color: Colors.grey[700],
|
||||||
maxLines: isExpanded ? null : 2,
|
maxLines: isExpanded ? null : 2,
|
||||||
overflow: isExpanded
|
overflow: isExpanded
|
||||||
? TextOverflow.visible
|
? TextOverflow.visible
|
||||||
: TextOverflow.ellipsis,
|
: TextOverflow.ellipsis,
|
||||||
),
|
),
|
||||||
if (hasOverflow)
|
if (hasOverflow)
|
||||||
GestureDetector(
|
GestureDetector(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
setState(() {
|
setState(() {
|
||||||
_expandedMap[bucket.id] =
|
_expandedMap[bucket.id] =
|
||||||
!isExpanded;
|
!isExpanded;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.only(
|
padding: const EdgeInsets.only(
|
||||||
top: 4),
|
top: 4),
|
||||||
child: MyText.labelSmall(
|
child: MyText.labelSmall(
|
||||||
isExpanded
|
isExpanded
|
||||||
? "Show less"
|
? "Show less"
|
||||||
: "Show more",
|
: "Show more",
|
||||||
fontWeight: 600,
|
fontWeight: 600,
|
||||||
color: Colors.red,
|
color: Colors.red,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
],
|
||||||
],
|
);
|
||||||
);
|
},
|
||||||
},
|
),
|
||||||
),
|
),
|
||||||
),
|
],
|
||||||
],
|
),
|
||||||
),
|
),
|
||||||
),
|
],
|
||||||
],
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user