1
0
mirror of https://gitlab.com/comunic/comunicmobile synced 2024-12-26 04:48:51 +00:00

Created inline user picker

This commit is contained in:
Pierre HUBERT 2019-04-27 14:40:27 +02:00
parent 09d43ab5c0
commit 765ca82300
3 changed files with 179 additions and 0 deletions

View 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()));
}
}

View 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),
);
}
}

View 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);
}
}