Pulled latest changes

This commit is contained in:
Abdullah Alassaf
2025-02-20 12:55:07 +03:00
3 changed files with 73 additions and 57 deletions

View File

@ -20,15 +20,22 @@ class DialogTextfieldDropdown extends StatefulWidget {
class _DialogTextfieldDropdownState extends State<DialogTextfieldDropdown> {
bool _isOpen = false;
late OverlayEntry _overlayEntry;
OverlayEntry? _overlayEntry;
final TextEditingController _controller = TextEditingController();
late List<String> _filteredItems; // Filtered items list
final FocusNode _focusNode = FocusNode();
List<String> _filteredItems = [];
@override
void initState() {
super.initState();
_controller.text = widget.initialValue ?? 'Select Tag';
_filteredItems = List.from(widget.items); // Initialize filtered items
_controller.text = widget.initialValue ?? '';
_filteredItems = List.from(widget.items);
_focusNode.addListener(() {
if (!_focusNode.hasFocus) {
_closeDropdown();
}
});
}
void _toggleDropdown() {
@ -41,14 +48,17 @@ class _DialogTextfieldDropdownState extends State<DialogTextfieldDropdown> {
void _openDropdown() {
_overlayEntry = _createOverlayEntry();
Overlay.of(context).insert(_overlayEntry);
Overlay.of(context).insert(_overlayEntry!);
_isOpen = true;
}
void _closeDropdown() {
_overlayEntry.remove();
if (_isOpen && _overlayEntry != null) {
_overlayEntry!.remove();
_overlayEntry = null;
_isOpen = false;
}
}
OverlayEntry _createOverlayEntry() {
final renderBox = context.findRenderObject() as RenderBox;
@ -58,9 +68,7 @@ class _DialogTextfieldDropdownState extends State<DialogTextfieldDropdown> {
return OverlayEntry(
builder: (context) {
return GestureDetector(
onTap: () {
_closeDropdown();
},
onTap: _closeDropdown,
behavior: HitTestBehavior.translucent,
child: Stack(
children: [
@ -72,14 +80,15 @@ class _DialogTextfieldDropdownState extends State<DialogTextfieldDropdown> {
elevation: 4.0,
child: Container(
color: ColorsManager.whiteColors,
constraints: const BoxConstraints(
maxHeight: 200.0,
),
child: ListView.builder(
constraints: const BoxConstraints(maxHeight: 200.0),
child: StatefulBuilder(
builder: (context, setStateDropdown) {
return ListView.builder(
shrinkWrap: true,
itemCount: _filteredItems.length,
itemBuilder: (context, index) {
final item = _filteredItems[index];
return Container(
decoration: const BoxDecoration(
border: Border(
@ -95,7 +104,8 @@ class _DialogTextfieldDropdownState extends State<DialogTextfieldDropdown> {
.textTheme
.bodyMedium
?.copyWith(
color: ColorsManager.textPrimaryColor)),
color: ColorsManager
.textPrimaryColor)),
onTap: () {
_controller.text = item;
widget.onSelected(item);
@ -108,6 +118,8 @@ class _DialogTextfieldDropdownState extends State<DialogTextfieldDropdown> {
),
);
},
);
},
),
),
),
@ -122,7 +134,8 @@ class _DialogTextfieldDropdownState extends State<DialogTextfieldDropdown> {
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: _toggleDropdown,
onTap: () => FocusScope.of(context).unfocus(),
behavior: HitTestBehavior.opaque,
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 12.0, vertical: 8.0),
decoration: BoxDecoration(
@ -135,23 +148,26 @@ class _DialogTextfieldDropdownState extends State<DialogTextfieldDropdown> {
Expanded(
child: TextFormField(
controller: _controller,
onChanged: (value) {
setState(() {
_filteredItems = widget.items
.where((item) =>
item.toLowerCase().contains(value.toLowerCase()))
.toList(); // Filter items dynamically
});
focusNode: _focusNode,
onFieldSubmitted: (value) {
widget.onSelected(value);
_closeDropdown();
},
onTapOutside: (event) {
widget.onSelected(_controller.text);
_closeDropdown();
},
style: Theme.of(context).textTheme.bodyMedium,
decoration: const InputDecoration(
hintText: 'Enter or Select tag',
hintText: 'Enter or Select a tag',
border: InputBorder.none,
),
),
),
const Icon(Icons.arrow_drop_down),
GestureDetector(
onTap: _toggleDropdown,
child: const Icon(Icons.arrow_drop_down),
),
],
),
),

View File

@ -14,7 +14,7 @@ class UserPermissionApi {
Future<List<RolesUserModel>> fetchUsers(String projectId) async {
try {
final response = await _httpService.get(
path: ApiEndpoints.getUsers.replaceAll('{projectUuid}', projectId),
path: ApiEndpoints.getUsers.replaceAll('{projectId}', projectId),
showServerMessage: true,
expectedResponseModel: (json) {
debugPrint('fetchUsers Response: $json');

View File

@ -25,7 +25,7 @@ abstract class ApiEndpoints {
////// Devices Management ////////////////
static const String getAllDevices = '/projects/{projectId}/device';
static const String getAllDevices = '/projects/{projectId}/devices';
static const String getSpaceDevices =
'/projects/{projectId}/communities/{communityUuid}/spaces/{spaceUuid}/devices';
static const String getDeviceStatus = '/device/{uuid}/functions/status';
@ -95,8 +95,8 @@ abstract class ApiEndpoints {
static const String inviteUser = '/invite-user';
static const String checkEmail = '/invite-user/check-email';
static const String getUsers = '/projects/{projectUuid}/user';
static const String getUserById = '/projects/{projectUuid}/user/{userUuid}';
static const String getUsers = '/projects/{projectId}/user';
static const String getUserById = '/projects/{projectId}/user/{userUuid}';
static const String editUser = '/invite-user/{inviteUserUuid}';
static const String deleteUser = '/invite-user/{inviteUserUuid}';
static const String changeUserStatus = '/invite-user/{invitedUserUuid}/disable';