Documentation, Basic Login Workflow

This commit is contained in:
Evan Reichard 2021-02-20 14:10:25 -05:00
parent fec590b16e
commit 5212d7bf70
27 changed files with 1327 additions and 341 deletions

2
.gitignore vendored
View File

@ -1,3 +1,5 @@
imagini.db
media/
notes
web/node_modules/
web/dist/

View File

@ -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

View File

@ -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)

View File

@ -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

View 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
}
}
}

View File

@ -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

View File

@ -2,6 +2,6 @@
<Workspace
version = "1.0">
<FileRef
location = "group:Runner.xcodeproj">
location = "self:">
</FileRef>
</Workspace>

View File

@ -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() {}

View File

@ -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;
});
}
}

View 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;
});
}
}

View File

@ -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.');

View 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;
});
}
}

View File

@ -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;
}));
}
}

View File

@ -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;
});
}
}

View 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));
}
}

View File

@ -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) {
// });
}
}

View File

@ -24,7 +24,6 @@ class AppComponentState extends State<AppComponent> {
@override
void dispose() async {
// Log.info('dispose');
super.dispose();
await _application.onTerminate();
}

View File

@ -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);

View File

@ -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);
}
}

View File

@ -0,0 +1,4 @@
abstract class BaseStorageClient {
Future<String> get(String key);
Future<void> set(String key, String value);
}

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -0,0 +1,4 @@
import './base_storage_client.dart';
BaseStorageClient getStorageClient() => throw UnsupportedError(
'Cannot create a storage client.');

View File

@ -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);
}

View File

@ -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(),
};

View File

@ -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(
child: ConstrainedBox(
constraints: BoxConstraints(maxWidth: 500),
child: Container(
margin: EdgeInsets.fromLTRB(50, 0, 50, 0),
height: 500,
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));
// }
}
}

View File

@ -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);
}
});
}
}
}