Documentation, Basic Login Workflow
This commit is contained in:
parent
fec590b16e
commit
5212d7bf70
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,3 +1,5 @@
|
||||
imagini.db
|
||||
media/
|
||||
notes
|
||||
web/node_modules/
|
||||
web/dist/
|
||||
|
34
README.md
34
README.md
@ -1,22 +1,32 @@
|
||||
#uImagini
|
||||
# Imagini
|
||||
A self hosted photo library with user management & authentication. Cross platform Client supporting Android, iOS, and Web.
|
||||
|
||||
## Running Server
|
||||
# cd ./cmd/
|
||||
CONFIG_PATH=$(pwd) DATA_PATH=$(pwd) go run main.go serve
|
||||
## Server
|
||||
### Running
|
||||
|
||||
## Generate GraphQL Models
|
||||
# cd ./cmd/
|
||||
CONFIG_PATH=$(pwd) DATA_PATH=$(pwd) go run cmd/main.go serve
|
||||
|
||||
## Building
|
||||
|
||||
# Generate GraphQL Models
|
||||
go run github.com/99designs/gqlgen generate
|
||||
go run main.go generate
|
||||
go run cmd/main.go generate
|
||||
|
||||
## Generate GraphQL Documentation
|
||||
# From app root
|
||||
# Generate GraphQL Documentation
|
||||
graphdoc -e http://localhost:8484/query -o ./docs/schema
|
||||
|
||||
## Server Build
|
||||
## Client
|
||||
See `web_native` subfolder.
|
||||
### Running
|
||||
|
||||
## Flutter Build
|
||||
# Chrome
|
||||
flutter run -d chrome
|
||||
|
||||
# Simulator
|
||||
open -a Simulator
|
||||
flutter run
|
||||
|
||||
## Generate GraphQL Flutter Models
|
||||
### Building
|
||||
|
||||
# Generate GraphQL Flutter Models
|
||||
flutter pub run build_runner build
|
||||
|
@ -41,35 +41,46 @@ func (api *API) refreshTokens(refreshToken jwt.Token) (string, string, error) {
|
||||
}
|
||||
|
||||
// Update Access Token
|
||||
accessTokenCookie, err := api.Auth.CreateJWTAccessToken(user, device)
|
||||
accessToken, err := api.Auth.CreateJWTAccessToken(user, device)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
return accessTokenCookie, "", err
|
||||
return accessToken, "", err
|
||||
}
|
||||
|
||||
func (api *API) validateTokens(w *http.ResponseWriter, r *http.Request) (jwt.Token, error) {
|
||||
// TODO: Check from X-Imagini-AccessToken
|
||||
// TODO: Check from X-Imagini-RefreshToken
|
||||
|
||||
// Validate Access Token
|
||||
accessCookie, _ := r.Cookie("AccessToken")
|
||||
if accessCookie != nil {
|
||||
accessToken, err := api.Auth.ValidateJWTAccessToken(accessCookie.Value)
|
||||
accessTokenHeader := r.Header.Get("X-Imagini-AccessToken")
|
||||
if accessTokenHeader != "" {
|
||||
accessToken, err := api.Auth.ValidateJWTAccessToken(accessTokenHeader)
|
||||
if err == nil {
|
||||
return accessToken, nil
|
||||
}
|
||||
}
|
||||
|
||||
// Validate Refresh Cookie Exists
|
||||
refreshCookie, _ := r.Cookie("RefreshToken")
|
||||
if refreshCookie == nil {
|
||||
refreshTokenHeader := r.Header.Get("X-Imagini-RefreshToken")
|
||||
if refreshTokenHeader == "" {
|
||||
return nil, errors.New("Tokens Invalid")
|
||||
}
|
||||
|
||||
// Validate Access Token
|
||||
// accessCookie, _ := r.Cookie("AccessToken")
|
||||
// if accessCookie != nil {
|
||||
// accessToken, err := api.Auth.ValidateJWTAccessToken(accessCookie.Value)
|
||||
// if err == nil {
|
||||
// return accessToken, nil
|
||||
// }
|
||||
// }
|
||||
|
||||
// Validate Refresh Cookie Exists
|
||||
// refreshCookie, _ := r.Cookie("RefreshToken")
|
||||
// if refreshCookie == nil {
|
||||
// return nil, errors.New("Tokens Invalid")
|
||||
// }
|
||||
|
||||
// Validate Refresh Token
|
||||
refreshToken, err := api.Auth.ValidateJWTRefreshToken(refreshCookie.Value)
|
||||
// refreshToken, err := api.Auth.ValidateJWTRefreshToken(refreshCookie.Value)
|
||||
refreshToken, err := api.Auth.ValidateJWTRefreshToken(refreshTokenHeader)
|
||||
if err != nil {
|
||||
return nil, errors.New("Tokens Invalid")
|
||||
}
|
||||
@ -81,21 +92,21 @@ func (api *API) validateTokens(w *http.ResponseWriter, r *http.Request) (jwt.Tok
|
||||
}
|
||||
|
||||
// TODO: Actually Refresh Refresh Token
|
||||
newRefreshToken = refreshCookie.Value
|
||||
// newRefreshToken = refreshCookie.Value
|
||||
newRefreshToken = refreshTokenHeader
|
||||
|
||||
// Set appropriate cookies (TODO: Only for web!)
|
||||
|
||||
// Update Access & Refresh Cookies
|
||||
http.SetCookie(*w, &http.Cookie{
|
||||
Name: "AccessToken",
|
||||
Value: newAccessToken,
|
||||
})
|
||||
http.SetCookie(*w, &http.Cookie{
|
||||
Name: "RefreshToken",
|
||||
Value: newRefreshToken,
|
||||
})
|
||||
// http.SetCookie(*w, &http.Cookie{
|
||||
// Name: "AccessToken",
|
||||
// Value: newAccessToken,
|
||||
// })
|
||||
// http.SetCookie(*w, &http.Cookie{
|
||||
// Name: "RefreshToken",
|
||||
// Value: newRefreshToken,
|
||||
// })
|
||||
|
||||
// Only for iOS & Android (TODO: Remove for web! Only cause affected by CORS during development)
|
||||
(*w).Header().Set("X-Imagini-AccessToken", newAccessToken)
|
||||
(*w).Header().Set("X-Imagini-RefreshToken", newRefreshToken)
|
||||
|
||||
|
@ -1,16 +1,16 @@
|
||||
# imagini
|
||||
# Imagini Client
|
||||
A cross platform (iOS, Android, & Web) client used with the Imagini server.
|
||||
|
||||
A new Flutter project.
|
||||
## Running
|
||||
|
||||
## Getting Started
|
||||
# Chrome
|
||||
flutter run -d chrome
|
||||
|
||||
This project is a starting point for a Flutter application.
|
||||
# Simulator
|
||||
open -a Simulator
|
||||
flutter run
|
||||
|
||||
A few resources to get you started if this is your first Flutter project:
|
||||
## Building
|
||||
|
||||
- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab)
|
||||
- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook)
|
||||
|
||||
For help getting started with Flutter, view our
|
||||
[online documentation](https://flutter.dev/docs), which offers tutorials,
|
||||
samples, guidance on mobile development, and a full API reference.
|
||||
# Generate GraphQL Flutter Models
|
||||
flutter pub run build_runner build
|
||||
|
18
web_native/graphql/mediaItems.graphql
Normal file
18
web_native/graphql/mediaItems.graphql
Normal file
@ -0,0 +1,18 @@
|
||||
query mediaItems($order: Order, $page: Page, $filter: MediaItemFilter) {
|
||||
mediaItems(filter: $filter, page: $page, order: $order) {
|
||||
data {
|
||||
id
|
||||
fileName
|
||||
latitude
|
||||
longitude
|
||||
isVideo
|
||||
origName
|
||||
createdAt
|
||||
}
|
||||
page {
|
||||
size
|
||||
page
|
||||
total
|
||||
}
|
||||
}
|
||||
}
|
@ -1,4 +1,7 @@
|
||||
PODS:
|
||||
- connectivity (0.0.1):
|
||||
- Flutter
|
||||
- Reachability
|
||||
- DKImagePickerController/Core (4.3.2):
|
||||
- DKImagePickerController/ImageDataManager
|
||||
- DKImagePickerController/Resource
|
||||
@ -38,6 +41,9 @@ PODS:
|
||||
- Flutter
|
||||
- integration_test (0.0.1):
|
||||
- Flutter
|
||||
- path_provider (0.0.1):
|
||||
- Flutter
|
||||
- Reachability (3.2)
|
||||
- SDWebImage (5.10.2):
|
||||
- SDWebImage/Core (= 5.10.2)
|
||||
- SDWebImage/Core (5.10.2)
|
||||
@ -48,10 +54,12 @@ PODS:
|
||||
- Flutter
|
||||
|
||||
DEPENDENCIES:
|
||||
- connectivity (from `.symlinks/plugins/connectivity/ios`)
|
||||
- file_picker (from `.symlinks/plugins/file_picker/ios`)
|
||||
- Flutter (from `Flutter`)
|
||||
- flutter_secure_storage (from `.symlinks/plugins/flutter_secure_storage/ios`)
|
||||
- integration_test (from `.symlinks/plugins/integration_test/ios`)
|
||||
- path_provider (from `.symlinks/plugins/path_provider/ios`)
|
||||
- shared_preferences (from `.symlinks/plugins/shared_preferences/ios`)
|
||||
- url_launcher (from `.symlinks/plugins/url_launcher/ios`)
|
||||
|
||||
@ -59,10 +67,13 @@ SPEC REPOS:
|
||||
trunk:
|
||||
- DKImagePickerController
|
||||
- DKPhotoGallery
|
||||
- Reachability
|
||||
- SDWebImage
|
||||
- SwiftyGif
|
||||
|
||||
EXTERNAL SOURCES:
|
||||
connectivity:
|
||||
:path: ".symlinks/plugins/connectivity/ios"
|
||||
file_picker:
|
||||
:path: ".symlinks/plugins/file_picker/ios"
|
||||
Flutter:
|
||||
@ -71,18 +82,23 @@ EXTERNAL SOURCES:
|
||||
:path: ".symlinks/plugins/flutter_secure_storage/ios"
|
||||
integration_test:
|
||||
:path: ".symlinks/plugins/integration_test/ios"
|
||||
path_provider:
|
||||
:path: ".symlinks/plugins/path_provider/ios"
|
||||
shared_preferences:
|
||||
:path: ".symlinks/plugins/shared_preferences/ios"
|
||||
url_launcher:
|
||||
:path: ".symlinks/plugins/url_launcher/ios"
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
connectivity: c4130b2985d4ef6fd26f9702e886bd5260681467
|
||||
DKImagePickerController: b5eb7f7a388e4643264105d648d01f727110fc3d
|
||||
DKPhotoGallery: fdfad5125a9fdda9cc57df834d49df790dbb4179
|
||||
file_picker: 3e6c3790de664ccf9b882732d9db5eaf6b8d4eb1
|
||||
Flutter: 434fef37c0980e73bb6479ef766c45957d4b510c
|
||||
flutter_secure_storage: 7953c38a04c3fdbb00571bcd87d8e3b5ceb9daec
|
||||
integration_test: 5ed24a436eb7ec17b6a13046e9bf7ca4a404e59e
|
||||
integration_test: 6eb66a19f7104200dcfdd62bc0077e1b09686e4f
|
||||
path_provider: abfe2b5c733d04e238b0d8691db0cfd63a27a93c
|
||||
Reachability: 33e18b67625424e47b6cde6d202dce689ad7af96
|
||||
SDWebImage: b969dcfc02c40a5da71eac0b03b8f1a0c794a86f
|
||||
shared_preferences: af6bfa751691cdc24be3045c43ec037377ada40d
|
||||
SwiftyGif: e466e86c660d343357ab944a819a101c4127cb40
|
||||
|
@ -2,6 +2,6 @@
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "group:Runner.xcodeproj">
|
||||
location = "self:">
|
||||
</FileRef>
|
||||
</Workspace>
|
||||
|
@ -1,61 +1,51 @@
|
||||
import 'dart:async';
|
||||
|
||||
// ignore: uri_does_not_exist
|
||||
import 'cookie_client_stub.dart'
|
||||
// ignore: uri_does_not_exist
|
||||
if (dart.library.html) 'browser_cookie_client.dart'
|
||||
// ignore: uri_does_not_exist
|
||||
if (dart.library.io) 'io_cookie_client.dart';
|
||||
import 'package:imagini/api/cookie_client/cookie_client.dart'
|
||||
if (dart.library.html) 'package:imagini/api/cookie_client/browser_cookie_client.dart'
|
||||
if (dart.library.io) 'package:imagini/api/cookie_client/io_cookie_client.dart';
|
||||
|
||||
import 'package:meta/meta.dart';
|
||||
import 'package:imagini/core/storage_client/base_storage_client.dart';
|
||||
import 'package:graphql_flutter/graphql_flutter.dart';
|
||||
import 'package:imagini/graphql/imagini_graphql.dart';
|
||||
|
||||
class APIProvider{
|
||||
String _server, _accessToken, _refreshToken;
|
||||
|
||||
GraphQLClient _client;
|
||||
HttpLink httpLink;
|
||||
// CookieLink cookieLink;
|
||||
static const String _GRAPHQL_ENDPOINT = "/query";
|
||||
|
||||
APIProvider({
|
||||
@required String server,
|
||||
String accessToken,
|
||||
String refreshToken
|
||||
}) {
|
||||
_server = server;
|
||||
_accessToken = accessToken;
|
||||
_refreshToken = refreshToken;
|
||||
BaseStorageClient _storage;
|
||||
GraphQLClient _client;
|
||||
HttpLink httpLink;
|
||||
|
||||
APIProvider(BaseStorageClient storage) {
|
||||
_storage = storage;
|
||||
init();
|
||||
}
|
||||
|
||||
Future<void> init() async {
|
||||
String _server = await _storage.get("server");
|
||||
|
||||
httpLink = HttpLink(_server + _GRAPHQL_ENDPOINT,
|
||||
httpClient: getCookieClient(),
|
||||
httpClient: getCookieClient(_storage),
|
||||
);
|
||||
|
||||
// cookieLink = CookieLink(_updateAccessToken, _updateRefreshToken);
|
||||
_client = GraphQLClient(
|
||||
cache: GraphQLCache(),
|
||||
link: httpLink,
|
||||
);
|
||||
}
|
||||
|
||||
// void _updateAccessToken(_accessToken) {
|
||||
// print("Updating Access Token: $_accessToken");
|
||||
// this._accessToken = _accessToken;
|
||||
// }
|
||||
|
||||
// void _updateRefreshToken(_refreshToken) {
|
||||
// print("Updating Refresh Token: $_accessToken");
|
||||
// this._refreshToken = _refreshToken;
|
||||
// }
|
||||
|
||||
Future<Login$Query$AuthResponse> login([
|
||||
Future<QueryResult> login(
|
||||
String username,
|
||||
String password,
|
||||
]) async {
|
||||
String server,
|
||||
) async {
|
||||
assert(
|
||||
(username != null && password != null)
|
||||
(username != null && password != null && server != null)
|
||||
);
|
||||
|
||||
// Initialize Connection
|
||||
await _storage.set("server", server);
|
||||
await init();
|
||||
|
||||
QueryResult response = await _client.query(
|
||||
QueryOptions(
|
||||
document: LoginQuery().document,
|
||||
@ -65,79 +55,27 @@ class APIProvider{
|
||||
},
|
||||
)
|
||||
);
|
||||
|
||||
final loginResponse = Login$Query.fromJson(response.data);
|
||||
return loginResponse.login;
|
||||
return response;
|
||||
}
|
||||
|
||||
Future<Me$Query$User> me() async {
|
||||
Future<QueryResult> me() async {
|
||||
QueryResult response = await _client.query(
|
||||
QueryOptions(
|
||||
document: MeQuery().document,
|
||||
)
|
||||
);
|
||||
|
||||
final meResponse = Me$Query.fromJson(response.data);
|
||||
return meResponse.me;
|
||||
return response;
|
||||
}
|
||||
|
||||
Future<String> mediaItems([
|
||||
String startDate,
|
||||
String endDate,
|
||||
String albumID,
|
||||
List<String> tagID,
|
||||
String type, // TODO: Make enum
|
||||
int page,
|
||||
]) async {
|
||||
// Query:
|
||||
// /api/v1/MediaItems
|
||||
// Derive Params:
|
||||
// startDate:
|
||||
// &createdAt=>2020-10-10T10:10:10
|
||||
// endDate:
|
||||
// &createdAt=<2020-10-10T10:10:10
|
||||
// albumID:
|
||||
// &albumID=9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d
|
||||
// tagID:
|
||||
// &tagID=9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d,9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d
|
||||
// type:
|
||||
// &type=Photos
|
||||
// &type=Videos
|
||||
// page:
|
||||
// &page=4
|
||||
Future<QueryResult> mediaItems() async {
|
||||
QueryResult response = await _client.query(
|
||||
QueryOptions(
|
||||
document: MediaItemsQuery().document,
|
||||
)
|
||||
);
|
||||
|
||||
// Returns:
|
||||
// {
|
||||
//
|
||||
// }
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
Future<String> tags([
|
||||
int page
|
||||
]) async {
|
||||
// Query:
|
||||
// /api/v1/Tags
|
||||
// Derive Params:
|
||||
// page:
|
||||
// &page=4
|
||||
return null;
|
||||
}
|
||||
|
||||
Future<String> albums([
|
||||
int page
|
||||
]) async {
|
||||
// Query:
|
||||
// /api/v1/Albums
|
||||
// Derive Params:
|
||||
// page:
|
||||
// &page=4
|
||||
return null;
|
||||
}
|
||||
|
||||
Future<String> me() async {
|
||||
return null;
|
||||
print(response);
|
||||
return response;
|
||||
}
|
||||
|
||||
void dispose() {}
|
||||
|
@ -1,30 +0,0 @@
|
||||
import 'package:http/browser_client.dart';
|
||||
import "package:http/http.dart";
|
||||
|
||||
BaseClient getCookieClient() => ClientWithCookies();
|
||||
|
||||
class ClientWithCookies extends BrowserClient {
|
||||
String _accessToken = "asdasdasd";
|
||||
String _refreshToken;
|
||||
|
||||
@override
|
||||
Future<StreamedResponse> send(BaseRequest request) async {
|
||||
request.headers.addAll({
|
||||
'X-Imagini-AccessToken': _accessToken,
|
||||
'X-Imagini-RefreshToken': _refreshToken,
|
||||
});
|
||||
|
||||
return super.send(request).then((response) {
|
||||
if (response.headers.containsKey("x-imagini-accesstoken")) {
|
||||
this._accessToken = response.headers["x-imagini-accesstoken"];
|
||||
}
|
||||
if (response.headers.containsKey("x-imagini-refreshtoken")) {
|
||||
this._refreshToken = response.headers["x-imagini-refreshtoken"];
|
||||
}
|
||||
|
||||
print("Access Token: $_accessToken");
|
||||
print("Refresh Token: $_refreshToken");
|
||||
return response;
|
||||
});
|
||||
}
|
||||
}
|
36
web_native/lib/api/cookie_client/browser_cookie_client.dart
Normal file
36
web_native/lib/api/cookie_client/browser_cookie_client.dart
Normal file
@ -0,0 +1,36 @@
|
||||
import 'package:http/browser_client.dart';
|
||||
import "package:http/http.dart";
|
||||
import "package:imagini/core/storage_client/base_storage_client.dart";
|
||||
|
||||
BaseClient getCookieClient(storage) => ClientWithCookies(storage);
|
||||
|
||||
class ClientWithCookies extends BrowserClient {
|
||||
BaseStorageClient _storage;
|
||||
|
||||
ClientWithCookies(BaseStorageClient storage) {
|
||||
_storage = storage;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<StreamedResponse> send(BaseRequest request) async {
|
||||
String _accessToken = await _storage.get("accessToken");
|
||||
String _refreshToken = await _storage.get("refreshToken");
|
||||
|
||||
request.headers.addAll({
|
||||
'X-Imagini-AccessToken': _accessToken,
|
||||
'X-Imagini-RefreshToken': _refreshToken,
|
||||
});
|
||||
|
||||
return super.send(request).then((response) async {
|
||||
// We've been told to update our access token
|
||||
if (response.headers.containsKey("x-imagini-accesstoken")) {
|
||||
await _storage.set("accessToken", response.headers["x-imagini-accesstoken"]);
|
||||
}
|
||||
// We've been told to update our refresh token
|
||||
if (response.headers.containsKey("x-imagini-refreshtoken")) {
|
||||
await _storage.set("refreshToken", response.headers["x-imagini-refreshtoken"]);
|
||||
}
|
||||
return response;
|
||||
});
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
import 'package:http/http.dart';
|
||||
|
||||
BaseClient getCookieClient() => throw UnsupportedError(
|
||||
BaseClient getCookieClient(storage) => throw UnsupportedError(
|
||||
'Cannot create a client without dart:html or dart:io.');
|
43
web_native/lib/api/cookie_client/io_cookie_client.dart
Normal file
43
web_native/lib/api/cookie_client/io_cookie_client.dart
Normal file
@ -0,0 +1,43 @@
|
||||
import 'package:http/io_client.dart';
|
||||
import "package:http/http.dart";
|
||||
import "package:imagini/core/storage_client/base_storage_client.dart";
|
||||
|
||||
BaseClient getCookieClient(storage) => IOClientWithCookies(storage);
|
||||
|
||||
class IOClientWithCookies extends IOClient {
|
||||
BaseStorageClient _storage;
|
||||
|
||||
IOClientWithCookies(BaseStorageClient storage) {
|
||||
_storage = storage;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<IOStreamedResponse> send(BaseRequest request) async {
|
||||
String _accessToken = await _storage.get("accessToken");
|
||||
String _refreshToken = await _storage.get("refreshToken");
|
||||
|
||||
request.headers.addAll({
|
||||
'X-Imagini-AccessToken': _accessToken,
|
||||
'X-Imagini-RefreshToken': _refreshToken,
|
||||
});
|
||||
|
||||
return super.send(request).then((response) async {
|
||||
// We've been told to update our access token
|
||||
if (response.headers.containsKey("x-imagini-accesstoken")) {
|
||||
await _storage.set("accessToken", response.headers["x-imagini-accesstoken"]);
|
||||
}
|
||||
// We've been told to update our refresh token
|
||||
if (response.headers.containsKey("x-imagini-refreshtoken")) {
|
||||
await _storage.set("refreshToken", response.headers["x-imagini-refreshtoken"]);
|
||||
}
|
||||
|
||||
_accessToken = await _storage.get("accessToken");
|
||||
_refreshToken = await _storage.get("refreshToken");
|
||||
|
||||
print("Access Token: $_accessToken");
|
||||
print("Refresh Token: $_refreshToken");
|
||||
|
||||
return response;
|
||||
});
|
||||
}
|
||||
}
|
@ -1,12 +1,35 @@
|
||||
import 'dart:async';
|
||||
import 'package:imagini/api/api_provider.dart';
|
||||
import 'package:imagini/graphql/imagini_graphql.dart';
|
||||
import 'package:graphql_flutter/graphql_flutter.dart';
|
||||
|
||||
class ImaginiAPIRepository {
|
||||
APIProvider _apiProvider;
|
||||
|
||||
ImaginiAPIRepository(this._apiProvider);
|
||||
|
||||
Stream<Login$Query$AuthResponse> login(String user, password) {
|
||||
return Stream.fromFuture(_apiProvider.login(user, password));
|
||||
Stream<bool> login(String user, password, server) {
|
||||
return Stream.fromFuture(_apiProvider.login(user, password, server).then((QueryResult resp) {
|
||||
if (resp.exception != null)
|
||||
return false;
|
||||
|
||||
final loginResponse = Login$Query.fromJson(resp.data);
|
||||
if (loginResponse.login.result == AuthResult.failure)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}));
|
||||
}
|
||||
|
||||
Stream<QueryResult> me() {
|
||||
return Stream.fromFuture(_apiProvider.me());
|
||||
}
|
||||
|
||||
Stream<bool> isAuthenticated() {
|
||||
return Stream.fromFuture(_apiProvider.me().then((QueryResult resp) {
|
||||
if (resp.exception != null)
|
||||
return false;
|
||||
return true;
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
@ -1,28 +0,0 @@
|
||||
import 'package:http/io_client.dart';
|
||||
import "package:http/http.dart";
|
||||
|
||||
BaseClient getCookieClient() => IOClientWithCookies();
|
||||
|
||||
class IOClientWithCookies extends IOClient {
|
||||
String _accessToken;
|
||||
String _refreshToken;
|
||||
|
||||
@override
|
||||
Future<IOStreamedResponse> send(BaseRequest request) async {
|
||||
// String cookie = await getCookie();
|
||||
// String getCookieString(String _) => cookie;
|
||||
// request.headers.update('cookie', getCookieString);
|
||||
return super.send(request).then((response) {
|
||||
if (response.headers.containsKey("x-imagini-accesstoken")) {
|
||||
this._accessToken = response.headers["x-imagini-accesstoken"];
|
||||
}
|
||||
if (response.headers.containsKey("x-imagini-refreshtoken")) {
|
||||
this._refreshToken = response.headers["x-imagini-refreshtoken"];
|
||||
}
|
||||
|
||||
print("Access Token: $_accessToken");
|
||||
print("Refresh Token: $_refreshToken");
|
||||
return response;
|
||||
});
|
||||
}
|
||||
}
|
40
web_native/lib/blocs/login_bloc.dart
Normal file
40
web_native/lib/blocs/login_bloc.dart
Normal file
@ -0,0 +1,40 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:imagini/core/imagini_application.dart';
|
||||
import 'package:imagini/api/imagini_api_repository.dart';
|
||||
|
||||
class LoginBloc{
|
||||
|
||||
final ImaginiApplication _application;
|
||||
ImaginiAPIRepository _imaginiAPI;
|
||||
|
||||
final _loginController = StreamController<bool>.broadcast();
|
||||
Stream<bool> get loginResult => _loginController.stream;
|
||||
|
||||
final _authenticatedController = StreamController<bool>.broadcast();
|
||||
Stream<bool> get authenticatedResult => _authenticatedController.stream;
|
||||
|
||||
LoginBloc(this._application){
|
||||
_init();
|
||||
}
|
||||
|
||||
void _init(){
|
||||
_imaginiAPI = _application.imaginiAPI;
|
||||
checkAuthentication();
|
||||
|
||||
// attemptLogin("admin", "admin", "http://localhost:8484");
|
||||
}
|
||||
|
||||
void dispose(){
|
||||
_loginController.close();
|
||||
_authenticatedController.close();
|
||||
}
|
||||
|
||||
checkAuthentication(){
|
||||
_authenticatedController.addStream(_imaginiAPI.isAuthenticated());
|
||||
}
|
||||
|
||||
attemptLogin(String username, password, server){
|
||||
_loginController.addStream(_imaginiAPI.login(username, password, server));
|
||||
}
|
||||
}
|
@ -1,36 +0,0 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:imagini/core/imagini_application.dart';
|
||||
import 'package:imagini/api/imagini_api_repository.dart';
|
||||
import 'package:imagini/graphql/imagini_graphql.dart';
|
||||
|
||||
class SplashBloc{
|
||||
|
||||
final ImaginiApplication _application;
|
||||
|
||||
final _loginController = StreamController<Login$Query$AuthResponse>();
|
||||
Stream<Login$Query$AuthResponse> get loginResult => _loginController.stream;
|
||||
|
||||
SplashBloc(this._application){
|
||||
_init();
|
||||
}
|
||||
|
||||
void _init(){
|
||||
// Do Initial Load
|
||||
initializeLogin();
|
||||
}
|
||||
|
||||
void dispose(){
|
||||
_loginController.close();
|
||||
}
|
||||
|
||||
initializeLogin(){
|
||||
ImaginiAPIRepository imaginiAPI = _application.imaginiAPI;
|
||||
|
||||
// TODO: This should actually attempt to load the existing Tokens, not login
|
||||
_loginController.addStream(imaginiAPI.login("admin", "admin"));
|
||||
|
||||
// imaginiAPI.login("admin", "admin1").listen((LoginResponse lr) {
|
||||
// });
|
||||
}
|
||||
}
|
@ -24,7 +24,6 @@ class AppComponentState extends State<AppComponent> {
|
||||
|
||||
@override
|
||||
void dispose() async {
|
||||
// Log.info('dispose');
|
||||
super.dispose();
|
||||
await _application.onTerminate();
|
||||
}
|
||||
|
@ -3,13 +3,13 @@ import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:imagini/screens/home_screen.dart';
|
||||
import 'package:imagini/screens/login_screen.dart';
|
||||
import 'package:imagini/screens/splash_screen.dart';
|
||||
// import 'package:imagini/screens/splash_screen.dart';
|
||||
|
||||
var splashHandler = new Handler(
|
||||
handlerFunc: (BuildContext context, Map<String, List<String>> params) {
|
||||
return SplashScreen();
|
||||
}
|
||||
);
|
||||
// var splashHandler = new Handler(
|
||||
// handlerFunc: (BuildContext context, Map<String, List<String>> params) {
|
||||
// return SplashScreen();
|
||||
// }
|
||||
// );
|
||||
|
||||
var loginHandler = new Handler(
|
||||
handlerFunc: (BuildContext context, Map<String, List<String>> params) {
|
||||
@ -42,7 +42,7 @@ class AppRoutes {
|
||||
return;
|
||||
}
|
||||
);
|
||||
router.define(SplashScreen.PATH, handler: splashHandler);
|
||||
// router.define(SplashScreen.PATH, handler: splashHandler);
|
||||
router.define(LoginScreen.PATH, handler: loginHandler);
|
||||
router.define(HomeScreen.PATH, handler: homeHandler);
|
||||
// router.define(AppDetailPage.PATH, handler: appDetailRouteHandler);
|
||||
|
@ -3,13 +3,20 @@ import 'package:fluro/fluro.dart';
|
||||
import 'package:imagini/core/app_routes.dart';
|
||||
import 'package:imagini/api/api_provider.dart';
|
||||
import 'package:imagini/api/imagini_api_repository.dart';
|
||||
import 'package:imagini/core/storage_client/base_storage_client.dart';
|
||||
|
||||
import 'package:imagini/core/storage_client/storage_client.dart'
|
||||
if (dart.library.html) 'package:imagini/core/storage_client/browser_storage_client.dart'
|
||||
if (dart.library.io) 'package:imagini/core/storage_client/mobile_storage_client.dart';
|
||||
|
||||
class ImaginiApplication {
|
||||
FluroRouter router;
|
||||
ImaginiAPIRepository imaginiAPI;
|
||||
BaseStorageClient storageClient;
|
||||
|
||||
Future<void> onCreate() async {
|
||||
_initRouter();
|
||||
_initStorageClient();
|
||||
_initAPIRepository();
|
||||
}
|
||||
|
||||
@ -20,8 +27,13 @@ class ImaginiApplication {
|
||||
AppRoutes.configureRoutes(router);
|
||||
}
|
||||
|
||||
_initStorageClient() {
|
||||
storageClient = getStorageClient();
|
||||
}
|
||||
|
||||
_initAPIRepository() {
|
||||
APIProvider apiProvider = new APIProvider(server: "http://localhost:8484");
|
||||
// TODO: Get from config
|
||||
APIProvider apiProvider = new APIProvider(storageClient);
|
||||
imaginiAPI = ImaginiAPIRepository(apiProvider);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,4 @@
|
||||
abstract class BaseStorageClient {
|
||||
Future<String> get(String key);
|
||||
Future<void> set(String key, String value);
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
import 'dart:html';
|
||||
|
||||
import './base_storage_client.dart';
|
||||
|
||||
BaseStorageClient getStorageClient() => BrowserStorageClient();
|
||||
|
||||
class BrowserStorageClient extends BaseStorageClient {
|
||||
|
||||
@override
|
||||
Future<String> get(String key) async {
|
||||
var requestedValue = window.localStorage.containsKey(key) ? window.localStorage[key] : "";
|
||||
return requestedValue;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> set(String key, String value) async {
|
||||
window.localStorage[key] = value;
|
||||
}
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||
|
||||
import './base_storage_client.dart';
|
||||
|
||||
BaseStorageClient getStorageClient() => MobileStorageClient();
|
||||
|
||||
class MobileStorageClient extends BaseStorageClient {
|
||||
final storage = new FlutterSecureStorage();
|
||||
|
||||
@override
|
||||
Future<String> get(String key) async {
|
||||
return storage.read(key: key);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> set(String key, String value) async {
|
||||
return storage.write(key: key, value: value);
|
||||
}
|
||||
}
|
4
web_native/lib/core/storage_client/storage_client.dart
Normal file
4
web_native/lib/core/storage_client/storage_client.dart
Normal file
@ -0,0 +1,4 @@
|
||||
import './base_storage_client.dart';
|
||||
|
||||
BaseStorageClient getStorageClient() => throw UnsupportedError(
|
||||
'Cannot create a storage client.');
|
@ -170,6 +170,362 @@ class Me$Query with EquatableMixin {
|
||||
Map<String, dynamic> toJson() => _$Me$QueryToJson(this);
|
||||
}
|
||||
|
||||
@JsonSerializable(explicitToJson: true)
|
||||
class MediaItems$Query$MediaItemResponse$MediaItem with EquatableMixin {
|
||||
MediaItems$Query$MediaItemResponse$MediaItem();
|
||||
|
||||
factory MediaItems$Query$MediaItemResponse$MediaItem.fromJson(
|
||||
Map<String, dynamic> json) =>
|
||||
_$MediaItems$Query$MediaItemResponse$MediaItemFromJson(json);
|
||||
|
||||
String id;
|
||||
|
||||
String fileName;
|
||||
|
||||
double latitude;
|
||||
|
||||
double longitude;
|
||||
|
||||
bool isVideo;
|
||||
|
||||
String origName;
|
||||
|
||||
DateTime createdAt;
|
||||
|
||||
@override
|
||||
List<Object> get props =>
|
||||
[id, fileName, latitude, longitude, isVideo, origName, createdAt];
|
||||
Map<String, dynamic> toJson() =>
|
||||
_$MediaItems$Query$MediaItemResponse$MediaItemToJson(this);
|
||||
}
|
||||
|
||||
@JsonSerializable(explicitToJson: true)
|
||||
class MediaItems$Query$MediaItemResponse$PageResponse with EquatableMixin {
|
||||
MediaItems$Query$MediaItemResponse$PageResponse();
|
||||
|
||||
factory MediaItems$Query$MediaItemResponse$PageResponse.fromJson(
|
||||
Map<String, dynamic> json) =>
|
||||
_$MediaItems$Query$MediaItemResponse$PageResponseFromJson(json);
|
||||
|
||||
int size;
|
||||
|
||||
int page;
|
||||
|
||||
int total;
|
||||
|
||||
@override
|
||||
List<Object> get props => [size, page, total];
|
||||
Map<String, dynamic> toJson() =>
|
||||
_$MediaItems$Query$MediaItemResponse$PageResponseToJson(this);
|
||||
}
|
||||
|
||||
@JsonSerializable(explicitToJson: true)
|
||||
class MediaItems$Query$MediaItemResponse with EquatableMixin {
|
||||
MediaItems$Query$MediaItemResponse();
|
||||
|
||||
factory MediaItems$Query$MediaItemResponse.fromJson(
|
||||
Map<String, dynamic> json) =>
|
||||
_$MediaItems$Query$MediaItemResponseFromJson(json);
|
||||
|
||||
List<MediaItems$Query$MediaItemResponse$MediaItem> data;
|
||||
|
||||
MediaItems$Query$MediaItemResponse$PageResponse page;
|
||||
|
||||
@override
|
||||
List<Object> get props => [data, page];
|
||||
Map<String, dynamic> toJson() =>
|
||||
_$MediaItems$Query$MediaItemResponseToJson(this);
|
||||
}
|
||||
|
||||
@JsonSerializable(explicitToJson: true)
|
||||
class MediaItems$Query with EquatableMixin {
|
||||
MediaItems$Query();
|
||||
|
||||
factory MediaItems$Query.fromJson(Map<String, dynamic> json) =>
|
||||
_$MediaItems$QueryFromJson(json);
|
||||
|
||||
MediaItems$Query$MediaItemResponse mediaItems;
|
||||
|
||||
@override
|
||||
List<Object> get props => [mediaItems];
|
||||
Map<String, dynamic> toJson() => _$MediaItems$QueryToJson(this);
|
||||
}
|
||||
|
||||
@JsonSerializable(explicitToJson: true)
|
||||
class TimeFilter with EquatableMixin {
|
||||
TimeFilter(
|
||||
{this.equalTo,
|
||||
this.notEqualTo,
|
||||
this.lessThan,
|
||||
this.lessThanOrEqualTo,
|
||||
this.greaterThan,
|
||||
this.greaterThanOrEqualTo});
|
||||
|
||||
factory TimeFilter.fromJson(Map<String, dynamic> json) =>
|
||||
_$TimeFilterFromJson(json);
|
||||
|
||||
DateTime equalTo;
|
||||
|
||||
DateTime notEqualTo;
|
||||
|
||||
DateTime lessThan;
|
||||
|
||||
DateTime lessThanOrEqualTo;
|
||||
|
||||
DateTime greaterThan;
|
||||
|
||||
DateTime greaterThanOrEqualTo;
|
||||
|
||||
@override
|
||||
List<Object> get props => [
|
||||
equalTo,
|
||||
notEqualTo,
|
||||
lessThan,
|
||||
lessThanOrEqualTo,
|
||||
greaterThan,
|
||||
greaterThanOrEqualTo
|
||||
];
|
||||
Map<String, dynamic> toJson() => _$TimeFilterToJson(this);
|
||||
}
|
||||
|
||||
@JsonSerializable(explicitToJson: true)
|
||||
class FloatFilter with EquatableMixin {
|
||||
FloatFilter(
|
||||
{this.equalTo,
|
||||
this.notEqualTo,
|
||||
this.lessThan,
|
||||
this.lessThanOrEqualTo,
|
||||
this.greaterThan,
|
||||
this.greaterThanOrEqualTo});
|
||||
|
||||
factory FloatFilter.fromJson(Map<String, dynamic> json) =>
|
||||
_$FloatFilterFromJson(json);
|
||||
|
||||
double equalTo;
|
||||
|
||||
double notEqualTo;
|
||||
|
||||
double lessThan;
|
||||
|
||||
double lessThanOrEqualTo;
|
||||
|
||||
double greaterThan;
|
||||
|
||||
double greaterThanOrEqualTo;
|
||||
|
||||
@override
|
||||
List<Object> get props => [
|
||||
equalTo,
|
||||
notEqualTo,
|
||||
lessThan,
|
||||
lessThanOrEqualTo,
|
||||
greaterThan,
|
||||
greaterThanOrEqualTo
|
||||
];
|
||||
Map<String, dynamic> toJson() => _$FloatFilterToJson(this);
|
||||
}
|
||||
|
||||
@JsonSerializable(explicitToJson: true)
|
||||
class BooleanFilter with EquatableMixin {
|
||||
BooleanFilter({this.equalTo, this.notEqualTo});
|
||||
|
||||
factory BooleanFilter.fromJson(Map<String, dynamic> json) =>
|
||||
_$BooleanFilterFromJson(json);
|
||||
|
||||
bool equalTo;
|
||||
|
||||
bool notEqualTo;
|
||||
|
||||
@override
|
||||
List<Object> get props => [equalTo, notEqualTo];
|
||||
Map<String, dynamic> toJson() => _$BooleanFilterToJson(this);
|
||||
}
|
||||
|
||||
@JsonSerializable(explicitToJson: true)
|
||||
class IDFilter with EquatableMixin {
|
||||
IDFilter({this.equalTo, this.notEqualTo});
|
||||
|
||||
factory IDFilter.fromJson(Map<String, dynamic> json) =>
|
||||
_$IDFilterFromJson(json);
|
||||
|
||||
String equalTo;
|
||||
|
||||
String notEqualTo;
|
||||
|
||||
@override
|
||||
List<Object> get props => [equalTo, notEqualTo];
|
||||
Map<String, dynamic> toJson() => _$IDFilterToJson(this);
|
||||
}
|
||||
|
||||
@JsonSerializable(explicitToJson: true)
|
||||
class StringFilter with EquatableMixin {
|
||||
StringFilter(
|
||||
{this.equalTo,
|
||||
this.notEqualTo,
|
||||
this.startsWith,
|
||||
this.notStartsWith,
|
||||
this.endsWith,
|
||||
this.notEndsWith,
|
||||
this.contains,
|
||||
this.notContains});
|
||||
|
||||
factory StringFilter.fromJson(Map<String, dynamic> json) =>
|
||||
_$StringFilterFromJson(json);
|
||||
|
||||
String equalTo;
|
||||
|
||||
String notEqualTo;
|
||||
|
||||
String startsWith;
|
||||
|
||||
String notStartsWith;
|
||||
|
||||
String endsWith;
|
||||
|
||||
String notEndsWith;
|
||||
|
||||
String contains;
|
||||
|
||||
String notContains;
|
||||
|
||||
@override
|
||||
List<Object> get props => [
|
||||
equalTo,
|
||||
notEqualTo,
|
||||
startsWith,
|
||||
notStartsWith,
|
||||
endsWith,
|
||||
notEndsWith,
|
||||
contains,
|
||||
notContains
|
||||
];
|
||||
Map<String, dynamic> toJson() => _$StringFilterToJson(this);
|
||||
}
|
||||
|
||||
@JsonSerializable(explicitToJson: true)
|
||||
class MediaItemFilter with EquatableMixin {
|
||||
MediaItemFilter(
|
||||
{this.id,
|
||||
this.createdAt,
|
||||
this.updatedAt,
|
||||
this.exifDate,
|
||||
this.latitude,
|
||||
this.longitude,
|
||||
this.isVideo,
|
||||
this.origName,
|
||||
this.tags,
|
||||
this.albums});
|
||||
|
||||
factory MediaItemFilter.fromJson(Map<String, dynamic> json) =>
|
||||
_$MediaItemFilterFromJson(json);
|
||||
|
||||
IDFilter id;
|
||||
|
||||
TimeFilter createdAt;
|
||||
|
||||
TimeFilter updatedAt;
|
||||
|
||||
TimeFilter exifDate;
|
||||
|
||||
FloatFilter latitude;
|
||||
|
||||
FloatFilter longitude;
|
||||
|
||||
BooleanFilter isVideo;
|
||||
|
||||
StringFilter origName;
|
||||
|
||||
TagFilter tags;
|
||||
|
||||
AlbumFilter albums;
|
||||
|
||||
@override
|
||||
List<Object> get props => [
|
||||
id,
|
||||
createdAt,
|
||||
updatedAt,
|
||||
exifDate,
|
||||
latitude,
|
||||
longitude,
|
||||
isVideo,
|
||||
origName,
|
||||
tags,
|
||||
albums
|
||||
];
|
||||
Map<String, dynamic> toJson() => _$MediaItemFilterToJson(this);
|
||||
}
|
||||
|
||||
@JsonSerializable(explicitToJson: true)
|
||||
class TagFilter with EquatableMixin {
|
||||
TagFilter({this.id, this.createdAt, this.updatedAt, this.name});
|
||||
|
||||
factory TagFilter.fromJson(Map<String, dynamic> json) =>
|
||||
_$TagFilterFromJson(json);
|
||||
|
||||
IDFilter id;
|
||||
|
||||
TimeFilter createdAt;
|
||||
|
||||
TimeFilter updatedAt;
|
||||
|
||||
StringFilter name;
|
||||
|
||||
@override
|
||||
List<Object> get props => [id, createdAt, updatedAt, name];
|
||||
Map<String, dynamic> toJson() => _$TagFilterToJson(this);
|
||||
}
|
||||
|
||||
@JsonSerializable(explicitToJson: true)
|
||||
class AlbumFilter with EquatableMixin {
|
||||
AlbumFilter({this.id, this.createdAt, this.updatedAt, this.name});
|
||||
|
||||
factory AlbumFilter.fromJson(Map<String, dynamic> json) =>
|
||||
_$AlbumFilterFromJson(json);
|
||||
|
||||
IDFilter id;
|
||||
|
||||
TimeFilter createdAt;
|
||||
|
||||
TimeFilter updatedAt;
|
||||
|
||||
StringFilter name;
|
||||
|
||||
@override
|
||||
List<Object> get props => [id, createdAt, updatedAt, name];
|
||||
Map<String, dynamic> toJson() => _$AlbumFilterToJson(this);
|
||||
}
|
||||
|
||||
@JsonSerializable(explicitToJson: true)
|
||||
class Page with EquatableMixin {
|
||||
Page({this.size, this.page});
|
||||
|
||||
factory Page.fromJson(Map<String, dynamic> json) => _$PageFromJson(json);
|
||||
|
||||
int size;
|
||||
|
||||
int page;
|
||||
|
||||
@override
|
||||
List<Object> get props => [size, page];
|
||||
Map<String, dynamic> toJson() => _$PageToJson(this);
|
||||
}
|
||||
|
||||
@JsonSerializable(explicitToJson: true)
|
||||
class Order with EquatableMixin {
|
||||
Order({this.by, this.direction});
|
||||
|
||||
factory Order.fromJson(Map<String, dynamic> json) => _$OrderFromJson(json);
|
||||
|
||||
String by;
|
||||
|
||||
@JsonKey(unknownEnumValue: OrderDirection.artemisUnknown)
|
||||
OrderDirection direction;
|
||||
|
||||
@override
|
||||
List<Object> get props => [by, direction];
|
||||
Map<String, dynamic> toJson() => _$OrderToJson(this);
|
||||
}
|
||||
|
||||
enum AuthResult {
|
||||
@JsonValue('Success')
|
||||
success,
|
||||
@ -194,6 +550,14 @@ enum AuthType {
|
||||
@JsonValue('ARTEMIS_UNKNOWN')
|
||||
artemisUnknown,
|
||||
}
|
||||
enum OrderDirection {
|
||||
@JsonValue('ASC')
|
||||
asc,
|
||||
@JsonValue('DESC')
|
||||
desc,
|
||||
@JsonValue('ARTEMIS_UNKNOWN')
|
||||
artemisUnknown,
|
||||
}
|
||||
|
||||
@JsonSerializable(explicitToJson: true)
|
||||
class LoginArguments extends JsonSerializable with EquatableMixin {
|
||||
@ -508,3 +872,161 @@ class MeQuery extends GraphQLQuery<Me$Query, JsonSerializable> {
|
||||
@override
|
||||
Me$Query parse(Map<String, dynamic> json) => Me$Query.fromJson(json);
|
||||
}
|
||||
|
||||
@JsonSerializable(explicitToJson: true)
|
||||
class MediaItemsArguments extends JsonSerializable with EquatableMixin {
|
||||
MediaItemsArguments({this.order, this.page, this.filter});
|
||||
|
||||
@override
|
||||
factory MediaItemsArguments.fromJson(Map<String, dynamic> json) =>
|
||||
_$MediaItemsArgumentsFromJson(json);
|
||||
|
||||
final Order order;
|
||||
|
||||
final Page page;
|
||||
|
||||
final MediaItemFilter filter;
|
||||
|
||||
@override
|
||||
List<Object> get props => [order, page, filter];
|
||||
@override
|
||||
Map<String, dynamic> toJson() => _$MediaItemsArgumentsToJson(this);
|
||||
}
|
||||
|
||||
class MediaItemsQuery
|
||||
extends GraphQLQuery<MediaItems$Query, MediaItemsArguments> {
|
||||
MediaItemsQuery({this.variables});
|
||||
|
||||
@override
|
||||
final DocumentNode document = DocumentNode(definitions: [
|
||||
OperationDefinitionNode(
|
||||
type: OperationType.query,
|
||||
name: NameNode(value: 'mediaItems'),
|
||||
variableDefinitions: [
|
||||
VariableDefinitionNode(
|
||||
variable: VariableNode(name: NameNode(value: 'order')),
|
||||
type: NamedTypeNode(
|
||||
name: NameNode(value: 'Order'), isNonNull: false),
|
||||
defaultValue: DefaultValueNode(value: null),
|
||||
directives: []),
|
||||
VariableDefinitionNode(
|
||||
variable: VariableNode(name: NameNode(value: 'page')),
|
||||
type: NamedTypeNode(
|
||||
name: NameNode(value: 'Page'), isNonNull: false),
|
||||
defaultValue: DefaultValueNode(value: null),
|
||||
directives: []),
|
||||
VariableDefinitionNode(
|
||||
variable: VariableNode(name: NameNode(value: 'filter')),
|
||||
type: NamedTypeNode(
|
||||
name: NameNode(value: 'MediaItemFilter'), isNonNull: false),
|
||||
defaultValue: DefaultValueNode(value: null),
|
||||
directives: [])
|
||||
],
|
||||
directives: [],
|
||||
selectionSet: SelectionSetNode(selections: [
|
||||
FieldNode(
|
||||
name: NameNode(value: 'mediaItems'),
|
||||
alias: null,
|
||||
arguments: [
|
||||
ArgumentNode(
|
||||
name: NameNode(value: 'filter'),
|
||||
value: VariableNode(name: NameNode(value: 'filter'))),
|
||||
ArgumentNode(
|
||||
name: NameNode(value: 'page'),
|
||||
value: VariableNode(name: NameNode(value: 'page'))),
|
||||
ArgumentNode(
|
||||
name: NameNode(value: 'order'),
|
||||
value: VariableNode(name: NameNode(value: 'order')))
|
||||
],
|
||||
directives: [],
|
||||
selectionSet: SelectionSetNode(selections: [
|
||||
FieldNode(
|
||||
name: NameNode(value: 'data'),
|
||||
alias: null,
|
||||
arguments: [],
|
||||
directives: [],
|
||||
selectionSet: SelectionSetNode(selections: [
|
||||
FieldNode(
|
||||
name: NameNode(value: 'id'),
|
||||
alias: null,
|
||||
arguments: [],
|
||||
directives: [],
|
||||
selectionSet: null),
|
||||
FieldNode(
|
||||
name: NameNode(value: 'fileName'),
|
||||
alias: null,
|
||||
arguments: [],
|
||||
directives: [],
|
||||
selectionSet: null),
|
||||
FieldNode(
|
||||
name: NameNode(value: 'latitude'),
|
||||
alias: null,
|
||||
arguments: [],
|
||||
directives: [],
|
||||
selectionSet: null),
|
||||
FieldNode(
|
||||
name: NameNode(value: 'longitude'),
|
||||
alias: null,
|
||||
arguments: [],
|
||||
directives: [],
|
||||
selectionSet: null),
|
||||
FieldNode(
|
||||
name: NameNode(value: 'isVideo'),
|
||||
alias: null,
|
||||
arguments: [],
|
||||
directives: [],
|
||||
selectionSet: null),
|
||||
FieldNode(
|
||||
name: NameNode(value: 'origName'),
|
||||
alias: null,
|
||||
arguments: [],
|
||||
directives: [],
|
||||
selectionSet: null),
|
||||
FieldNode(
|
||||
name: NameNode(value: 'createdAt'),
|
||||
alias: null,
|
||||
arguments: [],
|
||||
directives: [],
|
||||
selectionSet: null)
|
||||
])),
|
||||
FieldNode(
|
||||
name: NameNode(value: 'page'),
|
||||
alias: null,
|
||||
arguments: [],
|
||||
directives: [],
|
||||
selectionSet: SelectionSetNode(selections: [
|
||||
FieldNode(
|
||||
name: NameNode(value: 'size'),
|
||||
alias: null,
|
||||
arguments: [],
|
||||
directives: [],
|
||||
selectionSet: null),
|
||||
FieldNode(
|
||||
name: NameNode(value: 'page'),
|
||||
alias: null,
|
||||
arguments: [],
|
||||
directives: [],
|
||||
selectionSet: null),
|
||||
FieldNode(
|
||||
name: NameNode(value: 'total'),
|
||||
alias: null,
|
||||
arguments: [],
|
||||
directives: [],
|
||||
selectionSet: null)
|
||||
]))
|
||||
]))
|
||||
]))
|
||||
]);
|
||||
|
||||
@override
|
||||
final String operationName = 'mediaItems';
|
||||
|
||||
@override
|
||||
final MediaItemsArguments variables;
|
||||
|
||||
@override
|
||||
List<Object> get props => [document, operationName, variables];
|
||||
@override
|
||||
MediaItems$Query parse(Map<String, dynamic> json) =>
|
||||
MediaItems$Query.fromJson(json);
|
||||
}
|
||||
|
@ -192,6 +192,318 @@ Map<String, dynamic> _$Me$QueryToJson(Me$Query instance) => <String, dynamic>{
|
||||
'me': instance.me?.toJson(),
|
||||
};
|
||||
|
||||
MediaItems$Query$MediaItemResponse$MediaItem
|
||||
_$MediaItems$Query$MediaItemResponse$MediaItemFromJson(
|
||||
Map<String, dynamic> json) {
|
||||
return MediaItems$Query$MediaItemResponse$MediaItem()
|
||||
..id = json['id'] as String
|
||||
..fileName = json['fileName'] as String
|
||||
..latitude = (json['latitude'] as num)?.toDouble()
|
||||
..longitude = (json['longitude'] as num)?.toDouble()
|
||||
..isVideo = json['isVideo'] as bool
|
||||
..origName = json['origName'] as String
|
||||
..createdAt = json['createdAt'] == null
|
||||
? null
|
||||
: DateTime.parse(json['createdAt'] as String);
|
||||
}
|
||||
|
||||
Map<String, dynamic> _$MediaItems$Query$MediaItemResponse$MediaItemToJson(
|
||||
MediaItems$Query$MediaItemResponse$MediaItem instance) =>
|
||||
<String, dynamic>{
|
||||
'id': instance.id,
|
||||
'fileName': instance.fileName,
|
||||
'latitude': instance.latitude,
|
||||
'longitude': instance.longitude,
|
||||
'isVideo': instance.isVideo,
|
||||
'origName': instance.origName,
|
||||
'createdAt': instance.createdAt?.toIso8601String(),
|
||||
};
|
||||
|
||||
MediaItems$Query$MediaItemResponse$PageResponse
|
||||
_$MediaItems$Query$MediaItemResponse$PageResponseFromJson(
|
||||
Map<String, dynamic> json) {
|
||||
return MediaItems$Query$MediaItemResponse$PageResponse()
|
||||
..size = json['size'] as int
|
||||
..page = json['page'] as int
|
||||
..total = json['total'] as int;
|
||||
}
|
||||
|
||||
Map<String, dynamic> _$MediaItems$Query$MediaItemResponse$PageResponseToJson(
|
||||
MediaItems$Query$MediaItemResponse$PageResponse instance) =>
|
||||
<String, dynamic>{
|
||||
'size': instance.size,
|
||||
'page': instance.page,
|
||||
'total': instance.total,
|
||||
};
|
||||
|
||||
MediaItems$Query$MediaItemResponse _$MediaItems$Query$MediaItemResponseFromJson(
|
||||
Map<String, dynamic> json) {
|
||||
return MediaItems$Query$MediaItemResponse()
|
||||
..data = (json['data'] as List)
|
||||
?.map((e) => e == null
|
||||
? null
|
||||
: MediaItems$Query$MediaItemResponse$MediaItem.fromJson(
|
||||
e as Map<String, dynamic>))
|
||||
?.toList()
|
||||
..page = json['page'] == null
|
||||
? null
|
||||
: MediaItems$Query$MediaItemResponse$PageResponse.fromJson(
|
||||
json['page'] as Map<String, dynamic>);
|
||||
}
|
||||
|
||||
Map<String, dynamic> _$MediaItems$Query$MediaItemResponseToJson(
|
||||
MediaItems$Query$MediaItemResponse instance) =>
|
||||
<String, dynamic>{
|
||||
'data': instance.data?.map((e) => e?.toJson())?.toList(),
|
||||
'page': instance.page?.toJson(),
|
||||
};
|
||||
|
||||
MediaItems$Query _$MediaItems$QueryFromJson(Map<String, dynamic> json) {
|
||||
return MediaItems$Query()
|
||||
..mediaItems = json['mediaItems'] == null
|
||||
? null
|
||||
: MediaItems$Query$MediaItemResponse.fromJson(
|
||||
json['mediaItems'] as Map<String, dynamic>);
|
||||
}
|
||||
|
||||
Map<String, dynamic> _$MediaItems$QueryToJson(MediaItems$Query instance) =>
|
||||
<String, dynamic>{
|
||||
'mediaItems': instance.mediaItems?.toJson(),
|
||||
};
|
||||
|
||||
TimeFilter _$TimeFilterFromJson(Map<String, dynamic> json) {
|
||||
return TimeFilter(
|
||||
equalTo: json['equalTo'] == null
|
||||
? null
|
||||
: DateTime.parse(json['equalTo'] as String),
|
||||
notEqualTo: json['notEqualTo'] == null
|
||||
? null
|
||||
: DateTime.parse(json['notEqualTo'] as String),
|
||||
lessThan: json['lessThan'] == null
|
||||
? null
|
||||
: DateTime.parse(json['lessThan'] as String),
|
||||
lessThanOrEqualTo: json['lessThanOrEqualTo'] == null
|
||||
? null
|
||||
: DateTime.parse(json['lessThanOrEqualTo'] as String),
|
||||
greaterThan: json['greaterThan'] == null
|
||||
? null
|
||||
: DateTime.parse(json['greaterThan'] as String),
|
||||
greaterThanOrEqualTo: json['greaterThanOrEqualTo'] == null
|
||||
? null
|
||||
: DateTime.parse(json['greaterThanOrEqualTo'] as String),
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> _$TimeFilterToJson(TimeFilter instance) =>
|
||||
<String, dynamic>{
|
||||
'equalTo': instance.equalTo?.toIso8601String(),
|
||||
'notEqualTo': instance.notEqualTo?.toIso8601String(),
|
||||
'lessThan': instance.lessThan?.toIso8601String(),
|
||||
'lessThanOrEqualTo': instance.lessThanOrEqualTo?.toIso8601String(),
|
||||
'greaterThan': instance.greaterThan?.toIso8601String(),
|
||||
'greaterThanOrEqualTo': instance.greaterThanOrEqualTo?.toIso8601String(),
|
||||
};
|
||||
|
||||
FloatFilter _$FloatFilterFromJson(Map<String, dynamic> json) {
|
||||
return FloatFilter(
|
||||
equalTo: (json['equalTo'] as num)?.toDouble(),
|
||||
notEqualTo: (json['notEqualTo'] as num)?.toDouble(),
|
||||
lessThan: (json['lessThan'] as num)?.toDouble(),
|
||||
lessThanOrEqualTo: (json['lessThanOrEqualTo'] as num)?.toDouble(),
|
||||
greaterThan: (json['greaterThan'] as num)?.toDouble(),
|
||||
greaterThanOrEqualTo: (json['greaterThanOrEqualTo'] as num)?.toDouble(),
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> _$FloatFilterToJson(FloatFilter instance) =>
|
||||
<String, dynamic>{
|
||||
'equalTo': instance.equalTo,
|
||||
'notEqualTo': instance.notEqualTo,
|
||||
'lessThan': instance.lessThan,
|
||||
'lessThanOrEqualTo': instance.lessThanOrEqualTo,
|
||||
'greaterThan': instance.greaterThan,
|
||||
'greaterThanOrEqualTo': instance.greaterThanOrEqualTo,
|
||||
};
|
||||
|
||||
BooleanFilter _$BooleanFilterFromJson(Map<String, dynamic> json) {
|
||||
return BooleanFilter(
|
||||
equalTo: json['equalTo'] as bool,
|
||||
notEqualTo: json['notEqualTo'] as bool,
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> _$BooleanFilterToJson(BooleanFilter instance) =>
|
||||
<String, dynamic>{
|
||||
'equalTo': instance.equalTo,
|
||||
'notEqualTo': instance.notEqualTo,
|
||||
};
|
||||
|
||||
IDFilter _$IDFilterFromJson(Map<String, dynamic> json) {
|
||||
return IDFilter(
|
||||
equalTo: json['equalTo'] as String,
|
||||
notEqualTo: json['notEqualTo'] as String,
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> _$IDFilterToJson(IDFilter instance) => <String, dynamic>{
|
||||
'equalTo': instance.equalTo,
|
||||
'notEqualTo': instance.notEqualTo,
|
||||
};
|
||||
|
||||
StringFilter _$StringFilterFromJson(Map<String, dynamic> json) {
|
||||
return StringFilter(
|
||||
equalTo: json['equalTo'] as String,
|
||||
notEqualTo: json['notEqualTo'] as String,
|
||||
startsWith: json['startsWith'] as String,
|
||||
notStartsWith: json['notStartsWith'] as String,
|
||||
endsWith: json['endsWith'] as String,
|
||||
notEndsWith: json['notEndsWith'] as String,
|
||||
contains: json['contains'] as String,
|
||||
notContains: json['notContains'] as String,
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> _$StringFilterToJson(StringFilter instance) =>
|
||||
<String, dynamic>{
|
||||
'equalTo': instance.equalTo,
|
||||
'notEqualTo': instance.notEqualTo,
|
||||
'startsWith': instance.startsWith,
|
||||
'notStartsWith': instance.notStartsWith,
|
||||
'endsWith': instance.endsWith,
|
||||
'notEndsWith': instance.notEndsWith,
|
||||
'contains': instance.contains,
|
||||
'notContains': instance.notContains,
|
||||
};
|
||||
|
||||
MediaItemFilter _$MediaItemFilterFromJson(Map<String, dynamic> json) {
|
||||
return MediaItemFilter(
|
||||
id: json['id'] == null
|
||||
? null
|
||||
: IDFilter.fromJson(json['id'] as Map<String, dynamic>),
|
||||
createdAt: json['createdAt'] == null
|
||||
? null
|
||||
: TimeFilter.fromJson(json['createdAt'] as Map<String, dynamic>),
|
||||
updatedAt: json['updatedAt'] == null
|
||||
? null
|
||||
: TimeFilter.fromJson(json['updatedAt'] as Map<String, dynamic>),
|
||||
exifDate: json['exifDate'] == null
|
||||
? null
|
||||
: TimeFilter.fromJson(json['exifDate'] as Map<String, dynamic>),
|
||||
latitude: json['latitude'] == null
|
||||
? null
|
||||
: FloatFilter.fromJson(json['latitude'] as Map<String, dynamic>),
|
||||
longitude: json['longitude'] == null
|
||||
? null
|
||||
: FloatFilter.fromJson(json['longitude'] as Map<String, dynamic>),
|
||||
isVideo: json['isVideo'] == null
|
||||
? null
|
||||
: BooleanFilter.fromJson(json['isVideo'] as Map<String, dynamic>),
|
||||
origName: json['origName'] == null
|
||||
? null
|
||||
: StringFilter.fromJson(json['origName'] as Map<String, dynamic>),
|
||||
tags: json['tags'] == null
|
||||
? null
|
||||
: TagFilter.fromJson(json['tags'] as Map<String, dynamic>),
|
||||
albums: json['albums'] == null
|
||||
? null
|
||||
: AlbumFilter.fromJson(json['albums'] as Map<String, dynamic>),
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> _$MediaItemFilterToJson(MediaItemFilter instance) =>
|
||||
<String, dynamic>{
|
||||
'id': instance.id?.toJson(),
|
||||
'createdAt': instance.createdAt?.toJson(),
|
||||
'updatedAt': instance.updatedAt?.toJson(),
|
||||
'exifDate': instance.exifDate?.toJson(),
|
||||
'latitude': instance.latitude?.toJson(),
|
||||
'longitude': instance.longitude?.toJson(),
|
||||
'isVideo': instance.isVideo?.toJson(),
|
||||
'origName': instance.origName?.toJson(),
|
||||
'tags': instance.tags?.toJson(),
|
||||
'albums': instance.albums?.toJson(),
|
||||
};
|
||||
|
||||
TagFilter _$TagFilterFromJson(Map<String, dynamic> json) {
|
||||
return TagFilter(
|
||||
id: json['id'] == null
|
||||
? null
|
||||
: IDFilter.fromJson(json['id'] as Map<String, dynamic>),
|
||||
createdAt: json['createdAt'] == null
|
||||
? null
|
||||
: TimeFilter.fromJson(json['createdAt'] as Map<String, dynamic>),
|
||||
updatedAt: json['updatedAt'] == null
|
||||
? null
|
||||
: TimeFilter.fromJson(json['updatedAt'] as Map<String, dynamic>),
|
||||
name: json['name'] == null
|
||||
? null
|
||||
: StringFilter.fromJson(json['name'] as Map<String, dynamic>),
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> _$TagFilterToJson(TagFilter instance) => <String, dynamic>{
|
||||
'id': instance.id?.toJson(),
|
||||
'createdAt': instance.createdAt?.toJson(),
|
||||
'updatedAt': instance.updatedAt?.toJson(),
|
||||
'name': instance.name?.toJson(),
|
||||
};
|
||||
|
||||
AlbumFilter _$AlbumFilterFromJson(Map<String, dynamic> json) {
|
||||
return AlbumFilter(
|
||||
id: json['id'] == null
|
||||
? null
|
||||
: IDFilter.fromJson(json['id'] as Map<String, dynamic>),
|
||||
createdAt: json['createdAt'] == null
|
||||
? null
|
||||
: TimeFilter.fromJson(json['createdAt'] as Map<String, dynamic>),
|
||||
updatedAt: json['updatedAt'] == null
|
||||
? null
|
||||
: TimeFilter.fromJson(json['updatedAt'] as Map<String, dynamic>),
|
||||
name: json['name'] == null
|
||||
? null
|
||||
: StringFilter.fromJson(json['name'] as Map<String, dynamic>),
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> _$AlbumFilterToJson(AlbumFilter instance) =>
|
||||
<String, dynamic>{
|
||||
'id': instance.id?.toJson(),
|
||||
'createdAt': instance.createdAt?.toJson(),
|
||||
'updatedAt': instance.updatedAt?.toJson(),
|
||||
'name': instance.name?.toJson(),
|
||||
};
|
||||
|
||||
Page _$PageFromJson(Map<String, dynamic> json) {
|
||||
return Page(
|
||||
size: json['size'] as int,
|
||||
page: json['page'] as int,
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> _$PageToJson(Page instance) => <String, dynamic>{
|
||||
'size': instance.size,
|
||||
'page': instance.page,
|
||||
};
|
||||
|
||||
Order _$OrderFromJson(Map<String, dynamic> json) {
|
||||
return Order(
|
||||
by: json['by'] as String,
|
||||
direction: _$enumDecodeNullable(_$OrderDirectionEnumMap, json['direction'],
|
||||
unknownValue: OrderDirection.artemisUnknown),
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> _$OrderToJson(Order instance) => <String, dynamic>{
|
||||
'by': instance.by,
|
||||
'direction': _$OrderDirectionEnumMap[instance.direction],
|
||||
};
|
||||
|
||||
const _$OrderDirectionEnumMap = {
|
||||
OrderDirection.asc: 'ASC',
|
||||
OrderDirection.desc: 'DESC',
|
||||
OrderDirection.artemisUnknown: 'ARTEMIS_UNKNOWN',
|
||||
};
|
||||
|
||||
LoginArguments _$LoginArgumentsFromJson(Map<String, dynamic> json) {
|
||||
return LoginArguments(
|
||||
user: json['user'] as String,
|
||||
@ -219,3 +531,25 @@ Map<String, dynamic> _$CreateMediaItemArgumentsToJson(
|
||||
<String, dynamic>{
|
||||
'file': fromDartMultipartFileToGraphQLUpload(instance.file),
|
||||
};
|
||||
|
||||
MediaItemsArguments _$MediaItemsArgumentsFromJson(Map<String, dynamic> json) {
|
||||
return MediaItemsArguments(
|
||||
order: json['order'] == null
|
||||
? null
|
||||
: Order.fromJson(json['order'] as Map<String, dynamic>),
|
||||
page: json['page'] == null
|
||||
? null
|
||||
: Page.fromJson(json['page'] as Map<String, dynamic>),
|
||||
filter: json['filter'] == null
|
||||
? null
|
||||
: MediaItemFilter.fromJson(json['filter'] as Map<String, dynamic>),
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> _$MediaItemsArgumentsToJson(
|
||||
MediaItemsArguments instance) =>
|
||||
<String, dynamic>{
|
||||
'order': instance.order?.toJson(),
|
||||
'page': instance.page?.toJson(),
|
||||
'filter': instance.filter?.toJson(),
|
||||
};
|
||||
|
@ -1,12 +1,13 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:fluro/fluro.dart';
|
||||
|
||||
import 'package:flutter_platform_widgets/flutter_platform_widgets.dart';
|
||||
|
||||
import 'package:imagini/blocs/login_bloc.dart';
|
||||
import 'package:imagini/core/app_provider.dart';
|
||||
|
||||
class LoginScreen extends StatefulWidget {
|
||||
static const String PATH = '/Login';
|
||||
static const String PATH = '/';
|
||||
|
||||
LoginScreen({Key key}) : super(key: key);
|
||||
|
||||
@ -16,7 +17,7 @@ class LoginScreen extends StatefulWidget {
|
||||
|
||||
class _LoginScreenState extends State<LoginScreen> {
|
||||
|
||||
// LoginBloc bloc;
|
||||
LoginBloc bloc;
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
@ -29,12 +30,76 @@ class _LoginScreenState extends State<LoginScreen> {
|
||||
_init();
|
||||
|
||||
return Scaffold(
|
||||
body: Center(
|
||||
body: StreamBuilder<bool>(
|
||||
stream: bloc.authenticatedResult,
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.data == null || snapshot.data == true)
|
||||
return _appLoading();
|
||||
return _appLogin();
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
void _init(){
|
||||
if(bloc != null){
|
||||
return;
|
||||
}
|
||||
|
||||
bloc = LoginBloc(AppProvider.getApplication(context));
|
||||
bloc.authenticatedResult.listen((bool status) {
|
||||
if (status)
|
||||
AppProvider.getRouter(context).navigateTo(context, "/Home", transition: TransitionType.fadeIn);
|
||||
});
|
||||
|
||||
bloc.loginResult.listen((bool status) {
|
||||
if (status == null || status == false)
|
||||
return;
|
||||
|
||||
AppProvider.getRouter(context).navigateTo(context, "/Home", transition: TransitionType.fadeIn);
|
||||
});
|
||||
}
|
||||
|
||||
Widget _appLoading(){
|
||||
return Center(
|
||||
child: ConstrainedBox(
|
||||
constraints: BoxConstraints(maxWidth: 500),
|
||||
child: Container(
|
||||
margin: EdgeInsets.fromLTRB(50, 0, 50, 0),
|
||||
height: 270,
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
Container(
|
||||
child: FittedBox(
|
||||
fit: BoxFit.contain,
|
||||
child: const FlutterLogo(),
|
||||
),
|
||||
width: 175,
|
||||
margin: EdgeInsets.fromLTRB(0, 0, 0, 50),
|
||||
),
|
||||
PlatformCircularProgressIndicator()
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _appLogin(){
|
||||
TextEditingController serverController = new TextEditingController();
|
||||
TextEditingController userController = new TextEditingController();
|
||||
TextEditingController passwordController = new TextEditingController();
|
||||
|
||||
final _formKey = GlobalKey<FormState>();
|
||||
|
||||
return Center(
|
||||
child: ConstrainedBox(
|
||||
constraints: BoxConstraints(maxWidth: 500),
|
||||
child: Container(
|
||||
margin: EdgeInsets.fromLTRB(50, 0, 50, 0),
|
||||
height: 500,
|
||||
child: Form(
|
||||
key: _formKey,
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
Container(
|
||||
@ -46,24 +111,45 @@ class _LoginScreenState extends State<LoginScreen> {
|
||||
margin: EdgeInsets.fromLTRB(0, 0, 0, 50),
|
||||
),
|
||||
Expanded(
|
||||
child: TextField(
|
||||
child: TextFormField(
|
||||
controller: serverController,
|
||||
validator: (value) {
|
||||
if (value.isEmpty) {
|
||||
return 'Please enter server address';
|
||||
}
|
||||
return null;
|
||||
},
|
||||
decoration: InputDecoration(
|
||||
labelText: 'Server Address'
|
||||
),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: TextField(
|
||||
child: TextFormField(
|
||||
controller: userController,
|
||||
validator: (value) {
|
||||
if (value.isEmpty) {
|
||||
return 'Please enter username or email';
|
||||
}
|
||||
return null;
|
||||
},
|
||||
decoration: InputDecoration(
|
||||
labelText: 'Username / Email'
|
||||
),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: TextField(
|
||||
child: TextFormField(
|
||||
obscureText: true,
|
||||
enableSuggestions: false,
|
||||
autocorrect: false,
|
||||
controller: passwordController,
|
||||
validator: (value) {
|
||||
if (value.isEmpty) {
|
||||
return 'Please enter password';
|
||||
}
|
||||
return null;
|
||||
},
|
||||
decoration: InputDecoration(
|
||||
labelText: 'Password'
|
||||
),
|
||||
@ -73,11 +159,31 @@ class _LoginScreenState extends State<LoginScreen> {
|
||||
width: double.infinity,
|
||||
child: PlatformButton(
|
||||
onPressed: () {
|
||||
AppProvider.getRouter(context).navigateTo(context, "/Home", transition: TransitionType.fadeIn);
|
||||
if (!_formKey.currentState.validate())
|
||||
return;
|
||||
bloc.attemptLogin(userController.text, passwordController.text, serverController.text);
|
||||
},
|
||||
child: Text('Login')
|
||||
),
|
||||
),
|
||||
|
||||
StreamBuilder<bool>(
|
||||
stream: bloc.loginResult,
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.data == null || snapshot.data == true)
|
||||
return Container();
|
||||
|
||||
return Expanded(
|
||||
child: Padding(
|
||||
padding: EdgeInsets.fromLTRB(20, 20, 20, 20),
|
||||
child: Text(
|
||||
"Login Failed",
|
||||
style: TextStyle(color: Colors.red),
|
||||
)
|
||||
),
|
||||
);
|
||||
}
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
@ -85,10 +191,4 @@ class _LoginScreenState extends State<LoginScreen> {
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _init(){
|
||||
// if(null == bloc){
|
||||
// bloc = LoginBloc(AppProvider.getApplication(context));
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
@ -1,70 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_platform_widgets/flutter_platform_widgets.dart';
|
||||
import 'package:fluro/fluro.dart';
|
||||
|
||||
import 'package:imagini/core/app_provider.dart';
|
||||
import 'package:imagini/blocs/splash_bloc.dart';
|
||||
import 'package:imagini/graphql/imagini_graphql.dart';
|
||||
|
||||
class SplashScreen extends StatefulWidget {
|
||||
static const String PATH = '/';
|
||||
|
||||
SplashScreen({Key key}) : super(key: key);
|
||||
|
||||
@override
|
||||
_SplashScreenState createState() => _SplashScreenState();
|
||||
}
|
||||
|
||||
class _SplashScreenState extends State<SplashScreen> {
|
||||
|
||||
SplashBloc bloc;
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
super.dispose();
|
||||
bloc.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
_init();
|
||||
|
||||
return Scaffold(
|
||||
body: Center(
|
||||
child: ConstrainedBox(
|
||||
constraints: BoxConstraints(maxWidth: 500),
|
||||
child: Container(
|
||||
margin: EdgeInsets.fromLTRB(50, 0, 50, 0),
|
||||
height: 270,
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
Container(
|
||||
child: FittedBox(
|
||||
fit: BoxFit.contain,
|
||||
child: const FlutterLogo(),
|
||||
),
|
||||
width: 175,
|
||||
margin: EdgeInsets.fromLTRB(0, 0, 0, 50),
|
||||
),
|
||||
PlatformCircularProgressIndicator()
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _init(){
|
||||
if(null == bloc){
|
||||
bloc = SplashBloc(AppProvider.getApplication(context));
|
||||
bloc.loginResult.listen((Login$Query$AuthResponse lr) {
|
||||
if (lr.result == AuthResult.success) {
|
||||
AppProvider.getRouter(context).navigateTo(context, "/Home", transition: TransitionType.fadeIn);
|
||||
} else {
|
||||
AppProvider.getRouter(context).navigateTo(context, "/Login", transition: TransitionType.fadeIn);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user