From e025484cabec14ce996aa58aab99d0aa70397c1f Mon Sep 17 00:00:00 2001 From: Jonasz Bigda Date: Mon, 12 Oct 2020 19:51:53 +0200 Subject: [PATCH] + Autocomplete (prototype) --- android/app/src/main/AndroidManifest.xml | 1 + lib/components.dart | 149 ++++++++++++++++++----- lib/dataTypes.dart | 1 + lib/main.dart | 29 +++-- pubspec.lock | 21 ++++ pubspec.yaml | 1 + 6 files changed, 160 insertions(+), 42 deletions(-) create mode 100644 lib/dataTypes.dart diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index b48a1f5..e34f895 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -5,6 +5,7 @@ In most cases you can leave this as-is, but you if you want to provide additional functionality it is fine to subclass or reimplement FlutterApplication and put your custom class here. --> + { final _formKey = GlobalKey(); + var suggestions = []; + bool suggestionsOpen = false; + final LayerLink layerLink = LayerLink(); + OverlayEntry _overlayEntry; + + Future fetchAutocomplete(text) async { + final response = await http.get( + 'https://menui.azurewebsites.net/search/autocomplete?string=$text'); + final cities = jsonDecode(response.body)['cities']; + final restaurants = jsonDecode(response.body)['restaurants']; + final List result = [...cities, ...restaurants]; + + setState(() { + suggestions = result; + }); + + if (!suggestionsOpen && result.isNotEmpty) { + setState(() { + suggestionsOpen = true; + }); + _overlayEntry = _createOverlayEntry(); + Overlay.of(context).insert(_overlayEntry); + } + print(suggestions); + } + + void hideSuggestions() { + if (suggestionsOpen) { + _overlayEntry.remove(); + setState(() { + suggestionsOpen = false; + }); + } + } + + OverlayEntry _createOverlayEntry() { + RenderBox renderBox = context.findRenderObject(); + var size = renderBox.size; + + return OverlayEntry( + builder: (context) => GestureDetector( + behavior: HitTestBehavior.translucent, + onTap: () { + hideSuggestions(); + }, + child: Align( + alignment: Alignment.topCenter, + child: Stack( + children: [ + Positioned( + width: size.width, + child: CompositedTransformFollower( + offset: Offset(0.0, size.height + 5.0), + link: layerLink, + showWhenUnlinked: false, + child: Material( + color: Colors.grey[800], + elevation: 4.0, + child: ConstrainedBox( + constraints: new BoxConstraints(maxHeight: 200), + child: ListView.builder( + padding: EdgeInsets.zero, + shrinkWrap: true, + itemCount: suggestions.length, + itemBuilder: (context, index) { + return ListTile( + title: Text( + suggestions[index], + style: TextStyle(color: Colors.orange), + ), + ); + }), + ), + ), + ), + ) + ], + )))); + } @override Widget build(BuildContext context) { return Form( - key: _formKey, - child: Column( - children: [ - Padding( - padding: const EdgeInsets.all(12), - child: TextFormField( - style: TextStyle(color: Colors.orange), - decoration: InputDecoration( - hintStyle: TextStyle(color: Colors.grey), - enabledBorder: OutlineInputBorder( - borderSide: BorderSide(color: Colors.grey, width: 1.0), - borderRadius: BorderRadius.circular(12)), - focusedBorder: OutlineInputBorder( - borderSide: BorderSide(color: Colors.orange, width: 2.0), - borderRadius: BorderRadius.circular(12)), - hintText: 'Wyszukaj miasto lub nazwę restauracji.', - suffixIcon: Icon( - Icons.search, - color: Colors.orange, - )), - validator: (value) { - if (value.isEmpty) { - return 'Wpisz coś w pole wyszukiwania.'; - } - return null; - }, - cursorColor: Colors.orange, - ), + key: _formKey, + child: CompositedTransformTarget( + link: layerLink, + child: Column( + children: [ + Padding( + padding: const EdgeInsets.all(12), + child: TextFormField( + onChanged: (text) => fetchAutocomplete(text), + style: TextStyle(color: Colors.orange), + decoration: InputDecoration( + hintStyle: TextStyle(color: Colors.grey), + enabledBorder: OutlineInputBorder( + borderSide: + BorderSide(color: Colors.grey, width: 1.0), + borderRadius: BorderRadius.circular(12)), + focusedBorder: OutlineInputBorder( + borderSide: + BorderSide(color: Colors.orange, width: 2.0), + borderRadius: BorderRadius.circular(12)), + hintText: 'Wyszukaj miasto lub nazwę restauracji.', + suffixIcon: Icon( + Icons.search, + color: Colors.orange, + )), + validator: (value) { + if (value.isEmpty) { + return 'Wpisz coś w pole wyszukiwania.'; + } + return null; + }, + cursorColor: Colors.orange, + ), + ), + ], ), - ], - ), - ); + )); } } diff --git a/lib/dataTypes.dart b/lib/dataTypes.dart new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/lib/dataTypes.dart @@ -0,0 +1 @@ + diff --git a/lib/main.dart b/lib/main.dart index fd3224a..e7d6785 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -8,17 +8,24 @@ void main() { class App extends StatelessWidget { @override Widget build(BuildContext context) { - return MaterialApp( - title: 'Menui', - theme: ThemeData( - primarySwatch: Colors.orange, - primaryColor: Colors.orange, - accentColor: Colors.grey, - backgroundColor: Colors.grey, - visualDensity: VisualDensity.adaptivePlatformDensity, - ), - home: HomePage(title: 'Menui - food guide'), - ); + return GestureDetector( + onTap: () { + FocusScopeNode currentFocus = FocusScope.of(context); + if (!currentFocus.hasPrimaryFocus) { + currentFocus.focusedChild.unfocus(); + } + }, + child: MaterialApp( + title: 'Menui', + theme: ThemeData( + primarySwatch: Colors.orange, + primaryColor: Colors.orange, + accentColor: Colors.grey, + backgroundColor: Colors.grey, + visualDensity: VisualDensity.adaptivePlatformDensity, + ), + home: HomePage(title: 'Menui - food guide'), + )); } } diff --git a/pubspec.lock b/pubspec.lock index f628010..d3c2dc7 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -67,6 +67,20 @@ packages: description: flutter source: sdk version: "0.0.0" + http: + dependency: "direct main" + description: + name: http + url: "https://pub.dartlang.org" + source: hosted + version: "0.12.2" + http_parser: + dependency: transitive + description: + name: http_parser + url: "https://pub.dartlang.org" + source: hosted + version: "3.1.4" matcher: dependency: transitive description: @@ -88,6 +102,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.8.0-nullsafety.1" + pedantic: + dependency: transitive + description: + name: pedantic + url: "https://pub.dartlang.org" + source: hosted + version: "1.9.2" sky_engine: dependency: transitive description: flutter diff --git a/pubspec.yaml b/pubspec.yaml index 24c4184..3305688 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -21,6 +21,7 @@ environment: sdk: ">=2.7.0 <3.0.0" dependencies: + http: ^0.12.2 flutter: sdk: flutter