Done login routine
This commit is contained in:
commit
f9b1b25e91
20 changed files with 983 additions and 0 deletions
44
.gitignore
vendored
Normal file
44
.gitignore
vendored
Normal file
|
|
@ -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
|
||||||
45
.metadata
Normal file
45
.metadata
Normal file
|
|
@ -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'
|
||||||
3
README.md
Normal file
3
README.md
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
# tuuli_app
|
||||||
|
|
||||||
|
A new Flutter project.
|
||||||
1
analysis_options.yaml
Normal file
1
analysis_options.yaml
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
include: package:flutter_lints/flutter.yaml
|
||||||
94
lib/api/api_client.dart
Normal file
94
lib/api/api_client.dart
Normal file
|
|
@ -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<T> {
|
||||||
|
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<T> = Future<ErrorOrData<T>>;
|
||||||
|
|
||||||
|
class ApiClient {
|
||||||
|
final BrowserClient _client = BrowserClient();
|
||||||
|
|
||||||
|
final Uri baseUrl;
|
||||||
|
|
||||||
|
ApiClient(this.baseUrl);
|
||||||
|
|
||||||
|
ApiClient.fromString(String baseUrl) : this(Uri.parse(baseUrl));
|
||||||
|
|
||||||
|
FutureErrorOrData<AccessTokenModel> 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<StreamedResponse> get(
|
||||||
|
String path, {
|
||||||
|
Map<String, String>? headers,
|
||||||
|
}) {
|
||||||
|
return _request(path, 'GET', headers: headers);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<StreamedResponse> post(
|
||||||
|
String path, {
|
||||||
|
Map<String, String>? headers,
|
||||||
|
dynamic body,
|
||||||
|
}) {
|
||||||
|
return _request(path, 'POST', headers: headers, body: body);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<StreamedResponse> _request(
|
||||||
|
String path,
|
||||||
|
String method, {
|
||||||
|
Map<String, String>? 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
7
lib/api/model/access_token_model.dart
Normal file
7
lib/api/model/access_token_model.dart
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
class AccessTokenModel {
|
||||||
|
final String accessToken;
|
||||||
|
|
||||||
|
const AccessTokenModel({
|
||||||
|
required this.accessToken,
|
||||||
|
});
|
||||||
|
}
|
||||||
87
lib/main.dart
Normal file
87
lib/main.dart
Normal file
|
|
@ -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,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
52
lib/pages/checkup_page.dart
Normal file
52
lib/pages/checkup_page.dart
Normal file
|
|
@ -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<StatefulWidget> createState() => _CheckupPageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _CheckupPageState extends State<CheckupPage>
|
||||||
|
with TickerProviderStateMixin {
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
|
||||||
|
final accessToken = GetStorage().read<String?>("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(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
33
lib/pages/home_page.dart
Normal file
33
lib/pages/home_page.dart
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:get/get.dart';
|
||||||
|
|
||||||
|
class HomePage extends StatefulWidget {
|
||||||
|
const HomePage({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<StatefulWidget> createState() => _HomePageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _HomePageState extends State<HomePage> {
|
||||||
|
@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'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
145
lib/pages/login_page.dart
Normal file
145
lib/pages/login_page.dart
Normal file
|
|
@ -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<StatefulWidget> createState() => _LoginPageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _LoginPageState extends State<LoginPage> with TickerProviderStateMixin {
|
||||||
|
final _formKey = GlobalKey<FormState>();
|
||||||
|
|
||||||
|
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<void> _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;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
21
lib/pages/not_found_page.dart
Normal file
21
lib/pages/not_found_page.dart
Normal file
|
|
@ -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,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
333
pubspec.lock
Normal file
333
pubspec.lock
Normal file
|
|
@ -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"
|
||||||
24
pubspec.yaml
Normal file
24
pubspec.yaml
Normal file
|
|
@ -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
|
||||||
BIN
web/favicon.png
Normal file
BIN
web/favicon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 917 B |
BIN
web/icons/Icon-192.png
Normal file
BIN
web/icons/Icon-192.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.2 KiB |
BIN
web/icons/Icon-512.png
Normal file
BIN
web/icons/Icon-512.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 8.1 KiB |
BIN
web/icons/Icon-maskable-192.png
Normal file
BIN
web/icons/Icon-maskable-192.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.5 KiB |
BIN
web/icons/Icon-maskable-512.png
Normal file
BIN
web/icons/Icon-maskable-512.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 20 KiB |
59
web/index.html
Normal file
59
web/index.html
Normal file
|
|
@ -0,0 +1,59 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<!--
|
||||||
|
If you are serving your web app in a path other than the root, change the
|
||||||
|
href value below to reflect the base path you are serving from.
|
||||||
|
|
||||||
|
The path provided below has to start and end with a slash "/" in order for
|
||||||
|
it to work correctly.
|
||||||
|
|
||||||
|
For more details:
|
||||||
|
* https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base
|
||||||
|
|
||||||
|
This is a placeholder for base href that will be replaced by the value of
|
||||||
|
the `--base-href` argument provided to `flutter build`.
|
||||||
|
-->
|
||||||
|
<base href="$FLUTTER_BASE_HREF">
|
||||||
|
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta content="IE=Edge" http-equiv="X-UA-Compatible">
|
||||||
|
<meta name="description" content="A new Flutter project.">
|
||||||
|
|
||||||
|
<!-- iOS meta tags & icons -->
|
||||||
|
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||||
|
<meta name="apple-mobile-web-app-status-bar-style" content="black">
|
||||||
|
<meta name="apple-mobile-web-app-title" content="gws_playground">
|
||||||
|
<link rel="apple-touch-icon" href="icons/Icon-192.png">
|
||||||
|
|
||||||
|
<!-- Favicon -->
|
||||||
|
<link rel="icon" type="image/png" href="favicon.png"/>
|
||||||
|
|
||||||
|
<title>gws_playground</title>
|
||||||
|
<link rel="manifest" href="manifest.json">
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// The value below is injected by flutter build, do not touch.
|
||||||
|
var serviceWorkerVersion = null;
|
||||||
|
</script>
|
||||||
|
<!-- This script adds the flutter initialization JS code -->
|
||||||
|
<script src="flutter.js" defer></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<script>
|
||||||
|
window.addEventListener('load', function(ev) {
|
||||||
|
// Download main.dart.js
|
||||||
|
_flutter.loader.loadEntrypoint({
|
||||||
|
serviceWorker: {
|
||||||
|
serviceWorkerVersion: serviceWorkerVersion,
|
||||||
|
},
|
||||||
|
onEntrypointLoaded: function(engineInitializer) {
|
||||||
|
engineInitializer.initializeEngine().then(function(appRunner) {
|
||||||
|
appRunner.runApp();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
35
web/manifest.json
Normal file
35
web/manifest.json
Normal file
|
|
@ -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"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue