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 | notes | ||||||
| web/node_modules/ | web/node_modules/ | ||||||
| web/dist/ | 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 | ## Server | ||||||
|     # cd ./cmd/ | ### Running | ||||||
|     CONFIG_PATH=$(pwd) DATA_PATH=$(pwd) go run main.go serve |  | ||||||
| 
 | 
 | ||||||
| ## Generate GraphQL Models |     CONFIG_PATH=$(pwd) DATA_PATH=$(pwd) go run cmd/main.go serve | ||||||
|     # cd ./cmd/ | 
 | ||||||
|  | ## Building | ||||||
|  | 
 | ||||||
|  |     # Generate GraphQL Models | ||||||
|     go run github.com/99designs/gqlgen generate |     go run github.com/99designs/gqlgen generate | ||||||
|     go run main.go generate |     go run cmd/main.go generate | ||||||
| 
 | 
 | ||||||
| ## Generate GraphQL Documentation |     # Generate GraphQL Documentation | ||||||
|     # From app root |  | ||||||
|     graphdoc -e http://localhost:8484/query -o ./docs/schema |     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 |     flutter run | ||||||
| 
 | 
 | ||||||
| ## Generate GraphQL Flutter Models | ### Building | ||||||
|  | 
 | ||||||
|  |     # Generate GraphQL Flutter Models | ||||||
|     flutter pub run build_runner build |     flutter pub run build_runner build | ||||||
|  | |||||||
| @ -41,35 +41,46 @@ func (api *API) refreshTokens(refreshToken jwt.Token) (string, string, error) { | |||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// Update Access Token | 	// Update Access Token | ||||||
| 	accessTokenCookie, err := api.Auth.CreateJWTAccessToken(user, device) | 	accessToken, err := api.Auth.CreateJWTAccessToken(user, device) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return "", "", err | 		return "", "", err | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return accessTokenCookie, "", err | 	return accessToken, "", err | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (api *API) validateTokens(w *http.ResponseWriter, r *http.Request) (jwt.Token, error) { | func (api *API) validateTokens(w *http.ResponseWriter, r *http.Request) (jwt.Token, error) { | ||||||
| 	// TODO: Check from X-Imagini-AccessToken | 	accessTokenHeader := r.Header.Get("X-Imagini-AccessToken") | ||||||
| 	// TODO: Check from X-Imagini-RefreshToken | 	if accessTokenHeader != "" { | ||||||
| 
 | 		accessToken, err := api.Auth.ValidateJWTAccessToken(accessTokenHeader) | ||||||
| 	// Validate Access Token |  | ||||||
| 	accessCookie, _ := r.Cookie("AccessToken") |  | ||||||
| 	if accessCookie != nil { |  | ||||||
| 		accessToken, err := api.Auth.ValidateJWTAccessToken(accessCookie.Value) |  | ||||||
| 		if err == nil { | 		if err == nil { | ||||||
| 			return accessToken, nil | 			return accessToken, nil | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// Validate Refresh Cookie Exists | 	refreshTokenHeader := r.Header.Get("X-Imagini-RefreshToken") | ||||||
| 	refreshCookie, _ := r.Cookie("RefreshToken") | 	if refreshTokenHeader == "" { | ||||||
| 	if refreshCookie == nil { |  | ||||||
| 		return nil, errors.New("Tokens Invalid") | 		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 | 	// 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 { | 	if err != nil { | ||||||
| 		return nil, errors.New("Tokens Invalid") | 		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 | 	// TODO: Actually Refresh Refresh Token | ||||||
| 	newRefreshToken = refreshCookie.Value | 	// newRefreshToken = refreshCookie.Value | ||||||
|  | 	newRefreshToken = refreshTokenHeader | ||||||
| 
 | 
 | ||||||
| 	// Set appropriate cookies (TODO: Only for web!) | 	// Set appropriate cookies (TODO: Only for web!) | ||||||
| 
 | 
 | ||||||
| 	// Update Access & Refresh Cookies | 	// Update Access & Refresh Cookies | ||||||
| 	http.SetCookie(*w, &http.Cookie{ | 	// http.SetCookie(*w, &http.Cookie{ | ||||||
| 		Name:  "AccessToken", | 	// 	Name:  "AccessToken", | ||||||
| 		Value: newAccessToken, | 	// 	Value: newAccessToken, | ||||||
| 	}) | 	// }) | ||||||
| 	http.SetCookie(*w, &http.Cookie{ | 	// http.SetCookie(*w, &http.Cookie{ | ||||||
| 		Name:  "RefreshToken", | 	// 	Name:  "RefreshToken", | ||||||
| 		Value: newRefreshToken, | 	// 	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-AccessToken", newAccessToken) | ||||||
| 	(*w).Header().Set("X-Imagini-RefreshToken", newRefreshToken) | 	(*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) |     # Generate GraphQL Flutter Models | ||||||
| - [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) |     flutter pub run build_runner build | ||||||
| 
 |  | ||||||
| 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. |  | ||||||
|  | |||||||
							
								
								
									
										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: | PODS: | ||||||
|  |   - connectivity (0.0.1): | ||||||
|  |     - Flutter | ||||||
|  |     - Reachability | ||||||
|   - DKImagePickerController/Core (4.3.2): |   - DKImagePickerController/Core (4.3.2): | ||||||
|     - DKImagePickerController/ImageDataManager |     - DKImagePickerController/ImageDataManager | ||||||
|     - DKImagePickerController/Resource |     - DKImagePickerController/Resource | ||||||
| @ -38,6 +41,9 @@ PODS: | |||||||
|     - Flutter |     - Flutter | ||||||
|   - integration_test (0.0.1): |   - integration_test (0.0.1): | ||||||
|     - Flutter |     - Flutter | ||||||
|  |   - path_provider (0.0.1): | ||||||
|  |     - Flutter | ||||||
|  |   - Reachability (3.2) | ||||||
|   - SDWebImage (5.10.2): |   - SDWebImage (5.10.2): | ||||||
|     - SDWebImage/Core (= 5.10.2) |     - SDWebImage/Core (= 5.10.2) | ||||||
|   - SDWebImage/Core (5.10.2) |   - SDWebImage/Core (5.10.2) | ||||||
| @ -48,10 +54,12 @@ PODS: | |||||||
|     - Flutter |     - Flutter | ||||||
| 
 | 
 | ||||||
| DEPENDENCIES: | DEPENDENCIES: | ||||||
|  |   - connectivity (from `.symlinks/plugins/connectivity/ios`) | ||||||
|   - file_picker (from `.symlinks/plugins/file_picker/ios`) |   - file_picker (from `.symlinks/plugins/file_picker/ios`) | ||||||
|   - Flutter (from `Flutter`) |   - Flutter (from `Flutter`) | ||||||
|   - flutter_secure_storage (from `.symlinks/plugins/flutter_secure_storage/ios`) |   - flutter_secure_storage (from `.symlinks/plugins/flutter_secure_storage/ios`) | ||||||
|   - integration_test (from `.symlinks/plugins/integration_test/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`) |   - shared_preferences (from `.symlinks/plugins/shared_preferences/ios`) | ||||||
|   - url_launcher (from `.symlinks/plugins/url_launcher/ios`) |   - url_launcher (from `.symlinks/plugins/url_launcher/ios`) | ||||||
| 
 | 
 | ||||||
| @ -59,10 +67,13 @@ SPEC REPOS: | |||||||
|   trunk: |   trunk: | ||||||
|     - DKImagePickerController |     - DKImagePickerController | ||||||
|     - DKPhotoGallery |     - DKPhotoGallery | ||||||
|  |     - Reachability | ||||||
|     - SDWebImage |     - SDWebImage | ||||||
|     - SwiftyGif |     - SwiftyGif | ||||||
| 
 | 
 | ||||||
| EXTERNAL SOURCES: | EXTERNAL SOURCES: | ||||||
|  |   connectivity: | ||||||
|  |     :path: ".symlinks/plugins/connectivity/ios" | ||||||
|   file_picker: |   file_picker: | ||||||
|     :path: ".symlinks/plugins/file_picker/ios" |     :path: ".symlinks/plugins/file_picker/ios" | ||||||
|   Flutter: |   Flutter: | ||||||
| @ -71,18 +82,23 @@ EXTERNAL SOURCES: | |||||||
|     :path: ".symlinks/plugins/flutter_secure_storage/ios" |     :path: ".symlinks/plugins/flutter_secure_storage/ios" | ||||||
|   integration_test: |   integration_test: | ||||||
|     :path: ".symlinks/plugins/integration_test/ios" |     :path: ".symlinks/plugins/integration_test/ios" | ||||||
|  |   path_provider: | ||||||
|  |     :path: ".symlinks/plugins/path_provider/ios" | ||||||
|   shared_preferences: |   shared_preferences: | ||||||
|     :path: ".symlinks/plugins/shared_preferences/ios" |     :path: ".symlinks/plugins/shared_preferences/ios" | ||||||
|   url_launcher: |   url_launcher: | ||||||
|     :path: ".symlinks/plugins/url_launcher/ios" |     :path: ".symlinks/plugins/url_launcher/ios" | ||||||
| 
 | 
 | ||||||
| SPEC CHECKSUMS: | SPEC CHECKSUMS: | ||||||
|  |   connectivity: c4130b2985d4ef6fd26f9702e886bd5260681467 | ||||||
|   DKImagePickerController: b5eb7f7a388e4643264105d648d01f727110fc3d |   DKImagePickerController: b5eb7f7a388e4643264105d648d01f727110fc3d | ||||||
|   DKPhotoGallery: fdfad5125a9fdda9cc57df834d49df790dbb4179 |   DKPhotoGallery: fdfad5125a9fdda9cc57df834d49df790dbb4179 | ||||||
|   file_picker: 3e6c3790de664ccf9b882732d9db5eaf6b8d4eb1 |   file_picker: 3e6c3790de664ccf9b882732d9db5eaf6b8d4eb1 | ||||||
|   Flutter: 434fef37c0980e73bb6479ef766c45957d4b510c |   Flutter: 434fef37c0980e73bb6479ef766c45957d4b510c | ||||||
|   flutter_secure_storage: 7953c38a04c3fdbb00571bcd87d8e3b5ceb9daec |   flutter_secure_storage: 7953c38a04c3fdbb00571bcd87d8e3b5ceb9daec | ||||||
|   integration_test: 5ed24a436eb7ec17b6a13046e9bf7ca4a404e59e |   integration_test: 6eb66a19f7104200dcfdd62bc0077e1b09686e4f | ||||||
|  |   path_provider: abfe2b5c733d04e238b0d8691db0cfd63a27a93c | ||||||
|  |   Reachability: 33e18b67625424e47b6cde6d202dce689ad7af96 | ||||||
|   SDWebImage: b969dcfc02c40a5da71eac0b03b8f1a0c794a86f |   SDWebImage: b969dcfc02c40a5da71eac0b03b8f1a0c794a86f | ||||||
|   shared_preferences: af6bfa751691cdc24be3045c43ec037377ada40d |   shared_preferences: af6bfa751691cdc24be3045c43ec037377ada40d | ||||||
|   SwiftyGif: e466e86c660d343357ab944a819a101c4127cb40 |   SwiftyGif: e466e86c660d343357ab944a819a101c4127cb40 | ||||||
|  | |||||||
| @ -2,6 +2,6 @@ | |||||||
| <Workspace | <Workspace | ||||||
|    version = "1.0"> |    version = "1.0"> | ||||||
|    <FileRef |    <FileRef | ||||||
|       location = "group:Runner.xcodeproj"> |       location = "self:"> | ||||||
|    </FileRef> |    </FileRef> | ||||||
| </Workspace> | </Workspace> | ||||||
|  | |||||||
| @ -1,61 +1,51 @@ | |||||||
| import 'dart:async'; | import 'dart:async'; | ||||||
| 
 | 
 | ||||||
| // ignore: uri_does_not_exist | import 'package:imagini/api/cookie_client/cookie_client.dart' | ||||||
| import 'cookie_client_stub.dart' |     if (dart.library.html) 'package:imagini/api/cookie_client/browser_cookie_client.dart' | ||||||
|     // ignore: uri_does_not_exist |     if (dart.library.io) 'package:imagini/api/cookie_client/io_cookie_client.dart'; | ||||||
|     if (dart.library.html) 'browser_cookie_client.dart' |  | ||||||
|     // ignore: uri_does_not_exist |  | ||||||
|     if (dart.library.io) '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:graphql_flutter/graphql_flutter.dart'; | ||||||
| import 'package:imagini/graphql/imagini_graphql.dart'; | import 'package:imagini/graphql/imagini_graphql.dart'; | ||||||
| 
 | 
 | ||||||
| class APIProvider{ | class APIProvider{ | ||||||
|   String _server, _accessToken, _refreshToken; |  | ||||||
| 
 |  | ||||||
|   GraphQLClient _client; |  | ||||||
|   HttpLink httpLink; |  | ||||||
|   // CookieLink cookieLink; |  | ||||||
|   static const String _GRAPHQL_ENDPOINT = "/query"; |   static const String _GRAPHQL_ENDPOINT = "/query"; | ||||||
| 
 | 
 | ||||||
|   APIProvider({ |   BaseStorageClient _storage; | ||||||
|     @required String server, |   GraphQLClient _client; | ||||||
|     String accessToken, |   HttpLink httpLink; | ||||||
|     String refreshToken | 
 | ||||||
|   }) { |   APIProvider(BaseStorageClient storage) { | ||||||
|     _server = server; |     _storage = storage; | ||||||
|     _accessToken = accessToken; |     init(); | ||||||
|     _refreshToken = refreshToken; |   } | ||||||
|  | 
 | ||||||
|  |   Future<void> init() async { | ||||||
|  |     String _server = await _storage.get("server"); | ||||||
|  | 
 | ||||||
|     httpLink = HttpLink(_server + _GRAPHQL_ENDPOINT, |     httpLink = HttpLink(_server + _GRAPHQL_ENDPOINT, | ||||||
|       httpClient: getCookieClient(), |       httpClient: getCookieClient(_storage), | ||||||
|     ); |     ); | ||||||
| 
 | 
 | ||||||
|     // cookieLink = CookieLink(_updateAccessToken, _updateRefreshToken); |  | ||||||
|     _client = GraphQLClient( |     _client = GraphQLClient( | ||||||
|       cache: GraphQLCache(), |       cache: GraphQLCache(), | ||||||
|       link: httpLink, |       link: httpLink, | ||||||
|     ); |     ); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   // void _updateAccessToken(_accessToken) { |   Future<QueryResult> login( | ||||||
|   //   print("Updating Access Token: $_accessToken"); |  | ||||||
|   //   this._accessToken = _accessToken; |  | ||||||
|   // } |  | ||||||
| 
 |  | ||||||
|   // void _updateRefreshToken(_refreshToken) { |  | ||||||
|   //   print("Updating Refresh Token: $_accessToken"); |  | ||||||
|   //   this._refreshToken = _refreshToken; |  | ||||||
|   // } |  | ||||||
| 
 |  | ||||||
|   Future<Login$Query$AuthResponse> login([ |  | ||||||
|     String username, |     String username, | ||||||
|     String password, |     String password, | ||||||
|   ]) async { |     String server, | ||||||
|  |   ) async { | ||||||
|     assert( |     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( |     QueryResult response = await _client.query( | ||||||
|       QueryOptions( |       QueryOptions( | ||||||
|         document: LoginQuery().document, |         document: LoginQuery().document, | ||||||
| @ -65,79 +55,27 @@ class APIProvider{ | |||||||
|         }, |         }, | ||||||
|       ) |       ) | ||||||
|     ); |     ); | ||||||
| 
 |     return response; | ||||||
|     final loginResponse = Login$Query.fromJson(response.data); |  | ||||||
|     return loginResponse.login; |  | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   Future<Me$Query$User> me() async { |   Future<QueryResult> me() async { | ||||||
|     QueryResult response = await _client.query( |     QueryResult response = await _client.query( | ||||||
|       QueryOptions( |       QueryOptions( | ||||||
|         document: MeQuery().document, |         document: MeQuery().document, | ||||||
|       ) |       ) | ||||||
|     ); |     ); | ||||||
| 
 |     return response; | ||||||
|     final meResponse = Me$Query.fromJson(response.data); |  | ||||||
|     return meResponse.me; |  | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   Future<String> mediaItems([ |   Future<QueryResult> mediaItems() async { | ||||||
|     String startDate, |     QueryResult response = await _client.query( | ||||||
|     String endDate, |       QueryOptions( | ||||||
|     String albumID, |         document: MediaItemsQuery().document, | ||||||
|     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 |  | ||||||
| 
 | 
 | ||||||
|     // Returns: |     print(response); | ||||||
|     //    { |     return response; | ||||||
|     //     |  | ||||||
|     //    } |  | ||||||
| 
 |  | ||||||
|     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; |  | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   void dispose() {} |   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'; | import 'package:http/http.dart'; | ||||||
| 
 | 
 | ||||||
| BaseClient getCookieClient() => throw UnsupportedError( | BaseClient getCookieClient(storage) => throw UnsupportedError( | ||||||
|     'Cannot create a client without dart:html or dart:io.'); |     '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/api/api_provider.dart'; | ||||||
| import 'package:imagini/graphql/imagini_graphql.dart'; | import 'package:imagini/graphql/imagini_graphql.dart'; | ||||||
|  | import 'package:graphql_flutter/graphql_flutter.dart'; | ||||||
| 
 | 
 | ||||||
| class ImaginiAPIRepository { | class ImaginiAPIRepository { | ||||||
|   APIProvider _apiProvider; |   APIProvider _apiProvider; | ||||||
| 
 | 
 | ||||||
|   ImaginiAPIRepository(this._apiProvider); |   ImaginiAPIRepository(this._apiProvider); | ||||||
| 
 | 
 | ||||||
|   Stream<Login$Query$AuthResponse> login(String user, password) { |   Stream<bool> login(String user, password, server) { | ||||||
|     return Stream.fromFuture(_apiProvider.login(user, password)); |     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 |   @override | ||||||
|   void dispose() async { |   void dispose() async { | ||||||
|     // Log.info('dispose'); |  | ||||||
|     super.dispose(); |     super.dispose(); | ||||||
|     await _application.onTerminate(); |     await _application.onTerminate(); | ||||||
|   } |   } | ||||||
|  | |||||||
| @ -3,13 +3,13 @@ import 'package:flutter/material.dart'; | |||||||
| 
 | 
 | ||||||
| import 'package:imagini/screens/home_screen.dart'; | import 'package:imagini/screens/home_screen.dart'; | ||||||
| import 'package:imagini/screens/login_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( | // var splashHandler = new Handler( | ||||||
|   handlerFunc: (BuildContext context, Map<String, List<String>> params) { | //   handlerFunc: (BuildContext context, Map<String, List<String>> params) { | ||||||
|       return SplashScreen(); | //       return SplashScreen(); | ||||||
|   } | //   } | ||||||
| ); | // ); | ||||||
| 
 | 
 | ||||||
| var loginHandler = new Handler( | var loginHandler = new Handler( | ||||||
|   handlerFunc: (BuildContext context, Map<String, List<String>> params) { |   handlerFunc: (BuildContext context, Map<String, List<String>> params) { | ||||||
| @ -42,7 +42,7 @@ class AppRoutes { | |||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|       ); |       ); | ||||||
|       router.define(SplashScreen.PATH, handler: splashHandler); |       // router.define(SplashScreen.PATH, handler: splashHandler); | ||||||
|       router.define(LoginScreen.PATH,  handler: loginHandler); |       router.define(LoginScreen.PATH,  handler: loginHandler); | ||||||
|       router.define(HomeScreen.PATH,   handler: homeHandler); |       router.define(HomeScreen.PATH,   handler: homeHandler); | ||||||
|       // router.define(AppDetailPage.PATH, handler: appDetailRouteHandler); |       // 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/core/app_routes.dart'; | ||||||
| import 'package:imagini/api/api_provider.dart'; | import 'package:imagini/api/api_provider.dart'; | ||||||
| import 'package:imagini/api/imagini_api_repository.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 { | class ImaginiApplication { | ||||||
|     FluroRouter router; |     FluroRouter router; | ||||||
|     ImaginiAPIRepository imaginiAPI; |     ImaginiAPIRepository imaginiAPI; | ||||||
|  |     BaseStorageClient storageClient; | ||||||
| 
 | 
 | ||||||
|     Future<void> onCreate() async { |     Future<void> onCreate() async { | ||||||
|         _initRouter(); |         _initRouter(); | ||||||
|  |         _initStorageClient(); | ||||||
|         _initAPIRepository(); |         _initAPIRepository(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -20,8 +27,13 @@ class ImaginiApplication { | |||||||
|         AppRoutes.configureRoutes(router); |         AppRoutes.configureRoutes(router); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     _initStorageClient() { | ||||||
|  |         storageClient = getStorageClient(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     _initAPIRepository() { |     _initAPIRepository() { | ||||||
|         APIProvider apiProvider = new APIProvider(server: "http://localhost:8484"); |         // TODO: Get from config | ||||||
|  |         APIProvider apiProvider = new APIProvider(storageClient); | ||||||
|         imaginiAPI = ImaginiAPIRepository(apiProvider); |         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); |   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 { | enum AuthResult { | ||||||
|   @JsonValue('Success') |   @JsonValue('Success') | ||||||
|   success, |   success, | ||||||
| @ -194,6 +550,14 @@ enum AuthType { | |||||||
|   @JsonValue('ARTEMIS_UNKNOWN') |   @JsonValue('ARTEMIS_UNKNOWN') | ||||||
|   artemisUnknown, |   artemisUnknown, | ||||||
| } | } | ||||||
|  | enum OrderDirection { | ||||||
|  |   @JsonValue('ASC') | ||||||
|  |   asc, | ||||||
|  |   @JsonValue('DESC') | ||||||
|  |   desc, | ||||||
|  |   @JsonValue('ARTEMIS_UNKNOWN') | ||||||
|  |   artemisUnknown, | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| @JsonSerializable(explicitToJson: true) | @JsonSerializable(explicitToJson: true) | ||||||
| class LoginArguments extends JsonSerializable with EquatableMixin { | class LoginArguments extends JsonSerializable with EquatableMixin { | ||||||
| @ -508,3 +872,161 @@ class MeQuery extends GraphQLQuery<Me$Query, JsonSerializable> { | |||||||
|   @override |   @override | ||||||
|   Me$Query parse(Map<String, dynamic> json) => Me$Query.fromJson(json); |   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(), |       '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) { | LoginArguments _$LoginArgumentsFromJson(Map<String, dynamic> json) { | ||||||
|   return LoginArguments( |   return LoginArguments( | ||||||
|     user: json['user'] as String, |     user: json['user'] as String, | ||||||
| @ -219,3 +531,25 @@ Map<String, dynamic> _$CreateMediaItemArgumentsToJson( | |||||||
|     <String, dynamic>{ |     <String, dynamic>{ | ||||||
|       'file': fromDartMultipartFileToGraphQLUpload(instance.file), |       '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:flutter/material.dart'; | ||||||
| 
 |  | ||||||
| import 'package:fluro/fluro.dart'; | import 'package:fluro/fluro.dart'; | ||||||
|  | 
 | ||||||
| import 'package:flutter_platform_widgets/flutter_platform_widgets.dart'; | import 'package:flutter_platform_widgets/flutter_platform_widgets.dart'; | ||||||
| 
 | 
 | ||||||
|  | import 'package:imagini/blocs/login_bloc.dart'; | ||||||
| import 'package:imagini/core/app_provider.dart'; | import 'package:imagini/core/app_provider.dart'; | ||||||
| 
 | 
 | ||||||
| class LoginScreen extends StatefulWidget { | class LoginScreen extends StatefulWidget { | ||||||
|   static const String PATH = '/Login'; |   static const String PATH = '/'; | ||||||
| 
 | 
 | ||||||
|   LoginScreen({Key key}) : super(key: key); |   LoginScreen({Key key}) : super(key: key); | ||||||
| 
 | 
 | ||||||
| @ -16,7 +17,7 @@ class LoginScreen extends StatefulWidget { | |||||||
| 
 | 
 | ||||||
| class _LoginScreenState extends State<LoginScreen> { | class _LoginScreenState extends State<LoginScreen> { | ||||||
| 
 | 
 | ||||||
|   // LoginBloc bloc; |   LoginBloc bloc; | ||||||
| 
 | 
 | ||||||
|   @override |   @override | ||||||
|   void dispose() { |   void dispose() { | ||||||
| @ -29,12 +30,76 @@ class _LoginScreenState extends State<LoginScreen> { | |||||||
|     _init(); |     _init(); | ||||||
| 
 | 
 | ||||||
|     return Scaffold( |     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( |       child: ConstrainedBox( | ||||||
|         constraints: BoxConstraints(maxWidth: 500), |         constraints: BoxConstraints(maxWidth: 500), | ||||||
|         child: Container( |         child: Container( | ||||||
|           margin: EdgeInsets.fromLTRB(50, 0, 50, 0), |           margin: EdgeInsets.fromLTRB(50, 0, 50, 0), | ||||||
|           height: 500, |           height: 500, | ||||||
|  |           child: Form( | ||||||
|  |             key: _formKey, | ||||||
|             child: Column( |             child: Column( | ||||||
|               children: <Widget>[ |               children: <Widget>[ | ||||||
|                 Container( |                 Container( | ||||||
| @ -46,24 +111,45 @@ class _LoginScreenState extends State<LoginScreen> { | |||||||
|                   margin: EdgeInsets.fromLTRB(0, 0, 0, 50), |                   margin: EdgeInsets.fromLTRB(0, 0, 0, 50), | ||||||
|                 ), |                 ), | ||||||
|                 Expanded( |                 Expanded( | ||||||
|                   child: TextField( |                   child: TextFormField( | ||||||
|  |                     controller: serverController, | ||||||
|  |                     validator: (value) { | ||||||
|  |                       if (value.isEmpty) { | ||||||
|  |                         return 'Please enter server address'; | ||||||
|  |                       } | ||||||
|  |                       return null; | ||||||
|  |                     }, | ||||||
|                     decoration: InputDecoration( |                     decoration: InputDecoration( | ||||||
|                       labelText: 'Server Address' |                       labelText: 'Server Address' | ||||||
|                     ), |                     ), | ||||||
|                   ), |                   ), | ||||||
|                 ), |                 ), | ||||||
|                 Expanded( |                 Expanded( | ||||||
|                   child: TextField( |                   child: TextFormField( | ||||||
|  |                     controller: userController, | ||||||
|  |                     validator: (value) { | ||||||
|  |                       if (value.isEmpty) { | ||||||
|  |                         return 'Please enter username or email'; | ||||||
|  |                       } | ||||||
|  |                       return null; | ||||||
|  |                     }, | ||||||
|                     decoration: InputDecoration( |                     decoration: InputDecoration( | ||||||
|                       labelText: 'Username / Email' |                       labelText: 'Username / Email' | ||||||
|                     ), |                     ), | ||||||
|                   ), |                   ), | ||||||
|                 ), |                 ), | ||||||
|                 Expanded( |                 Expanded( | ||||||
|                   child: TextField( |                   child: TextFormField( | ||||||
|                     obscureText: true, |                     obscureText: true, | ||||||
|                     enableSuggestions: false, |                     enableSuggestions: false, | ||||||
|                     autocorrect: false, |                     autocorrect: false, | ||||||
|  |                     controller: passwordController, | ||||||
|  |                     validator: (value) { | ||||||
|  |                       if (value.isEmpty) { | ||||||
|  |                         return 'Please enter password'; | ||||||
|  |                       } | ||||||
|  |                       return null; | ||||||
|  |                     }, | ||||||
|                     decoration: InputDecoration( |                     decoration: InputDecoration( | ||||||
|                       labelText: 'Password' |                       labelText: 'Password' | ||||||
|                     ), |                     ), | ||||||
| @ -73,11 +159,31 @@ class _LoginScreenState extends State<LoginScreen> { | |||||||
|                   width: double.infinity, |                   width: double.infinity, | ||||||
|                   child: PlatformButton( |                   child: PlatformButton( | ||||||
|                     onPressed: () { |                     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') |                     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