Rain/lib/app/ui/home.dart

312 lines
9.3 KiB
Dart
Raw Normal View History

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
}
2025-05-28 17:42:15 +03:00
Widget _buildAppBarTitle(
int tabIndex,
TextStyle? textStyle,
TextStyle? labelLarge,
) {
switch (tabIndex) {
case 0:
return visible
? _buildSearchField(labelLarge)
: 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,
);
});
case 1:
return Text('cities'.tr, style: textStyle);
case 2:
return settings.hideMap
? Text('settings_full'.tr, style: textStyle)
: Text('map'.tr, style: textStyle);
case 3:
return Text('settings_full'.tr, style: textStyle);
default:
return const SizedBox.shrink();
}
}
Widget _buildSearchField(TextStyle? labelLarge) {
return RawAutocomplete<Result>(
focusNode: _focusNode,
textEditingController: _controller,
fieldViewBuilder: (_, __, ___, ____) {
return TextField(
controller: _controller,
focusNode: _focusNode,
style: labelLarge?.copyWith(fontSize: 16),
decoration: InputDecoration(hintText: 'search'.tr),
);
},
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 _buildOptionsView(context, onSelected, options, labelLarge);
},
);
}
Widget _buildOptionsView(
BuildContext context,
AutocompleteOnSelected<Result> onSelected,
Iterable<Result> options,
TextStyle? labelLarge,
) {
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,
),
),
);
},
),
),
),
);
}
Widget _buildSearchIconButton() {
return 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,
),
);
}
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,
2025-05-28 17:42:15 +03:00
leading:
tabIndex == 0
? IconButton(
onPressed: () {
Get.to(
() => const SelectGeolocation(isStart: false),
transition: Transition.downToUp,
2024-08-18 18:35:30 +03:00
);
},
2025-05-28 17:42:15 +03:00
icon: const Icon(
IconsaxPlusLinear.global_search,
size: 18,
),
2024-08-18 18:35:30 +03:00
)
2025-05-28 17:42:15 +03:00
: null,
title: _buildAppBarTitle(tabIndex, textStyle, labelLarge),
actions: tabIndex == 0 ? [_buildSearchIconButton()] : null,
2024-08-18 18:35:30 +03:00
),
2023-09-05 21:31:29 +03:00
body: SafeArea(
2025-03-15 23:40:48 +03:00
child: TabBarView(controller: tabController, children: pages),
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),
label: 'settings_full'.tr,
2023-09-05 21:31:29 +03:00
),
],
),
2025-03-15 23:40:48 +03:00
floatingActionButton:
tabIndex == 1
? FloatingActionButton(
onPressed:
() => showModalBottomSheet(
context: context,
isScrollControlled: true,
enableDrag: false,
builder:
(BuildContext context) => const CreatePlace(),
),
child: const Icon(IconsaxPlusLinear.add),
)
: null,
2023-06-17 20:57:57 +03:00
),
),
);
}
}