mirror of
https://github.com/go-vikunja/app
synced 2025-01-22 07:36:04 +00:00
Add working login implementation
This commit is contained in:
parent
4bfd13536e
commit
1994892b63
@ -1 +1,2 @@
|
||||
#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
|
||||
#include "Generated.xcconfig"
|
||||
|
@ -1 +1,2 @@
|
||||
#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
|
||||
#include "Generated.xcconfig"
|
||||
|
@ -19,6 +19,7 @@
|
||||
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
|
||||
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
|
||||
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
|
||||
ACA854A11123D371B9168194 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C102A622A93B95B5704BDD24 /* Pods_Runner.framework */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXCopyFilesBuildPhase section */
|
||||
@ -53,6 +54,7 @@
|
||||
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
||||
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
C102A622A93B95B5704BDD24 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
@ -62,12 +64,28 @@
|
||||
files = (
|
||||
9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */,
|
||||
3B80C3941E831B6300D905FE /* App.framework in Frameworks */,
|
||||
ACA854A11123D371B9168194 /* Pods_Runner.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
4D8888AA13EBD37D6777D23F /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
C102A622A93B95B5704BDD24 /* Pods_Runner.framework */,
|
||||
);
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
7CACC4C503C5D851EB73C215 /* Pods */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
);
|
||||
name = Pods;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
9740EEB11CF90186004384FC /* Flutter */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@ -88,6 +106,8 @@
|
||||
9740EEB11CF90186004384FC /* Flutter */,
|
||||
97C146F01CF9000F007C117D /* Runner */,
|
||||
97C146EF1CF9000F007C117D /* Products */,
|
||||
7CACC4C503C5D851EB73C215 /* Pods */,
|
||||
4D8888AA13EBD37D6777D23F /* Frameworks */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
@ -129,12 +149,15 @@
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
|
||||
buildPhases = (
|
||||
3185B6CCDCA9C2025E57C488 /* [CP] Check Pods Manifest.lock */,
|
||||
9740EEB61CF901F6004384FC /* Run Script */,
|
||||
97C146EA1CF9000F007C117D /* Sources */,
|
||||
97C146EB1CF9000F007C117D /* Frameworks */,
|
||||
97C146EC1CF9000F007C117D /* Resources */,
|
||||
9705A1C41CF9048500538489 /* Embed Frameworks */,
|
||||
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
|
||||
85082CB7F9EE2F3E7985BDB9 /* [CP] Embed Pods Frameworks */,
|
||||
7C22F5DE30AEBAB42040EB3F /* [CP] Copy Pods Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
@ -156,6 +179,7 @@
|
||||
TargetAttributes = {
|
||||
97C146ED1CF9000F007C117D = {
|
||||
CreatedOnToolsVersion = 7.3.1;
|
||||
DevelopmentTeam = Z48VLBM2R7;
|
||||
LastSwiftMigration = 0910;
|
||||
};
|
||||
};
|
||||
@ -195,6 +219,24 @@
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXShellScriptBuildPhase section */
|
||||
3185B6CCDCA9C2025E57C488 /* [CP] Check Pods Manifest.lock */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
|
||||
"${PODS_ROOT}/Manifest.lock",
|
||||
);
|
||||
name = "[CP] Check Pods Manifest.lock";
|
||||
outputPaths = (
|
||||
"$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
@ -209,6 +251,41 @@
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin";
|
||||
};
|
||||
7C22F5DE30AEBAB42040EB3F /* [CP] Copy Pods Resources */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
name = "[CP] Copy Pods Resources";
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
85082CB7F9EE2F3E7985BDB9 /* [CP] Embed Pods Frameworks */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
"${SRCROOT}/Pods/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh",
|
||||
"${PODS_ROOT}/../.symlinks/flutter/ios/Flutter.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/flutter_secure_storage/flutter_secure_storage.framework",
|
||||
);
|
||||
name = "[CP] Embed Pods Frameworks";
|
||||
outputPaths = (
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Flutter.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_secure_storage.framework",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
9740EEB61CF901F6004384FC /* Run Script */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
@ -367,6 +444,7 @@
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||
DEVELOPMENT_TEAM = Z48VLBM2R7;
|
||||
ENABLE_BITCODE = NO;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
@ -395,6 +473,7 @@
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||
DEVELOPMENT_TEAM = Z48VLBM2R7;
|
||||
ENABLE_BITCODE = NO;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
@ -439,4 +518,4 @@
|
||||
/* End XCConfigurationList section */
|
||||
};
|
||||
rootObject = 97C146E61CF9000F007C117D /* Project object */;
|
||||
}
|
||||
}
|
||||
|
3
ios/Runner.xcworkspace/contents.xcworkspacedata
generated
3
ios/Runner.xcworkspace/contents.xcworkspacedata
generated
@ -4,4 +4,7 @@
|
||||
<FileRef
|
||||
location = "group:Runner.xcodeproj">
|
||||
</FileRef>
|
||||
<FileRef
|
||||
location = "group:Pods/Pods.xcodeproj">
|
||||
</FileRef>
|
||||
</Workspace>
|
||||
|
@ -1,7 +1,17 @@
|
||||
class Client {
|
||||
final String _token;
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'package:http/http.dart' as http;
|
||||
|
||||
Client(this._token);
|
||||
class Client {
|
||||
final JsonDecoder _decoder = new JsonDecoder();
|
||||
final JsonEncoder _encoder = new JsonEncoder();
|
||||
final String _token;
|
||||
final String _base;
|
||||
|
||||
String get base => _base;
|
||||
|
||||
Client(this._token, String base)
|
||||
: _base = base.endsWith('/api/v1') ? base : '$base/api/v1';
|
||||
|
||||
bool operator ==(dynamic otherClient) {
|
||||
return otherClient._token == _token;
|
||||
@ -9,4 +19,43 @@ class Client {
|
||||
|
||||
@override
|
||||
int get hashCode => _token.hashCode;
|
||||
|
||||
get _headers => {
|
||||
'Authorization': _token != null ? 'Bearer $_token' : '',
|
||||
'Content-Type': 'application/json'
|
||||
};
|
||||
|
||||
Future<dynamic> get(String url) {
|
||||
return http
|
||||
.get('${this.base}$url', headers: _headers)
|
||||
.then(_handleResponse);
|
||||
}
|
||||
|
||||
Future<dynamic> post(String url, {dynamic body}) {
|
||||
return http
|
||||
.post('${this.base}$url',
|
||||
headers: _headers, body: _encoder.convert(body))
|
||||
.then(_handleResponse);
|
||||
}
|
||||
|
||||
dynamic _handleResponse(http.Response response) {
|
||||
if (response.statusCode < 200 ||
|
||||
response.statusCode > 400 ||
|
||||
json == null) {
|
||||
throw new ApiException(
|
||||
response.statusCode, response.request.url.toString());
|
||||
}
|
||||
return _decoder.convert(response.body);
|
||||
}
|
||||
}
|
||||
|
||||
class ApiException implements Exception {
|
||||
final int errorCode;
|
||||
final String path;
|
||||
ApiException(this.errorCode, this.path);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return "Can't fetch data from server. (Error-Code: $errorCode)";
|
||||
}
|
||||
}
|
||||
|
27
lib/api/user_implementation.dart
Normal file
27
lib/api/user_implementation.dart
Normal file
@ -0,0 +1,27 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:fluttering_vikunja/api/client.dart';
|
||||
import 'package:fluttering_vikunja/models/user.dart';
|
||||
import 'package:fluttering_vikunja/service/services.dart';
|
||||
|
||||
class UserAPIService implements UserService {
|
||||
final Client _client;
|
||||
|
||||
UserAPIService(this._client);
|
||||
|
||||
@override
|
||||
Future<UserTokenPair> login(String username, password) async {
|
||||
var token = await _client.post('/login', body: {
|
||||
'username': username,
|
||||
'password': password
|
||||
}).then((map) => map['token']);
|
||||
return UserAPIService(Client(token, _client.base))
|
||||
.getCurrentUser()
|
||||
.then((user) => UserTokenPair(user, token));
|
||||
}
|
||||
|
||||
@override
|
||||
Future<User> getCurrentUser() {
|
||||
return _client.get('/user').then((map) => User.fromJson(map));
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||
import 'package:fluttering_vikunja/api/client.dart';
|
||||
import 'package:fluttering_vikunja/api/user_implementation.dart';
|
||||
import 'package:fluttering_vikunja/managers/user.dart';
|
||||
import 'package:fluttering_vikunja/models/user.dart';
|
||||
import 'package:fluttering_vikunja/service/mocked_services.dart';
|
||||
@ -33,7 +34,8 @@ class VikunjaGlobalState extends State<VikunjaGlobal> {
|
||||
Client get client => _client;
|
||||
|
||||
UserManager get userManager => new UserManager(_storage);
|
||||
UserService get userService => new MockedUserService();
|
||||
UserService get userService => new UserAPIService(_client);
|
||||
UserService newLoginService(base) => new UserAPIService(Client(null, base));
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@ -41,7 +43,7 @@ class VikunjaGlobalState extends State<VikunjaGlobal> {
|
||||
_loadCurrentUser();
|
||||
}
|
||||
|
||||
void changeUser(User newUser, {String token}) async {
|
||||
void changeUser(User newUser, {String token, String base}) async {
|
||||
setState(() {
|
||||
_loading = true;
|
||||
});
|
||||
@ -51,27 +53,43 @@ class VikunjaGlobalState extends State<VikunjaGlobal> {
|
||||
// Write new token to secure storage
|
||||
await _storage.write(key: newUser.id.toString(), value: token);
|
||||
}
|
||||
if (base == null) {
|
||||
base = await _storage.read(key: "${newUser.id.toString()}_base");
|
||||
} else {
|
||||
// Write new base to secure storage
|
||||
await _storage.write(key: "${newUser.id.toString()}_base", value: base);
|
||||
}
|
||||
// Set current user in storage
|
||||
await _storage.write(key: 'currentUser', value: newUser.id.toString());
|
||||
setState(() {
|
||||
_currentUser = newUser;
|
||||
_client = Client(token);
|
||||
_client = Client(token, base);
|
||||
_loading = false;
|
||||
});
|
||||
}
|
||||
|
||||
void _loadCurrentUser() async {
|
||||
var currentUser = await _storage.read(key: 'currentUser');
|
||||
var token;
|
||||
var loadedCurrentUser;
|
||||
if (currentUser != null) {
|
||||
token = await _storage.read(key: currentUser);
|
||||
loadedCurrentUser = await userService.get(int.tryParse(currentUser));
|
||||
if (currentUser == null) {
|
||||
setState(() {
|
||||
_loading = false;
|
||||
});
|
||||
return;
|
||||
}
|
||||
var token = await _storage.read(key: currentUser);
|
||||
var base = await _storage.read(key: '${currentUser}_base');
|
||||
if (token == null || base == null) {
|
||||
setState(() {
|
||||
_loading = false;
|
||||
});
|
||||
return;
|
||||
}
|
||||
setState(() {
|
||||
_client = Client(token, base);
|
||||
});
|
||||
var loadedCurrentUser = await userService.getCurrentUser();
|
||||
setState(() {
|
||||
_currentUser = loadedCurrentUser;
|
||||
_client = token != null ? Client(token) : null;
|
||||
_loading = false;
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -68,20 +68,23 @@ class _LoginPageState extends State<LoginPage> {
|
||||
obscureText: true,
|
||||
),
|
||||
),
|
||||
ButtonTheme(
|
||||
height: _loading ? 55.0 : 36.0,
|
||||
child: RaisedButton(
|
||||
onPressed: !_loading
|
||||
? () {
|
||||
if (_formKey.currentState.validate()) {
|
||||
_loginUser(context);
|
||||
}
|
||||
}
|
||||
: null,
|
||||
child: _loading
|
||||
? CircularProgressIndicator()
|
||||
: Text('Login'),
|
||||
))
|
||||
Builder(
|
||||
builder: (context) => ButtonTheme(
|
||||
height: _loading ? 55.0 : 36.0,
|
||||
child: RaisedButton(
|
||||
onPressed: !_loading
|
||||
? () {
|
||||
if (_formKey.currentState
|
||||
.validate()) {
|
||||
Form.of(context).save();
|
||||
_loginUser(context);
|
||||
}
|
||||
}
|
||||
: null,
|
||||
child: _loading
|
||||
? CircularProgressIndicator()
|
||||
: Text('Login'),
|
||||
))),
|
||||
],
|
||||
)),
|
||||
),
|
||||
@ -90,11 +93,28 @@ class _LoginPageState extends State<LoginPage> {
|
||||
|
||||
_loginUser(BuildContext context) async {
|
||||
setState(() => _loading = true);
|
||||
var vGlobal = VikunjaGlobal.of(context);
|
||||
var newUser = await vGlobal.userService.login(_username, _password);
|
||||
vGlobal.changeUser(newUser.user, token: newUser.token);
|
||||
setState(() {
|
||||
_loading = false;
|
||||
});
|
||||
try {
|
||||
var vGlobal = VikunjaGlobal.of(context);
|
||||
var newUser =
|
||||
await vGlobal.newLoginService(_server).login(_username, _password);
|
||||
vGlobal.changeUser(newUser.user, token: newUser.token, base: _server);
|
||||
} catch (ex) {
|
||||
print(ex);
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => new AlertDialog(
|
||||
title:
|
||||
const Text('Login failed! Please check you credentials.'),
|
||||
actions: <Widget>[
|
||||
FlatButton(
|
||||
onPressed: () => Navigator.pop(context),
|
||||
child: const Text('CLOSE'))
|
||||
],
|
||||
));
|
||||
} finally {
|
||||
setState(() {
|
||||
_loading = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -137,7 +137,7 @@ class MockedUserService implements UserService {
|
||||
}
|
||||
|
||||
@override
|
||||
Future<User> get(int userId) {
|
||||
return Future.value(_users[userId]);
|
||||
Future<User> getCurrentUser() {
|
||||
return Future.value(_users[1]);
|
||||
}
|
||||
}
|
||||
|
@ -28,5 +28,5 @@ abstract class TaskService {
|
||||
|
||||
abstract class UserService {
|
||||
Future<UserTokenPair> login(String username, password);
|
||||
Future<User> get(int userId);
|
||||
Future<User> getCurrentUser();
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user