mirror of
				https://gitlab.com/foxixus/neomovies_mobile.git
				synced 2025-10-29 12:38:50 +05:00 
			
		
		
		
	Compare commits
	
		
			5 Commits
		
	
	
		
			fd296d800f
			...
			fix-api-au
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | 86611976a7 | ||
|  | e70c477238 | ||
|  | 7b8f64842a | ||
|  | b167c73699 | ||
|  | 23a3068b37 | 
							
								
								
									
										76
									
								
								.github/workflows/gitlab-mirror.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										76
									
								
								.github/workflows/gitlab-mirror.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,76 @@ | |||||||
|  | name: Full Mirror to GitLab | ||||||
|  |  | ||||||
|  | on: | ||||||
|  |   push: | ||||||
|  |     branches: | ||||||
|  |       - "**" | ||||||
|  |   pull_request: | ||||||
|  |     types: [opened, reopened, closed, edited] | ||||||
|  |   issues: | ||||||
|  |     types: [opened, edited, closed, reopened] | ||||||
|  |  | ||||||
|  | jobs: | ||||||
|  |   mirror-code: | ||||||
|  |     runs-on: ubuntu-latest | ||||||
|  |     steps: | ||||||
|  |       - name: Checkout repo | ||||||
|  |         uses: actions/checkout@v3 | ||||||
|  |  | ||||||
|  |       - name: Setup Git | ||||||
|  |         run: | | ||||||
|  |           git config --global user.email "github-actions[bot]@users.noreply.github.com" | ||||||
|  |           git config --global user.name "github-actions[bot]" | ||||||
|  |  | ||||||
|  |       - name: Fetch GitLab branch | ||||||
|  |         run: | | ||||||
|  |           git remote add gitlab https://oauth2:${{ secrets.GITLAB_TOKEN }}@gitlab.com/foxixus/neomovies_mobile.git | ||||||
|  |           git fetch gitlab main || true | ||||||
|  |  | ||||||
|  |       - name: Check for differences with GitLab | ||||||
|  |         id: diffcheck | ||||||
|  |         run: | | ||||||
|  |           # Если нет ветки main на GitLab, пушим всегда | ||||||
|  |           if ! git rev-parse gitlab/main >/dev/null 2>&1; then | ||||||
|  |             echo "has_diff=true" >> $GITHUB_OUTPUT | ||||||
|  |           else | ||||||
|  |             DIFF=$(git rev-list --left-right --count HEAD...gitlab/main | awk '{print $1}') | ||||||
|  |             if [[ "$DIFF" -gt 0 ]]; then | ||||||
|  |               echo "has_diff=true" >> $GITHUB_OUTPUT | ||||||
|  |             else | ||||||
|  |               echo "has_diff=false" >> $GITHUB_OUTPUT | ||||||
|  |             fi | ||||||
|  |           fi | ||||||
|  |  | ||||||
|  |       - name: Push to GitLab if there are changes | ||||||
|  |         if: steps.diffcheck.outputs.has_diff == 'true' | ||||||
|  |         run: git push gitlab HEAD:main | ||||||
|  |  | ||||||
|  |   mirror-issues: | ||||||
|  |     runs-on: ubuntu-latest | ||||||
|  |     if: github.event_name == 'issues' | ||||||
|  |     steps: | ||||||
|  |       - name: Sync issue to GitLab | ||||||
|  |         run: | | ||||||
|  |           curl --request POST "https://gitlab.com/api/v4/projects/foxixus%2Fneomovies_mobile/issues" \ | ||||||
|  |             --header "PRIVATE-TOKEN: ${{ secrets.GITLAB_TOKEN }}" \ | ||||||
|  |             --header "Content-Type: application/json" \ | ||||||
|  |             --data "{ | ||||||
|  |               \"title\": \"${{ github.event.issue.title }}\", | ||||||
|  |               \"description\": \"${{ github.event.issue.body }}\" | ||||||
|  |             }" | ||||||
|  |  | ||||||
|  |   mirror-prs: | ||||||
|  |     runs-on: ubuntu-latest | ||||||
|  |     if: github.event_name == 'pull_request' | ||||||
|  |     steps: | ||||||
|  |       - name: Sync PR to GitLab MR | ||||||
|  |         run: | | ||||||
|  |           curl --request POST "https://gitlab.com/api/v4/projects/foxixus%2Fneomovies_mobile/merge_requests" \ | ||||||
|  |             --header "PRIVATE-TOKEN: ${{ secrets.GITLAB_TOKEN }}" \ | ||||||
|  |             --header "Content-Type: application/json" \ | ||||||
|  |             --data "{ | ||||||
|  |               \"title\": \"${{ github.event.pull_request.title }}\", | ||||||
|  |               \"source_branch\": \"${{ github.event.pull_request.head.ref }}\", | ||||||
|  |               \"target_branch\": \"${{ github.event.pull_request.base.ref }}\", | ||||||
|  |               \"description\": \"${{ github.event.pull_request.body }}\" | ||||||
|  |             }" | ||||||
							
								
								
									
										2
									
								
								.github/workflows/release.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/release.yml
									
									
									
									
										vendored
									
									
								
							| @@ -175,7 +175,7 @@ jobs: | |||||||
