Tab bar to scroll different location
This commit is contained in:
Vendored
+8
-7
@@ -5,15 +5,16 @@
|
|||||||
"version": "0.2.0",
|
"version": "0.2.0",
|
||||||
"configurations": [
|
"configurations": [
|
||||||
{
|
{
|
||||||
"name": "wetter",
|
"name": "wetter-simulator",
|
||||||
"request": "launch",
|
|
||||||
"type": "dart"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "wetter (profile mode)",
|
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"type": "dart",
|
"type": "dart",
|
||||||
"flutterMode": "profile"
|
"deviceId": "emulator-5554"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "wetter-handy",
|
||||||
|
"request": "launch",
|
||||||
|
"type": "dart",
|
||||||
|
"deviceId": "20113d66",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "wetter (release mode)",
|
"name": "wetter (release mode)",
|
||||||
|
|||||||
@@ -26,16 +26,7 @@ class _CompactWeatherDataState extends State<CompactWeatherData> {
|
|||||||
style: Theme.of(context).textTheme.headline5,
|
style: Theme.of(context).textTheme.headline5,
|
||||||
),
|
),
|
||||||
const SizedBox(height: 10),
|
const SizedBox(height: 10),
|
||||||
Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [
|
|
||||||
_weatherData(),
|
_weatherData(),
|
||||||
Expanded(
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.all(35),
|
|
||||||
child: FittedBox(
|
|
||||||
fit: BoxFit.fill,
|
|
||||||
child: Icon(weatherIcon(
|
|
||||||
widget.dwm.prevalentWeatherIcon()))))),
|
|
||||||
]),
|
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
Row(
|
Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
@@ -63,7 +54,8 @@ class _CompactWeatherDataState extends State<CompactWeatherData> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Widget _weatherData() {
|
Widget _weatherData() {
|
||||||
return Column(
|
return Row(children: [
|
||||||
|
Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Row(
|
Row(
|
||||||
@@ -113,6 +105,14 @@ class _CompactWeatherDataState extends State<CompactWeatherData> {
|
|||||||
Text("${widget.dwm.dailyAverageWindSpeed().toString()} km/h")
|
Text("${widget.dwm.dailyAverageWindSpeed().toString()} km/h")
|
||||||
]),
|
]),
|
||||||
],
|
],
|
||||||
);
|
),
|
||||||
|
Expanded(
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 35),
|
||||||
|
child: FittedBox(
|
||||||
|
fit: BoxFit.contain,
|
||||||
|
child:
|
||||||
|
Icon(weatherIcon(widget.dwm.prevalentWeatherIcon()))))),
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+19
-55
@@ -1,9 +1,6 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
|
||||||
import 'package:wetter/components/compact_weather_data.dart';
|
|
||||||
import 'package:wetter/components/main_menu.dart';
|
import 'package:wetter/components/main_menu.dart';
|
||||||
import 'package:wetter/models/daily_weather_model.dart';
|
import 'package:wetter/screens/main_weather_view.dart';
|
||||||
import 'package:wetter/services/brightsky_api_service.dart';
|
|
||||||
|
|
||||||
void main() => runApp(const MyApp());
|
void main() => runApp(const MyApp());
|
||||||
|
|
||||||
@@ -15,25 +12,6 @@ class MyApp extends StatefulWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _MyAppState extends State<MyApp> {
|
class _MyAppState extends State<MyApp> {
|
||||||
SharedPreferences? prefs;
|
|
||||||
int _daysToLoad = 7;
|
|
||||||
late Future<List<DailyWeatherModel>> dailyWeather;
|
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
initializePreferences();
|
|
||||||
dailyWeather =
|
|
||||||
BrightSkyAPI.fetchForecastForTimeRange(DateTime.now(), _daysToLoad);
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> initializePreferences() async {
|
|
||||||
prefs = await SharedPreferences.getInstance();
|
|
||||||
setState(() {
|
|
||||||
_daysToLoad = prefs!.getInt("daysToLoad") ?? 7;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return MaterialApp(
|
return MaterialApp(
|
||||||
@@ -46,43 +24,29 @@ class _MyAppState extends State<MyApp> {
|
|||||||
bodyText2: TextStyle(fontSize: 14.0, fontFamily: 'Hind'),
|
bodyText2: TextStyle(fontSize: 14.0, fontFamily: 'Hind'),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
home: Scaffold(
|
home: DefaultTabController(
|
||||||
|
length: 3,
|
||||||
|
child: Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: const Text('Wetter in Harburg'),
|
title: const Text('Wetter'),
|
||||||
|
bottom: const TabBar(
|
||||||
|
tabs: [
|
||||||
|
Tab(icon: Text("Hamburg")),
|
||||||
|
Tab(icon: Text("Frankfurt")),
|
||||||
|
Tab(icon: Text("Freiburg")),
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
drawer: const NavBar(),
|
drawer: const NavBar(),
|
||||||
body: RefreshIndicator(
|
body: const TabBarView(
|
||||||
onRefresh: () {
|
children: [
|
||||||
return Future(() {
|
MainWeatherView(53.46, 9.98),
|
||||||
setState(() {
|
MainWeatherView(50.15, 8.70),
|
||||||
_daysToLoad = prefs?.getInt("daysToLoad") ?? 7;
|
MainWeatherView(47.99, 7.85)
|
||||||
dailyWeather = BrightSkyAPI.fetchForecastForTimeRange(
|
],
|
||||||
DateTime.now(), _daysToLoad);
|
),
|
||||||
});
|
|
||||||
});
|
|
||||||
},
|
|
||||||
child: SingleChildScrollView(
|
|
||||||
physics: const AlwaysScrollableScrollPhysics(),
|
|
||||||
child: Center(
|
|
||||||
child: FutureBuilder<List<DailyWeatherModel>>(
|
|
||||||
future: BrightSkyAPI.fetchForecastForTimeRange(
|
|
||||||
DateTime.now(), _daysToLoad),
|
|
||||||
builder: (context, snapshot) {
|
|
||||||
if (snapshot.hasData) {
|
|
||||||
return Column(
|
|
||||||
children: snapshot.data!
|
|
||||||
.map((e) => CompactWeatherData(e))
|
|
||||||
.toList());
|
|
||||||
} else if (snapshot.hasError) {
|
|
||||||
return Text('${snapshot.error}');
|
|
||||||
}
|
|
||||||
|
|
||||||
// By default, show a loading spinner.
|
|
||||||
return const CircularProgressIndicator();
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
))),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,79 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
|
||||||
|
import '../components/compact_weather_data.dart';
|
||||||
|
import '../models/daily_weather_model.dart';
|
||||||
|
import '../services/brightsky_api_service.dart';
|
||||||
|
|
||||||
|
class MainWeatherView extends StatefulWidget {
|
||||||
|
final double lat;
|
||||||
|
final double lon;
|
||||||
|
|
||||||
|
const MainWeatherView(this.lat, this.lon, {Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<MainWeatherView> createState() => _MainWeatherViewState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _MainWeatherViewState extends State<MainWeatherView>
|
||||||
|
with AutomaticKeepAliveClientMixin<MainWeatherView> {
|
||||||
|
SharedPreferences? prefs;
|
||||||
|
int _daysToLoad = 7;
|
||||||
|
late Future<List<DailyWeatherModel>> dailyWeather;
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool get wantKeepAlive => true;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
initializePreferences();
|
||||||
|
dailyWeather = BrightSkyAPI.fetchForecastForTimeRange(
|
||||||
|
DateTime.now(), _daysToLoad, widget.lat, widget.lon);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> initializePreferences() async {
|
||||||
|
prefs = await SharedPreferences.getInstance();
|
||||||
|
setState(() {
|
||||||
|
_daysToLoad = prefs!.getInt("daysToLoad") ?? 7;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return RefreshIndicator(
|
||||||
|
onRefresh: () {
|
||||||
|
return Future(() {
|
||||||
|
setState(() {
|
||||||
|
_daysToLoad = prefs?.getInt("daysToLoad") ?? 7;
|
||||||
|
dailyWeather = BrightSkyAPI.fetchForecastForTimeRange(
|
||||||
|
DateTime.now(), _daysToLoad, widget.lat, widget.lon);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
child: SingleChildScrollView(
|
||||||
|
physics: const AlwaysScrollableScrollPhysics(),
|
||||||
|
child: Center(
|
||||||
|
child: FutureBuilder<List<DailyWeatherModel>>(
|
||||||
|
future: BrightSkyAPI.fetchForecastForTimeRange(
|
||||||
|
DateTime.now(), _daysToLoad, widget.lat, widget.lon),
|
||||||
|
builder: (context, snapshot) {
|
||||||
|
if (snapshot.hasData) {
|
||||||
|
return Column(
|
||||||
|
children: snapshot.data!
|
||||||
|
.map((e) => Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 5),
|
||||||
|
child: CompactWeatherData(e)))
|
||||||
|
.toList());
|
||||||
|
} else if (snapshot.hasError) {
|
||||||
|
return Text('${snapshot.error}');
|
||||||
|
}
|
||||||
|
|
||||||
|
// By default, show a loading spinner.
|
||||||
|
return const CircularProgressIndicator();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,11 +3,12 @@ import 'package:http/http.dart' as http;
|
|||||||
import 'package:wetter/models/daily_weather_model.dart';
|
import 'package:wetter/models/daily_weather_model.dart';
|
||||||
|
|
||||||
class BrightSkyAPI {
|
class BrightSkyAPI {
|
||||||
static Future<DailyWeatherModel> fetchForecastOfSingleDay(DateTime d) async {
|
static Future<DailyWeatherModel> fetchForecastOfSingleDay(
|
||||||
|
DateTime d, double lat, double lon) async {
|
||||||
String dt = "${d.year}-${d.month}-${d.day}";
|
String dt = "${d.year}-${d.month}-${d.day}";
|
||||||
final response = await http.get(
|
final response = await http.get(
|
||||||
Uri.parse(
|
Uri.parse(
|
||||||
'https://api.brightsky.dev/weather?lat=53.43&lon=10&date=$dt&tz=Europe/Berlin'),
|
'https://api.brightsky.dev/weather?lat=$lat&lon=$lon&date=$dt&tz=Europe/Berlin'),
|
||||||
headers: {"Accept": "application/json"});
|
headers: {"Accept": "application/json"});
|
||||||
if (response.statusCode == 200) {
|
if (response.statusCode == 200) {
|
||||||
return DailyWeatherModel.fromJson(jsonDecode(response.body));
|
return DailyWeatherModel.fromJson(jsonDecode(response.body));
|
||||||
@@ -17,13 +18,13 @@ class BrightSkyAPI {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static Future<List<DailyWeatherModel>> fetchForecastForTimeRange(
|
static Future<List<DailyWeatherModel>> fetchForecastForTimeRange(
|
||||||
DateTime from, int noOfDays) async {
|
DateTime from, int noOfDays, double lat, double lon) async {
|
||||||
DateTime until = from.add(Duration(days: noOfDays));
|
DateTime until = from.add(Duration(days: noOfDays));
|
||||||
String fromDay = "${from.year}-${from.month}-${from.day}";
|
String fromDay = "${from.year}-${from.month}-${from.day}";
|
||||||
String untilDay = "${until.year}-${until.month}-${until.day}";
|
String untilDay = "${until.year}-${until.month}-${until.day}";
|
||||||
final response = await http.get(
|
final response = await http.get(
|
||||||
Uri.parse(
|
Uri.parse(
|
||||||
'https://api.brightsky.dev/weather?lat=53.43&lon=10&date=$fromDay&last_date=$untilDay&tz=Europe/Berlin'),
|
'https://api.brightsky.dev/weather?lat=$lat&lon=$lon&date=$fromDay&last_date=$untilDay&tz=Europe/Berlin'),
|
||||||
headers: {"Accept": "application/json"});
|
headers: {"Accept": "application/json"});
|
||||||
final Map<String, dynamic> responseAsJson = jsonDecode(response.body);
|
final Map<String, dynamic> responseAsJson = jsonDecode(response.body);
|
||||||
if (response.statusCode == 200) {
|
if (response.statusCode == 200) {
|
||||||
|
|||||||
Reference in New Issue
Block a user