2023-06-17 20:57:57 +03:00
|
|
|
import 'package:flutter/material.dart';
|
|
|
|
import 'package:get/get.dart';
|
2024-08-12 21:03:35 +03:00
|
|
|
import 'package:iconsax_plus/iconsax_plus.dart';
|
2023-09-19 15:26:59 +03:00
|
|
|
import 'package:isar/isar.dart';
|
2023-06-17 20:57:57 +03:00
|
|
|
import 'package:rain/app/api/api.dart';
|
2024-08-02 22:52:33 +03:00
|
|
|
import 'package:rain/app/api/city_api.dart';
|
2023-06-17 20:57:57 +03:00
|
|
|
import 'package:rain/app/controller/controller.dart';
|
2024-09-06 22:07:50 +03:00
|
|
|
import 'package:rain/app/data/db.dart';
|
|
|
|
import 'package:rain/app/ui/places/view/place_list.dart';
|
|
|
|
import 'package:rain/app/ui/places/widgets/create_place.dart';
|
|
|
|
import 'package:rain/app/ui/geolocation.dart';
|
|
|
|
import 'package:rain/app/ui/main/view/main.dart';
|
|
|
|
import 'package:rain/app/ui/map/view/map.dart';
|
|
|
|
import 'package:rain/app/ui/settings/view/settings.dart';
|
|
|
|
import 'package:rain/app/utils/show_snack_bar.dart';
|
2023-06-17 20:57:57 +03:00
|
|
|
import 'package:rain/main.dart';
|
|
|
|
|
|
|
|
class HomePage extends StatefulWidget {
|
|
|
|
const HomePage({super.key});
|
|
|
|
|
|
|
|
@override
|
|
|
|
State<HomePage> createState() => _HomePageState();
|
|
|
|
}
|
|
|
|
|
2023-06-28 23:10:43 +03:00
|
|
|
class _HomePageState extends State<HomePage> with TickerProviderStateMixin {
|
2023-06-17 20:57:57 +03:00
|
|
|
int tabIndex = 0;
|
2023-09-03 09:08:43 +03:00
|
|
|
bool visible = false;
|
|
|
|
final _focusNode = FocusNode();
|
2023-06-28 23:10:43 +03:00
|
|
|
late TabController tabController;
|
2023-09-01 20:18:40 +03:00
|
|
|
final weatherController = Get.put(WeatherController());
|
2023-08-04 21:19:30 +03:00
|
|
|
final _controller = TextEditingController();
|
2023-06-28 23:10:43 +03:00
|
|
|
|
2024-08-30 22:31:42 +03:00
|
|
|
final List<Widget> pages = [
|
2024-09-06 22:07:50 +03:00
|
|
|
const MainPage(),
|
|
|
|
const PlaceList(),
|
|
|
|
if (!settings.hideMap) const MapPage(),
|
2023-06-28 23:10:43 +03:00
|
|
|
const SettingsPage(),
|
|
|
|
];
|
2023-06-17 20:57:57 +03:00
|
|
|
|
|
|
|
@override
|
|
|
|
void initState() {
|
2024-08-30 22:31:42 +03:00
|
|
|
super.initState();
|
2023-06-17 20:57:57 +03:00
|
|
|
getData();
|
2024-08-30 22:31:42 +03:00
|
|
|
setupTabController();
|
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
void dispose() {
|
|
|
|
tabController.dispose();
|
|
|
|
super.dispose();
|
|
|
|
}
|
|
|
|
|
|
|
|
void setupTabController() {
|
2023-06-28 23:10:43 +03:00
|
|
|
tabController = TabController(
|
|
|
|
initialIndex: tabIndex,
|
|
|
|
length: pages.length,
|
|
|
|
vsync: this,
|
|
|
|
);
|
2024-08-30 22:31:42 +03:00
|
|
|
|
2024-02-10 14:56:28 +03:00
|
|
|
tabController.animation?.addListener(() {
|
2024-02-10 15:02:22 +03:00
|
|
|
int value = (tabController.animation!.value).round();
|
|
|
|
if (value != tabIndex) setState(() => tabIndex = value);
|
2024-02-10 14:56:28 +03:00
|
|
|
});
|
2024-08-30 22:31:42 +03:00
|
|
|
|
2023-06-28 23:10:43 +03:00
|
|
|
tabController.addListener(() {
|
|
|
|
setState(() {
|
|
|
|
tabIndex = tabController.index;
|
|
|
|
});
|
|
|
|
});
|
2023-06-17 20:57:57 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void getData() async {
|
2023-09-01 20:18:40 +03:00
|
|
|
await weatherController.deleteCache();
|
|
|
|
await weatherController.updateCacheCard(false);
|
|
|
|
await weatherController.setLocation();
|
2023-06-17 20:57:57 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void changeTabIndex(int index) {
|
|
|
|
setState(() {
|
|
|
|
tabIndex = index;
|
|
|
|
});
|
2023-07-12 20:52:25 +03:00
|
|
|
tabController.animateTo(tabIndex);
|
2023-06-17 20:57:57 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
Widget build(BuildContext context) {
|
2023-10-28 15:23:39 +05:30
|
|
|
final textTheme = context.textTheme;
|
|
|
|
final labelLarge = textTheme.labelLarge;
|
|
|
|
|
2024-08-12 21:03:35 +03:00
|
|
|
final textStyle = textTheme.titleMedium?.copyWith(
|
|
|
|
fontWeight: FontWeight.w600,
|
|
|
|
fontSize: 18,
|
|
|
|
);
|
|
|
|
|
2023-06-28 23:10:43 +03:00
|
|
|
return DefaultTabController(
|
|
|
|
length: pages.length,
|
2023-09-05 21:31:29 +03:00
|
|
|
child: ScaffoldMessenger(
|
|
|
|
key: globalKey,
|
|
|
|
child: Scaffold(
|
2024-08-18 18:35:30 +03:00
|
|
|
appBar: AppBar(
|
|
|
|
centerTitle: true,
|
|
|
|
automaticallyImplyLeading: false,
|
|
|
|
leading: switch (tabIndex) {
|
|
|
|
0 => IconButton(
|
|
|
|
onPressed: () {
|
|
|
|
Get.to(() => const SelectGeolocation(isStart: false),
|
|
|
|
transition: Transition.downToUp);
|
2024-02-12 19:04:42 +03:00
|
|
|
},
|
2024-08-18 18:35:30 +03:00
|
|
|
icon: const Icon(
|
|
|
|
IconsaxPlusLinear.global_search,
|
|
|
|
size: 18,
|
|
|
|
),
|
|
|
|
),
|
|
|
|
int() => null,
|
|
|
|
},
|
|
|
|
title: switch (tabIndex) {
|
|
|
|
0 => visible
|
|
|
|
? RawAutocomplete<Result>(
|
|
|
|
focusNode: _focusNode,
|
|
|
|
textEditingController: _controller,
|
|
|
|
fieldViewBuilder: (_, __, ___, ____) {
|
|
|
|
return TextField(
|
|
|
|
controller: _controller,
|
|
|
|
focusNode: _focusNode,
|
|
|
|
style: labelLarge?.copyWith(fontSize: 16),
|
|
|
|
decoration: InputDecoration(
|
|
|
|
hintText: 'search'.tr,
|
2023-06-28 23:10:43 +03:00
|
|
|
),
|
2024-08-18 18:35:30 +03:00
|
|
|
);
|
|
|
|
},
|
|
|
|
optionsBuilder: (TextEditingValue textEditingValue) {
|
|
|
|
if (textEditingValue.text.isEmpty) {
|
|
|
|
return const Iterable<Result>.empty();
|
|
|
|
}
|
|
|
|
return WeatherAPI()
|
|
|
|
.getCity(textEditingValue.text, locale);
|
|
|
|
},
|
|
|
|
onSelected: (Result selection) async {
|
|
|
|
await weatherController.deleteAll(true);
|
|
|
|
await weatherController.getLocation(
|
|
|
|
double.parse('${selection.latitude}'),
|
|
|
|
double.parse('${selection.longitude}'),
|
|
|
|
selection.admin1,
|
|
|
|
selection.name,
|
|
|
|
);
|
|
|
|
visible = false;
|
|
|
|
_controller.clear();
|
|
|
|
_focusNode.unfocus();
|
|
|
|
setState(() {});
|
|
|
|
},
|
|
|
|
displayStringForOption: (Result option) =>
|
|
|
|
'${option.name}, ${option.admin1}',
|
|
|
|
optionsViewBuilder: (BuildContext context,
|
|
|
|
AutocompleteOnSelected<Result> onSelected,
|
|
|
|
Iterable<Result> options) {
|
|
|
|
return Align(
|
|
|
|
alignment: Alignment.topLeft,
|
|
|
|
child: Material(
|
|
|
|
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.name}, ${option.admin1}',
|
|
|
|
style: labelLarge,
|
|
|
|
),
|
|
|
|
),
|
|
|
|
);
|
|
|
|
},
|
|
|
|
),
|
|
|
|
),
|
2024-08-18 14:08:54 +03:00
|
|
|
),
|
2024-08-18 18:35:30 +03:00
|
|
|
);
|
|
|
|
},
|
|
|
|
)
|
|
|
|
: Obx(
|
|
|
|
() {
|
|
|
|
final location = weatherController.location;
|
|
|
|
final city = location.city;
|
|
|
|
final district = location.district;
|
|
|
|
return Text(
|
|
|
|
weatherController.isLoading.isFalse
|
|
|
|
? district!.isEmpty
|
|
|
|
? '$city'
|
|
|
|
: city!.isEmpty
|
|
|
|
? district
|
|
|
|
: city == district
|
|
|
|
? city
|
|
|
|
: '$city' ', $district'
|
|
|
|
: settings.location
|
|
|
|
? 'search'.tr
|
|
|
|
: (isar.locationCaches.where().findAllSync())
|
|
|
|
.isNotEmpty
|
|
|
|
? 'loading'.tr
|
|
|
|
: 'searchCity'.tr,
|
|
|
|
style: textStyle,
|
|
|
|
);
|
|
|
|
},
|
|
|
|
),
|
|
|
|
1 => Text(
|
|
|
|
'cities'.tr,
|
|
|
|
style: textStyle,
|
|
|
|
),
|
2024-08-30 22:31:42 +03:00
|
|
|
2 => settings.hideMap
|
|
|
|
? Text(
|
|
|
|
'settings_full'.tr,
|
|
|
|
style: textStyle,
|
|
|
|
)
|
|
|
|
: Text(
|
|
|
|
'map'.tr,
|
|
|
|
style: textStyle,
|
|
|
|
),
|
2024-08-18 18:35:30 +03:00
|
|
|
3 => Text(
|
|
|
|
'settings_full'.tr,
|
|
|
|
style: textStyle,
|
|
|
|
),
|
|
|
|
int() => null,
|
|
|
|
},
|
|
|
|
actions: switch (tabIndex) {
|
|
|
|
0 => [
|
|
|
|
IconButton(
|
|
|
|
onPressed: () {
|
|
|
|
if (visible) {
|
|
|
|
_controller.clear();
|
|
|
|
_focusNode.unfocus();
|
|
|
|
visible = false;
|
|
|
|
} else {
|
|
|
|
visible = true;
|
|
|
|
}
|
|
|
|
setState(() {});
|
|
|
|
},
|
|
|
|
icon: Icon(
|
|
|
|
visible
|
|
|
|
? IconsaxPlusLinear.close_circle
|
|
|
|
: IconsaxPlusLinear.search_normal_1,
|
|
|
|
size: 18,
|
|
|
|
),
|
|
|
|
)
|
|
|
|
],
|
|
|
|
int() => null,
|
|
|
|
},
|
|
|
|
),
|
2023-09-05 21:31:29 +03:00
|
|
|
body: SafeArea(
|
2023-09-08 20:35:56 +03:00
|
|
|
child: TabBarView(
|
|
|
|
controller: tabController,
|
|
|
|
children: pages,
|
2023-07-12 20:52:25 +03:00
|
|
|
),
|
2023-09-05 21:31:29 +03:00
|
|
|
),
|
|
|
|
bottomNavigationBar: NavigationBar(
|
2024-02-10 14:56:28 +03:00
|
|
|
onDestinationSelected: (int index) => changeTabIndex(index),
|
2023-09-05 21:31:29 +03:00
|
|
|
selectedIndex: tabIndex,
|
|
|
|
destinations: [
|
|
|
|
NavigationDestination(
|
2024-08-12 21:03:35 +03:00
|
|
|
icon: const Icon(IconsaxPlusLinear.cloud_sunny),
|
|
|
|
selectedIcon: const Icon(IconsaxPlusBold.cloud_sunny),
|
2023-09-05 21:31:29 +03:00
|
|
|
label: 'name'.tr,
|
|
|
|
),
|
|
|
|
NavigationDestination(
|
2024-08-12 21:03:35 +03:00
|
|
|
icon: const Icon(IconsaxPlusLinear.buildings),
|
|
|
|
selectedIcon: const Icon(IconsaxPlusBold.buildings),
|
2024-02-10 15:02:22 +03:00
|
|
|
label: 'cities'.tr,
|
2023-09-05 21:31:29 +03:00
|
|
|
),
|
2024-08-30 22:31:42 +03:00
|
|
|
if (!settings.hideMap)
|
|
|
|
NavigationDestination(
|
|
|
|
icon: const Icon(IconsaxPlusLinear.map),
|
|
|
|
selectedIcon: const Icon(IconsaxPlusBold.map),
|
|
|
|
label: 'map'.tr,
|
|
|
|
),
|
2024-08-12 21:03:35 +03:00
|
|
|
NavigationDestination(
|
|
|
|
icon: const Icon(IconsaxPlusLinear.category),
|
|
|
|
selectedIcon: const Icon(IconsaxPlusBold.category),
|
2024-05-11 22:31:43 +05:30
|
|
|
label: 'settings_full'.tr,
|
2023-09-05 21:31:29 +03:00
|
|
|
),
|
|
|
|
],
|
|
|
|
),
|
|
|
|
floatingActionButton: tabIndex == 1
|
|
|
|
? FloatingActionButton(
|
|
|
|
onPressed: () => showModalBottomSheet(
|
|
|
|
context: context,
|
|
|
|
isScrollControlled: true,
|
|
|
|
enableDrag: false,
|
2024-09-06 22:07:50 +03:00
|
|
|
builder: (BuildContext context) => const CreatePlace(),
|
2023-09-05 21:31:29 +03:00
|
|
|
),
|
2023-10-28 15:23:39 +05:30
|
|
|
child: const Icon(
|
2024-08-12 21:03:35 +03:00
|
|
|
IconsaxPlusLinear.add,
|
2023-10-28 15:23:39 +05:30
|
|
|
),
|
2023-09-05 21:31:29 +03:00
|
|
|
)
|
|
|
|
: null,
|
2023-06-17 20:57:57 +03:00
|
|
|
),
|
|
|
|
),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|