commit f9b1b25e91efa4b50201ecf8cdccd4b91f577a83 Author: Andrew nuark G Date: Sat Apr 8 03:51:25 2023 +0700 Done login routine diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..24476c5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,44 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ +migrate_working_dir/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +**/doc/api/ +**/ios/Flutter/.last_build_id +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Android Studio will place build artifacts here +/android/app/debug +/android/app/profile +/android/app/release diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..1c353fa --- /dev/null +++ b/.metadata @@ -0,0 +1,45 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled. + +version: + revision: 9ba0d08ebc074bf0da6dfd1fadea39f5c5566198 + channel: master + +project_type: app + +# Tracks metadata for the flutter migrate command +migration: + platforms: + - platform: root + create_revision: 9ba0d08ebc074bf0da6dfd1fadea39f5c5566198 + base_revision: 9ba0d08ebc074bf0da6dfd1fadea39f5c5566198 + - platform: android + create_revision: 9ba0d08ebc074bf0da6dfd1fadea39f5c5566198 + base_revision: 9ba0d08ebc074bf0da6dfd1fadea39f5c5566198 + - platform: ios + create_revision: 9ba0d08ebc074bf0da6dfd1fadea39f5c5566198 + base_revision: 9ba0d08ebc074bf0da6dfd1fadea39f5c5566198 + - platform: linux + create_revision: 9ba0d08ebc074bf0da6dfd1fadea39f5c5566198 + base_revision: 9ba0d08ebc074bf0da6dfd1fadea39f5c5566198 + - platform: macos + create_revision: 9ba0d08ebc074bf0da6dfd1fadea39f5c5566198 + base_revision: 9ba0d08ebc074bf0da6dfd1fadea39f5c5566198 + - platform: web + create_revision: 9ba0d08ebc074bf0da6dfd1fadea39f5c5566198 + base_revision: 9ba0d08ebc074bf0da6dfd1fadea39f5c5566198 + - platform: windows + create_revision: 9ba0d08ebc074bf0da6dfd1fadea39f5c5566198 + base_revision: 9ba0d08ebc074bf0da6dfd1fadea39f5c5566198 + + # User provided section + + # List of Local paths (relative to this file) that should be + # ignored by the migrate tool. + # + # Files that are not part of the templates will be ignored by default. + unmanaged_files: + - 'lib/main.dart' + - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/README.md b/README.md new file mode 100644 index 0000000..733eff9 --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# tuuli_app + +A new Flutter project. diff --git a/analysis_options.yaml b/analysis_options.yaml new file mode 100644 index 0000000..f9b3034 --- /dev/null +++ b/analysis_options.yaml @@ -0,0 +1 @@ +include: package:flutter_lints/flutter.yaml diff --git a/lib/api/api_client.dart b/lib/api/api_client.dart new file mode 100644 index 0000000..4176c2a --- /dev/null +++ b/lib/api/api_client.dart @@ -0,0 +1,94 @@ +import 'dart:async'; +import 'dart:convert'; +import 'package:tuuli_app/api/model/access_token_model.dart'; +import 'package:http/browser_client.dart'; +import 'package:http/http.dart'; + +class ErrorOrData { + final T? data; + final Exception? error; + + ErrorOrData(this.data, this.error); + + void unfold( + void Function(T data) onData, void Function(Exception error) onError) { + if (data != null) { + onData(data as T); + } else { + onError(error!); + } + } +} + +typedef FutureErrorOrData = Future>; + +class ApiClient { + final BrowserClient _client = BrowserClient(); + + final Uri baseUrl; + + ApiClient(this.baseUrl); + + ApiClient.fromString(String baseUrl) : this(Uri.parse(baseUrl)); + + FutureErrorOrData login( + String username, + String password, + ) async { + AccessTokenModel? data; + Exception? error; + + final response = await post('/api/getAccessToken', body: { + 'username': username, + 'password': password, + }, headers: { + 'Content-Type': 'application/json', + }); + if (response.statusCode == 200) { + final body = json.decode(await response.stream.bytesToString()); + if (body['error'] != null) { + error = Exception(body['error']); + } else if (body['access_token'] == null) { + error = Exception('No access token'); + } else { + data = AccessTokenModel(accessToken: body['access_token']); + } + } else { + error = Exception('HTTP ${response.statusCode}'); + } + + return ErrorOrData(data, error); + } + + Future get( + String path, { + Map? headers, + }) { + return _request(path, 'GET', headers: headers); + } + + Future post( + String path, { + Map? headers, + dynamic body, + }) { + return _request(path, 'POST', headers: headers, body: body); + } + + Future _request( + String path, + String method, { + Map? headers, + dynamic body, + }) async { + final uri = baseUrl.resolve(path); + final request = Request(method, uri); + if (headers != null) { + request.headers.addAll(headers); + } + if (body != null) { + request.body = json.encode(body); + } + return _client.send(request); + } +} diff --git a/lib/api/model/access_token_model.dart b/lib/api/model/access_token_model.dart new file mode 100644 index 0000000..9c9c140 --- /dev/null +++ b/lib/api/model/access_token_model.dart @@ -0,0 +1,7 @@ +class AccessTokenModel { + final String accessToken; + + const AccessTokenModel({ + required this.accessToken, + }); +} diff --git a/lib/main.dart b/lib/main.dart new file mode 100644 index 0000000..8d0a51d --- /dev/null +++ b/lib/main.dart @@ -0,0 +1,87 @@ +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; +import 'package:get_storage/get_storage.dart'; +import 'package:tuuli_app/pages/checkup_page.dart'; +import 'package:tuuli_app/pages/home_page.dart'; +import 'package:tuuli_app/pages/login_page.dart'; +import 'package:tuuli_app/pages/not_found_page.dart'; + +void main() async { + await GetStorage.init(); + + runApp(const MainApp()); +} + +class MainApp extends StatelessWidget { + const MainApp({super.key}); + + @override + Widget build(BuildContext context) { + return GetMaterialApp( + debugShowCheckedModeBanner: false, + debugShowMaterialGrid: false, + initialRoute: "/login", + onGenerateRoute: _onGenerateRoute, + theme: ThemeData( + brightness: Brightness.dark, + primaryColor: Colors.blueGrey, + ), + ); + } + + Route _onGenerateRoute(RouteSettings settings) { + Widget? pageBody; + bool appBarNeeded = true; + switch (settings.name) { + case "/": + appBarNeeded = false; + pageBody = const CheckupPage(); + break; + case "/login": + appBarNeeded = false; + pageBody = const LoginPage(); + break; + case "/home": + pageBody = const HomePage(); + break; + default: + pageBody = const NotFoundPage(); + break; + } + + return MaterialPageRoute( + builder: (context) => Scaffold( + appBar: appBarNeeded + ? AppBar( + title: const Text('GWS Playground'), + actions: [ + if (Navigator.of(context).canPop()) + IconButton( + icon: const Icon(Icons.arrow_back), + onPressed: () { + Get.back(canPop: false); + }, + ), + IconButton( + icon: const Icon(Icons.home), + onPressed: () { + Get.offAllNamed("/"); + }, + ), + IconButton( + icon: const Icon(Icons.logout), + onPressed: () { + GetStorage().erase().then((value) { + GetStorage().save(); + Get.offAllNamed("/"); + }); + }, + ), + ], + ) + : null, + body: pageBody, + ), + ); + } +} diff --git a/lib/pages/checkup_page.dart b/lib/pages/checkup_page.dart new file mode 100644 index 0000000..e3599a8 --- /dev/null +++ b/lib/pages/checkup_page.dart @@ -0,0 +1,52 @@ +import 'package:animated_background/animated_background.dart'; +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; +import 'package:get_storage/get_storage.dart'; + +class CheckupPage extends StatefulWidget { + const CheckupPage({super.key}); + + @override + State createState() => _CheckupPageState(); +} + +class _CheckupPageState extends State + with TickerProviderStateMixin { + @override + void initState() { + super.initState(); + + final accessToken = GetStorage().read("accessToken"); + WidgetsBinding.instance.addPostFrameCallback((_) { + if (accessToken == null) { + Get.offAllNamed("/login"); + } else { + Get.offAllNamed("/home"); + } + }); + } + + @override + Widget build(BuildContext context) { + return AnimatedBackground( + behaviour: RandomParticleBehaviour(), + vsync: this, + child: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + 'Checking credentials...', + style: Theme.of(context).textTheme.headlineMedium, + ), + const SizedBox(height: 16), + const SizedBox.square( + dimension: 32, + child: CircularProgressIndicator(), + ), + ], + ), + ), + ); + } +} diff --git a/lib/pages/home_page.dart b/lib/pages/home_page.dart new file mode 100644 index 0000000..9861e65 --- /dev/null +++ b/lib/pages/home_page.dart @@ -0,0 +1,33 @@ +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; + +class HomePage extends StatefulWidget { + const HomePage({super.key}); + + @override + State createState() => _HomePageState(); +} + +class _HomePageState extends State { + @override + Widget build(BuildContext context) { + return Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + 'Home Page', + style: Theme.of(context).textTheme.headlineMedium, + ), + const SizedBox(height: 16), + ElevatedButton( + onPressed: () { + Get.offNamed("/login"); + }, + child: const Text('Login'), + ), + ], + ), + ); + } +} diff --git a/lib/pages/login_page.dart b/lib/pages/login_page.dart new file mode 100644 index 0000000..b034b00 --- /dev/null +++ b/lib/pages/login_page.dart @@ -0,0 +1,145 @@ +import 'dart:async'; + +import 'package:animated_background/animated_background.dart'; +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; +import 'package:get_storage/get_storage.dart'; +import 'package:tuuli_app/api/api_client.dart'; + +class LoginPage extends StatefulWidget { + const LoginPage({super.key}); + + @override + State createState() => _LoginPageState(); +} + +class _LoginPageState extends State with TickerProviderStateMixin { + final _formKey = GlobalKey(); + + final apiClient = ApiClient.fromString("http://127.0.0.1:8000"); + var submitted = false; + + final loginController = TextEditingController(); + final passwordController = TextEditingController(); + + @override + Widget build(BuildContext context) { + final screenSize = MediaQuery.of(context).size; + final formWidth = screenSize.width <= 600 ? screenSize.width : 300.0; + return Stack( + children: [ + AnimatedBackground( + behaviour: RandomParticleBehaviour(), + vsync: this, + child: const SizedBox.square( + dimension: 0, + ), + ), + Row( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + LimitedBox( + maxWidth: formWidth, + child: Container( + color: Colors.black.withAlpha(100), + padding: const EdgeInsets.all(16), + child: Form( + key: _formKey, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + TextFormField( + controller: loginController, + enabled: !submitted, + decoration: const InputDecoration( + labelText: 'Login', + hintText: 'Enter your login', + ), + validator: (value) { + if (value == null || value.isEmpty) { + return 'Please enter your Login'; + } + return null; + }, + ), + TextFormField( + controller: passwordController, + obscureText: true, + enabled: !submitted, + decoration: const InputDecoration( + labelText: 'Password', + hintText: 'Enter your password', + ), + validator: (value) { + if (value == null || value.isEmpty) { + return 'Please enter your password'; + } + return null; + }, + ), + const SizedBox(height: 16), + ElevatedButton( + onPressed: submitted ? null : _submit, + child: const Text('Login'), + ), + ], + ), + ), + ), + ), + ], + ), + ], + ); + } + + Future _submit() async { + if (!_formKey.currentState!.validate()) { + return; + } + + setState(() { + submitted = true; + }); + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('Trying to login...'), + ), + ); + + final response = await apiClient.login( + loginController.text.trim(), + passwordController.text.trim(), + ); + response.unfold((data) { + ScaffoldMessenger.of(context).hideCurrentSnackBar(); + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('Login successful'), + ), + ); + GetStorage() + .write("accessToken", data.accessToken) + .then((value) => GetStorage().save()); + Timer(1.seconds, () { + ScaffoldMessenger.of(context).hideCurrentSnackBar(); + WidgetsBinding.instance.addPostFrameCallback((_) { + Get.offAllNamed("/home"); + }); + }); + }, (error) { + ScaffoldMessenger.of(context).hideCurrentSnackBar(); + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text(error.toString()), + ), + ); + setState(() { + submitted = false; + }); + }); + } +} diff --git a/lib/pages/not_found_page.dart b/lib/pages/not_found_page.dart new file mode 100644 index 0000000..b22bdd7 --- /dev/null +++ b/lib/pages/not_found_page.dart @@ -0,0 +1,21 @@ +import 'package:animated_background/animated_background.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/src/scheduler/ticker.dart'; + +class NotFoundPage extends StatelessWidget { + const NotFoundPage({super.key}); + + @override + Widget build(BuildContext context) { + return AnimatedBackground( + behaviour: RandomParticleBehaviour(), + vsync: Scaffold.of(context), + child: Center( + child: Text( + 'Page not found', + style: Theme.of(context).textTheme.headlineMedium, + ), + ), + ); + } +} diff --git a/pubspec.lock b/pubspec.lock new file mode 100644 index 0000000..99d4e7d --- /dev/null +++ b/pubspec.lock @@ -0,0 +1,333 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + animated_background: + dependency: "direct main" + description: + name: animated_background + sha256: "24b05a6dca2cb0231b011f9e8fd2e9d8060faac08a78cf0643915bb7d6e9b03b" + url: "https://pub.dev" + source: hosted + version: "2.0.0" + async: + dependency: transitive + description: + name: async + sha256: bfe67ef28df125b7dddcea62755991f807aa39a2492a23e1550161692950bbe0 + url: "https://pub.dev" + source: hosted + version: "2.10.0" + boolean_selector: + dependency: transitive + description: + name: boolean_selector + sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + characters: + dependency: transitive + description: + name: characters + sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" + url: "https://pub.dev" + source: hosted + version: "1.3.0" + clock: + dependency: transitive + description: + name: clock + sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf + url: "https://pub.dev" + source: hosted + version: "1.1.1" + collection: + dependency: transitive + description: + name: collection + sha256: "4a07be6cb69c84d677a6c3096fcf960cc3285a8330b4603e0d463d15d9bd934c" + url: "https://pub.dev" + source: hosted + version: "1.17.1" + fake_async: + dependency: transitive + description: + name: fake_async + sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" + url: "https://pub.dev" + source: hosted + version: "1.3.1" + ffi: + dependency: transitive + description: + name: ffi + sha256: a38574032c5f1dd06c4aee541789906c12ccaab8ba01446e800d9c5b79c4a978 + url: "https://pub.dev" + source: hosted + version: "2.0.1" + file: + dependency: transitive + description: + name: file + sha256: "1b92bec4fc2a72f59a8e15af5f52cd441e4a7860b49499d69dfa817af20e925d" + url: "https://pub.dev" + source: hosted + version: "6.1.4" + flutter: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" + flutter_lints: + dependency: "direct dev" + description: + name: flutter_lints + sha256: aeb0b80a8b3709709c9cc496cdc027c5b3216796bc0af0ce1007eaf24464fd4c + url: "https://pub.dev" + source: hosted + version: "2.0.1" + flutter_test: + dependency: "direct dev" + description: flutter + source: sdk + version: "0.0.0" + get: + dependency: "direct main" + description: + name: get + sha256: "2ba20a47c8f1f233bed775ba2dd0d3ac97b4cf32fc17731b3dfc672b06b0e92a" + url: "https://pub.dev" + source: hosted + version: "4.6.5" + get_storage: + dependency: "direct main" + description: + name: get_storage + sha256: "39db1fffe779d0c22b3a744376e86febe4ade43bf65e06eab5af707dc84185a2" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + http: + dependency: "direct main" + description: + name: http + sha256: "6aa2946395183537c8b880962d935877325d6a09a2867c3970c05c0fed6ac482" + url: "https://pub.dev" + source: hosted + version: "0.13.5" + http_parser: + dependency: transitive + description: + name: http_parser + sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" + url: "https://pub.dev" + source: hosted + version: "4.0.2" + js: + dependency: transitive + description: + name: js + sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3 + url: "https://pub.dev" + source: hosted + version: "0.6.7" + lints: + dependency: transitive + description: + name: lints + sha256: "5e4a9cd06d447758280a8ac2405101e0e2094d2a1dbdd3756aec3fe7775ba593" + url: "https://pub.dev" + source: hosted + version: "2.0.1" + matcher: + dependency: transitive + description: + name: matcher + sha256: c94db23593b89766cda57aab9ac311e3616cf87c6fa4e9749df032f66f30dcb8 + url: "https://pub.dev" + source: hosted + version: "0.12.14" + material_color_utilities: + dependency: transitive + description: + name: material_color_utilities + sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724 + url: "https://pub.dev" + source: hosted + version: "0.2.0" + meta: + dependency: transitive + description: + name: meta + sha256: "12307e7f0605ce3da64cf0db90e5fcab0869f3ca03f76be6bb2991ce0a55e82b" + url: "https://pub.dev" + source: hosted + version: "1.9.0" + path: + dependency: transitive + description: + name: path + sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" + url: "https://pub.dev" + source: hosted + version: "1.8.3" + path_provider: + dependency: transitive + description: + name: path_provider + sha256: c7edf82217d4b2952b2129a61d3ad60f1075b9299e629e149a8d2e39c2e6aad4 + url: "https://pub.dev" + source: hosted + version: "2.0.14" + path_provider_android: + dependency: transitive + description: + name: path_provider_android + sha256: "019f18c9c10ae370b08dce1f3e3b73bc9f58e7f087bb5e921f06529438ac0ae7" + url: "https://pub.dev" + source: hosted + version: "2.0.24" + path_provider_foundation: + dependency: transitive + description: + name: path_provider_foundation + sha256: "818b2dc38b0f178e0ea3f7cf3b28146faab11375985d815942a68eee11c2d0f7" + url: "https://pub.dev" + source: hosted + version: "2.2.1" + path_provider_linux: + dependency: transitive + description: + name: path_provider_linux + sha256: "2ae08f2216225427e64ad224a24354221c2c7907e448e6e0e8b57b1eb9f10ad1" + url: "https://pub.dev" + source: hosted + version: "2.1.10" + path_provider_platform_interface: + dependency: transitive + description: + name: path_provider_platform_interface + sha256: "57585299a729335f1298b43245842678cb9f43a6310351b18fb577d6e33165ec" + url: "https://pub.dev" + source: hosted + version: "2.0.6" + path_provider_windows: + dependency: transitive + description: + name: path_provider_windows + sha256: f53720498d5a543f9607db4b0e997c4b5438884de25b0f73098cc2671a51b130 + url: "https://pub.dev" + source: hosted + version: "2.1.5" + platform: + dependency: transitive + description: + name: platform + sha256: "4a451831508d7d6ca779f7ac6e212b4023dd5a7d08a27a63da33756410e32b76" + url: "https://pub.dev" + source: hosted + version: "3.1.0" + plugin_platform_interface: + dependency: transitive + description: + name: plugin_platform_interface + sha256: "6a2128648c854906c53fa8e33986fc0247a1116122f9534dd20e3ab9e16a32bc" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + process: + dependency: transitive + description: + name: process + sha256: "53fd8db9cec1d37b0574e12f07520d582019cb6c44abf5479a01505099a34a09" + url: "https://pub.dev" + source: hosted + version: "4.2.4" + sky_engine: + dependency: transitive + description: flutter + source: sdk + version: "0.0.99" + source_span: + dependency: transitive + description: + name: source_span + sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250 + url: "https://pub.dev" + source: hosted + version: "1.9.1" + stack_trace: + dependency: transitive + description: + name: stack_trace + sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5 + url: "https://pub.dev" + source: hosted + version: "1.11.0" + stream_channel: + dependency: transitive + description: + name: stream_channel + sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + string_scanner: + dependency: transitive + description: + name: string_scanner + sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + url: "https://pub.dev" + source: hosted + version: "1.2.0" + term_glyph: + dependency: transitive + description: + name: term_glyph + sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 + url: "https://pub.dev" + source: hosted + version: "1.2.1" + test_api: + dependency: transitive + description: + name: test_api + sha256: "6182294da5abf431177fccc1ee02401f6df30f766bc6130a0852c6b6d7ee6b2d" + url: "https://pub.dev" + source: hosted + version: "0.4.18" + typed_data: + dependency: transitive + description: + name: typed_data + sha256: "26f87ade979c47a150c9eaab93ccd2bebe70a27dc0b4b29517f2904f04eb11a5" + url: "https://pub.dev" + source: hosted + version: "1.3.1" + vector_math: + dependency: transitive + description: + name: vector_math + sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + win32: + dependency: transitive + description: + name: win32 + sha256: c9ebe7ee4ab0c2194e65d3a07d8c54c5d00bb001b76081c4a04cdb8448b59e46 + url: "https://pub.dev" + source: hosted + version: "3.1.3" + xdg_directories: + dependency: transitive + description: + name: xdg_directories + sha256: ee1505df1426458f7f60aac270645098d318a8b4766d85fde75f76f2e21807d1 + url: "https://pub.dev" + source: hosted + version: "1.0.0" +sdks: + dart: ">=3.0.0-322.0.dev <4.0.0" + flutter: ">=3.0.0" diff --git a/pubspec.yaml b/pubspec.yaml new file mode 100644 index 0000000..3a69500 --- /dev/null +++ b/pubspec.yaml @@ -0,0 +1,24 @@ +name: tuuli_app +description: A new Flutter project. +publish_to: "none" +version: 0.1.0 + +environment: + sdk: ">=3.0.0-322.0.dev <4.0.0" + +dependencies: + flutter: + sdk: flutter + + animated_background: ^2.0.0 + get: ^4.6.5 + get_storage: ^2.1.1 + http: ^0.13.5 + +dev_dependencies: + flutter_test: + sdk: flutter + flutter_lints: ^2.0.0 + +flutter: + uses-material-design: true diff --git a/web/favicon.png b/web/favicon.png new file mode 100644 index 0000000..8aaa46a Binary files /dev/null and b/web/favicon.png differ diff --git a/web/icons/Icon-192.png b/web/icons/Icon-192.png new file mode 100644 index 0000000..b749bfe Binary files /dev/null and b/web/icons/Icon-192.png differ diff --git a/web/icons/Icon-512.png b/web/icons/Icon-512.png new file mode 100644 index 0000000..88cfd48 Binary files /dev/null and b/web/icons/Icon-512.png differ diff --git a/web/icons/Icon-maskable-192.png b/web/icons/Icon-maskable-192.png new file mode 100644 index 0000000..eb9b4d7 Binary files /dev/null and b/web/icons/Icon-maskable-192.png differ diff --git a/web/icons/Icon-maskable-512.png b/web/icons/Icon-maskable-512.png new file mode 100644 index 0000000..d69c566 Binary files /dev/null and b/web/icons/Icon-maskable-512.png differ diff --git a/web/index.html b/web/index.html new file mode 100644 index 0000000..c6ac2e2 --- /dev/null +++ b/web/index.html @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + gws_playground + + + + + + + + + + diff --git a/web/manifest.json b/web/manifest.json new file mode 100644 index 0000000..101df57 --- /dev/null +++ b/web/manifest.json @@ -0,0 +1,35 @@ +{ + "name": "Tuuli", + "short_name": "Tuuli", + "start_url": ".", + "display": "standalone", + "background_color": "#0175C2", + "theme_color": "#0175C2", + "description": "A new Flutter project.", + "orientation": "portrait-primary", + "prefer_related_applications": false, + "icons": [ + { + "src": "icons/Icon-192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "icons/Icon-512.png", + "sizes": "512x512", + "type": "image/png" + }, + { + "src": "icons/Icon-maskable-192.png", + "sizes": "192x192", + "type": "image/png", + "purpose": "maskable" + }, + { + "src": "icons/Icon-maskable-512.png", + "sizes": "512x512", + "type": "image/png", + "purpose": "maskable" + } + ] +}