Skip to content

Commit

Permalink
issues #11
Browse files Browse the repository at this point in the history
  • Loading branch information
Leonavichus committed Apr 1, 2023
1 parent 07e4d22 commit e2b69d5
Show file tree
Hide file tree
Showing 6 changed files with 193 additions and 174 deletions.
16 changes: 12 additions & 4 deletions lib/app/api/api.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import 'package:dio/dio.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:rain/app/api/card_api.dart';
import 'package:rain/app/api/city.dart';
import 'package:rain/app/api/daily.dart';
import 'package:rain/app/api/hourly.dart';
import 'package:rain/app/data/weather.dart';
Expand Down Expand Up @@ -77,16 +78,23 @@ class WeatherAPI {
}
}

Future<List<dynamic>> getSuggestions(
Future<Iterable<Result>> getSuggestions(
String query, Locale? locale, String apiKey) async {
final url =
'https://api.geoapify.com/v1/geocode/search?city=$query&apiKey=$apiKey&lang=${locale?.languageCode}&format=json';
try {
Response response = await dioLocation.get(url);
if (response.statusCode == 200) {
final data = response.data;
final results = data['results'];
return results;
CityApi cityData = CityApi.fromJson(response.data);
return cityData.results.map(
(e) => Result(
country: e.country,
state: e.state,
city: e.city,
lon: e.lon,
lat: e.lat,
),
);
} else {
throw Exception('Failed to load suggestions');
}
Expand Down
36 changes: 36 additions & 0 deletions lib/app/api/city.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
class CityApi {
CityApi({
required this.results,
});

List<Result> results;

factory CityApi.fromJson(Map<String, dynamic> json) => CityApi(
results:
List<Result>.from(json["results"].map((x) => Result.fromJson(x))),
);
}

class Result {
Result({
this.country,
this.state,
this.city,
required this.lon,
required this.lat,
});

String? country;
String? state;
String? city;
double lon;
double lat;

factory Result.fromJson(Map<String, dynamic> json) => Result(
country: json["country"],
state: json["state"],
city: json["city"],
lon: json["lon"],
lat: json["lat"],
);
}
122 changes: 70 additions & 52 deletions lib/app/modules/home.dart
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import 'package:flutter_typeahead/flutter_typeahead.dart';
import 'package:custom_navigation_bar/custom_navigation_bar.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:get/get.dart';
import 'package:iconsax/iconsax.dart';
import 'package:rain/api_key.dart';
import 'package:rain/app/api/api.dart';
import 'package:rain/app/api/city.dart';
import 'package:rain/app/controller/controller.dart';
import 'package:rain/app/modules/card_weather.dart';
import 'package:rain/app/modules/settings.dart';
Expand All @@ -25,6 +25,7 @@ class _HomePageState extends State<HomePage> {
final locale = Get.locale;
final locationController = Get.put(LocationController());
final TextEditingController _controller = TextEditingController();
final FocusNode _focusNode = FocusNode();

@override
void initState() {
Expand Down Expand Up @@ -66,68 +67,83 @@ class _HomePageState extends State<HomePage> {
scale: 20,
),
title: visible
? TypeAheadField(
suggestionsBoxDecoration: SuggestionsBoxDecoration(
color: context.theme.scaffoldBackgroundColor,
borderRadius: BorderRadius.circular(20),
),
textFieldConfiguration: TextFieldConfiguration(
controller: _controller,
decoration: InputDecoration(
hintText: 'search'.tr,
border: InputBorder.none,
),
),
errorBuilder: (context, error) {
return Container(
margin:
const EdgeInsets.symmetric(horizontal: 10, vertical: 5),
height: 45,
child: Center(
child: Text(
'enter_name'.tr,
style: context.theme.textTheme.bodyLarge,
),
? RawAutocomplete<Result>(
focusNode: _focusNode,
textEditingController: _controller,
fieldViewBuilder: (BuildContext context,
TextEditingController fieldTextEditingController,
FocusNode fieldFocusNode,
VoidCallback onFieldSubmitted) {
return TextField(
controller: _controller,
focusNode: _focusNode,
decoration: InputDecoration(
hintText: 'search'.tr,
border: InputBorder.none,
),
);
},
noItemsFoundBuilder: (context) {
return Container(
margin:
const EdgeInsets.symmetric(horizontal: 10, vertical: 5),
height: 45,
child: Center(
child: Text(
'notFound'.tr,
style: context.theme.textTheme.bodyLarge,
),
),
);
optionsBuilder: (TextEditingValue textEditingValue) {
if (textEditingValue.text.isEmpty) {
return const Iterable<Result>.empty();
}
return WeatherAPI()
.getSuggestions(textEditingValue.text, locale, apiKey);
},
suggestionsCallback: (query) =>
WeatherAPI().getSuggestions(query, locale, apiKey),
itemBuilder: (context, suggestion) => ListTile(
title: Text(
suggestion['state'] == null
? '${suggestion['city']}, ${suggestion['country']}'
: suggestion['city'] == null
? '${suggestion['state']}, ${suggestion['country']}'
: '${suggestion['city']}, ${suggestion['state']}',
style: context.theme.textTheme.bodyLarge,
),
),
onSuggestionSelected: (suggestion) async {
onSelected: (Result selection) async {
await locationController.deleteAll(true);
await locationController.getLocation(
double.parse('${suggestion['lat'].toStringAsFixed(4)}'),
double.parse('${suggestion['lon'].toStringAsFixed(4)}'),
suggestion['state'] ?? suggestion['country'],
suggestion['city'] ?? suggestion['state'],
double.parse(selection.lat.toStringAsFixed(4)),
double.parse(selection.lon.toStringAsFixed(4)),
selection.state ?? selection.country!,
selection.city ?? selection.state!,
);
visible = false;
_controller.clear();
_focusNode.unfocus();
setState(() {});
},
displayStringForOption: (Result option) => option.state == null
? '${option.city}, ${option.country}'
: option.city == null
? '${option.state}, ${option.country}'
: '${option.city}, ${option.state}',
optionsViewBuilder: (BuildContext context,
AutocompleteOnSelected<Result> onSelected,
Iterable<Result> options) {
return Align(
alignment: Alignment.topLeft,
child: Material(
color: context.theme.scaffoldBackgroundColor,
borderRadius: BorderRadius.circular(20),
elevation: 4.0,
child: SizedBox(
width: 250,
child: ListView.builder(
padding: EdgeInsets.zero,
shrinkWrap: true,
itemCount: options.length,
itemBuilder: (BuildContext context, int index) {
final Result option = options.elementAt(index);
return InkWell(
onTap: () => onSelected(option),
child: ListTile(
title: Text(
option.state == null
? '${option.city}, ${option.country}'
: option.city == null
? '${option.state}, ${option.country}'
: '${option.city}, ${option.state}',
style: context.theme.textTheme.bodyLarge,
),
),
);
},
),
),
),
);
},
)
: Obx(() => Text(
locationController.isLoading.isFalse
Expand All @@ -154,6 +170,8 @@ class _HomePageState extends State<HomePage> {
IconButton(
onPressed: () {
if (visible) {
_controller.clear();
_focusNode.unfocus();
visible = false;
} else {
visible = true;
Expand Down
Loading

0 comments on commit e2b69d5

Please sign in to comment.