From 0f23c4d0f358005f4d220ed38bd466f7b59e1a4b Mon Sep 17 00:00:00 2001 From: konrad Date: Sun, 12 Jan 2020 12:59:28 +0000 Subject: [PATCH] Make it build again (#38) Fix parsing of user model if email is not present Use user avatar hash instead of calculating it from the email Format Replace GravatarImageProvider Set min sdk version to 19 Change target api version to 28 Limit drone pipeline execution to master or pr Remove drone debug Use username instead of id Format "Fix" clone permissions Drone debug Fix drone permissions with different flutter build docker image Switch CI build image Bump Gradle sdk version Fix formatting Update packages for support for androidX Update gitignore AndroidX Make GravatarImageProvider work again Co-authored-by: kolaente Reviewed-on: https://kolaente.dev/vikunja/app/pulls/38 --- .drone.yml | 47 ++++-- .gitignore | 1 + android/app/build.gradle | 8 +- android/build.gradle | 2 - android/gradle.properties | 3 + android/settings_aar.gradle | 1 + ios/Flutter/flutter_export_environment.sh | 10 ++ lib/components/GravatarImage.dart | 9 - lib/global.dart | 4 +- lib/models/user.dart | 13 +- lib/pages/home.dart | 18 +- lib/pages/list/list_edit.dart | 120 +++++++------- lib/pages/namespace/namespace_edit.dart | 120 +++++++------- lib/pages/user/login.dart | 148 ++++++++--------- lib/pages/user/register.dart | 193 +++++++++++----------- lib/service/mocked_services.dart | 2 +- pubspec.lock | 48 +++--- pubspec.yaml | 11 +- 18 files changed, 387 insertions(+), 371 deletions(-) create mode 100644 android/settings_aar.gradle create mode 100755 ios/Flutter/flutter_export_environment.sh delete mode 100644 lib/components/GravatarImage.dart diff --git a/.drone.yml b/.drone.yml index b42ef20..9422ffe 100644 --- a/.drone.yml +++ b/.drone.yml @@ -2,16 +2,27 @@ kind: pipeline name: testing workspace: - base: /app + base: /home/cirrus/app clone: depth: 50 +# Only run on prs or pushes to master +trigger: + branch: + include: + - master + event: + include: + - push + - pull_request + steps: - name: build - image: vikunja/flutter-build + image: cirrusci/flutter:stable pull: true commands: + - sudo chown cirrus . -R # The clone step clones everything as root, this is our "fix" until we find a better solution - flutter packages get - make format-check - make build-debug @@ -32,12 +43,12 @@ depends_on: trigger: branch: - - master + - master event: - - push + - push workspace: - base: /app + base: /home/cirrus/app clone: depth: 50 @@ -45,13 +56,14 @@ clone: steps: # Because drone separates the pipelines, we have to add the build step to this pipeline. This is double code, we should change it at some point if possible. - name: build - image: vikunja/flutter-build + image: cirrusci/flutter:stable pull: true commands: - - flutter packages get - - make build-all - - mkdir apks - - mv build/app/outputs/apk/*/*/*.apk apks + - sudo chown cirrus . -R # The clone step clones everything as root, this is our "fix" until we find a better solution + - flutter packages get + - make build-all + - mkdir apks + - mv build/app/outputs/apk/*/*/*.apk apks # Push the releases to our pseudo-s3-bucket - name: release @@ -78,10 +90,10 @@ depends_on: trigger: event: - - tag + - tag workspace: - base: /app + base: /home/cirrus/app clone: depth: 50 @@ -89,13 +101,14 @@ clone: steps: # Because drone separates the pipelines, we have to add the build step to this pipeline. This is double code, we should change it at some point if possible. - name: build - image: vikunja/flutter-build + image: cirrusci/flutter:stable pull: true commands: - - flutter packages get - - make build-all - - mkdir apks - - mv build/app/outputs/apk/*/*/*.apk apks + - sudo chown cirrus . -R # The clone step clones everything as root, this is our "fix" until we find a better solution + - flutter packages get + - make build-all + - mkdir apks + - mv build/app/outputs/apk/*/*/*.apk apks # Push the releases to our pseudo-s3-bucket - name: release image: plugins/s3:1 diff --git a/.gitignore b/.gitignore index 816ad73..b0658dd 100644 --- a/.gitignore +++ b/.gitignore @@ -28,6 +28,7 @@ .pub/ build/ !pubspec.lock +.flutter-plugins-dependencies # Android related **/android/**/gradle-wrapper.jar diff --git a/android/app/build.gradle b/android/app/build.gradle index f8df111..9e084af 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -26,7 +26,7 @@ apply plugin: 'kotlin-android' apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" android { - compileSdkVersion 27 + compileSdkVersion 28 sourceSets { main.java.srcDirs += 'src/main/kotlin' @@ -37,14 +37,12 @@ android { } defaultConfig { - // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). applicationId "io.vikunja.app" - minSdkVersion 18 - targetSdkVersion 27 + minSdkVersion 19 + targetSdkVersion 28 versionCode flutterVersionCode.toInteger() versionName flutterVersionName testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" - } flavorDimensions "deploy" diff --git a/android/build.gradle b/android/build.gradle index 830798d..cfc1d0e 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -21,8 +21,6 @@ allprojects { rootProject.buildDir = '../build' subprojects { project.buildDir = "${rootProject.buildDir}/${project.name}" -} -subprojects { project.evaluationDependsOn(':app') } diff --git a/android/gradle.properties b/android/gradle.properties index 8bd86f6..38c8d45 100644 --- a/android/gradle.properties +++ b/android/gradle.properties @@ -1 +1,4 @@ org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +android.useAndroidX=true +android.enableJetifier=true diff --git a/android/settings_aar.gradle b/android/settings_aar.gradle new file mode 100644 index 0000000..e7b4def --- /dev/null +++ b/android/settings_aar.gradle @@ -0,0 +1 @@ +include ':app' diff --git a/ios/Flutter/flutter_export_environment.sh b/ios/Flutter/flutter_export_environment.sh new file mode 100755 index 0000000..ba8483e --- /dev/null +++ b/ios/Flutter/flutter_export_environment.sh @@ -0,0 +1,10 @@ +#!/bin/sh +# This is a generated file; do not edit or check into version control. +export "FLUTTER_ROOT=/nix/store/nyvp7jf7sfxsbc6jsm1y4fc18631ap26-flutter-stable-1.12.13+hotfix.5-unwrapped" +export "FLUTTER_APPLICATION_PATH=/home/konrad/www/vikunja/app2" +export "FLUTTER_TARGET=lib/main.dart" +export "FLUTTER_BUILD_DIR=build" +export "SYMROOT=${SOURCE_ROOT}/../build/ios" +export "FLUTTER_FRAMEWORK_DIR=/home/konrad/.cache/flutter/artifacts/engine/ios" +export "FLUTTER_BUILD_NAME=0.1.0" +export "FLUTTER_BUILD_NUMBER=0.1.0" diff --git a/lib/components/GravatarImage.dart b/lib/components/GravatarImage.dart deleted file mode 100644 index a3f4efc..0000000 --- a/lib/components/GravatarImage.dart +++ /dev/null @@ -1,9 +0,0 @@ -import 'package:flutter/material.dart'; - -import 'package:crypto/crypto.dart'; - -class GravatarImageProvider extends NetworkImage { - GravatarImageProvider(String email) - : super("https://secure.gravatar.com/avatar/" + - md5.convert(email.trim().toLowerCase().codeUnits).toString()); -} diff --git a/lib/global.dart b/lib/global.dart index 061ae99..0f8081a 100644 --- a/lib/global.dart +++ b/lib/global.dart @@ -120,9 +120,9 @@ class VikunjaGlobalState extends State { }); return; } - loadedCurrentUser = User(int.tryParse(currentUser), "", ""); + loadedCurrentUser = User(int.tryParse(currentUser), "", "", ""); } catch (otherExceptions) { - loadedCurrentUser = User(int.tryParse(currentUser), "", ""); + loadedCurrentUser = User(int.tryParse(currentUser), "", "", ""); } setState(() { _client = client; diff --git a/lib/models/user.dart b/lib/models/user.dart index 464d897..17f7639 100644 --- a/lib/models/user.dart +++ b/lib/models/user.dart @@ -1,14 +1,19 @@ class User { final int id; - final String email, username; + final String email, username, avatarHash; - User(this.id, this.email, this.username); + User(this.id, this.email, this.username, this.avatarHash); User.fromJson(Map json) : id = json['id'], - email = json['email'], - username = json['username']; + email = json.containsKey('email') ? json['email'] : '', + username = json['username'], + avatarHash = json['avatarUrl']; toJSON() => {"id": this.id, "email": this.email, "username": this.username}; + + String avatarUrl() { + return "https://secure.gravatar.com/avatar/" + this.avatarHash; + } } class UserTokenPair { diff --git a/lib/pages/home.dart b/lib/pages/home.dart index 54210cc..e37c07e 100644 --- a/lib/pages/home.dart +++ b/lib/pages/home.dart @@ -4,7 +4,6 @@ import 'package:flutter/material.dart'; import 'package:after_layout/after_layout.dart'; import 'package:vikunja_app/components/AddDialog.dart'; -import 'package:vikunja_app/components/GravatarImage.dart'; import 'package:vikunja_app/pages/namespace/namespace.dart'; import 'package:vikunja_app/pages/namespace/namespace_edit.dart'; import 'package:vikunja_app/pages/placeholder.dart'; @@ -90,8 +89,10 @@ class HomePageState extends State with AfterLayoutMixin { drawer: new Drawer( child: new Column(children: [ new UserAccountsDrawerHeader( - accountEmail: currentUser == null ? null : Text(currentUser.email), - accountName: currentUser == null ? null : Text(currentUser.username), + accountEmail: + currentUser?.email == null ? null : Text(currentUser.email), + accountName: + currentUser?.username == null ? null : Text(currentUser.username), onDetailsPressed: () { setState(() { _showUserDetails = !_showUserDetails; @@ -100,7 +101,8 @@ class HomePageState extends State with AfterLayoutMixin { currentAccountPicture: currentUser == null ? null : CircleAvatar( - backgroundImage: GravatarImageProvider(currentUser.username)), + backgroundImage: NetworkImage(currentUser.avatarUrl()), + ), decoration: BoxDecoration( image: DecorationImage( image: AssetImage("assets/graphics/hypnotize.png"), @@ -118,10 +120,10 @@ class HomePageState extends State with AfterLayoutMixin { alignment: FractionalOffset.bottomCenter, child: Builder( builder: (context) => ListTile( - leading: const Icon(Icons.add), - title: const Text('Add namespace...'), - onTap: () => _addNamespaceDialog(context), - ), + leading: const Icon(Icons.add), + title: const Text('Add namespace...'), + onTap: () => _addNamespaceDialog(context), + ), ), ), ])), diff --git a/lib/pages/list/list_edit.dart b/lib/pages/list/list_edit.dart index 7b0682f..b151e96 100644 --- a/lib/pages/list/list_edit.dart +++ b/lib/pages/list/list_edit.dart @@ -26,68 +26,68 @@ class _ListEditPageState extends State { ), body: Builder( builder: (BuildContext context) => SafeArea( - child: Form( - key: _formKey, - child: ListView( - padding: const EdgeInsets.all(16.0), - children: [ - Padding( - padding: EdgeInsets.symmetric(vertical: 10.0), - child: TextFormField( - maxLines: null, - keyboardType: TextInputType.multiline, - initialValue: widget.list.title, - onSaved: (title) => _title = title, - validator: (title) { - if (title.length < 3 || title.length > 250) { - return 'The title needs to have between 3 and 250 characters.'; - } - return null; - }, - decoration: new InputDecoration( - labelText: 'Title', - border: OutlineInputBorder(), - ), - ), + child: Form( + key: _formKey, + child: ListView( + padding: const EdgeInsets.all(16.0), + children: [ + Padding( + padding: EdgeInsets.symmetric(vertical: 10.0), + child: TextFormField( + maxLines: null, + keyboardType: TextInputType.multiline, + initialValue: widget.list.title, + onSaved: (title) => _title = title, + validator: (title) { + if (title.length < 3 || title.length > 250) { + return 'The title needs to have between 3 and 250 characters.'; + } + return null; + }, + decoration: new InputDecoration( + labelText: 'Title', + border: OutlineInputBorder(), ), - Padding( - padding: EdgeInsets.symmetric(vertical: 10.0), - child: TextFormField( - maxLines: null, - keyboardType: TextInputType.multiline, - initialValue: widget.list.description, - onSaved: (description) => _description = description, - validator: (description) { - if (description.length > 1000) { - return 'The description can have a maximum of 1000 characters.'; - } - return null; - }, - decoration: new InputDecoration( - labelText: 'Description', - border: OutlineInputBorder(), - ), - ), + ), + ), + Padding( + padding: EdgeInsets.symmetric(vertical: 10.0), + child: TextFormField( + maxLines: null, + keyboardType: TextInputType.multiline, + initialValue: widget.list.description, + onSaved: (description) => _description = description, + validator: (description) { + if (description.length > 1000) { + return 'The description can have a maximum of 1000 characters.'; + } + return null; + }, + decoration: new InputDecoration( + labelText: 'Description', + border: OutlineInputBorder(), ), - Builder( - builder: (context) => Padding( - padding: EdgeInsets.symmetric(vertical: 10.0), - child: FancyButton( - onPressed: !_loading - ? () { - if (_formKey.currentState.validate()) { - Form.of(context).save(); - _saveList(context); - } - } - : null, - child: _loading - ? CircularProgressIndicator() - : VikunjaButtonText('Save'), - ))), - ]), - ), - ), + ), + ), + Builder( + builder: (context) => Padding( + padding: EdgeInsets.symmetric(vertical: 10.0), + child: FancyButton( + onPressed: !_loading + ? () { + if (_formKey.currentState.validate()) { + Form.of(context).save(); + _saveList(context); + } + } + : null, + child: _loading + ? CircularProgressIndicator() + : VikunjaButtonText('Save'), + ))), + ]), + ), + ), ), ); } diff --git a/lib/pages/namespace/namespace_edit.dart b/lib/pages/namespace/namespace_edit.dart index d27cca1..a9d21cd 100644 --- a/lib/pages/namespace/namespace_edit.dart +++ b/lib/pages/namespace/namespace_edit.dart @@ -26,68 +26,68 @@ class _NamespaceEditPageState extends State { ), body: Builder( builder: (BuildContext context) => SafeArea( - child: Form( - key: _formKey, - child: ListView( - padding: const EdgeInsets.all(16.0), - children: [ - Padding( - padding: EdgeInsets.symmetric(vertical: 10.0), - child: TextFormField( - maxLines: null, - keyboardType: TextInputType.multiline, - initialValue: widget.namespace.name, - onSaved: (name) => _name = name, - validator: (name) { - if (name.length < 3 || name.length > 250) { - return 'The name needs to have between 3 and 250 characters.'; - } - return null; - }, - decoration: new InputDecoration( - labelText: 'Name', - border: OutlineInputBorder(), - ), - ), + child: Form( + key: _formKey, + child: ListView( + padding: const EdgeInsets.all(16.0), + children: [ + Padding( + padding: EdgeInsets.symmetric(vertical: 10.0), + child: TextFormField( + maxLines: null, + keyboardType: TextInputType.multiline, + initialValue: widget.namespace.name, + onSaved: (name) => _name = name, + validator: (name) { + if (name.length < 3 || name.length > 250) { + return 'The name needs to have between 3 and 250 characters.'; + } + return null; + }, + decoration: new InputDecoration( + labelText: 'Name', + border: OutlineInputBorder(), ), - Padding( - padding: EdgeInsets.symmetric(vertical: 10.0), - child: TextFormField( - maxLines: null, - keyboardType: TextInputType.multiline, - initialValue: widget.namespace.description, - onSaved: (description) => _description = description, - validator: (description) { - if (description.length > 1000) { - return 'The description can have a maximum of 1000 characters.'; - } - return null; - }, - decoration: new InputDecoration( - labelText: 'Description', - border: OutlineInputBorder(), - ), - ), + ), + ), + Padding( + padding: EdgeInsets.symmetric(vertical: 10.0), + child: TextFormField( + maxLines: null, + keyboardType: TextInputType.multiline, + initialValue: widget.namespace.description, + onSaved: (description) => _description = description, + validator: (description) { + if (description.length > 1000) { + return 'The description can have a maximum of 1000 characters.'; + } + return null; + }, + decoration: new InputDecoration( + labelText: 'Description', + border: OutlineInputBorder(), ), - Builder( - builder: (context) => Padding( - padding: EdgeInsets.symmetric(vertical: 10.0), - child: FancyButton( - onPressed: !_loading - ? () { - if (_formKey.currentState.validate()) { - Form.of(context).save(); - _saveNamespace(context); - } - } - : null, - child: _loading - ? CircularProgressIndicator() - : VikunjaButtonText('Save'), - ))), - ]), - ), - ), + ), + ), + Builder( + builder: (context) => Padding( + padding: EdgeInsets.symmetric(vertical: 10.0), + child: FancyButton( + onPressed: !_loading + ? () { + if (_formKey.currentState.validate()) { + Form.of(context).save(); + _saveNamespace(context); + } + } + : null, + child: _loading + ? CircularProgressIndicator() + : VikunjaButtonText('Save'), + ))), + ]), + ), + ), ), ); } diff --git a/lib/pages/user/login.dart b/lib/pages/user/login.dart index 411d92f..aca7e76 100644 --- a/lib/pages/user/login.dart +++ b/lib/pages/user/login.dart @@ -24,83 +24,81 @@ class _LoginPageState extends State { padding: const EdgeInsets.all(16.0), child: Builder( builder: (BuildContext context) => Form( - autovalidate: true, - key: _formKey, - child: Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Padding( - padding: EdgeInsets.symmetric(vertical: 30), - child: Image( - image: AssetImage('assets/vikunja_logo_full.png'), - height: 85.0, - semanticLabel: 'Vikunja Logo', - ), - ), - Padding( - padding: vStandardVerticalPadding, - child: TextFormField( - enabled: !_loading, - onSaved: (serverAddress) => _server = serverAddress, - validator: (address) { - return isUrl(address) ? null : 'Invalid URL'; - }, - decoration: new InputDecoration( - border: OutlineInputBorder(), - labelText: 'Server Address'), - ), - ), - Padding( - padding: vStandardVerticalPadding, - child: TextFormField( - enabled: !_loading, - onSaved: (username) => _username = username, - decoration: new InputDecoration( - border: OutlineInputBorder(), - labelText: 'Username'), - ), - ), - Padding( - padding: vStandardVerticalPadding, - child: TextFormField( - enabled: !_loading, - onSaved: (password) => _password = password, - decoration: new InputDecoration( - border: OutlineInputBorder(), - labelText: 'Password'), - obscureText: true, - ), - ), - Builder( - builder: (context) => FancyButton( - onPressed: !_loading - ? () { - if (_formKey.currentState - .validate()) { - Form.of(context).save(); - _loginUser(context); - } - } - : null, - child: _loading - ? CircularProgressIndicator() - : VikunjaButtonText('Login'), - )), - Builder( - builder: (context) => FancyButton( - onPressed: () => Navigator.push( - context, - MaterialPageRoute( - builder: (context) => - RegisterPage())), - child: VikunjaButtonText('Register'), - )), - ], + autovalidate: true, + key: _formKey, + child: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Padding( + padding: EdgeInsets.symmetric(vertical: 30), + child: Image( + image: AssetImage('assets/vikunja_logo_full.png'), + height: 85.0, + semanticLabel: 'Vikunja Logo', + ), ), - ), + Padding( + padding: vStandardVerticalPadding, + child: TextFormField( + enabled: !_loading, + onSaved: (serverAddress) => _server = serverAddress, + validator: (address) { + return isUrl(address) ? null : 'Invalid URL'; + }, + decoration: new InputDecoration( + border: OutlineInputBorder(), + labelText: 'Server Address'), + ), + ), + Padding( + padding: vStandardVerticalPadding, + child: TextFormField( + enabled: !_loading, + onSaved: (username) => _username = username, + decoration: new InputDecoration( + border: OutlineInputBorder(), + labelText: 'Username'), + ), + ), + Padding( + padding: vStandardVerticalPadding, + child: TextFormField( + enabled: !_loading, + onSaved: (password) => _password = password, + decoration: new InputDecoration( + border: OutlineInputBorder(), + labelText: 'Password'), + obscureText: true, + ), + ), + Builder( + builder: (context) => FancyButton( + onPressed: !_loading + ? () { + if (_formKey.currentState.validate()) { + Form.of(context).save(); + _loginUser(context); + } + } + : null, + child: _loading + ? CircularProgressIndicator() + : VikunjaButtonText('Login'), + )), + Builder( + builder: (context) => FancyButton( + onPressed: () => Navigator.push( + context, + MaterialPageRoute( + builder: (context) => RegisterPage())), + child: VikunjaButtonText('Register'), + )), + ], ), + ), + ), ), ), ), diff --git a/lib/pages/user/register.dart b/lib/pages/user/register.dart index 7d48285..fb9c0a7 100644 --- a/lib/pages/user/register.dart +++ b/lib/pages/user/register.dart @@ -24,103 +24,102 @@ class _RegisterPageState extends State { ), body: Builder( builder: (BuildContext context) => SafeArea( - top: false, - bottom: false, - child: Form( - key: _formKey, - child: ListView( - padding: const EdgeInsets.all(16), - children: [ - Padding( - padding: vStandardVerticalPadding, - child: TextFormField( - onSaved: (serverAddress) => _server = serverAddress, - validator: (address) { - return isUrl(address) ? null : 'Invalid URL'; - }, - decoration: new InputDecoration( - border: OutlineInputBorder(), - labelText: 'Server Address'), - ), - ), - Padding( - padding: vStandardVerticalPadding, - child: TextFormField( - onSaved: (username) => _username = username.trim(), - validator: (username) { - return username.trim().isNotEmpty - ? null - : 'Please specify a username'; - }, - decoration: new InputDecoration( - border: OutlineInputBorder(), - labelText: 'Username'), - ), - ), - Padding( - padding: vStandardVerticalPadding, - child: TextFormField( - onSaved: (email) => _email = email, - validator: (email) { - return isEmail(email) - ? null - : 'Email adress is invalid'; - }, - decoration: new InputDecoration( - border: OutlineInputBorder(), - labelText: 'Email Address'), - ), - ), - Padding( - padding: vStandardVerticalPadding, - child: TextFormField( - controller: passwordController, - onSaved: (password) => _password = password, - validator: (password) { - return password.length >= 8 - ? null - : 'Please use at least 8 characters'; - }, - decoration: new InputDecoration( - border: OutlineInputBorder(), - labelText: 'Password'), - obscureText: true, - ), - ), - Padding( - padding: vStandardVerticalPadding, - child: TextFormField( - validator: (password) { - return passwordController.text == password - ? null - : 'Passwords don\'t match.'; - }, - decoration: new InputDecoration( - border: OutlineInputBorder(), - labelText: 'Repeat Password'), - obscureText: true, - ), - ), - Builder( - builder: (context) => FancyButton( - onPressed: !_loading - ? () { - if (_formKey.currentState - .validate()) { - Form.of(context).save(); - _registerUser(context); - } else { - print("awhat"); - } - } - : null, - child: _loading - ? CircularProgressIndicator() - : VikunjaButtonText('Register'), - )), - ], - )), - ), + top: false, + bottom: false, + child: Form( + key: _formKey, + child: ListView( + padding: const EdgeInsets.all(16), + children: [ + Padding( + padding: vStandardVerticalPadding, + child: TextFormField( + onSaved: (serverAddress) => _server = serverAddress, + validator: (address) { + return isUrl(address) ? null : 'Invalid URL'; + }, + decoration: new InputDecoration( + border: OutlineInputBorder(), + labelText: 'Server Address'), + ), + ), + Padding( + padding: vStandardVerticalPadding, + child: TextFormField( + onSaved: (username) => _username = username.trim(), + validator: (username) { + return username.trim().isNotEmpty + ? null + : 'Please specify a username'; + }, + decoration: new InputDecoration( + border: OutlineInputBorder(), + labelText: 'Username'), + ), + ), + Padding( + padding: vStandardVerticalPadding, + child: TextFormField( + onSaved: (email) => _email = email, + validator: (email) { + return isEmail(email) + ? null + : 'Email adress is invalid'; + }, + decoration: new InputDecoration( + border: OutlineInputBorder(), + labelText: 'Email Address'), + ), + ), + Padding( + padding: vStandardVerticalPadding, + child: TextFormField( + controller: passwordController, + onSaved: (password) => _password = password, + validator: (password) { + return password.length >= 8 + ? null + : 'Please use at least 8 characters'; + }, + decoration: new InputDecoration( + border: OutlineInputBorder(), + labelText: 'Password'), + obscureText: true, + ), + ), + Padding( + padding: vStandardVerticalPadding, + child: TextFormField( + validator: (password) { + return passwordController.text == password + ? null + : 'Passwords don\'t match.'; + }, + decoration: new InputDecoration( + border: OutlineInputBorder(), + labelText: 'Repeat Password'), + obscureText: true, + ), + ), + Builder( + builder: (context) => FancyButton( + onPressed: !_loading + ? () { + if (_formKey.currentState.validate()) { + Form.of(context).save(); + _registerUser(context); + } else { + print("awhat"); + } + } + : null, + child: _loading + ? CircularProgressIndicator() + : VikunjaButtonText('Register'), + )), + ], + )), + ), )); } diff --git a/lib/service/mocked_services.dart b/lib/service/mocked_services.dart index 35d5fbb..98913e1 100644 --- a/lib/service/mocked_services.dart +++ b/lib/service/mocked_services.dart @@ -7,7 +7,7 @@ import 'package:vikunja_app/models/user.dart'; import 'package:vikunja_app/service/services.dart'; // Data for mocked services -var _users = {1: User(1, 'test@testuser.org', 'test1')}; +var _users = {1: User(1, 'test@testuser.org', 'test1', '')}; var _namespaces = { 1: Namespace( diff --git a/pubspec.lock b/pubspec.lock index 3e86bc3..a781b71 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1,5 +1,5 @@ # Generated by pub -# See https://www.dartlang.org/tools/pub/glossary#lockfile +# See https://dart.dev/tools/pub/glossary#lockfile packages: after_layout: dependency: "direct main" @@ -7,35 +7,35 @@ packages: name: after_layout url: "https://pub.dartlang.org" source: hosted - version: "1.0.7" + version: "1.0.7+2" archive: dependency: transitive description: name: archive url: "https://pub.dartlang.org" source: hosted - version: "2.0.8" + version: "2.0.11" args: dependency: transitive description: name: args url: "https://pub.dartlang.org" source: hosted - version: "1.5.1" + version: "1.5.2" async: dependency: transitive description: name: async url: "https://pub.dartlang.org" source: hosted - version: "2.0.8" + version: "2.4.0" boolean_selector: dependency: transitive description: name: boolean_selector url: "https://pub.dartlang.org" source: hosted - version: "1.0.4" + version: "1.0.5" charcode: dependency: transitive description: @@ -63,14 +63,14 @@ packages: name: crypto url: "https://pub.dartlang.org" source: hosted - version: "2.0.6" + version: "2.1.3" cupertino_icons: dependency: "direct main" description: name: cupertino_icons url: "https://pub.dartlang.org" source: hosted - version: "0.1.2" + version: "0.1.3" dart_config: dependency: transitive description: @@ -98,7 +98,7 @@ packages: name: flutter_secure_storage url: "https://pub.dartlang.org" source: hosted - version: "3.1.1" + version: "3.3.1+1" flutter_test: dependency: "direct dev" description: flutter @@ -110,7 +110,7 @@ packages: name: http url: "https://pub.dartlang.org" source: hosted - version: "0.12.0" + version: "0.12.0+3" http_parser: dependency: transitive description: @@ -124,49 +124,49 @@ packages: name: image url: "https://pub.dartlang.org" source: hosted - version: "2.0.7" + version: "2.1.4" matcher: dependency: transitive description: name: matcher url: "https://pub.dartlang.org" source: hosted - version: "0.12.3+1" + version: "0.12.6" meta: dependency: transitive description: name: meta url: "https://pub.dartlang.org" source: hosted - version: "1.1.6" + version: "1.1.8" path: dependency: transitive description: name: path url: "https://pub.dartlang.org" source: hosted - version: "1.6.2" + version: "1.6.4" pedantic: dependency: transitive description: name: pedantic url: "https://pub.dartlang.org" source: hosted - version: "1.4.0" + version: "1.8.0+1" petitparser: dependency: transitive description: name: petitparser url: "https://pub.dartlang.org" source: hosted - version: "2.1.1" + version: "2.4.0" quiver: dependency: transitive description: name: quiver url: "https://pub.dartlang.org" source: hosted - version: "2.0.1" + version: "2.0.5" sky_engine: dependency: transitive description: flutter @@ -178,7 +178,7 @@ packages: name: source_span url: "https://pub.dartlang.org" source: hosted - version: "1.5.4" + version: "1.5.5" stack_trace: dependency: transitive description: @@ -192,14 +192,14 @@ packages: name: stream_channel url: "https://pub.dartlang.org" source: hosted - version: "1.6.8" + version: "2.0.0" string_scanner: dependency: transitive description: name: string_scanner url: "https://pub.dartlang.org" source: hosted - version: "1.0.4" + version: "1.0.5" term_glyph: dependency: transitive description: @@ -213,7 +213,7 @@ packages: name: test_api url: "https://pub.dartlang.org" source: hosted - version: "0.2.2" + version: "0.2.11" typed_data: dependency: transitive description: @@ -234,13 +234,13 @@ packages: name: xml url: "https://pub.dartlang.org" source: hosted - version: "3.3.1" + version: "3.5.0" yaml: dependency: transitive description: name: yaml url: "https://pub.dartlang.org" source: hosted - version: "2.1.15" + version: "2.2.0" sdks: - dart: ">=2.1.0 <3.0.0" + dart: ">=2.4.0 <3.0.0" diff --git a/pubspec.yaml b/pubspec.yaml index f5b5eb4..067ec71 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -4,17 +4,14 @@ description: Vikunja as Flutter cross platform app version: 0.1.0 environment: - sdk: ">=2.0.0-dev.63.0 <3.0.0" + sdk: ">=2.1.0 <3.0.0" dependencies: flutter: sdk: flutter - - # The following adds the Cupertino Icons font to your application. - # Use with the CupertinoIcons class for iOS style icons. - cupertino_icons: ^0.1.2 - flutter_secure_storage: 3.1.1 - http: 0.12.0 + cupertino_icons: ^0.1.3 + flutter_secure_storage: 3.3.1+1 + http: 0.12.0+3 after_layout: ^1.0.7 dev_dependencies: