Commit 5d73fef8 by Rizal Hermawan

feat (login): implementation of the login page of the json component using the…

feat (login): implementation of the login page of the json component using the widgetparser package, REST API, json schema validator, and state rebuilder package. Story #1

there are still bugs that need to be fixed. bugs related to the state rebuilder, one of which is the validator textfield.
parent f0064b8a
......@@ -3,7 +3,7 @@
#
# For more info see: https://dart.dev/go/dot-packages-deprecation
#
# Generated by pub on 2021-06-23 14:29:28.997524.
# Generated by pub on 2021-06-28 17:34:00.086929.
async:file:///D:/flutter/2.0.4-stable/.pub-cache/hosted/pub.dartlang.org/async-2.5.0/lib/
boolean_selector:file:///D:/flutter/2.0.4-stable/.pub-cache/hosted/pub.dartlang.org/boolean_selector-2.1.0/lib/
characters:file:///D:/flutter/2.0.4-stable/.pub-cache/hosted/pub.dartlang.org/characters-1.1.0/lib/
......
......@@ -4,8 +4,7 @@
"name": "Flutter",
"program": "example/lib/main.dart",
"request": "launch",
"type": "dart",
"args": ["--no-sound-null-safety"]
"type": "dart"
}
]
}
\ No newline at end of file
## 0.0.8 - 2021-06-06
### feat (login): implementation of the login page of the json component using the widgetparser package, REST API, json schema validator, and state rebuilder package.
* there are still bugs that need to be fixed. bugs related to the state rebuilder, one of which is the validator textfield.
## 0.0.5 - 2021-06-06
### feat (ui component): add and implemet carousel, toggle and toast components.
......
......@@ -3,7 +3,7 @@
#
# For more info see: https://dart.dev/go/dot-packages-deprecation
#
# Generated by pub on 2021-06-23 15:35:44.277132.
# Generated by pub on 2021-06-28 19:37:02.142195.
args:file:///D:/flutter/2.0.4-stable/.pub-cache/hosted/pub.dartlang.org/args-2.1.1/lib/
async:file:///D:/flutter/2.0.4-stable/.pub-cache/hosted/pub.dartlang.org/async-2.5.0/lib/
bloc:file:///D:/flutter/2.0.4-stable/.pub-cache/hosted/pub.dartlang.org/bloc-7.0.0/lib/
......@@ -22,7 +22,6 @@ flutter:file:///D:/flutter/2.0.4-stable/packages/flutter/lib/
flutter_bloc:file:///D:/flutter/2.0.4-stable/.pub-cache/hosted/pub.dartlang.org/flutter_bloc-7.0.1/lib/
flutter_sequence_animation_null_safety:file:///D:/flutter/2.0.4-stable/.pub-cache/git/flutter_sequence_animation_null_safety-773d67311fed31fae22214b385265ae275854495/lib/
flutter_test:file:///D:/flutter/2.0.4-stable/packages/flutter_test/lib/
flutter_user_agent:file:///D:/flutter/2.0.4-stable/.pub-cache/hosted/pub.dartlang.org/flutter_user_agent-1.2.2/lib/
flutter_web_plugins:file:///D:/flutter/2.0.4-stable/packages/flutter_web_plugins/lib/
fluttertoast:file:///D:/flutter/2.0.4-stable/.pub-cache/hosted/pub.dartlang.org/fluttertoast-8.0.7/lib/
font_awesome_flutter:file:///D:/flutter/2.0.4-stable/.pub-cache/hosted/pub.dartlang.org/font_awesome_flutter-9.0.0/lib/
......
......@@ -2,7 +2,8 @@
package="com.demo_package_ui_semantic">
<application
android:label="Demo Package UI Semantic"
android:icon="@mipmap/ic_launcher">
android:icon="@mipmap/ic_launcher"
android:usesCleartextTraffic="true">
<activity
android:name=".MainActivity"
android:launchMode="singleTop"
......
import 'package:flutter/cupertino.dart';
import 'package:flutter/services.dart';
import 'package:fluttertoast/fluttertoast.dart';
// ignore: import_of_legacy_library_into_null_safe
import 'package:flutter_user_agent/flutter_user_agent.dart';
import 'package:llswidget/llswidget.dart';
......
......@@ -100,13 +100,13 @@ showToastWidget(
);
}
Future<String> initUserAgentState() async {
String userAgent;
try {
userAgent = await FlutterUserAgent.getPropertyAsync('userAgent');
await FlutterUserAgent.init();
} on PlatformException {
userAgent = '<error>';
}
return userAgent;
}
\ No newline at end of file
// Future<String> initUserAgentState() async {
// String userAgent;
// try {
// userAgent = await FlutterUserAgent.getPropertyAsync('userAgent');
// await FlutterUserAgent.init();
// } on PlatformException {
// userAgent = '<error>';
// }
// return userAgent;
// }
\ No newline at end of file
......@@ -2,7 +2,6 @@ import 'package:flutter/material.dart';
import 'package:responsive_framework/responsive_framework.dart';
import 'package:states_rebuilder/states_rebuilder.dart';
import 'package:demo_package_ui_semantic/data_source/hive_storage.dart';
import 'route_generator.dart';
import 'ui/pages/pages.dart';
void main() async {
......@@ -12,6 +11,7 @@ void main() async {
print("Error : ${details.exception}");
print("StackTrace : ${details.stack}");
};
RM.navigate.transitionsBuilder = RM.transitions.bottomToUp();
runApp(MyApp());
}
......@@ -58,7 +58,7 @@ class MyApp extends StatelessWidget {
),
home: On.auth(
onInitialWaiting: () => Center(child: CircularProgressIndicator()),
onUnsigned: () => LoginPage(),
onUnsigned: () => LoginDynamicPage(),
onSigned: () => MainPage(),
).listenTo(
user,
......@@ -68,7 +68,7 @@ class MyApp extends StatelessWidget {
onGenerateRoute: RM.navigate.onGenerateRoute(
{
MainPage.routeName: (_) => MainPage(),
LoginPage.routeName: (_) => LoginPage(),
LoginDynamicPage.routeName: (_) => LoginDynamicPage(),
ButtonsPage.routeName: (_) => ButtonsPage(),
StandardsButtonPage.routeName: (_) => StandardsButtonPage(),
LabelPage.routeName: (_) => LabelPage(),
......
......@@ -11,12 +11,10 @@ class AuthRepository implements IAuth<AuthModel?, LoginParam> {
Future<AuthModel?> signIn(LoginParam? param) async {
AuthModel auth;
String url = '${SharedValue.api}/login/store';
String userAgent = await initUserAgentState();
// String userAgent = await initUserAgentState();
var response = await http.post(Uri.parse(url), body: {
"email": param!.email,
"password": param.password
}, headers: {
"User-Agent" : userAgent
});
if (response.statusCode == 200) {
auth = AuthModel.fromJson(response.body);
......@@ -34,11 +32,9 @@ class AuthRepository implements IAuth<AuthModel?, LoginParam> {
@override
Future<String> signOut(LoginParam? param) async {
String url = '${SharedValue.api}/logout?token=${param!.token}';
String userAgent = await initUserAgentState();
// String userAgent = await initUserAgentState();
var response = await http.post(Uri.parse(url), body: {
"userId": param.userId.toString()
}, headers: {
"User-Agent" : userAgent
});
if (response.statusCode == 200) {
return '200';
......
import 'package:flutter/material.dart';
import 'package:llswidget/llswidget.dart';
import 'ui/pages/pages.dart';
class RouteGenerator {
static Route<dynamic> generateRoute(RouteSettings settings) {
//final args = settings.arguments;
switch (settings.name) {
case MainPage.routeName:
return MaterialPageRoute(builder: (_) => MainPage());
case ButtonsPage.routeName:
return MaterialPageRoute(builder: (_) => ButtonsPage());
case StandardsButtonPage.routeName:
return MaterialPageRoute(builder: (_) => StandardsButtonPage());
case LabelPage.routeName:
return MaterialPageRoute(builder: (_) => LabelPage());
case TilesPage.routeName:
return MaterialPageRoute(builder: (_) => TilesPage());
case RoundedButtonPage.routeName:
return MaterialPageRoute(builder: (_) => RoundedButtonPage());
case SquareButtonPage.routeName:
return MaterialPageRoute(builder: (_) => SquareButtonPage());
case ButtonsPageDynamic.routeName:
return MaterialPageRoute(builder: (_) => ButtonsPageDynamic());
case AccordionPage.routeName:
return MaterialPageRoute(builder: (_) => AccordionPage());
case AlertPage.routeName:
return MaterialPageRoute(builder: (_) => AlertPage());
case AppbarHomePage.routeName:
return MaterialPageRoute(builder: (_) => AppbarHomePage());
case AvatarPage.routeName:
return MaterialPageRoute(builder: (_) => AvatarPage());
case BadgesPage.routeName:
return MaterialPageRoute(builder: (_) => BadgesPage());
case IconsButtonsPage.routeName:
return MaterialPageRoute(builder: (_) => IconsButtonsPage());
case CardPage.routeName:
return MaterialPageRoute(builder: (_) => CardPage());
case TestStatePage.routeName:
return MaterialPageRoute(builder: (_) => TestStatePage());
case TabsPage.routeName:
return MaterialPageRoute(builder: (_) => TabsPage());
case SegmentedTabPage.routeName:
return MaterialPageRoute(builder: (_) => SegmentedTabPage());
case IconTabPage.routeName:
return MaterialPageRoute(builder: (_) => IconTabPage());
case LabeledTabPage.routeName:
return MaterialPageRoute(builder: (_) => LabeledTabPage());
case BottomIconTabPage.routeName:
return MaterialPageRoute(builder: (_) => BottomIconTabPage());
case BottomLabeledTabPage.routeName:
return MaterialPageRoute(builder: (_) => BottomLabeledTabPage());
case CarouselPage.routeName:
return MaterialPageRoute(builder: (_) => CarouselPage());
case ToastPage.routeName:
return MaterialPageRoute(builder: (_) => ToastPage());
case TogglePage.routeName:
return MaterialPageRoute(builder: (_) => TogglePage());
default:
// If there is no such named route in the switch statement
return MaterialPageRoute(builder: (context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Text(
'In Progress. Sabar yah :)',
style: TextStyle(fontSize: 20),
),
const SizedBox(
height: 15
),
LLSButton(
onPressed: () {
Navigator.of(context).pop();
},
child: const Text(
'Back',
style: TextStyle(fontSize: 16),
),
type: LLSButtonType.outline,
color: LLSColors.SUCCESS,
),
]
),
)
);
});
}
}
}
part of '../pages.dart';
final user = RM.injectAuth<AuthModel?, LoginParam>(
() => AuthRepository(),
persist: () => PersistState<AuthModel?>(
key: '__AuthModel__',
toJson: (user) => user!.toJson(),
fromJson: (json) {
final user = AuthModel.fromJson(json);
return user.data!.token != null ? user : null;
},
debugPrintOperations: true,
),
autoSignOut: (user) {
if (user!.data == null) {
return Duration(seconds: 5);
}
return Duration(days: 3);
},
onSetState: On.error(
(error, refresh) {
String err = checkError(error.toString());
showToastWidget(
err,
duration: 'long'
);
},
),
);
final RegExp _passwordRegExp = RegExp(
r'^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d]{8,}$',
);
final RegExp _emailRegExp = RegExp(
r'^[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$',
);
final _email = RM.injectTextEditing(
validator: (email) {
if (!_emailRegExp.hasMatch(email!)) {
return "Enter a valid email";
}
},
);
final _password = RM.injectTextEditing(
validateOnTyping: true,
validator: (password) {
if (password!.length < 4) {
return "Enter a valid password";
}
},
);
final _form = RM.injectForm(
submit: () async {
await user.auth.signIn(
(_) => LoginParam(
email: _email.text,
password: _password.text,
),
onError: (error, refresh) {
showToastWidget(
error.message,
duration: 'long'
);
}
);
if (user.error != null) {
showToastWidget(
user.error.message,
duration: 'long'
);
}
},
);
class AuthException implements Exception {
final String message;
AuthException(this.message);
}
class LoginDynamicPage extends StatefulWidget {
const LoginDynamicPage({Key? key}) : super(key: key);
static const routeName = '/login_dynamic_page';
@override
_LoginDynamicPageState createState() => _LoginDynamicPageState();
}
class _LoginDynamicPageState extends State<LoginDynamicPage> {
Map<String, dynamic> variables = {
"listenToFormState": _form,
"emailFieldKey": Key('__EmailField__'),
"emailController": _email.controller,
"emailFocusNode": _email.focusNode,
"emailErrorText": _email.error,
"passwordFieldKey": Key('__PasswordField__'),
"passwordController": _password.controller,
"passwordFocusNode": _password.focusNode,
"passwordErrorText": _password.error,
"submitFocusNode": _form.submitFocusNode
};
final pageJson = '''
{
"widget": "Scaffold",
"body": {
"widget": "Padding",
"padding": "10.0,10.0,10.0,10.0",
"child": {
"widget": "Onform",
"child": {
"widget": "Column",
"mainAxisAlignment": "center",
"crossAxisAlignment": "stretch",
"children": [
{
"widget": "TextField",
"key": "emailFieldKey",
"controller": "emailController",
"focusNode": "emailFocusNode",
"decoration": {
"icon": {
"widget": "Icon",
"data": "email"
},
"labelText": "Email",
"errorText": "emailErrorText"
},
"keyboardType": "emailAddress",
"autocorrect": false,
"onSubmitted": {
"function": "emailOnSubmitted"
}
},
{
"widget": "TextField",
"key": "passwordFieldKey",
"controller": "passwordController",
"focusNode": "passwordFocusNode",
"decoration": {
"icon": {
"widget": "Icon",
"data": "lock"
},
"labelText": "Password",
"errorText": "passwordErrorText"
},
"obscureText": true,
"autocorrect": false,
"onSubmitted": {
"function": "passwordOnSubmitted"
}
},
{
"widget": "SizedBox",
"height": 10.0
},
{
"widget": "OnformSubmission",
"onSubmitting": {
"widget": "Center",
"child": {
"widget": "CircularProgressIndicator"
}
},
"child": {
"widget": "LLSButton",
"size": "small",
"text": "Sign In",
"textColor": "lls_white",
"onPressed": {
"function": "submitOnPressed"
}
},
"state": "listenToFormState"
},
{
"widget": "SizedBox",
"height": 10.0
}
]
},
"state": "listenToFormState"
}
}
}
''';
Widget _buildErrorPage(String error, BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
error,
style: TextStyle(fontSize: 14),
),
),
const SizedBox(
height: 15
),
LLSButton(
onPressed: () {
Navigator.of(context).pop();
},
child: const Text(
'Back',
style: TextStyle(fontSize: 16),
),
type: LLSButtonType.outline,
color: LLSColors.SUCCESS,
),
]
),
)
);
}
Future<Widget?> _buildWidget(BuildContext context) async {
try {
return WidgetParserBuilder.build(pageJson, context, LoginPageMethodListener(), variables);
} catch (e) {
String err = e.toString();
return _buildErrorPage(err, context);
}
}
@override
Widget build(BuildContext context) {
return FutureBuilder<Widget?>(
future: _buildWidget(context),
builder: (BuildContext context, AsyncSnapshot<Widget?> snapshot) {
if (snapshot.hasError) {
return _buildErrorPage(snapshot.error.toString(), context);
}
return snapshot.hasData ? snapshot.data! : Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
CircularProgressIndicator()
]
),
)
);
},
);
}
}
class LoginPageMethodListener extends MethodListener {
@override
run(BuildContext context, Map<String, dynamic>? event) {
if (isFunctionNameExist(event)) {
if (event!['function'] == 'emailOnSubmitted') {
_password.focusNode.requestFocus();
} else if (event['function'] == 'passwordOnSubmitted') {
_form.submitFocusNode.requestFocus();
} else if (event['function'] == 'submitOnPressed') {
_form.submit();
}
} else {
print("receiver event: ${event.toString()}");
}
}
}
\ No newline at end of file
part of '../pages.dart';
// part of '../pages.dart';
final user = RM.injectAuth<AuthModel?, LoginParam>(
() => AuthRepository(),
persist: () => PersistState<AuthModel?>(
key: '__AuthModel__',
toJson: (user) => user!.toJson(),
fromJson: (json) {
final user = AuthModel.fromJson(json);
return user.data!.token != null ? user : null;
},
debugPrintOperations: true,
),
autoSignOut: (user) {
if (user!.data == null) {
return Duration(seconds: 5);
}
return Duration(days: 3);
},
onSetState: On.error(
(error, refresh) {
String err = checkError(error.toString());
showToastWidget(
err,
duration: 'long'
);
},
),
);
// final user = RM.injectAuth<AuthModel?, LoginParam>(
// () => AuthRepository(),
// persist: () => PersistState<AuthModel?>(
// key: '__AuthModel__',
// toJson: (user) => user!.toJson(),
// fromJson: (json) {
// final user = AuthModel.fromJson(json);
// return user.data!.token != null ? user : null;
// },
// debugPrintOperations: true,
// ),
// autoSignOut: (user) {
// if (user!.data == null) {
// return Duration(seconds: 5);
// }
// return Duration(days: 3);
// },
// onSetState: On.error(
// (error, refresh) {
// String err = checkError(error.toString());
// showToastWidget(
// err,
// duration: 'long'
// );
// },
// ),
// );
final RegExp _passwordRegExp = RegExp(
r'^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d]{8,}$',
);
// final RegExp _passwordRegExp = RegExp(
// r'^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d]{8,}$',
// );
final RegExp _emailRegExp = RegExp(
r'^[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$',
);
// final RegExp _emailRegExp = RegExp(
// r'^[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$',
// );
final _email = RM.injectTextEditing(
validator: (email) {
if (!_emailRegExp.hasMatch(email!)) {
return "Enter a valid email";
}
},
);
final _password = RM.injectTextEditing(
validateOnTyping: true,
validator: (password) {
if (password!.length < 4) {
return "Enter a valid password";
}
},
);
// final _email = RM.injectTextEditing(
// validator: (email) {
// if (!_emailRegExp.hasMatch(email!)) {
// return "Enter a valid email";
// }
// },
// );
// final _password = RM.injectTextEditing(
// validateOnTyping: true,
// validator: (password) {
// if (password!.length < 4) {
// return "Enter a valid password";
// }
// },
// );
final _form = RM.injectForm(
submit: () async {
await user.auth.signIn(
(_) => LoginParam(
email: _email.text,
password: _password.text,
),
onError: (error, refresh) {
showToastWidget(
error.message,
duration: 'long'
);
}
);
if (user.error != null) {
showToastWidget(
user.error.message,
duration: 'long'
);
}
},
);
// final _form = RM.injectForm(
// submit: () async {
// await user.auth.signIn(
// (_) => LoginParam(
// email: _email.text,
// password: _password.text,
// ),
// onError: (error, refresh) {
// showToastWidget(
// error.message,
// duration: 'long'
// );
// }
// );
// if (user.error != null) {
// showToastWidget(
// user.error.message,
// duration: 'long'
// );
// }
// },
// );
class AuthException implements Exception {
final String message;
AuthException(this.message);
}
// class AuthException implements Exception {
// final String message;
// AuthException(this.message);
// }
class LoginPage extends StatelessWidget {
const LoginPage({Key? key}) : super(key: key);
static const routeName = '/login_page';
// class LoginPage extends StatelessWidget {
// const LoginPage({Key? key}) : super(key: key);
// static const routeName = '/login_page';
@override
Widget build(BuildContext context) {
return Scaffold(
body: Padding(
padding: EdgeInsets.all(10),
child: On.form(
() => Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
TextField(
key: Key('__EmailField__'),
controller: _email.controller,
focusNode: _email.focusNode,
decoration: InputDecoration(
icon: Icon(Icons.email),
labelText: "Email",
errorText: _email.error,
),
keyboardType: TextInputType.emailAddress,
autocorrect: false,
onSubmitted: (_) {
_password.focusNode.requestFocus();
},
),
TextField(
key: Key('__PasswordField__'),
controller: _password.controller,
focusNode: _password.focusNode,
decoration: InputDecoration(
icon: Icon(Icons.lock),
labelText: "Password",
errorText: _password.error,
),
obscureText: true,
autocorrect: false,
onSubmitted: (_) {
_form.submitFocusNode.requestFocus();
},
),
SizedBox(height: 10),
On.formSubmission(
onSubmitting: () => const Center(
child: CircularProgressIndicator(),
),
child: ElevatedButton(
focusNode: _form.submitFocusNode,
child: Text("Sign in"),
onPressed: _form.submit,
),
).listenTo(_form),
SizedBox(height: 10),
SelectableText("email : ${SharedValue.email}"),
SelectableText("password : ${SharedValue.password}"),
],
),
).listenTo(_form)
)
);
}
}
\ No newline at end of file
// @override
// Widget build(BuildContext context) {
// return Scaffold(
// body: Padding(
// padding: EdgeInsets.all(10),
// child: On.form(
// () => Column(
// mainAxisAlignment: MainAxisAlignment.center,
// crossAxisAlignment: CrossAxisAlignment.stretch,
// children: <Widget>[
// TextField(
// key: Key('__EmailField__'),
// controller: _email.controller,
// focusNode: _email.focusNode,
// decoration: InputDecoration(
// icon: Icon(Icons.email),
// labelText: "Email",
// errorText: _email.error,
// ),
// keyboardType: TextInputType.emailAddress,
// autocorrect: false,
// onSubmitted: (_) {
// _password.focusNode.requestFocus();
// },
// ),
// TextField(
// key: Key('__PasswordField__'),
// controller: _password.controller,
// focusNode: _password.focusNode,
// decoration: InputDecoration(
// icon: Icon(Icons.lock),
// labelText: "Password",
// errorText: _password.error,
// ),
// obscureText: true,
// autocorrect: false,
// onSubmitted: (_) {
// _form.submitFocusNode.requestFocus();
// },
// ),
// SizedBox(height: 10),
// On.formSubmission(
// onSubmitting: () => const Center(
// child: CircularProgressIndicator(),
// ),
// child: ElevatedButton(
// focusNode: _form.submitFocusNode,
// child: Text("Sign in"),
// onPressed: _form.submit,
// ),
// ).listenTo(_form),
// SizedBox(height: 10),
// SelectableText("email : ${SharedValue.email}"),
// SelectableText("password : ${SharedValue.password}"),
// ],
// ),
// ).listenTo(_form)
// )
// );
// }
// }
\ No newline at end of file
......@@ -37,4 +37,5 @@ part 'tabs_page/bottom_labeled_tab_page.dart';
part 'carousel_page.dart';
part 'toast_page.dart';
part 'toggle_page.dart';
part 'auth/login_page.dart';
\ No newline at end of file
//part 'auth/login_page.dart';
part 'auth/login_dynamic_page.dart';
\ No newline at end of file
......@@ -44,7 +44,7 @@ class _TilesPageState extends State<TilesPage> {
LLSCard(
content: LLSListTile(
titleText: 'Title',
subTitleText: 'Open source UI library',
subTitleText: 'PT Locator Logic Solutions',
icon: Icon(Icons.favorite),
),
),
......@@ -73,7 +73,7 @@ class _TilesPageState extends State<TilesPage> {
shape: LLSAvatarShape.circle,
),
titleText: 'Title',
subTitleText: 'Open source UI library',
subTitleText: 'PT Locator Logic Solutions',
),
),
const LLSCard(
......
......@@ -125,13 +125,6 @@ packages:
description: flutter
source: sdk
version: "0.0.0"
flutter_user_agent:
dependency: "direct main"
description:
name: flutter_user_agent
url: "https://pub.dartlang.org"
source: hosted
version: "1.2.2"
flutter_web_plugins:
dependency: transitive
description: flutter
......@@ -213,7 +206,7 @@ packages:
path: ".."
relative: true
source: path
version: "0.0.5"
version: "0.0.8"
logging:
dependency: transitive
description:
......@@ -360,7 +353,7 @@ packages:
source: hosted
version: "1.10.0"
states_rebuilder:
dependency: "direct main"
dependency: transitive
description:
name: states_rebuilder
url: "https://pub.dartlang.org"
......@@ -428,7 +421,7 @@ packages:
path: "../../widgetparser"
relative: true
source: path
version: "0.0.1"
version: "0.0.6"
win32:
dependency: transitive
description:
......
......@@ -31,9 +31,7 @@ dependencies:
flutter_bloc: 7.0.1
equatable: 1.1.1
http: 0.13.0
states_rebuilder: 4.3.0
fluttertoast: 8.0.7
flutter_user_agent: 1.2.2
hive: 2.0.4
hive_flutter: 1.1.0
......
name: llswidget
description: A Flutter UI Components package.
version: 0.0.5
version: 0.0.8
author: Rizal Hermawan
homepage: https://locatorlogic.com
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment