diff --git a/Mobile/lib/dashboard.dart b/Mobile/lib/dashboard.dart new file mode 100644 index 0000000..04cc13f --- /dev/null +++ b/Mobile/lib/dashboard.dart @@ -0,0 +1,19 @@ +import 'package:flutter/material.dart'; +import 'global_components.dart'; + +class Dashboard extends StatelessWidget { + const Dashboard({super.key}); + + @override + Widget build(BuildContext context) { + return const Scaffold( + body: Row(mainAxisAlignment: MainAxisAlignment.center, children: [ + Column(mainAxisAlignment: MainAxisAlignment.center, children: [ + Text( + "Not implemented", + style: TextStyle(fontSize: 32), + ) + ]) + ])); + } +} diff --git a/Mobile/lib/global_components.dart b/Mobile/lib/global_components.dart new file mode 100644 index 0000000..2bfdb75 --- /dev/null +++ b/Mobile/lib/global_components.dart @@ -0,0 +1,18 @@ +import 'package:flutter/material.dart'; + +class PrimaryButton extends StatelessWidget { + final void Function()? onPressed; + final Widget child; + + const PrimaryButton( + {super.key, required this.onPressed, required this.child}); + + @override + Widget build(BuildContext context) { + return TextButton( + onPressed: onPressed, + style: TextButton.styleFrom( + backgroundColor: Colors.blue, foregroundColor: Colors.white), + child: child); + } +} diff --git a/Mobile/lib/landing_page.dart b/Mobile/lib/landing_page.dart new file mode 100644 index 0000000..c779929 --- /dev/null +++ b/Mobile/lib/landing_page.dart @@ -0,0 +1,26 @@ +import 'package:flutter/material.dart'; +import 'log_in_page.dart'; +import 'global_components.dart'; + +class LandingPage extends StatelessWidget { + const LandingPage({super.key}); + + @override + Widget build(BuildContext context) { + return Row(mainAxisAlignment: MainAxisAlignment.center, children: [ + Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Text("Fresh Plaza", style: TextStyle(fontSize: 64.0)), + PrimaryButton( + onPressed: () => { + Navigator.of(context).push(MaterialPageRoute( + builder: (context) => const LogInPage())) + }, + child: const Text("Log ind")), + PrimaryButton(onPressed: () => {}, child: const Text("Opret bruger")) + ], + ) + ]); + } +} diff --git a/Mobile/lib/log_in_page.dart b/Mobile/lib/log_in_page.dart new file mode 100644 index 0000000..2bf1b34 --- /dev/null +++ b/Mobile/lib/log_in_page.dart @@ -0,0 +1,60 @@ +import 'package:flutter/material.dart'; +import 'dashboard.dart'; +import 'global_components.dart'; + +class PrimaryInput extends StatelessWidget { + final double width; + final double height; + final String label; + final String placeholderText; + + const PrimaryInput( + {super.key, + this.width = 300, + this.height = 100, + required this.label, + required this.placeholderText}); + + @override + Widget build(BuildContext context) { + return SizedBox( + width: width, + height: height, + child: TextField( + decoration: InputDecoration( + border: const OutlineInputBorder(), + label: Text(label), + hintText: placeholderText), + )); + } +} + +class LogInPage extends StatelessWidget { + const LogInPage({super.key}); + + @override + Widget build(BuildContext context) { + return Scaffold( + body: Row(mainAxisAlignment: MainAxisAlignment.center, children: [ + Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Text( + "Log ind", + style: TextStyle(fontSize: 64), + ), + const PrimaryInput( + label: "Mail/Tlf", + placeholderText: "f.eks. example@example.com eller 12345678"), + const PrimaryInput(label: "Password", placeholderText: "*********"), + PrimaryButton( + onPressed: () => { + Navigator.of(context).push(MaterialPageRoute( + builder: (context) => const Dashboard())) + }, + child: const Text("Log ind")) + ], + ) + ])); + } +} diff --git a/Mobile/lib/main.dart b/Mobile/lib/main.dart index 7485536..324104d 100644 --- a/Mobile/lib/main.dart +++ b/Mobile/lib/main.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'weather.dart'; +import 'landing_page.dart'; void main() { runApp(const MyApp()); @@ -8,31 +8,15 @@ void main() { class MyApp extends StatelessWidget { const MyApp({super.key}); - // This widget is the root of your application. @override Widget build(BuildContext context) { return MaterialApp( - title: 'H4 Flutter', + title: 'Flutter Demo', theme: ThemeData( - // This is the theme of your application. - // - // TRY THIS: Try running your application with "flutter run". You'll see - // the application has a purple toolbar. Then, without quitting the app, - // try changing the seedColor in the colorScheme below to Colors.green - // and then invoke "hot reload" (save your changes or press the "hot - // reload" button in a Flutter-supported IDE, or press "r" if you used - // the command line to start the app). - // - // Notice that the counter didn't reset back to zero; the application - // state is not lost during the reload. To reset the state, use hot - // restart instead. - // - // This works for code too, not just values: Most code changes can be - // tested with just a hot reload. - colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple), + colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue), useMaterial3: true, ), - home: const MyHomePage(title: 'H4 med Flutter'), + home: const MyHomePage(title: 'Fresh Plaza'), ); } } @@ -40,15 +24,6 @@ class MyApp extends StatelessWidget { class MyHomePage extends StatefulWidget { const MyHomePage({super.key, required this.title}); - // This widget is the home page of your application. It is stateful, meaning - // that it has a State object (defined below) that contains fields that affect - // how it looks. - - // This class is the configuration for the state. It holds the values (in this - // case the title) provided by the parent (in this case the App widget) and - // used by the build method of the State. Fields in a Widget subclass are - // always marked "final". - final String title; @override @@ -56,63 +31,10 @@ class MyHomePage extends StatefulWidget { } class _MyHomePageState extends State { - int _counter = 0; - - void _incrementCounter() { - setState(() { - // This call to setState tells the Flutter framework that something has - // changed in this State, which causes it to rerun the build method below - // so that the display can reflect the updated values. If we changed - // _counter without calling setState(), then the build method would not be - // called again, and so nothing would appear to happen. - _counter++; - }); - } - - void _navigateToWeatherForecastPage() { - Navigator.push( - context, - MaterialPageRoute(builder: (context) => WeatherForecastPage()), - ); - } - @override Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - backgroundColor: Theme.of(context).colorScheme.inversePrimary, - title: Text(widget.title), - ), - body: Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - const Text( - 'You have clicked the button this many times:', - ), - Text( - '$_counter', - style: Theme.of(context).textTheme.headlineMedium, - ), - ], - ), - ), - floatingActionButton: Row( - mainAxisAlignment: MainAxisAlignment.end, - children: [ - FloatingActionButton( - onPressed: _incrementCounter, - tooltip: 'Increment', - child: const Icon(Icons.add), - ), - SizedBox(width: 10), // Optional: Adds space between buttons - FloatingActionButton( - onPressed: _navigateToWeatherForecastPage, - tooltip: 'Show Weather', - child: const Icon(Icons.star), - ), - ], - ), + return const Scaffold( + body: LandingPage(), ); } } diff --git a/Mobile/lib/weather.dart b/Mobile/lib/weather.dart deleted file mode 100644 index 5be79e2..0000000 --- a/Mobile/lib/weather.dart +++ /dev/null @@ -1,165 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:http/http.dart' as http; -import 'dart:convert'; -import 'package:fl_chart/fl_chart.dart'; - -class WeatherForecastPage extends StatefulWidget { - @override - _WeatherForecastPageState createState() => _WeatherForecastPageState(); -} - -class _WeatherForecastPageState extends State { - List forecasts = []; - List temperaturesC = []; - List dates = []; - - Future fetchForecasts() async { - final response = - await http.get(Uri.parse('https://h4api.onrender.com/WeatherForecast')); - - if (response.statusCode == 200) { - setState(() { - temperaturesC.clear(); - dates.clear(); - forecasts = json.decode(response.body).map((f) { - temperaturesC.add(f['temperatureC'].toDouble()); - dates.add(f['date']); - return f; - }).toList(); - }); - } else { - throw Exception('Failed to load forecasts'); - } - } - - @override - void initState() { - super.initState(); - fetchForecasts(); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: Text('Weather Forecast Graph'), - actions: [ - IconButton( - icon: Icon(Icons.refresh), - onPressed: fetchForecasts, - ), - ], - ), - body: forecasts.isEmpty - ? Center(child: CircularProgressIndicator()) - : Padding( - padding: const EdgeInsets.all(8.0), - child: Column( - children: [ - Expanded( - child: LineChart( - LineChartData( - minY: - (temperaturesC.reduce((a, b) => a < b ? a : b) - 10) - .toDouble(), - maxY: - (temperaturesC.reduce((a, b) => a > b ? a : b) + 20) - .toDouble(), - gridData: FlGridData(show: true), // Grid - titlesData: FlTitlesData( - leftTitles: AxisTitles( - sideTitles: SideTitles( - showTitles: true, - reservedSize: 40, - getTitlesWidget: (value, meta) { - return SideTitleWidget( - axisSide: meta.axisSide, - child: Text( - '${value.toInt()}°C', - style: const TextStyle( - color: Colors.black, - fontWeight: FontWeight.bold, - fontSize: 12, - ), - ), - ); - }, - interval: 10, - ), - ), - bottomTitles: AxisTitles( - sideTitles: SideTitles( - showTitles: true, - reservedSize: 40, - getTitlesWidget: (value, meta) { - int index = value.toInt(); - if (index >= 0 && index < dates.length) { - return SideTitleWidget( - axisSide: meta.axisSide, - child: Text( - dates[index].substring(5), // MM-DD - style: const TextStyle( - color: Colors.black, - fontWeight: FontWeight.bold, - fontSize: 12, - ), - ), - ); - } - return const SizedBox.shrink(); - }, - ), - ), - ), - borderData: FlBorderData( - show: true, - border: Border.all(color: Colors.black, width: 1), - ), - lineBarsData: [ - LineChartBarData( - spots: temperaturesC.asMap().entries.map((e) { - return FlSpot(e.key.toDouble(), e.value); - }).toList(), - isCurved: true, - color: - Colors.blue, // Use `color` instead of `colors` - barWidth: 4, - dotData: FlDotData(show: true), - belowBarData: BarAreaData(show: false), - ), - ], - ), - ), - ), - SizedBox(height: 20), - Text( - 'Weather Summaries', - style: TextStyle( - fontSize: 20, - fontWeight: FontWeight.bold, - ), - ), - Expanded( - child: ListView.builder( - itemCount: forecasts.length, - itemBuilder: (context, index) { - final forecast = forecasts[index]; - return ListTile( - title: Text( - '${forecast['date']}: ${forecast['summary']}', - ), - ); - }, - ), - ), - SizedBox(height: 20), - ElevatedButton( - onPressed: fetchForecasts, - child: Text('Refresh Data'), - ), - ], - ), - ), - ); - } -} diff --git a/Mobile/pubspec.lock b/Mobile/pubspec.lock index aedd0ac..b03e60c 100644 --- a/Mobile/pubspec.lock +++ b/Mobile/pubspec.lock @@ -37,10 +37,10 @@ packages: dependency: transitive description: name: collection - sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a + sha256: a1ace0a119f20aabc852d165077c036cd864315bd99b7eaa10a60100341941bf url: "https://pub.dev" source: hosted - version: "1.18.0" + version: "1.19.0" cupertino_icons: dependency: "direct main" description: @@ -111,18 +111,18 @@ packages: dependency: transitive description: name: leak_tracker - sha256: "7f0df31977cb2c0b88585095d168e689669a2cc9b97c309665e3386f3e9d341a" + sha256: "7bb2830ebd849694d1ec25bf1f44582d6ac531a57a365a803a6034ff751d2d06" url: "https://pub.dev" source: hosted - version: "10.0.4" + version: "10.0.7" leak_tracker_flutter_testing: dependency: transitive description: name: leak_tracker_flutter_testing - sha256: "06e98f569d004c1315b991ded39924b21af84cf14cc94791b8aea337d25b57f8" + sha256: "9491a714cca3667b60b5c420da8217e6de0d1ba7a5ec322fab01758f6998f379" url: "https://pub.dev" source: hosted - version: "3.0.3" + version: "3.0.8" leak_tracker_testing: dependency: transitive description: @@ -151,18 +151,18 @@ packages: dependency: transitive description: name: material_color_utilities - sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a" + sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec url: "https://pub.dev" source: hosted - version: "0.8.0" + version: "0.11.1" meta: dependency: transitive description: name: meta - sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136" + sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7 url: "https://pub.dev" source: hosted - version: "1.12.0" + version: "1.15.0" path: dependency: transitive description: @@ -175,7 +175,7 @@ packages: dependency: transitive description: flutter source: sdk - version: "0.0.99" + version: "0.0.0" source_span: dependency: transitive description: @@ -188,10 +188,10 @@ packages: dependency: transitive description: name: stack_trace - sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" + sha256: "9f47fd3630d76be3ab26f0ee06d213679aa425996925ff3feffdec504931c377" url: "https://pub.dev" source: hosted - version: "1.11.1" + version: "1.12.0" stream_channel: dependency: transitive description: @@ -204,10 +204,10 @@ packages: dependency: transitive description: name: string_scanner - sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + sha256: "688af5ed3402a4bde5b3a6c15fd768dbf2621a614950b17f04626c431ab3c4c3" url: "https://pub.dev" source: hosted - version: "1.2.0" + version: "1.3.0" term_glyph: dependency: transitive description: @@ -220,10 +220,10 @@ packages: dependency: transitive description: name: test_api - sha256: "9955ae474176f7ac8ee4e989dadfb411a58c30415bcfb648fa04b2b8a03afa7f" + sha256: "664d3a9a64782fcdeb83ce9c6b39e78fd2971d4e37827b9b06c3aa1edc5e760c" url: "https://pub.dev" source: hosted - version: "0.7.0" + version: "0.7.3" typed_data: dependency: transitive description: @@ -244,10 +244,10 @@ packages: dependency: transitive description: name: vm_service - sha256: "3923c89304b715fb1eb6423f017651664a03bf5f4b29983627c4da791f74a4ec" + sha256: f6be3ed8bd01289b34d679c2b62226f63c0e69f9fd2e50a6b3c1c729a961041b url: "https://pub.dev" source: hosted - version: "14.2.1" + version: "14.3.0" web: dependency: transitive description: