mirror of
https://gitlab.com/comunic/comunicmobile
synced 2024-11-25 22:39:22 +00:00
Created inline user picker
This commit is contained in:
parent
09d43ab5c0
commit
765ca82300
31
lib/helpers/search_helper.dart
Normal file
31
lib/helpers/search_helper.dart
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
import 'package:comunic/helpers/users_helper.dart';
|
||||||
|
import 'package:comunic/lists/users_list.dart';
|
||||||
|
import 'package:comunic/models/api_request.dart';
|
||||||
|
import 'package:comunic/utils/list_utils.dart';
|
||||||
|
|
||||||
|
/// Search helper
|
||||||
|
///
|
||||||
|
/// @author Pierre HUBERT
|
||||||
|
|
||||||
|
class SearchHelper {
|
||||||
|
|
||||||
|
/// Search for user. This method returns information about the target users
|
||||||
|
///
|
||||||
|
/// Returns information about the target users or null if an error occurred
|
||||||
|
Future<UsersList> searchUser(String query) async {
|
||||||
|
// Execute the query on the server
|
||||||
|
final response = await APIRequest(
|
||||||
|
uri: "user/search",
|
||||||
|
needLogin: true,
|
||||||
|
args: {
|
||||||
|
"query": query
|
||||||
|
}
|
||||||
|
).exec();
|
||||||
|
|
||||||
|
if (response.code != 200) return null;
|
||||||
|
|
||||||
|
return await UsersHelper().getUsersInfo(
|
||||||
|
listToIntList(response.getArray()));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
31
lib/ui/tiles/simple_user_tile.dart
Normal file
31
lib/ui/tiles/simple_user_tile.dart
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
import 'package:comunic/models/user.dart';
|
||||||
|
import 'package:comunic/ui/widgets/account_image_widget.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
/// Simple user tile
|
||||||
|
///
|
||||||
|
/// Basically this only shows the name of the user + its account image
|
||||||
|
///
|
||||||
|
/// @author Pierre HUBERT
|
||||||
|
|
||||||
|
typedef OnUserTap = void Function(User);
|
||||||
|
|
||||||
|
class SimpleUserTile extends StatelessWidget {
|
||||||
|
final User user;
|
||||||
|
final OnUserTap onTap;
|
||||||
|
|
||||||
|
const SimpleUserTile({Key key, this.user, this.onTap})
|
||||||
|
: assert(user != null),
|
||||||
|
super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return ListTile(
|
||||||
|
onTap: onTap == null ? null : () => onTap(user),
|
||||||
|
leading: AccountImageWidget(
|
||||||
|
user: user,
|
||||||
|
),
|
||||||
|
title: Text(user.fullName),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
117
lib/ui/widgets/pick_user_widget.dart
Normal file
117
lib/ui/widgets/pick_user_widget.dart
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
import 'package:comunic/helpers/search_helper.dart';
|
||||||
|
import 'package:comunic/lists/users_list.dart';
|
||||||
|
import 'package:comunic/models/user.dart';
|
||||||
|
import 'package:comunic/ui/tiles/simple_user_tile.dart';
|
||||||
|
import 'package:comunic/utils/intl_utils.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
/// Pick user widget
|
||||||
|
///
|
||||||
|
/// Allows to choose a user by starting to type his name and tapping on it
|
||||||
|
/// when his name appear
|
||||||
|
///
|
||||||
|
/// @author Pierre HUBERT
|
||||||
|
|
||||||
|
typedef OnSelectUserCallback = void Function(User);
|
||||||
|
|
||||||
|
class PickUserWidget extends StatefulWidget {
|
||||||
|
final OnSelectUserCallback onSelectUser;
|
||||||
|
|
||||||
|
const PickUserWidget({Key key, @required this.onSelectUser})
|
||||||
|
: assert(onSelectUser != null),
|
||||||
|
super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<StatefulWidget> createState() => _PickUserWidgetState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _PickUserWidgetState extends State<PickUserWidget> {
|
||||||
|
// Helper
|
||||||
|
final SearchHelper _searchHelper = SearchHelper();
|
||||||
|
|
||||||
|
// Widget properties
|
||||||
|
final FocusNode _focusNode = FocusNode();
|
||||||
|
final TextEditingController _controller = TextEditingController();
|
||||||
|
OverlayEntry _overlayEntry;
|
||||||
|
UsersList _suggestions;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
|
||||||
|
_focusNode.addListener(() {
|
||||||
|
if (_focusNode.hasFocus) {
|
||||||
|
//Check for focus
|
||||||
|
_overlayEntry = _createOverlayEntry();
|
||||||
|
Overlay.of(context).insert(_overlayEntry);
|
||||||
|
} else {
|
||||||
|
//Remove overlay
|
||||||
|
_removeOverlay();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return TextField(
|
||||||
|
focusNode: _focusNode,
|
||||||
|
onChanged: (s) => _updateSuggestions(),
|
||||||
|
controller: _controller,
|
||||||
|
decoration: InputDecoration(labelText: tr("Select user")),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
OverlayEntry _createOverlayEntry() {
|
||||||
|
RenderBox renderBox = context.findRenderObject();
|
||||||
|
final size = renderBox.size;
|
||||||
|
final offset = renderBox.localToGlobal(Offset.zero);
|
||||||
|
|
||||||
|
return OverlayEntry(builder: (c) {
|
||||||
|
return Positioned(
|
||||||
|
left: offset.dx,
|
||||||
|
top: offset.dy + size.height + 5.0,
|
||||||
|
width: size.width,
|
||||||
|
child: Material(
|
||||||
|
elevation: 4.0,
|
||||||
|
child: ListView.builder(
|
||||||
|
padding: EdgeInsets.zero,
|
||||||
|
shrinkWrap: true,
|
||||||
|
itemCount: _suggestions == null ? 0 : _suggestions.length,
|
||||||
|
itemBuilder: (c, i) => SimpleUserTile(
|
||||||
|
user: _suggestions[i],
|
||||||
|
onTap: _userTapped,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void _removeOverlay() {
|
||||||
|
if (_overlayEntry != null) {
|
||||||
|
_overlayEntry.remove();
|
||||||
|
_overlayEntry = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This method get called each time the input value is updated
|
||||||
|
Future<void> _updateSuggestions() async {
|
||||||
|
if (_controller.value.text.length == 0) return;
|
||||||
|
|
||||||
|
final results = await _searchHelper.searchUser(_controller.value.text);
|
||||||
|
|
||||||
|
if (results == null) return;
|
||||||
|
|
||||||
|
_suggestions = results;
|
||||||
|
if (_overlayEntry != null) _overlayEntry.markNeedsBuild();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Method called each time a user is tapped (selected)
|
||||||
|
void _userTapped(User user) {
|
||||||
|
_controller.text = user.fullName;
|
||||||
|
_removeOverlay();
|
||||||
|
_focusNode.unfocus();
|
||||||
|
|
||||||
|
widget.onSelectUser(user);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user