|           - Workflow Run: [#${{ github.run_number }}](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}) |           - Workflow Run: [#${{ github.run_number }}](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}) | ||||||
|  |  | ||||||
|           **Downloads:** |           **Downloads:** | ||||||
|           - **ARM64 (arm64-v8a)**: \`app-arm64-v8a-release.apk\` (${{ steps.sizes.outputs.arm64_size }}) - ✅ Recommended for modern devices |           - **ARM64 (arm64-v8a)**: \`app-arm64-v8a-release.apk\` (${{ steps.sizes.outputs.arm64_size }}) - Recommended for modern devices | ||||||
|           - **ARM32 (armeabi-v7a)**: \`app-armeabi-v7a-release.apk\` (${{ steps.sizes.outputs.arm32_size }}) - For older devices |           - **ARM32 (armeabi-v7a)**: \`app-armeabi-v7a-release.apk\` (${{ steps.sizes.outputs.arm32_size }}) - For older devices | ||||||
|           - **x86_64**: \`app-x86_64-release.apk\` (${{ steps.sizes.outputs.x64_size }}) - For emulators |           - **x86_64**: \`app-x86_64-release.apk\` (${{ steps.sizes.outputs.x64_size }}) - For emulators | ||||||
|  |  | ||||||
|   | |||||||
| @@ -2,6 +2,8 @@ | |||||||
|  |  | ||||||
| Мобильное приложение для просмотра фильмов и сериалов, созданное на Flutter. | Мобильное приложение для просмотра фильмов и сериалов, созданное на Flutter. | ||||||
|  |  | ||||||
|  | [](https://github.com/Neo-Open-Source/neomovies-mobile/releases/latest) | ||||||
|  |  | ||||||
| ## Возможности | ## Возможности | ||||||
|  |  | ||||||
| - 📱 Кроссплатформенное приложение (Android/iOS(пока не реализовано)) | - 📱 Кроссплатформенное приложение (Android/iOS(пока не реализовано)) | ||||||
|   | |||||||
| @@ -5,6 +5,7 @@ import 'package:neomovies_mobile/data/models/reaction.dart'; | |||||||
| import 'package:neomovies_mobile/data/models/auth_response.dart'; | import 'package:neomovies_mobile/data/models/auth_response.dart'; | ||||||
| import 'package:neomovies_mobile/data/models/user.dart'; | import 'package:neomovies_mobile/data/models/user.dart'; | ||||||
| import 'package:neomovies_mobile/data/api/neomovies_api_client.dart'; // новый клиент | import 'package:neomovies_mobile/data/api/neomovies_api_client.dart'; // новый клиент | ||||||
|  | import 'package:neomovies_mobile/data/exceptions/auth_exceptions.dart'; | ||||||
|  |  | ||||||
| class ApiClient { | class ApiClient { | ||||||
|   final NeoMoviesApiClient _neoClient; |   final NeoMoviesApiClient _neoClient; | ||||||
| @@ -116,12 +117,22 @@ class ApiClient { | |||||||
|     ).then((_) {}); // старый код ничего не возвращал |     ).then((_) {}); // старый код ничего не возвращал | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   Future<AuthResponse> login(String email, String password) { |   Future<AuthResponse> login(String email, String password) async { | ||||||
|     return _neoClient.login(email: email, password: password); |     try { | ||||||
|  |       return await _neoClient.login(email: email, password: password); | ||||||
|  |     } catch (e) { | ||||||
|  |       final errorMessage = e.toString(); | ||||||
|  |       if (errorMessage.contains('Account not activated') ||  | ||||||
|  |           errorMessage.contains('not verified') || | ||||||
|  |           errorMessage.contains('Please verify your email')) { | ||||||
|  |         throw UnverifiedAccountException(email, message: errorMessage); | ||||||
|  |       } | ||||||
|  |       rethrow; | ||||||
|  |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   Future<void> verify(String email, String code) { |   Future<AuthResponse> verify(String email, String code) { | ||||||
|     return _neoClient.verifyEmail(email: email, code: code).then((_) {}); |     return _neoClient.verifyEmail(email: email, code: code); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   Future<void> resendCode(String email) { |   Future<void> resendCode(String email) { | ||||||
|   | |||||||
| @@ -97,23 +97,25 @@ class Movie extends HiveObject { | |||||||
|  |  | ||||||
|   String get fullPosterUrl { |   String get fullPosterUrl { | ||||||
|     if (posterPath == null || posterPath!.isEmpty) { |     if (posterPath == null || posterPath!.isEmpty) { | ||||||
|       // Use a generic placeholder |       // Use API placeholder | ||||||
|       return 'https://via.placeholder.com/500x750.png?text=No+Poster'; |       final apiUrl = dotenv.env['API_URL'] ?? 'https://api.neomovies.ru'; | ||||||
|  |       return '$apiUrl/api/v1/images/w500/placeholder.jpg'; | ||||||
|     } |     } | ||||||
|     // TMDB CDN base URL |     // Use NeoMovies API images endpoint instead of TMDB directly | ||||||
|     const tmdbBaseUrl = 'https://image.tmdb.org/t/p'; |     final apiUrl = dotenv.env['API_URL'] ?? 'https://api.neomovies.ru'; | ||||||
|     final cleanPath = posterPath!.startsWith('/') ? posterPath!.substring(1) : posterPath!; |     final cleanPath = posterPath!.startsWith('/') ? posterPath!.substring(1) : posterPath!; | ||||||
|     return '$tmdbBaseUrl/w500/$cleanPath'; |     return '$apiUrl/api/v1/images/w500/$cleanPath'; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   String get fullBackdropUrl { |   String get fullBackdropUrl { | ||||||
|     if (backdropPath == null || backdropPath!.isEmpty) { |     if (backdropPath == null || backdropPath!.isEmpty) { | ||||||
|       // Use a generic placeholder |       // Use API placeholder | ||||||
|       return 'https://via.placeholder.com/1280x720.png?text=No+Backdrop'; |       final apiUrl = dotenv.env['API_URL'] ?? 'https://api.neomovies.ru'; | ||||||
|  |       return '$apiUrl/api/v1/images/w780/placeholder.jpg'; | ||||||
|     } |     } | ||||||
|     // TMDB CDN base URL |     // Use NeoMovies API images endpoint instead of TMDB directly | ||||||
|     const tmdbBaseUrl = 'https://image.tmdb.org/t/p'; |     final apiUrl = dotenv.env['API_URL'] ?? 'https://api.neomovies.ru'; | ||||||
|     final cleanPath = backdropPath!.startsWith('/') ? backdropPath!.substring(1) : backdropPath!; |     final cleanPath = backdropPath!.startsWith('/') ? backdropPath!.substring(1) : backdropPath!; | ||||||
|     return '$tmdbBaseUrl/w780/$cleanPath'; |     return '$apiUrl/api/v1/images/w780/$cleanPath'; | ||||||
|   } |   } | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										34
									
								
								lib/data/models/player/audio_track.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								lib/data/models/player/audio_track.dart
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,34 @@ | |||||||
|  | class AudioTrack { | ||||||
|  |   final String name; | ||||||
|  |   final String language; | ||||||
|  |   final String url; | ||||||
|  |   final bool isDefault; | ||||||
|  |  | ||||||
|  |   AudioTrack({ | ||||||
|  |     required this.name, | ||||||
|  |     required this.language, | ||||||
|  |     required this.url, | ||||||
|  |     this.isDefault = false, | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   factory AudioTrack.fromJson(Map<String, dynamic> json) { | ||||||
|  |     return AudioTrack( | ||||||
|  |       name: json['name'] ?? '', | ||||||
|  |       language: json['language'] ?? '', | ||||||
|  |       url: json['url'] ?? '', | ||||||
|  |       isDefault: json['isDefault'] ?? false, | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   Map<String, dynamic> toJson() { | ||||||
|  |     return { | ||||||
|  |       'name': name, | ||||||
|  |       'language': language, | ||||||
|  |       'url': url, | ||||||
|  |       'isDefault': isDefault, | ||||||
|  |     }; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   String toString() => name; | ||||||
|  | } | ||||||
							
								
								
									
										73
									
								
								lib/data/models/player/player_settings.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								lib/data/models/player/player_settings.dart
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,73 @@ | |||||||
|  | import 'package:neomovies_mobile/data/models/player/video_quality.dart'; | ||||||
|  | import 'package:neomovies_mobile/data/models/player/audio_track.dart'; | ||||||
|  | import 'package:neomovies_mobile/data/models/player/subtitle.dart'; | ||||||
|  |  | ||||||
|  | class PlayerSettings { | ||||||
|  |   final VideoQuality? selectedQuality; | ||||||
|  |   final AudioTrack? selectedAudioTrack; | ||||||
|  |   final Subtitle? selectedSubtitle; | ||||||
|  |   final double volume; | ||||||
|  |   final double playbackSpeed; | ||||||
|  |   final bool autoPlay; | ||||||
|  |   final bool muted; | ||||||
|  |  | ||||||
|  |   PlayerSettings({ | ||||||
|  |     this.selectedQuality, | ||||||
|  |     this.selectedAudioTrack, | ||||||
|  |     this.selectedSubtitle, | ||||||
|  |     this.volume = 1.0, | ||||||
|  |     this.playbackSpeed = 1.0, | ||||||
|  |     this.autoPlay = true, | ||||||
|  |     this.muted = false, | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   PlayerSettings copyWith({ | ||||||
|  |     VideoQuality? selectedQuality, | ||||||
|  |     AudioTrack? selectedAudioTrack, | ||||||
|  |     Subtitle? selectedSubtitle, | ||||||
|  |     double? volume, | ||||||
|  |     double? playbackSpeed, | ||||||
|  |     bool? autoPlay, | ||||||
|  |     bool? muted, | ||||||
|  |   }) { | ||||||
|  |     return PlayerSettings( | ||||||
|  |       selectedQuality: selectedQuality ?? this.selectedQuality, | ||||||
|  |       selectedAudioTrack: selectedAudioTrack ?? this.selectedAudioTrack, | ||||||
|  |       selectedSubtitle: selectedSubtitle ?? this.selectedSubtitle, | ||||||
|  |       volume: volume ?? this.volume, | ||||||
|  |       playbackSpeed: playbackSpeed ?? this.playbackSpeed, | ||||||
|  |       autoPlay: autoPlay ?? this.autoPlay, | ||||||
|  |       muted: muted ?? this.muted, | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   factory PlayerSettings.fromJson(Map<String, dynamic> json) { | ||||||
|  |     return PlayerSettings( | ||||||
|  |       selectedQuality: json['selectedQuality'] != null  | ||||||
|  |           ? VideoQuality.fromJson(json['selectedQuality'])  | ||||||
|  |           : null, | ||||||
|  |       selectedAudioTrack: json['selectedAudioTrack'] != null  | ||||||
|  |           ? AudioTrack.fromJson(json['selectedAudioTrack'])  | ||||||
|  |           : null, | ||||||
|  |       selectedSubtitle: json['selectedSubtitle'] != null  | ||||||
|  |           ? Subtitle.fromJson(json['selectedSubtitle'])  | ||||||
|  |           : null, | ||||||
|  |       volume: json['volume']?.toDouble() ?? 1.0, | ||||||
|  |       playbackSpeed: json['playbackSpeed']?.toDouble() ?? 1.0, | ||||||
|  |       autoPlay: json['autoPlay'] ?? true, | ||||||
|  |       muted: json['muted'] ?? false, | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   Map<String, dynamic> toJson() { | ||||||
|  |     return { | ||||||
|  |       'selectedQuality': selectedQuality?.toJson(), | ||||||
|  |       'selectedAudioTrack': selectedAudioTrack?.toJson(), | ||||||
|  |       'selectedSubtitle': selectedSubtitle?.toJson(), | ||||||
|  |       'volume': volume, | ||||||
|  |       'playbackSpeed': playbackSpeed, | ||||||
|  |       'autoPlay': autoPlay, | ||||||
|  |       'muted': muted, | ||||||
|  |     }; | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										34
									
								
								lib/data/models/player/subtitle.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								lib/data/models/player/subtitle.dart
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,34 @@ | |||||||
|  | class Subtitle { | ||||||
|  |   final String name; | ||||||
|  |   final String language; | ||||||
|  |   final String url; | ||||||
|  |   final bool isDefault; | ||||||
|  |  | ||||||
|  |   Subtitle({ | ||||||
|  |     required this.name, | ||||||
|  |     required this.language, | ||||||
|  |     required this.url, | ||||||
|  |     this.isDefault = false, | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   factory Subtitle.fromJson(Map<String, dynamic> json) { | ||||||
|  |     return Subtitle( | ||||||
|  |       name: json['name'] ?? '', | ||||||
|  |       language: json['language'] ?? '', | ||||||
|  |       url: json['url'] ?? '', | ||||||
|  |       isDefault: json['isDefault'] ?? false, | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   Map<String, dynamic> toJson() { | ||||||
|  |     return { | ||||||
|  |       'name': name, | ||||||
|  |       'language': language, | ||||||
|  |       'url': url, | ||||||
|  |       'isDefault': isDefault, | ||||||
|  |     }; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   String toString() => name; | ||||||
|  | } | ||||||
							
								
								
									
										38
									
								
								lib/data/models/player/video_quality.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								lib/data/models/player/video_quality.dart
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,38 @@ | |||||||
|  | class VideoQuality { | ||||||
|  |   final String quality; | ||||||
|  |   final String url; | ||||||
|  |   final int bandwidth; | ||||||
|  |   final int width; | ||||||
|  |   final int height; | ||||||
|  |  | ||||||
|  |   VideoQuality({ | ||||||
|  |     required this.quality, | ||||||
|  |     required this.url, | ||||||
|  |     required this.bandwidth, | ||||||
|  |     required this.width, | ||||||
|  |     required this.height, | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   factory VideoQuality.fromJson(Map<String, dynamic> json) { | ||||||
|  |     return VideoQuality( | ||||||
|  |       quality: json['quality'] ?? '', | ||||||
|  |       url: json['url'] ?? '', | ||||||
|  |       bandwidth: json['bandwidth'] ?? 0, | ||||||
|  |       width: json['width'] ?? 0, | ||||||
|  |       height: json['height'] ?? 0, | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   Map<String, dynamic> toJson() { | ||||||
|  |     return { | ||||||
|  |       'quality': quality, | ||||||
|  |       'url': url, | ||||||
|  |       'bandwidth': bandwidth, | ||||||
|  |       'width': width, | ||||||
|  |       'height': height, | ||||||
|  |     }; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   String toString() => quality; | ||||||
|  | } | ||||||
| @@ -33,8 +33,13 @@ class AuthRepository { | |||||||
|   } |   } | ||||||
|  |  | ||||||
|   Future<void> verifyEmail(String email, String code) async { |   Future<void> verifyEmail(String email, String code) async { | ||||||
|     await _apiClient.verify(email, code); |     final response = await _apiClient.verify(email, code); | ||||||
|     // After successful verification, the user should log in. |     // Auto-login user after successful verification | ||||||
|  |     await _storageService.saveToken(response.token); | ||||||
|  |     await _storageService.saveUserData( | ||||||
|  |       name: response.user.name, | ||||||
|  |       email: response.user.email, | ||||||
|  |     ); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   Future<void> resendVerificationCode(String email) async { |   Future<void> resendVerificationCode(String email) async { | ||||||
|   | |||||||
| @@ -93,9 +93,9 @@ class AuthProvider extends ChangeNotifier { | |||||||
|     notifyListeners(); |     notifyListeners(); | ||||||
|     try { |     try { | ||||||
|       await _authRepository.verifyEmail(email, code); |       await _authRepository.verifyEmail(email, code); | ||||||
|       // After verification, user should log in. |       // Auto-login after successful verification | ||||||
|       // For a better UX, we could auto-login them, but for now, we'll just go to the unauthenticated state. |       _user = await _authRepository.getCurrentUser(); | ||||||
|       _state = AuthState.unauthenticated; |       _state = AuthState.authenticated; | ||||||
|     } catch (e) { |     } catch (e) { | ||||||
|       _error = e.toString(); |       _error = e.toString(); | ||||||
|       _state = AuthState.error; |       _state = AuthState.error; | ||||||
|   | |||||||
| @@ -61,16 +61,7 @@ class _VerifyScreenState extends State<VerifyScreen> { | |||||||
|     if (_formKey.currentState!.validate()) { |     if (_formKey.currentState!.validate()) { | ||||||
|       _formKey.currentState!.save(); |       _formKey.currentState!.save(); | ||||||
|       Provider.of<AuthProvider>(context, listen: false) |       Provider.of<AuthProvider>(context, listen: false) | ||||||
|           .verifyEmail(widget.email, _code) |           .verifyEmail(widget.email, _code); | ||||||
|           .then((_) { |  | ||||||
|         final auth = Provider.of<AuthProvider>(context, listen: false); |  | ||||||
|         if (auth.state != AuthState.error) { |  | ||||||
|           Navigator.of(context).pop(); // Go back to LoginScreen |  | ||||||
|           ScaffoldMessenger.of(context).showSnackBar( |  | ||||||
|             const SnackBar(content: Text('Email verified. You can now login.')), |  | ||||||
|           ); |  | ||||||
|         } |  | ||||||
|       }); |  | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
| @@ -82,6 +73,16 @@ class _VerifyScreenState extends State<VerifyScreen> { | |||||||
|       ), |       ), | ||||||
|       body: Consumer<AuthProvider>( |       body: Consumer<AuthProvider>( | ||||||
|         builder: (context, auth, child) { |         builder: (context, auth, child) { | ||||||
|  |           // Auto-navigate when user becomes authenticated | ||||||
|  |           if (auth.state == AuthState.authenticated) { | ||||||
|  |             WidgetsBinding.instance.addPostFrameCallback((_) { | ||||||
|  |               Navigator.of(context).pop(); // Go back to previous screen | ||||||
|  |               ScaffoldMessenger.of(context).showSnackBar( | ||||||
|  |                 const SnackBar(content: Text('Email verified and logged in successfully!')), | ||||||
|  |               ); | ||||||
|  |             }); | ||||||
|  |           } | ||||||
|  |  | ||||||
|           return Form( |           return Form( | ||||||
|             key: _formKey, |             key: _formKey, | ||||||
|             child: Padding( |             child: Padding( | ||||||
|   | |||||||
| @@ -12,6 +12,7 @@ import path_provider_foundation | |||||||
| import shared_preferences_foundation | import shared_preferences_foundation | ||||||
| import sqflite_darwin | import sqflite_darwin | ||||||
| import url_launcher_macos | import url_launcher_macos | ||||||
|  | import video_player_avfoundation | ||||||
| import wakelock_plus | import wakelock_plus | ||||||
| import webview_flutter_wkwebview | import webview_flutter_wkwebview | ||||||
|  |  | ||||||
| @@ -23,6 +24,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { | |||||||
|   SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) |   SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) | ||||||
|   SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin")) |   SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin")) | ||||||
|   UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) |   UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) | ||||||
|  |   FVPVideoPlayerPlugin.register(with: registry.registrar(forPlugin: "FVPVideoPlayerPlugin")) | ||||||
|   WakelockPlusMacosPlugin.register(with: registry.registrar(forPlugin: "WakelockPlusMacosPlugin")) |   WakelockPlusMacosPlugin.register(with: registry.registrar(forPlugin: "WakelockPlusMacosPlugin")) | ||||||
|   WebViewFlutterPlugin.register(with: registry.registrar(forPlugin: "WebViewFlutterPlugin")) |   WebViewFlutterPlugin.register(with: registry.registrar(forPlugin: "WebViewFlutterPlugin")) | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										66
									
								
								pubspec.lock
									
									
									
									
									
								
							
							
						
						
									
										66
									
								
								pubspec.lock
									
									
									
									
									
								
							| @@ -161,6 +161,14 @@ packages: | |||||||
|       url: "https://pub.dev" |       url: "https://pub.dev" | ||||||
|     source: hosted |     source: hosted | ||||||
|     version: "2.0.4" |     version: "2.0.4" | ||||||
|  |   chewie: | ||||||
|  |     dependency: "direct main" | ||||||
|  |     description: | ||||||
|  |       name: chewie | ||||||
|  |       sha256: "19b93a1e60e4ba640a792208a6543f1c7d5b124d011ce0199e2f18802199d984" | ||||||
|  |       url: "https://pub.dev" | ||||||
|  |     source: hosted | ||||||
|  |     version: "1.12.1" | ||||||
|   cli_util: |   cli_util: | ||||||
|     dependency: transitive |     dependency: transitive | ||||||
|     description: |     description: | ||||||
| @@ -209,6 +217,14 @@ packages: | |||||||
|       url: "https://pub.dev" |       url: "https://pub.dev" | ||||||
|     source: hosted |     source: hosted | ||||||
|     version: "3.0.6" |     version: "3.0.6" | ||||||
|  |   csslib: | ||||||
|  |     dependency: transitive | ||||||
|  |     description: | ||||||
|  |       name: csslib | ||||||
|  |       sha256: "09bad715f418841f976c77db72d5398dc1253c21fb9c0c7f0b0b985860b2d58e" | ||||||
|  |       url: "https://pub.dev" | ||||||
|  |     source: hosted | ||||||
|  |     version: "1.0.2" | ||||||
|   cupertino_icons: |   cupertino_icons: | ||||||
|     dependency: "direct main" |     dependency: "direct main" | ||||||
|     description: |     description: | ||||||
| @@ -456,6 +472,14 @@ packages: | |||||||
|       url: "https://pub.dev" |       url: "https://pub.dev" | ||||||
|     source: hosted |     source: hosted | ||||||
|     version: "2.0.1" |     version: "2.0.1" | ||||||
|  |   html: | ||||||
|  |     dependency: transitive | ||||||
|  |     description: | ||||||
|  |       name: html | ||||||
|  |       sha256: "6d1264f2dffa1b1101c25a91dff0dc2daee4c18e87cd8538729773c073dbf602" | ||||||
|  |       url: "https://pub.dev" | ||||||
|  |     source: hosted | ||||||
|  |     version: "0.15.6" | ||||||
|   http: |   http: | ||||||
|     dependency: "direct main" |     dependency: "direct main" | ||||||
|     description: |     description: | ||||||
| @@ -1069,6 +1093,46 @@ packages: | |||||||
|       url: "https://pub.dev" |       url: "https://pub.dev" | ||||||
|     source: hosted |     source: hosted | ||||||
|     version: "2.2.0" |     version: "2.2.0" | ||||||
|  |   video_player: | ||||||
|  |     dependency: "direct main" | ||||||
|  |     description: | ||||||
|  |       name: video_player | ||||||
|  |       sha256: "0d55b1f1a31e5ad4c4967bfaa8ade0240b07d20ee4af1dfef5f531056512961a" | ||||||
|  |       url: "https://pub.dev" | ||||||
|  |     source: hosted | ||||||
|  |     version: "2.10.0" | ||||||
|  |   video_player_android: | ||||||
|  |     dependency: transitive | ||||||
|  |     description: | ||||||
|  |       name: video_player_android | ||||||
|  |       sha256: "6cfe0b1e102522eda1e139b82bf00602181c5844fd2885340f595fb213d74842" | ||||||
|  |       url: "https://pub.dev" | ||||||
|  |     source: hosted | ||||||
|  |     version: "2.8.14" | ||||||
|  |   video_player_avfoundation: | ||||||
|  |     dependency: transitive | ||||||
|  |     description: | ||||||
|  |       name: video_player_avfoundation | ||||||
|  |       sha256: f9a780aac57802b2892f93787e5ea53b5f43cc57dc107bee9436458365be71cd | ||||||
|  |       url: "https://pub.dev" | ||||||
|  |     source: hosted | ||||||
|  |     version: "2.8.4" | ||||||
|  |   video_player_platform_interface: | ||||||
|  |     dependency: transitive | ||||||
|  |     description: | ||||||
|  |       name: video_player_platform_interface | ||||||
|  |       sha256: cf2a1d29a284db648fd66cbd18aacc157f9862d77d2cc790f6f9678a46c1db5a | ||||||
|  |       url: "https://pub.dev" | ||||||
|  |     source: hosted | ||||||
|  |     version: "6.4.0" | ||||||
|  |   video_player_web: | ||||||
|  |     dependency: transitive | ||||||
|  |     description: | ||||||
|  |       name: video_player_web | ||||||
|  |       sha256: "9f3c00be2ef9b76a95d94ac5119fb843dca6f2c69e6c9968f6f2b6c9e7afbdeb" | ||||||
|  |       url: "https://pub.dev" | ||||||
|  |     source: hosted | ||||||
|  |     version: "2.4.0" | ||||||
|   vm_service: |   vm_service: | ||||||
|     dependency: transitive |     dependency: transitive | ||||||
|     description: |     description: | ||||||
| @@ -1191,4 +1255,4 @@ packages: | |||||||
|     version: "3.1.3" |     version: "3.1.3" | ||||||
| sdks: | sdks: | ||||||
|   dart: ">=3.8.1 <4.0.0" |   dart: ">=3.8.1 <4.0.0" | ||||||
|   flutter: ">=3.27.0" |   flutter: ">=3.29.0" | ||||||
|   | |||||||
| @@ -52,6 +52,9 @@ dependencies: | |||||||
|   # Video Player (WebView only) |   # Video Player (WebView only) | ||||||
|   webview_flutter: ^4.7.0 |   webview_flutter: ^4.7.0 | ||||||
|   wakelock_plus: ^1.2.1 |   wakelock_plus: ^1.2.1 | ||||||
|  |   # Video Player with native controls | ||||||
|  |   video_player: ^2.9.2 | ||||||
|  |   chewie: ^1.8.5 | ||||||
|   # Utils |   # Utils | ||||||
|   equatable: ^2.0.5 |   equatable: ^2.0.5 | ||||||
|   url_launcher: ^6.3.2 |   url_launcher: ^6.3.2 | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user