mirror of
https://github.com/go-vikunja/app
synced 2024-11-14 08:40:45 +00:00
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 <k@knt.li> Reviewed-on: vikunja/app#38
This commit is contained in:
parent
d1eb3fbc37
commit
edbadd9913
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
|
||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -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
|
||||
|
1
android/settings_aar.gradle
Normal file
1
android/settings_aar.gradle
Normal file
@ -0,0 +1 @@
|
||||
include ':app'
|
10
ios/Flutter/flutter_export_environment.sh
Executable file
10
ios/Flutter/flutter_export_environment.sh
Executable file
@ -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());
|
||||
}
|
@ -120,9 +120,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(
|
||||
|
48
pubspec.lock
48
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"
|
||||
|
11
pubspec.yaml
11
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:
|
||||
|
Loading…
Reference in New Issue
Block a user