Merge branch 'master' into feature/edit-task
# Conflicts: # pubspec.lock # pubspec.yaml
This commit is contained in:
commit
67e055d9cb
47
.drone.yml
47
.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
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
.pub/
|
||||
build/
|
||||
!pubspec.lock
|
||||
.flutter-plugins-dependencies
|
||||
|
||||
# Android related
|
||||
**/android/**/gradle-wrapper.jar
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -21,8 +21,6 @@ allprojects {
|
|||
rootProject.buildDir = '../build'
|
||||
subprojects {
|
||||
project.buildDir = "${rootProject.buildDir}/${project.name}"
|
||||
}
|
||||
subprojects {
|
||||
project.evaluationDependsOn(':app')
|
||||
}
|
||||
|
||||
|
|
|
@ -1 +1,4 @@
|
|||
org.gradle.jvmargs=-Xmx1536M
|
||||
android.enableR8=true
|
||||
android.useAndroidX=true
|
||||
android.enableJetifier=true
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
include ':app'
|
|
@ -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"
|
|
@ -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());
|
||||
}
|
|
@ -130,9 +130,9 @@ class VikunjaGlobalState extends State<VikunjaGlobal> {
|
|||
});
|
||||
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;
|
||||
|
|
|
@ -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<String, dynamic> 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 {
|
||||
|
|
|
@ -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<HomePage> with AfterLayoutMixin<HomePage> {
|
|||
drawer: new Drawer(
|
||||
child: new Column(children: <Widget>[
|
||||
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<HomePage> with AfterLayoutMixin<HomePage> {
|
|||
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<HomePage> with AfterLayoutMixin<HomePage> {
|
|||
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),
|
||||
),
|
||||
),
|
||||
),
|
||||
])),
|
||||
|
|
|
@ -26,68 +26,68 @@ class _ListEditPageState extends State<ListEditPage> {
|
|||
),
|
||||
body: Builder(
|
||||
builder: (BuildContext context) => SafeArea(
|
||||
child: Form(
|
||||
key: _formKey,
|
||||
child: ListView(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
children: <Widget>[
|
||||
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: <Widget>[
|
||||
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'),
|
||||
))),
|
||||
]),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
|
@ -26,68 +26,68 @@ class _NamespaceEditPageState extends State<NamespaceEditPage> {
|
|||
),
|
||||
body: Builder(
|
||||
builder: (BuildContext context) => SafeArea(
|
||||
child: Form(
|
||||
key: _formKey,
|
||||
child: ListView(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
children: <Widget>[
|
||||
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: <Widget>[
|
||||
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'),
|
||||
))),
|
||||
]),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
|
@ -24,83 +24,81 @@ class _LoginPageState extends State<LoginPage> {
|
|||
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: <Widget>[
|
||||
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: <Widget>[
|
||||
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'),
|
||||
)),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
|
@ -24,103 +24,102 @@ class _RegisterPageState extends State<RegisterPage> {
|
|||
),
|
||||
body: Builder(
|
||||
builder: (BuildContext context) => SafeArea(
|
||||
top: false,
|
||||
bottom: false,
|
||||
child: Form(
|
||||
key: _formKey,
|
||||
child: ListView(
|
||||
padding: const EdgeInsets.all(16),
|
||||
children: <Widget>[
|
||||
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: <Widget>[
|
||||
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'),
|
||||
)),
|
||||
],
|
||||
)),
|
||||
),
|
||||
));
|
||||
}
|
||||
|
||||
|
|
|
@ -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(
|
||||
|
|
294
pubspec.lock
294
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,42 +7,35 @@ packages:
|
|||
name: after_layout
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.0.7"
|
||||
analyzer:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: analyzer
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.34.3"
|
||||
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:
|
||||
|
@ -70,21 +63,14 @@ packages:
|
|||
name: crypto
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.6"
|
||||
csslib:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: csslib
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.14.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:
|
||||
|
@ -94,13 +80,6 @@ packages:
|
|||
url: "https://github.com/MarkOSullivan94/dart_config.git"
|
||||
source: git
|
||||
version: "0.5.0"
|
||||
datetime_picker_formfield:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: datetime_picker_formfield
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.1.8"
|
||||
flutter:
|
||||
dependency: "direct main"
|
||||
description: flutter
|
||||
|
@ -119,54 +98,19 @@ 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
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
flutter_typeahead:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: flutter_typeahead
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.2.1"
|
||||
front_end:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: front_end
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.1.9+1"
|
||||
glob:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: glob
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.1.7"
|
||||
html:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: html
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.13.4+1"
|
||||
http:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: http
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.12.0"
|
||||
http_multi_server:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: http_multi_server
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.5"
|
||||
version: "0.12.0+3"
|
||||
http_parser:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -180,208 +124,61 @@ packages:
|
|||
name: image
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.7"
|
||||
intl:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: intl
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.15.7"
|
||||
io:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: io
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.3.3"
|
||||
js:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: js
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.6.1+1"
|
||||
json_rpc_2:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: json_rpc_2
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.9"
|
||||
kernel:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: kernel
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.3.9+1"
|
||||
keyboard_visibility:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: keyboard_visibility
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.5.2"
|
||||
logging:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: logging
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.11.3+2"
|
||||
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"
|
||||
mime:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: mime
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.9.6+2"
|
||||
multi_server_socket:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: multi_server_socket
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.0.2"
|
||||
node_preamble:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: node_preamble
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.4.4"
|
||||
package_config:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: package_config
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.0.5"
|
||||
package_resolver:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: package_resolver
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.0.9"
|
||||
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"
|
||||
plugin:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: plugin
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.2.0+3"
|
||||
pool:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: pool
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.4.0"
|
||||
pub_semver:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: pub_semver
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.4.2"
|
||||
version: "2.4.0"
|
||||
quiver:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: quiver
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.1"
|
||||
shelf:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shelf
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.7.4"
|
||||
shelf_packages_handler:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shelf_packages_handler
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.0.4"
|
||||
shelf_static:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shelf_static
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.2.8"
|
||||
shelf_web_socket:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shelf_web_socket
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.2.2+4"
|
||||
version: "2.0.5"
|
||||
sky_engine:
|
||||
dependency: transitive
|
||||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.99"
|
||||
source_map_stack_trace:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: source_map_stack_trace
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.1.5"
|
||||
source_maps:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: source_maps
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.10.8"
|
||||
source_span:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: source_span
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.5.4"
|
||||
version: "1.5.5"
|
||||
stack_trace:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -395,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:
|
||||
|
@ -410,27 +207,13 @@ packages:
|
|||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.1.0"
|
||||
test:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: test
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.5.3"
|
||||
test_api:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: test_api
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.2.2"
|
||||
test_core:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: test_core
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.2.1+1"
|
||||
version: "0.2.11"
|
||||
typed_data:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -438,13 +221,6 @@ packages:
|
|||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.1.6"
|
||||
utf:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: utf
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.9.0+5"
|
||||
vector_math:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -452,41 +228,19 @@ packages:
|
|||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.8"
|
||||
vm_service_client:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: vm_service_client
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.2.6"
|
||||
watcher:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: watcher
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.9.7+10"
|
||||
web_socket_channel:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: web_socket_channel
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.0.9"
|
||||
xml:
|
||||
dependency: transitive
|
||||
description:
|
||||
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"
|
||||
flutter: ">=0.1.4 <2.0.0"
|
||||
dart: ">=2.4.0 <3.0.0"
|
||||
|
|
|
@ -4,14 +4,14 @@ description: Vikunja as Flutter cross platform app
|
|||
version: 0.1.0
|
||||
|
||||
environment:
|
||||
sdk: ">=2.0.0-dev.68.0 <3.0.0"
|
||||
sdk: ">=2.1.0 <3.0.0"
|
||||
|
||||
dependencies:
|
||||
flutter:
|
||||
sdk: flutter
|
||||
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
|
||||
datetime_picker_formfield: ^0.1.8
|
||||
flutter_typeahead: ^1.2.1
|
||||
|
|
Reference in New Issue