├── .gitignore
├── .metadata
├── LICENCE
├── README.md
├── analysis_options.yaml
├── android
├── .gitignore
├── app
│ ├── build.gradle
│ └── src
│ │ ├── debug
│ │ └── AndroidManifest.xml
│ │ ├── main
│ │ ├── AndroidManifest.xml
│ │ ├── kotlin
│ │ │ └── com
│ │ │ │ └── devsadeq
│ │ │ │ └── jobs_flutter_app
│ │ │ │ └── MainActivity.kt
│ │ └── res
│ │ │ ├── drawable-night-v21
│ │ │ ├── background.png
│ │ │ └── launch_background.xml
│ │ │ ├── drawable-night
│ │ │ ├── background.png
│ │ │ └── launch_background.xml
│ │ │ ├── drawable-v21
│ │ │ ├── background.png
│ │ │ └── launch_background.xml
│ │ │ ├── drawable
│ │ │ ├── background.png
│ │ │ └── launch_background.xml
│ │ │ ├── mipmap-hdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-mdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xhdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xxhdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xxxhdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── values-night-v31
│ │ │ └── styles.xml
│ │ │ ├── values-night
│ │ │ └── styles.xml
│ │ │ ├── values-v31
│ │ │ └── styles.xml
│ │ │ └── values
│ │ │ └── styles.xml
│ │ └── profile
│ │ └── AndroidManifest.xml
├── build.gradle
├── gradle.properties
├── gradle
│ └── wrapper
│ │ └── gradle-wrapper.properties
└── settings.gradle
├── assets
├── empty.json
├── empty_save.svg
├── header_bg.svg
├── screenshots
│ ├── cover.png
│ ├── screenshot (1).png
│ ├── screenshot (10).png
│ ├── screenshot (11).png
│ ├── screenshot (12).png
│ ├── screenshot (13).png
│ ├── screenshot (2).png
│ ├── screenshot (3).png
│ ├── screenshot (4).png
│ ├── screenshot (5).png
│ ├── screenshot (6).png
│ ├── screenshot (7).png
│ ├── screenshot (8).png
│ └── screenshot (9).png
└── space.json
├── ios
├── .gitignore
├── Flutter
│ ├── AppFrameworkInfo.plist
│ ├── Debug.xcconfig
│ └── Release.xcconfig
├── Runner.xcodeproj
│ ├── project.pbxproj
│ ├── project.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ │ ├── IDEWorkspaceChecks.plist
│ │ │ └── WorkspaceSettings.xcsettings
│ └── xcshareddata
│ │ └── xcschemes
│ │ └── Runner.xcscheme
├── Runner.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ ├── IDEWorkspaceChecks.plist
│ │ └── WorkspaceSettings.xcsettings
└── Runner
│ ├── AppDelegate.swift
│ ├── Assets.xcassets
│ ├── AppIcon.appiconset
│ │ ├── Contents.json
│ │ ├── Icon-App-1024x1024@1x.png
│ │ ├── Icon-App-20x20@1x.png
│ │ ├── Icon-App-20x20@2x.png
│ │ ├── Icon-App-20x20@3x.png
│ │ ├── Icon-App-29x29@1x.png
│ │ ├── Icon-App-29x29@2x.png
│ │ ├── Icon-App-29x29@3x.png
│ │ ├── Icon-App-40x40@1x.png
│ │ ├── Icon-App-40x40@2x.png
│ │ ├── Icon-App-40x40@3x.png
│ │ ├── Icon-App-60x60@2x.png
│ │ ├── Icon-App-60x60@3x.png
│ │ ├── Icon-App-76x76@1x.png
│ │ ├── Icon-App-76x76@2x.png
│ │ └── Icon-App-83.5x83.5@2x.png
│ ├── LaunchBackground.imageset
│ │ ├── Contents.json
│ │ ├── background.png
│ │ └── darkbackground.png
│ └── LaunchImage.imageset
│ │ ├── Contents.json
│ │ ├── LaunchImage.png
│ │ ├── LaunchImage@2x.png
│ │ ├── LaunchImage@3x.png
│ │ └── README.md
│ ├── Base.lproj
│ ├── LaunchScreen.storyboard
│ └── Main.storyboard
│ ├── Info.plist
│ └── Runner-Bridging-Header.h
├── lib
├── app
│ ├── core
│ │ ├── theme
│ │ │ └── app_theme.dart
│ │ └── values
│ │ │ └── strings.dart
│ ├── data
│ │ ├── local
│ │ │ ├── base
│ │ │ │ ├── i_entity.dart
│ │ │ │ └── iservice.dart
│ │ │ ├── entities
│ │ │ │ └── user_entity.dart
│ │ │ └── services
│ │ │ │ └── storage_service.dart
│ │ └── remote
│ │ │ ├── api
│ │ │ ├── api_routes.dart
│ │ │ ├── dio_Interceptor.dart
│ │ │ └── dio_client.dart
│ │ │ ├── base
│ │ │ ├── idto.dart
│ │ │ ├── status.dart
│ │ │ └── status.freezed.dart
│ │ │ ├── dto
│ │ │ ├── application
│ │ │ │ ├── application_in_dto.dart
│ │ │ │ └── application_out_dto.dart
│ │ │ ├── auth
│ │ │ │ ├── login_in_dto.dart
│ │ │ │ ├── login_out_dto.dart
│ │ │ │ ├── register_company_dto.dart
│ │ │ │ ├── register_company_out_dto.dart
│ │ │ │ ├── register_customer_dto.dart
│ │ │ │ └── register_customer_out_dto.dart
│ │ │ ├── choices
│ │ │ │ └── position_out_dto.dart
│ │ │ ├── company
│ │ │ │ ├── company_out_dto.dart
│ │ │ │ └── company_search_out_dto.dart
│ │ │ ├── customer
│ │ │ │ ├── customer_profile_out_dto.dart
│ │ │ │ ├── single_customer_out_dto.dart
│ │ │ │ └── toggle_save_out_dto.dart
│ │ │ ├── job
│ │ │ │ ├── job_in_dto.dart
│ │ │ │ └── job_out_dto.dart
│ │ │ └── search
│ │ │ │ └── search_out_dto.dart
│ │ │ ├── exceptions
│ │ │ └── dio_exceptions.dart
│ │ │ ├── repositories
│ │ │ ├── application
│ │ │ │ ├── application_repository.dart
│ │ │ │ └── i_application_repository.dart
│ │ │ ├── auth
│ │ │ │ ├── auth_repository.dart
│ │ │ │ └── i_auth_repository.dart
│ │ │ ├── company
│ │ │ │ ├── company_repository.dart
│ │ │ │ └── i_company_repository.dart
│ │ │ ├── customer
│ │ │ │ ├── customer_repository.dart
│ │ │ │ └── i_customer_repository.dart
│ │ │ ├── job
│ │ │ │ ├── i_job_repository.dart
│ │ │ │ └── job_repository.dart
│ │ │ ├── position
│ │ │ │ ├── i_choice_repository.dart
│ │ │ │ └── position_repository.dart
│ │ │ └── search
│ │ │ │ ├── i_search_repository.dart
│ │ │ │ └── search_repository.dart
│ │ │ └── services
│ │ │ ├── application
│ │ │ ├── application_service.dart
│ │ │ └── i_application_service.dart
│ │ │ ├── auth
│ │ │ ├── auth_service.dart
│ │ │ └── i_auth_service.dart
│ │ │ ├── company
│ │ │ ├── comapny_service.dart
│ │ │ └── i_company_service.dart
│ │ │ ├── customer
│ │ │ ├── customer_service.dart
│ │ │ └── i_customer_service.dart
│ │ │ ├── job
│ │ │ ├── i_job_service.dart
│ │ │ └── job_service.dart
│ │ │ ├── position
│ │ │ ├── i_choice_service.dart
│ │ │ └── position_choice_service.dart
│ │ │ └── search
│ │ │ ├── i_search_service.dart
│ │ │ └── search_service.dart
│ ├── di
│ │ └── locator.dart
│ ├── domain
│ │ └── enums
│ │ │ └── user_type.dart
│ ├── icons.dart
│ ├── modules
│ │ ├── JobDetails
│ │ │ ├── bindings
│ │ │ │ └── job_details_binding.dart
│ │ │ ├── controllers
│ │ │ │ └── job_details_controller.dart
│ │ │ └── views
│ │ │ │ ├── job_details_view.dart
│ │ │ │ └── widgets
│ │ │ │ ├── about_the_employer.dart
│ │ │ │ ├── apply_bottom_sheet.dart
│ │ │ │ ├── body.dart
│ │ │ │ ├── description.dart
│ │ │ │ ├── details_bottom_nav_bar.dart
│ │ │ │ ├── details_sliver_app_bar.dart
│ │ │ │ ├── header.dart
│ │ │ │ ├── similar_jobs.dart
│ │ │ │ ├── slimilar_job_card.dart
│ │ │ │ └── submit_bottom_sheet.dart
│ │ ├── auth
│ │ │ ├── bindings
│ │ │ │ └── auth_binding.dart
│ │ │ ├── controllers
│ │ │ │ └── auth_controller.dart
│ │ │ └── views
│ │ │ │ ├── login
│ │ │ │ ├── login_view.dart
│ │ │ │ └── widgets
│ │ │ │ │ ├── body.dart
│ │ │ │ │ ├── choose_bottom_sheet.dart
│ │ │ │ │ ├── custom_choose_button.dart
│ │ │ │ │ └── login_form.dart
│ │ │ │ ├── register
│ │ │ │ ├── register_view.dart
│ │ │ │ └── widgets
│ │ │ │ │ ├── body.dart
│ │ │ │ │ ├── employee_form.dart
│ │ │ │ │ └── employer_form.dart
│ │ │ │ └── widgets
│ │ │ │ ├── button_with_text.dart
│ │ │ │ └── header.dart
│ │ ├── companyProfile
│ │ │ ├── bindings
│ │ │ │ └── company_profile_binding.dart
│ │ │ ├── controllers
│ │ │ │ └── company_profile_controller.dart
│ │ │ └── views
│ │ │ │ ├── company_profile_view.dart
│ │ │ │ └── widgets
│ │ │ │ ├── about_us.dart
│ │ │ │ ├── body.dart
│ │ │ │ ├── company_profile_sliver_app_bar.dart
│ │ │ │ ├── company_tab_view.dart
│ │ │ │ ├── company_tap_bar.dart
│ │ │ │ ├── header.dart
│ │ │ │ ├── jobs_list.dart
│ │ │ │ ├── profile_header.dart
│ │ │ │ └── sliverPersistentHeaderDelegateImp.dart
│ │ ├── customerProfile
│ │ │ ├── bindings
│ │ │ │ └── customer_profile_binding.dart
│ │ │ ├── controllers
│ │ │ │ └── customer_profile_controller.dart
│ │ │ └── views
│ │ │ │ ├── customer_profile_view.dart
│ │ │ │ └── widgets
│ │ │ │ ├── about_me.dart
│ │ │ │ ├── body.dart
│ │ │ │ ├── customer_profile_sliver_app_bar.dart
│ │ │ │ ├── education.dart
│ │ │ │ ├── experience.dart
│ │ │ │ ├── header.dart
│ │ │ │ ├── languages.dart
│ │ │ │ ├── skills.dart
│ │ │ │ └── wrapped_chips.dart
│ │ ├── home
│ │ │ ├── bindings
│ │ │ │ └── home_binding.dart
│ │ │ ├── controllers
│ │ │ │ └── home_controller.dart
│ │ │ └── views
│ │ │ │ ├── home_view.dart
│ │ │ │ └── widgets
│ │ │ │ ├── body.dart
│ │ │ │ ├── chips_list.dart
│ │ │ │ ├── featured_jobs.dart
│ │ │ │ └── recent_jobs.dart
│ │ ├── root
│ │ │ ├── bindings
│ │ │ │ └── root_binding.dart
│ │ │ ├── controllers
│ │ │ │ └── root_controller.dart
│ │ │ └── views
│ │ │ │ ├── root_view.dart
│ │ │ │ └── widgets
│ │ │ │ └── menu_view.dart
│ │ ├── saved
│ │ │ ├── bindings
│ │ │ │ └── saved_binding.dart
│ │ │ ├── controllers
│ │ │ │ └── saved_controller.dart
│ │ │ └── views
│ │ │ │ ├── saved_view.dart
│ │ │ │ └── widgets
│ │ │ │ ├── body.dart
│ │ │ │ ├── no_saving.dart
│ │ │ │ └── saved_jobs.dart
│ │ ├── search
│ │ │ ├── bindings
│ │ │ │ └── search_binding.dart
│ │ │ ├── controllers
│ │ │ │ └── search_controller.dart
│ │ │ └── views
│ │ │ │ ├── search_view.dart
│ │ │ │ └── widgets
│ │ │ │ ├── body.dart
│ │ │ │ ├── items_card.dart
│ │ │ │ └── search_items.dart
│ │ └── waiting
│ │ │ ├── bindings
│ │ │ └── waiting_binding.dart
│ │ │ ├── controllers
│ │ │ └── waiting_controller.dart
│ │ │ └── views
│ │ │ ├── waiting_view.dart
│ │ │ └── widgets
│ │ │ └── body.dart
│ ├── routes
│ │ ├── app_pages.dart
│ │ └── app_routes.dart
│ ├── utils
│ │ ├── extensions.dart
│ │ ├── functions.dart
│ │ └── validators.dart
│ └── widgets
│ │ ├── custom_appbar.dart
│ │ ├── custom_avatar.dart
│ │ ├── custom_bottom_sheet.dart
│ │ ├── custom_button.dart
│ │ ├── custom_chip.dart
│ │ ├── custom_info_card.dart
│ │ ├── custom_job_card.dart
│ │ ├── custom_lottie.dart
│ │ ├── custom_save_button.dart
│ │ ├── custom_tag.dart
│ │ ├── custom_text_field.dart
│ │ ├── dialogs.dart
│ │ ├── section_header.dart
│ │ ├── shimmer
│ │ ├── chips_shimmer.dart
│ │ ├── company_profile_shimmer.dart
│ │ ├── customer_profile_shimmer.dart
│ │ ├── featured_job_shimmer.dart
│ │ ├── job_details_shimmer.dart
│ │ ├── recent_jobs_shimmer.dart
│ │ └── shimmer_widget.dart
│ │ └── snackbars.dart
└── main.dart
├── pubspec.lock
└── pubspec.yaml
/.gitignore:
--------------------------------------------------------------------------------
1 | # Miscellaneous
2 | *.class
3 | *.log
4 | *.pyc
5 | *.swp
6 | .DS_Store
7 | .atom/
8 | .buildlog/
9 | .history
10 | .svn/
11 | migrate_working_dir/
12 |
13 | # IntelliJ related
14 | *.iml
15 | *.ipr
16 | *.iws
17 | .idea/
18 |
19 | # The .vscode folder contains launch configuration and tasks you configure in
20 | # VS Code which you may wish to be included in version control, so this line
21 | # is commented out by default.
22 | #.vscode/
23 |
24 | # Flutter/Dart/Pub related
25 | **/doc/api/
26 | **/ios/Flutter/.last_build_id
27 | .dart_tool/
28 | .flutter-plugins
29 | .flutter-plugins-dependencies
30 | .packages
31 | .pub-cache/
32 | .pub/
33 | /build/
34 |
35 | # Web related
36 | lib/generated_plugin_registrant.dart
37 |
38 | # Symbolication related
39 | app.*.symbols
40 |
41 | # Obfuscation related
42 | app.*.map.json
43 |
44 | # Android Studio will place build artifacts here
45 | /android/app/debug
46 | /android/app/profile
47 | /android/app/release
--------------------------------------------------------------------------------
/.metadata:
--------------------------------------------------------------------------------
1 | # This file tracks properties of this Flutter project.
2 | # Used by Flutter tool to assess capabilities and perform upgrades etc.
3 | #
4 | # This file should be version controlled.
5 |
6 | version:
7 | revision: f1875d570e39de09040c8f79aa13cc56baab8db1
8 | channel: stable
9 |
10 | project_type: app
11 |
12 | # Tracks metadata for the flutter migrate command
13 | migration:
14 | platforms:
15 | - platform: root
16 | create_revision: f1875d570e39de09040c8f79aa13cc56baab8db1
17 | base_revision: f1875d570e39de09040c8f79aa13cc56baab8db1
18 | - platform: android
19 | create_revision: f1875d570e39de09040c8f79aa13cc56baab8db1
20 | base_revision: f1875d570e39de09040c8f79aa13cc56baab8db1
21 | - platform: ios
22 | create_revision: f1875d570e39de09040c8f79aa13cc56baab8db1
23 | base_revision: f1875d570e39de09040c8f79aa13cc56baab8db1
24 |
25 | # User provided section
26 |
27 | # List of Local paths (relative to this file) that should be
28 | # ignored by the migrate tool.
29 | #
30 | # Files that are not part of the templates will be ignored by default.
31 | unmanaged_files:
32 | - 'lib/main.dart'
33 | - 'ios/Runner.xcodeproj/project.pbxproj'
34 |
--------------------------------------------------------------------------------
/LICENCE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 Sadeq Al-Mhana
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/analysis_options.yaml:
--------------------------------------------------------------------------------
1 | # This file configures the analyzer, which statically analyzes Dart code to
2 | # check for errors, warnings, and lints.
3 | #
4 | # The issues identified by the analyzer are surfaced in the UI of Dart-enabled
5 | # IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
6 | # invoked from the command line by running `flutter analyze`.
7 |
8 | # The following line activates a set of recommended lints for Flutter apps,
9 | # packages, and plugins designed to encourage good coding practices.
10 | include: package:flutter_lints/flutter.yaml
11 |
12 | linter:
13 | # The lint rules applied to this project can be customized in the
14 | # section below to disable rules from the `package:flutter_lints/flutter.yaml`
15 | # included above or to enable additional rules. A list of all available lints
16 | # and their documentation is published at
17 | # https://dart-lang.github.io/linter/lints/index.html.
18 | #
19 | # Instead of disabling a lint rule for the entire project in the
20 | # section below, it can also be suppressed for a single line of code
21 | # or a specific dart file by using the `// ignore: name_of_lint` and
22 | # `// ignore_for_file: name_of_lint` syntax on the line or in the file
23 | # producing the lint.
24 | rules:
25 | # avoid_print: false # Uncomment to disable the `avoid_print` rule
26 | # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
27 |
28 | # Additional information about this file can be found at
29 | # https://dart.dev/guides/language/analysis-options
30 |
--------------------------------------------------------------------------------
/android/.gitignore:
--------------------------------------------------------------------------------
1 | gradle-wrapper.jar
2 | /.gradle
3 | /captures/
4 | /gradlew
5 | /gradlew.bat
6 | /local.properties
7 | GeneratedPluginRegistrant.java
8 |
9 | # Remember to never publicly share your keystore.
10 | # See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app
11 | key.properties
12 | **/*.keystore
13 | **/*.jks
14 |
--------------------------------------------------------------------------------
/android/app/build.gradle:
--------------------------------------------------------------------------------
1 | def localProperties = new Properties()
2 | def localPropertiesFile = rootProject.file('local.properties')
3 | if (localPropertiesFile.exists()) {
4 | localPropertiesFile.withReader('UTF-8') { reader ->
5 | localProperties.load(reader)
6 | }
7 | }
8 |
9 | def flutterRoot = localProperties.getProperty('flutter.sdk')
10 | if (flutterRoot == null) {
11 | throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
12 | }
13 |
14 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
15 | if (flutterVersionCode == null) {
16 | flutterVersionCode = '1'
17 | }
18 |
19 | def flutterVersionName = localProperties.getProperty('flutter.versionName')
20 | if (flutterVersionName == null) {
21 | flutterVersionName = '1.0'
22 | }
23 |
24 | apply plugin: 'com.android.application'
25 | apply plugin: 'kotlin-android'
26 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
27 |
28 | android {
29 | compileSdkVersion flutter.compileSdkVersion
30 | ndkVersion flutter.ndkVersion
31 |
32 | compileOptions {
33 | sourceCompatibility JavaVersion.VERSION_1_8
34 | targetCompatibility JavaVersion.VERSION_1_8
35 | }
36 |
37 | kotlinOptions {
38 | jvmTarget = '1.8'
39 | }
40 |
41 | sourceSets {
42 | main.java.srcDirs += 'src/main/kotlin'
43 | }
44 |
45 | defaultConfig {
46 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
47 | applicationId "com.devsadeq.jobs_flutter_app"
48 | // You can update the following values to match your application needs.
49 | // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-build-configuration.
50 | minSdkVersion flutter.minSdkVersion
51 | targetSdkVersion flutter.targetSdkVersion
52 | versionCode flutterVersionCode.toInteger()
53 | versionName flutterVersionName
54 | }
55 |
56 | buildTypes {
57 | release {
58 | // TODO: Add your own signing config for the release build.
59 | // Signing with the debug keys for now, so `flutter run --release` works.
60 | signingConfig signingConfigs.debug
61 | }
62 | }
63 | }
64 |
65 | flutter {
66 | source '../..'
67 | }
68 |
69 | dependencies {
70 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
71 | }
72 |
--------------------------------------------------------------------------------
/android/app/src/debug/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/android/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
23 |
31 |
35 |
38 |
39 |
40 |
41 |
42 |
43 |
45 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/android/app/src/main/kotlin/com/devsadeq/jobs_flutter_app/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package com.devsadeq.jobs_flutter_app
2 |
3 | import io.flutter.embedding.android.FlutterActivity
4 |
5 | class MainActivity: FlutterActivity() {
6 | }
7 |
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-night-v21/background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devsadeq/JobsFlutterApp/bae75ee511308191fa43526bacfbf1fcb6003e26/android/app/src/main/res/drawable-night-v21/background.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-night-v21/launch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-night/background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devsadeq/JobsFlutterApp/bae75ee511308191fa43526bacfbf1fcb6003e26/android/app/src/main/res/drawable-night/background.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-night/launch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-v21/background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devsadeq/JobsFlutterApp/bae75ee511308191fa43526bacfbf1fcb6003e26/android/app/src/main/res/drawable-v21/background.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-v21/launch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable/background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devsadeq/JobsFlutterApp/bae75ee511308191fa43526bacfbf1fcb6003e26/android/app/src/main/res/drawable/background.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable/launch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devsadeq/JobsFlutterApp/bae75ee511308191fa43526bacfbf1fcb6003e26/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devsadeq/JobsFlutterApp/bae75ee511308191fa43526bacfbf1fcb6003e26/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devsadeq/JobsFlutterApp/bae75ee511308191fa43526bacfbf1fcb6003e26/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devsadeq/JobsFlutterApp/bae75ee511308191fa43526bacfbf1fcb6003e26/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devsadeq/JobsFlutterApp/bae75ee511308191fa43526bacfbf1fcb6003e26/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/values-night-v31/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
16 |
19 |
20 |
--------------------------------------------------------------------------------
/android/app/src/main/res/values-night/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
12 |
18 |
21 |
22 |
--------------------------------------------------------------------------------
/android/app/src/main/res/values-v31/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
16 |
19 |
20 |
--------------------------------------------------------------------------------
/android/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
12 |
18 |
21 |
22 |
--------------------------------------------------------------------------------
/android/app/src/profile/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/android/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | ext.kotlin_version = '1.6.10'
3 | repositories {
4 | google()
5 | mavenCentral()
6 | }
7 |
8 | dependencies {
9 | classpath 'com.android.tools.build:gradle:7.1.2'
10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
11 | }
12 | }
13 |
14 | allprojects {
15 | repositories {
16 | google()
17 | mavenCentral()
18 | }
19 | }
20 |
21 | rootProject.buildDir = '../build'
22 | subprojects {
23 | project.buildDir = "${rootProject.buildDir}/${project.name}"
24 | }
25 | subprojects {
26 | project.evaluationDependsOn(':app')
27 | }
28 |
29 | task clean(type: Delete) {
30 | delete rootProject.buildDir
31 | }
32 |
--------------------------------------------------------------------------------
/android/gradle.properties:
--------------------------------------------------------------------------------
1 | org.gradle.jvmargs=-Xmx1536M
2 | android.useAndroidX=true
3 | android.enableJetifier=true
4 |
--------------------------------------------------------------------------------
/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Fri Jun 23 08:50:38 CEST 2017
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-all.zip
7 |
--------------------------------------------------------------------------------
/android/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
3 | def localPropertiesFile = new File(rootProject.projectDir, "local.properties")
4 | def properties = new Properties()
5 |
6 | assert localPropertiesFile.exists()
7 | localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) }
8 |
9 | def flutterSdkPath = properties.getProperty("flutter.sdk")
10 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
11 | apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle"
12 |
--------------------------------------------------------------------------------
/assets/screenshots/cover.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devsadeq/JobsFlutterApp/bae75ee511308191fa43526bacfbf1fcb6003e26/assets/screenshots/cover.png
--------------------------------------------------------------------------------
/assets/screenshots/screenshot (1).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devsadeq/JobsFlutterApp/bae75ee511308191fa43526bacfbf1fcb6003e26/assets/screenshots/screenshot (1).png
--------------------------------------------------------------------------------
/assets/screenshots/screenshot (10).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devsadeq/JobsFlutterApp/bae75ee511308191fa43526bacfbf1fcb6003e26/assets/screenshots/screenshot (10).png
--------------------------------------------------------------------------------
/assets/screenshots/screenshot (11).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devsadeq/JobsFlutterApp/bae75ee511308191fa43526bacfbf1fcb6003e26/assets/screenshots/screenshot (11).png
--------------------------------------------------------------------------------
/assets/screenshots/screenshot (12).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devsadeq/JobsFlutterApp/bae75ee511308191fa43526bacfbf1fcb6003e26/assets/screenshots/screenshot (12).png
--------------------------------------------------------------------------------
/assets/screenshots/screenshot (13).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devsadeq/JobsFlutterApp/bae75ee511308191fa43526bacfbf1fcb6003e26/assets/screenshots/screenshot (13).png
--------------------------------------------------------------------------------
/assets/screenshots/screenshot (2).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devsadeq/JobsFlutterApp/bae75ee511308191fa43526bacfbf1fcb6003e26/assets/screenshots/screenshot (2).png
--------------------------------------------------------------------------------
/assets/screenshots/screenshot (3).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devsadeq/JobsFlutterApp/bae75ee511308191fa43526bacfbf1fcb6003e26/assets/screenshots/screenshot (3).png
--------------------------------------------------------------------------------
/assets/screenshots/screenshot (4).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devsadeq/JobsFlutterApp/bae75ee511308191fa43526bacfbf1fcb6003e26/assets/screenshots/screenshot (4).png
--------------------------------------------------------------------------------
/assets/screenshots/screenshot (5).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devsadeq/JobsFlutterApp/bae75ee511308191fa43526bacfbf1fcb6003e26/assets/screenshots/screenshot (5).png
--------------------------------------------------------------------------------
/assets/screenshots/screenshot (6).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devsadeq/JobsFlutterApp/bae75ee511308191fa43526bacfbf1fcb6003e26/assets/screenshots/screenshot (6).png
--------------------------------------------------------------------------------
/assets/screenshots/screenshot (7).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devsadeq/JobsFlutterApp/bae75ee511308191fa43526bacfbf1fcb6003e26/assets/screenshots/screenshot (7).png
--------------------------------------------------------------------------------
/assets/screenshots/screenshot (8).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devsadeq/JobsFlutterApp/bae75ee511308191fa43526bacfbf1fcb6003e26/assets/screenshots/screenshot (8).png
--------------------------------------------------------------------------------
/assets/screenshots/screenshot (9).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devsadeq/JobsFlutterApp/bae75ee511308191fa43526bacfbf1fcb6003e26/assets/screenshots/screenshot (9).png
--------------------------------------------------------------------------------
/ios/.gitignore:
--------------------------------------------------------------------------------
1 | **/dgph
2 | *.mode1v3
3 | *.mode2v3
4 | *.moved-aside
5 | *.pbxuser
6 | *.perspectivev3
7 | **/*sync/
8 | .sconsign.dblite
9 | .tags*
10 | **/.vagrant/
11 | **/DerivedData/
12 | Icon?
13 | **/Pods/
14 | **/.symlinks/
15 | profile
16 | xcuserdata
17 | **/.generated/
18 | Flutter/App.framework
19 | Flutter/Flutter.framework
20 | Flutter/Flutter.podspec
21 | Flutter/Generated.xcconfig
22 | Flutter/ephemeral/
23 | Flutter/app.flx
24 | Flutter/app.zip
25 | Flutter/flutter_assets/
26 | Flutter/flutter_export_environment.sh
27 | ServiceDefinitions.json
28 | Runner/GeneratedPluginRegistrant.*
29 |
30 | # Exceptions to above rules.
31 | !default.mode1v3
32 | !default.mode2v3
33 | !default.pbxuser
34 | !default.perspectivev3
35 |
--------------------------------------------------------------------------------
/ios/Flutter/AppFrameworkInfo.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | App
9 | CFBundleIdentifier
10 | io.flutter.flutter.app
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | App
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1.0
23 | MinimumOSVersion
24 | 9.0
25 |
26 |
27 |
--------------------------------------------------------------------------------
/ios/Flutter/Debug.xcconfig:
--------------------------------------------------------------------------------
1 | #include "Generated.xcconfig"
2 |
--------------------------------------------------------------------------------
/ios/Flutter/Release.xcconfig:
--------------------------------------------------------------------------------
1 | #include "Generated.xcconfig"
2 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PreviewsEnabled
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ios/Runner.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PreviewsEnabled
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ios/Runner/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 | import Flutter
3 |
4 | @UIApplicationMain
5 | @objc class AppDelegate: FlutterAppDelegate {
6 | override func application(
7 | _ application: UIApplication,
8 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
9 | ) -> Bool {
10 | GeneratedPluginRegistrant.register(with: self)
11 | return super.application(application, didFinishLaunchingWithOptions: launchOptions)
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devsadeq/JobsFlutterApp/bae75ee511308191fa43526bacfbf1fcb6003e26/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devsadeq/JobsFlutterApp/bae75ee511308191fa43526bacfbf1fcb6003e26/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devsadeq/JobsFlutterApp/bae75ee511308191fa43526bacfbf1fcb6003e26/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devsadeq/JobsFlutterApp/bae75ee511308191fa43526bacfbf1fcb6003e26/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devsadeq/JobsFlutterApp/bae75ee511308191fa43526bacfbf1fcb6003e26/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devsadeq/JobsFlutterApp/bae75ee511308191fa43526bacfbf1fcb6003e26/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devsadeq/JobsFlutterApp/bae75ee511308191fa43526bacfbf1fcb6003e26/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devsadeq/JobsFlutterApp/bae75ee511308191fa43526bacfbf1fcb6003e26/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devsadeq/JobsFlutterApp/bae75ee511308191fa43526bacfbf1fcb6003e26/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devsadeq/JobsFlutterApp/bae75ee511308191fa43526bacfbf1fcb6003e26/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devsadeq/JobsFlutterApp/bae75ee511308191fa43526bacfbf1fcb6003e26/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devsadeq/JobsFlutterApp/bae75ee511308191fa43526bacfbf1fcb6003e26/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devsadeq/JobsFlutterApp/bae75ee511308191fa43526bacfbf1fcb6003e26/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devsadeq/JobsFlutterApp/bae75ee511308191fa43526bacfbf1fcb6003e26/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devsadeq/JobsFlutterApp/bae75ee511308191fa43526bacfbf1fcb6003e26/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchBackground.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "background.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "appearances" : [
10 | {
11 | "appearance" : "luminosity",
12 | "value" : "dark"
13 | }
14 | ],
15 | "filename" : "darkbackground.png",
16 | "idiom" : "universal",
17 | "scale" : "1x"
18 | },
19 | {
20 | "idiom" : "universal",
21 | "scale" : "2x"
22 | },
23 | {
24 | "appearances" : [
25 | {
26 | "appearance" : "luminosity",
27 | "value" : "dark"
28 | }
29 | ],
30 | "idiom" : "universal",
31 | "scale" : "2x"
32 | },
33 | {
34 | "idiom" : "universal",
35 | "scale" : "3x"
36 | },
37 | {
38 | "appearances" : [
39 | {
40 | "appearance" : "luminosity",
41 | "value" : "dark"
42 | }
43 | ],
44 | "idiom" : "universal",
45 | "scale" : "3x"
46 | }
47 | ],
48 | "info" : {
49 | "author" : "xcode",
50 | "version" : 1
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchBackground.imageset/background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devsadeq/JobsFlutterApp/bae75ee511308191fa43526bacfbf1fcb6003e26/ios/Runner/Assets.xcassets/LaunchBackground.imageset/background.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchBackground.imageset/darkbackground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devsadeq/JobsFlutterApp/bae75ee511308191fa43526bacfbf1fcb6003e26/ios/Runner/Assets.xcassets/LaunchBackground.imageset/darkbackground.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "LaunchImage.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "filename" : "LaunchImage@2x.png",
10 | "idiom" : "universal",
11 | "scale" : "2x"
12 | },
13 | {
14 | "filename" : "LaunchImage@3x.png",
15 | "idiom" : "universal",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "author" : "xcode",
21 | "version" : 1
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devsadeq/JobsFlutterApp/bae75ee511308191fa43526bacfbf1fcb6003e26/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devsadeq/JobsFlutterApp/bae75ee511308191fa43526bacfbf1fcb6003e26/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devsadeq/JobsFlutterApp/bae75ee511308191fa43526bacfbf1fcb6003e26/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md:
--------------------------------------------------------------------------------
1 | # Launch Screen Assets
2 |
3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory.
4 |
5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images.
--------------------------------------------------------------------------------
/ios/Runner/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/ios/Runner/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleDisplayName
8 | Jobs Flutter App
9 | CFBundleExecutable
10 | $(EXECUTABLE_NAME)
11 | CFBundleIdentifier
12 | $(PRODUCT_BUNDLE_IDENTIFIER)
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | jobs_flutter_app
17 | CFBundlePackageType
18 | APPL
19 | CFBundleShortVersionString
20 | $(FLUTTER_BUILD_NAME)
21 | CFBundleSignature
22 | ????
23 | CFBundleVersion
24 | $(FLUTTER_BUILD_NUMBER)
25 | LSRequiresIPhoneOS
26 |
27 | UILaunchStoryboardName
28 | LaunchScreen
29 | UIMainStoryboardFile
30 | Main
31 | UISupportedInterfaceOrientations
32 |
33 | UIInterfaceOrientationPortrait
34 | UIInterfaceOrientationLandscapeLeft
35 | UIInterfaceOrientationLandscapeRight
36 |
37 | UISupportedInterfaceOrientations~ipad
38 |
39 | UIInterfaceOrientationPortrait
40 | UIInterfaceOrientationPortraitUpsideDown
41 | UIInterfaceOrientationLandscapeLeft
42 | UIInterfaceOrientationLandscapeRight
43 |
44 | UIViewControllerBasedStatusBarAppearance
45 |
46 | CADisableMinimumFrameDurationOnPhone
47 |
48 | UIStatusBarHidden
49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/ios/Runner/Runner-Bridging-Header.h:
--------------------------------------------------------------------------------
1 | #import "GeneratedPluginRegistrant.h"
2 |
--------------------------------------------------------------------------------
/lib/app/data/local/base/i_entity.dart:
--------------------------------------------------------------------------------
1 | abstract class IEntity {
2 | Map toMap();
3 |
4 | IEntity.fromMap(dynamic map);
5 | }
6 |
--------------------------------------------------------------------------------
/lib/app/data/local/base/iservice.dart:
--------------------------------------------------------------------------------
1 | import 'i_entity.dart';
2 |
3 | abstract class IService {
4 | Future read({required String key});
5 |
6 | Future write({required String key, required IEntity entity});
7 |
8 | Future remove({required String key});
9 | }
10 |
--------------------------------------------------------------------------------
/lib/app/data/local/entities/user_entity.dart:
--------------------------------------------------------------------------------
1 | import 'package:jobs_flutter_app/app/data/local/base/i_entity.dart';
2 |
3 | class UserEntity implements IEntity {
4 | String? id;
5 | String? name;
6 | String? email;
7 | String? phoneNumber;
8 | String? token;
9 | String? status;
10 | String? role;
11 |
12 | UserEntity({
13 | required this.id,
14 | required this.name,
15 | required this.email,
16 | required this.phoneNumber,
17 | required this.token,
18 | required this.status,
19 | required this.role,
20 | });
21 |
22 | @override
23 | UserEntity.fromMap(dynamic map) {
24 | id = map['id'];
25 | name = map['name'];
26 | email = map['email'];
27 | phoneNumber = map['phone'];
28 | token = map['token'];
29 | status = map['status'];
30 | role = map['role'];
31 | }
32 |
33 | @override
34 | Map toMap() {
35 | final map = {};
36 | map['id'] = id;
37 | map['name'] = name;
38 | map['email'] = email;
39 | map['phone'] = phoneNumber;
40 | map['token'] = token;
41 | map['role'] = role;
42 | map['status'] = status;
43 | return map;
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/lib/app/data/local/services/storage_service.dart:
--------------------------------------------------------------------------------
1 | import 'package:get_storage/get_storage.dart';
2 | import 'package:jobs_flutter_app/app/data/local/base/iservice.dart';
3 |
4 | import '../base/i_entity.dart';
5 |
6 | class StorageService implements IService {
7 | final GetStorage _storage;
8 |
9 | StorageService(this._storage);
10 |
11 | @override
12 | Future read({required String key}) async {
13 | try {
14 | return await _storage.read(key);
15 | } catch (e) {
16 | rethrow;
17 | }
18 | }
19 |
20 | @override
21 | Future write({required String key, required IEntity entity}) async {
22 | try {
23 | await _storage.write(key, entity.toMap());
24 | } catch (e) {
25 | rethrow;
26 | }
27 | }
28 |
29 | @override
30 | Future remove({required String key}) async {
31 | try {
32 | await _storage.remove(key);
33 | } catch (e) {
34 | rethrow;
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/lib/app/data/remote/api/api_routes.dart:
--------------------------------------------------------------------------------
1 | class ApiRoutes {
2 | static const BASE_URL = "https://kasmtj.pythonanywhere.com";
3 | static const _API = "/api";
4 |
5 | static const JOBS = "$_API/jobs/";
6 | static const POSITIONS = "$_API/meta/get_all_job_titles";
7 | static const SEARCH = "$_API/companies/search";
8 | static const COMPANIES = "$_API/companies/";
9 | static const COMPANY_REGISTER = "$_API/auth/company_signup";
10 | static const CUSTOMER_REGISTER = "$_API/auth/customer_signup";
11 | static const LOGIN = "$_API/auth/login";
12 | static const CUSTOMERS = "$_API/customers";
13 | static const SAVED_JOBS = "$CUSTOMERS/get_all_saved_jobs/";
14 | static const TOGGLE_SAVE = "$CUSTOMERS/save/";
15 | static const APPLICATIONS = "$_API/applications/";
16 | static const JOB_APPLY = "$CUSTOMERS/Aplly/";
17 | }
18 |
--------------------------------------------------------------------------------
/lib/app/data/remote/api/dio_Interceptor.dart:
--------------------------------------------------------------------------------
1 | import 'package:dio/dio.dart';
2 | import 'package:logger/logger.dart';
3 |
4 | import '../../../modules/auth/controllers/auth_controller.dart';
5 |
6 | class DioInterceptor extends Interceptor {
7 | final logger = Logger(printer: PrettyPrinter());
8 | final loggerNoStack = Logger(printer: PrettyPrinter(methodCount: 0));
9 |
10 | @override
11 | void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
12 | options.headers['Authorization'] =
13 | "Bearer ${AuthController.to.currentUser?.token}";
14 |
15 | logger.d("On new Request");
16 | logger.i("Headers: \n${options.headers.toString()}");
17 | super.onRequest(options, handler);
18 | }
19 |
20 | @override
21 | void onResponse(Response response, ResponseInterceptorHandler handler) {
22 | logger.d("On new Response.");
23 | loggerNoStack.i("Status Code: ${response.statusCode}");
24 | loggerNoStack.i("Status Msg: ${response.statusMessage}");
25 | loggerNoStack.i("Headers: \n${response.headers.toString()}");
26 | loggerNoStack.v(response.data.toString());
27 | super.onResponse(response, handler);
28 | }
29 |
30 | @override
31 | void onError(DioError err, ErrorInterceptorHandler handler) {
32 | logger.d("On Error.");
33 | loggerNoStack.e("Error Msg: ${err.message}");
34 | loggerNoStack.e("Error Type: ${err.type}");
35 | loggerNoStack.e("Error Response: ${err.response.toString()}");
36 | super.onError(err, handler);
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/lib/app/data/remote/base/idto.dart:
--------------------------------------------------------------------------------
1 | abstract class IDto {
2 | Map toJson();
3 |
4 | IDto.fromJson(dynamic json);
5 | }
6 |
--------------------------------------------------------------------------------
/lib/app/data/remote/base/status.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/foundation.dart';
2 | import 'package:freezed_annotation/freezed_annotation.dart';
3 |
4 | part 'status.freezed.dart';
5 |
6 | @freezed
7 | abstract class Status with _$State {
8 | const factory Status.idle() = Idle;
9 |
10 | const factory Status.loading() = Loading;
11 |
12 | const factory Status.success({@required T? data}) = Success;
13 |
14 | const factory Status.failure({@required String? reason}) = Failure;
15 | }
16 |
--------------------------------------------------------------------------------
/lib/app/data/remote/dto/application/application_in_dto.dart:
--------------------------------------------------------------------------------
1 | import '../../base/idto.dart';
2 |
3 | class ApplicationInDto implements IDto {
4 | ApplicationInDto({
5 | this.customerId,
6 | this.jobId,
7 | this.whyApply,
8 | });
9 |
10 | ApplicationInDto.fromJson(dynamic json) {
11 | customerId = json['customer_id'];
12 | jobId = json['job_id'];
13 | whyApply = json['why_apply'];
14 | }
15 |
16 | String? customerId;
17 | String? jobId;
18 | String? whyApply;
19 |
20 | ApplicationInDto copyWith({
21 | String? customerId,
22 | String? jobId,
23 | String? whyApply,
24 | }) =>
25 | ApplicationInDto(
26 | customerId: customerId ?? this.customerId,
27 | jobId: jobId ?? this.jobId,
28 | whyApply: whyApply ?? this.whyApply,
29 | );
30 |
31 | Map toJson() {
32 | final map = {};
33 | map['customer_id'] = customerId;
34 | map['job_id'] = jobId;
35 | map['why_apply'] = whyApply;
36 | return map;
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/lib/app/data/remote/dto/application/application_out_dto.dart:
--------------------------------------------------------------------------------
1 | import '../../base/idto.dart';
2 |
3 | class ApplicationOutDto implements IDto {
4 | ApplicationOutDto({
5 | this.id,
6 | this.customer,
7 | this.job,
8 | this.whyApply,
9 | });
10 |
11 | ApplicationOutDto.fromJson(dynamic json) {
12 | id = json['id'];
13 | customer =
14 | json['customer'] != null ? Customer.fromJson(json['customer']) : null;
15 | job = json['job'] != null ? Job.fromJson(json['job']) : null;
16 | whyApply = json['why_apply'];
17 | }
18 |
19 | String? id;
20 | Customer? customer;
21 | Job? job;
22 | String? whyApply;
23 |
24 | ApplicationOutDto copyWith({
25 | String? id,
26 | Customer? customer,
27 | Job? job,
28 | String? whyApply,
29 | }) =>
30 | ApplicationOutDto(
31 | id: id ?? this.id,
32 | customer: customer ?? this.customer,
33 | job: job ?? this.job,
34 | whyApply: whyApply ?? this.whyApply,
35 | );
36 |
37 | Map toJson() {
38 | final map = {};
39 | map['id'] = id;
40 | if (customer != null) {
41 | map['customer'] = customer?.toJson();
42 | }
43 | if (job != null) {
44 | map['job'] = job?.toJson();
45 | }
46 | map['why_apply'] = whyApply;
47 | return map;
48 | }
49 | }
50 |
51 | class Job {
52 | Job({
53 | this.id,
54 | });
55 |
56 | Job.fromJson(dynamic json) {
57 | id = json['id'];
58 | }
59 |
60 | String? id;
61 |
62 | Job copyWith({
63 | String? id,
64 | }) =>
65 | Job(
66 | id: id ?? this.id,
67 | );
68 |
69 | Map toJson() {
70 | final map = {};
71 | map['id'] = id;
72 | return map;
73 | }
74 | }
75 |
76 | class Customer {
77 | Customer({
78 | this.id,
79 | this.name,
80 | this.jobTitle,
81 | this.image,
82 | });
83 |
84 | Customer.fromJson(dynamic json) {
85 | id = json['id'];
86 | name = json['name'];
87 | jobTitle = json['job_title'];
88 | image = json['image'];
89 | }
90 |
91 | String? id;
92 | String? name;
93 | String? jobTitle;
94 | String? image;
95 |
96 | Customer copyWith({
97 | String? id,
98 | String? name,
99 | String? jobTitle,
100 | String? image,
101 | }) =>
102 | Customer(
103 | id: id ?? this.id,
104 | name: name ?? this.name,
105 | jobTitle: jobTitle ?? this.jobTitle,
106 | image: image ?? this.image,
107 | );
108 |
109 | Map toJson() {
110 | final map = {};
111 | map['id'] = id;
112 | map['name'] = name;
113 | map['job_title'] = jobTitle;
114 | map['image'] = image;
115 | return map;
116 | }
117 | }
118 |
--------------------------------------------------------------------------------
/lib/app/data/remote/dto/auth/login_in_dto.dart:
--------------------------------------------------------------------------------
1 | import '../../base/idto.dart';
2 |
3 | class LoginInDto implements IDto {
4 | LoginInDto({
5 | this.emailOrPhone,
6 | this.password,
7 | });
8 |
9 | String? emailOrPhone;
10 | String? password;
11 |
12 | LoginInDto.fromJson(dynamic json) {
13 | emailOrPhone = json['email_or_phone'];
14 | password = json['password'];
15 | }
16 |
17 | LoginInDto copyWith({
18 | String? email,
19 | String? password,
20 | }) =>
21 | LoginInDto(
22 | emailOrPhone: email ?? this.emailOrPhone,
23 | password: password ?? this.password,
24 | );
25 |
26 | Map toJson() {
27 | final map = {};
28 | map['email_or_phone'] = emailOrPhone;
29 | map['password'] = password;
30 | return map;
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/lib/app/data/remote/dto/auth/login_out_dto.dart:
--------------------------------------------------------------------------------
1 | import 'package:jobs_flutter_app/app/data/remote/base/idto.dart';
2 |
3 | class LoginOutDto implements IDto {
4 | LoginOutDto({
5 | this.token,
6 | this.id,
7 | this.name,
8 | this.email,
9 | this.role,
10 | this.status,
11 | });
12 |
13 | LoginOutDto.fromJson(dynamic json) {
14 | token = json['token'] != null ? Token.fromJson(json['token']) : null;
15 | id = json['id'];
16 | name = json['name'];
17 | email = json['email'];
18 | role = json['role'];
19 | status = json['status'];
20 | }
21 |
22 | Token? token;
23 | String? id;
24 | String? name;
25 | String? email;
26 | String? role;
27 | String? status;
28 |
29 | LoginOutDto copyWith({
30 | Token? token,
31 | String? id,
32 | String? name,
33 | String? email,
34 | String? status,
35 | }) =>
36 | LoginOutDto(
37 | token: token ?? this.token,
38 | id: id ?? this.id,
39 | name: name ?? this.name,
40 | email: email ?? this.email,
41 | status: status ?? this.status,
42 | );
43 |
44 | Map toJson() {
45 | final map = {};
46 | if (token != null) {
47 | map['token'] = token?.toJson();
48 | }
49 | map['id'] = id;
50 | map['name'] = name;
51 | map['email'] = email;
52 | map['role'] = role;
53 | map['status'] = status;
54 | return map;
55 | }
56 | }
57 |
58 | class Token {
59 | Token({
60 | this.access,
61 | });
62 |
63 | Token.fromJson(dynamic json) {
64 | access = json['access'];
65 | }
66 |
67 | String? access;
68 |
69 | Token copyWith({
70 | String? access,
71 | }) =>
72 | Token(
73 | access: access ?? this.access,
74 | );
75 |
76 | Map toJson() {
77 | final map = {};
78 | map['access'] = access;
79 | return map;
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/lib/app/data/remote/dto/auth/register_company_dto.dart:
--------------------------------------------------------------------------------
1 | import 'package:jobs_flutter_app/app/data/remote/base/idto.dart';
2 |
3 | class RegisterCompanyDto implements IDto {
4 | RegisterCompanyDto({
5 | this.name,
6 | this.phone,
7 | this.email,
8 | this.address,
9 | this.country,
10 | this.password,
11 | });
12 |
13 | RegisterCompanyDto.fromJson(dynamic json) {
14 | name = json['name'];
15 | phone = json['phone'];
16 | email = json['email'];
17 | address = json['address'];
18 | country = json['country'];
19 | password = json['password'];
20 | }
21 |
22 | String? name;
23 | String? phone;
24 | String? email;
25 | String? address;
26 | String? country;
27 | String? password;
28 |
29 | RegisterCompanyDto copyWith({
30 | String? name,
31 | String? phone,
32 | String? email,
33 | String? address,
34 | String? country,
35 | String? password,
36 | }) =>
37 | RegisterCompanyDto(
38 | name: name ?? this.name,
39 | phone: phone ?? this.phone,
40 | email: email ?? this.email,
41 | address: address ?? this.address,
42 | country: country ?? this.country,
43 | password: password ?? this.password,
44 | );
45 |
46 | Map toJson() {
47 | final map = {};
48 | map['name'] = name;
49 | map['phone'] = phone;
50 | map['email'] = email;
51 | map['address'] = address;
52 | map['country'] = country;
53 | map['password'] = password;
54 | return map;
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/lib/app/data/remote/dto/auth/register_company_out_dto.dart:
--------------------------------------------------------------------------------
1 | import 'package:jobs_flutter_app/app/data/remote/base/idto.dart';
2 |
3 | class RegisterCompanyOutDto implements IDto {
4 | RegisterCompanyOutDto({
5 | this.token,
6 | this.company,
7 | });
8 |
9 | RegisterCompanyOutDto.fromJson(dynamic json) {
10 | token = json['token'] != null ? Token.fromJson(json['token']) : null;
11 | company =
12 | json['company'] != null ? Company.fromJson(json['company']) : null;
13 | }
14 |
15 | Token? token;
16 | Company? company;
17 |
18 | RegisterCompanyOutDto copyWith({
19 | Token? token,
20 | Company? company,
21 | }) =>
22 | RegisterCompanyOutDto(
23 | token: token ?? this.token,
24 | company: company ?? this.company,
25 | );
26 |
27 | Map toJson() {
28 | final map = {};
29 | if (token != null) {
30 | map['token'] = token?.toJson();
31 | }
32 | if (company != null) {
33 | map['company'] = company?.toJson();
34 | }
35 | return map;
36 | }
37 | }
38 |
39 | class Company {
40 | Company({
41 | this.id,
42 | this.name,
43 | this.phone,
44 | this.email,
45 | });
46 |
47 | Company.fromJson(dynamic json) {
48 | id = json['id'];
49 | name = json['name'];
50 | phone = json['phone'];
51 | email = json['email'];
52 | }
53 |
54 | String? id;
55 | String? name;
56 | String? phone;
57 | String? email;
58 |
59 | Company copyWith({
60 | String? id,
61 | String? name,
62 | String? phone,
63 | String? email,
64 | }) =>
65 | Company(
66 | id: id ?? this.id,
67 | name: name ?? this.name,
68 | phone: phone ?? this.phone,
69 | email: email ?? this.email,
70 | );
71 |
72 | Map toJson() {
73 | final map = {};
74 | map['id'] = id;
75 | map['name'] = name;
76 | map['phone'] = phone;
77 | map['email'] = email;
78 | return map;
79 | }
80 | }
81 |
82 | class Token {
83 | Token({
84 | this.access,
85 | });
86 |
87 | Token.fromJson(dynamic json) {
88 | access = json['access'];
89 | }
90 |
91 | String? access;
92 |
93 | Token copyWith({
94 | String? access,
95 | }) =>
96 | Token(
97 | access: access ?? this.access,
98 | );
99 |
100 | Map toJson() {
101 | final map = {};
102 | map['access'] = access;
103 | return map;
104 | }
105 | }
106 |
--------------------------------------------------------------------------------
/lib/app/data/remote/dto/auth/register_customer_dto.dart:
--------------------------------------------------------------------------------
1 | import 'package:jobs_flutter_app/app/data/remote/base/idto.dart';
2 |
3 | class RegisterCustomerDto implements IDto {
4 | RegisterCustomerDto({
5 | this.name,
6 | this.email,
7 | this.phone,
8 | this.password,
9 | });
10 |
11 | RegisterCustomerDto.fromJson(dynamic json) {
12 | name = json['name'];
13 | email = json['email'];
14 | phone = json['phone'];
15 | password = json['password'];
16 | }
17 |
18 | String? name;
19 | String? email;
20 | String? phone;
21 | String? password;
22 |
23 | RegisterCustomerDto copyWith({
24 | String? name,
25 | String? email,
26 | String? phone,
27 | String? password,
28 | }) =>
29 | RegisterCustomerDto(
30 | name: name ?? this.name,
31 | email: email ?? this.email,
32 | phone: phone ?? this.phone,
33 | password: password ?? this.password,
34 | );
35 |
36 | @override
37 | Map toJson() {
38 | final map = {};
39 | map['name'] = name;
40 | map['email'] = email;
41 | map['phone'] = phone;
42 | map['password'] = password;
43 | return map;
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/lib/app/data/remote/dto/auth/register_customer_out_dto.dart:
--------------------------------------------------------------------------------
1 | import 'package:jobs_flutter_app/app/data/remote/base/idto.dart';
2 |
3 | class RegisterCustomerOutDto implements IDto {
4 | RegisterCustomerOutDto({
5 | this.token,
6 | this.customer,
7 | });
8 |
9 | RegisterCustomerOutDto.fromJson(dynamic json) {
10 | token = json['token'] != null ? Token.fromJson(json['token']) : null;
11 | customer =
12 | json['customer'] != null ? Customer.fromJson(json['customer']) : null;
13 | }
14 |
15 | Token? token;
16 | Customer? customer;
17 |
18 | RegisterCustomerOutDto copyWith({
19 | Token? token,
20 | Customer? customer,
21 | }) =>
22 | RegisterCustomerOutDto(
23 | token: token ?? this.token,
24 | customer: customer ?? this.customer,
25 | );
26 |
27 | Map toJson() {
28 | final map = {};
29 | if (token != null) {
30 | map['token'] = token?.toJson();
31 | }
32 | if (customer != null) {
33 | map['customer'] = customer?.toJson();
34 | }
35 | return map;
36 | }
37 | }
38 |
39 | class Customer {
40 | Customer({
41 | this.id,
42 | this.name,
43 | this.email,
44 | this.phone,
45 | });
46 |
47 | Customer.fromJson(dynamic json) {
48 | id = json['id'];
49 | name = json['name'];
50 | email = json['email'];
51 | phone = json['phone'];
52 | }
53 |
54 | String? id;
55 | String? name;
56 | String? email;
57 | String? phone;
58 |
59 | Customer copyWith({
60 | String? id,
61 | String? name,
62 | String? email,
63 | String? phone,
64 | }) =>
65 | Customer(
66 | id: id ?? this.id,
67 | name: name ?? this.name,
68 | email: email ?? this.email,
69 | phone: phone ?? this.phone,
70 | );
71 |
72 | Map toJson() {
73 | final map = {};
74 | map['id'] = id;
75 | map['name'] = name;
76 | map['email'] = email;
77 | map['phone'] = phone;
78 | return map;
79 | }
80 | }
81 |
82 | class Token {
83 | Token({
84 | this.access,
85 | });
86 |
87 | Token.fromJson(dynamic json) {
88 | access = json['access'];
89 | }
90 |
91 | String? access;
92 |
93 | Token copyWith({
94 | String? access,
95 | }) =>
96 | Token(
97 | access: access ?? this.access,
98 | );
99 |
100 | Map toJson() {
101 | final map = {};
102 | map['access'] = access;
103 | return map;
104 | }
105 | }
106 |
--------------------------------------------------------------------------------
/lib/app/data/remote/dto/choices/position_out_dto.dart:
--------------------------------------------------------------------------------
1 | class PositionOutDto {
2 | PositionOutDto({
3 | this.jobTitle,
4 | });
5 |
6 | PositionOutDto.fromJson(dynamic json) {
7 | jobTitle = json['job_title'];
8 | }
9 |
10 | String? jobTitle;
11 |
12 | PositionOutDto copyWith({
13 | String? jobTitle,
14 | }) =>
15 | PositionOutDto(
16 | jobTitle: jobTitle ?? this.jobTitle,
17 | );
18 |
19 | Map toJson() {
20 | final map = {};
21 | map['job_title'] = jobTitle;
22 | return map;
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/lib/app/data/remote/dto/company/company_out_dto.dart:
--------------------------------------------------------------------------------
1 | import 'package:jobs_flutter_app/app/data/remote/base/idto.dart';
2 |
3 | class CompanyOutDto implements IDto {
4 | CompanyOutDto({
5 | this.id,
6 | this.name,
7 | this.email,
8 | this.phone,
9 | this.description,
10 | this.workType,
11 | this.city,
12 | this.address,
13 | this.image,
14 | });
15 |
16 | CompanyOutDto.fromJson(dynamic json) {
17 | id = json['id'];
18 | name = json['name'];
19 | email = json['email'];
20 | phone = json['phone'];
21 | description = json['description'];
22 | workType = json['work_type'];
23 | city = json['city'];
24 | address = json['address'];
25 | image = json['image'];
26 | }
27 |
28 | String? id;
29 | String? name;
30 | String? email;
31 | String? phone;
32 | String? description;
33 | String? workType;
34 | String? city;
35 | String? address;
36 | String? image;
37 |
38 | CompanyOutDto copyWith({
39 | String? id,
40 | String? name,
41 | String? email,
42 | String? phone,
43 | String? description,
44 | String? workType,
45 | String? city,
46 | String? address,
47 | String? image,
48 | }) =>
49 | CompanyOutDto(
50 | id: id ?? this.id,
51 | name: name ?? this.name,
52 | email: email ?? this.email,
53 | phone: phone ?? this.phone,
54 | description: description ?? this.description,
55 | workType: workType ?? this.workType,
56 | city: city ?? this.city,
57 | address: address ?? this.address,
58 | image: image ?? this.image,
59 | );
60 |
61 | Map toJson() {
62 | final map = {};
63 | map['id'] = id;
64 | map['name'] = name;
65 | map['email'] = email;
66 | map['phone'] = phone;
67 | map['description'] = description;
68 | map['work_type'] = workType;
69 | map['city'] = city;
70 | map['address'] = address;
71 | map['image'] = image;
72 | return map;
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/lib/app/data/remote/dto/company/company_search_out_dto.dart:
--------------------------------------------------------------------------------
1 | class CompanySearchOutDto {
2 | CompanySearchOutDto({
3 | this.id,
4 | this.name,
5 | this.image,
6 | this.workType,
7 | });
8 |
9 | CompanySearchOutDto.fromJson(dynamic json) {
10 | id = json['id'];
11 | name = json['name'];
12 | image = json['image'];
13 | workType = json['work_type'];
14 | }
15 |
16 | String? id;
17 | String? name;
18 | String? image;
19 | String? workType;
20 |
21 | CompanySearchOutDto copyWith({
22 | String? id,
23 | String? name,
24 | String? image,
25 | String? workType,
26 | }) =>
27 | CompanySearchOutDto(
28 | id: id ?? this.id,
29 | name: name ?? this.name,
30 | image: image ?? this.image,
31 | workType: workType ?? this.workType,
32 | );
33 |
34 | Map toJson() {
35 | final map = {};
36 | map['id'] = id;
37 | map['name'] = name;
38 | map['image'] = image;
39 | map['work_type'] = workType;
40 | return map;
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/lib/app/data/remote/dto/customer/single_customer_out_dto.dart:
--------------------------------------------------------------------------------
1 | import 'package:jobs_flutter_app/app/data/remote/base/idto.dart';
2 |
3 | class SingleCustomerOutDto implements IDto {
4 | SingleCustomerOutDto({
5 | this.id,
6 | this.name,
7 | this.email,
8 | this.phone,
9 | });
10 |
11 | SingleCustomerOutDto.fromJson(dynamic json) {
12 | id = json['id'];
13 | name = json['name'];
14 | email = json['email'];
15 | phone = json['phone'];
16 | }
17 |
18 | String? id;
19 | String? name;
20 | String? email;
21 | String? phone;
22 |
23 | SingleCustomerOutDto copyWith({
24 | String? id,
25 | String? name,
26 | String? email,
27 | String? phone,
28 | }) =>
29 | SingleCustomerOutDto(
30 | id: id ?? this.id,
31 | name: name ?? this.name,
32 | email: email ?? this.email,
33 | phone: phone ?? this.phone,
34 | );
35 |
36 | Map toJson() {
37 | final map = {};
38 | map['id'] = id;
39 | map['name'] = name;
40 | map['email'] = email;
41 | map['phone'] = phone;
42 | return map;
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/lib/app/data/remote/dto/customer/toggle_save_out_dto.dart:
--------------------------------------------------------------------------------
1 | import '../../base/idto.dart';
2 |
3 | class ToggleSaveOutDto implements IDto {
4 | ToggleSaveOutDto({
5 | this.message,
6 | this.saved,
7 | });
8 |
9 | ToggleSaveOutDto.fromJson(dynamic json) {
10 | message = json['message'];
11 | saved = json['saved'];
12 | }
13 |
14 | String? message;
15 | bool? saved;
16 |
17 | ToggleSaveOutDto copyWith({
18 | String? message,
19 | bool? saved,
20 | }) =>
21 | ToggleSaveOutDto(
22 | message: message ?? this.message,
23 | saved: saved ?? this.saved,
24 | );
25 |
26 | Map toJson() {
27 | final map = {};
28 | map['message'] = message;
29 | map['saved'] = saved;
30 | return map;
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/lib/app/data/remote/dto/job/job_in_dto.dart:
--------------------------------------------------------------------------------
1 | import '../../base/idto.dart';
2 |
3 | class JobInDto implements IDto {
4 | JobInDto({
5 | this.companyId,
6 | this.position,
7 | this.employmentType,
8 | this.description,
9 | this.location,
10 | this.workplace,
11 | });
12 |
13 | JobInDto.fromJson(dynamic json) {
14 | companyId = json['company_id'];
15 | position = json['position'];
16 | employmentType = json['employment_type'];
17 | description = json['description'];
18 | location = json['location'];
19 | workplace = json['workplace'];
20 | }
21 |
22 | String? companyId;
23 | String? position;
24 | String? employmentType;
25 | String? description;
26 | String? location;
27 | String? workplace;
28 |
29 | JobInDto copyWith({
30 | String? companyId,
31 | String? position,
32 | String? employmentType,
33 | String? description,
34 | String? location,
35 | String? workplace,
36 | }) =>
37 | JobInDto(
38 | companyId: companyId ?? this.companyId,
39 | position: position ?? this.position,
40 | employmentType: employmentType ?? this.employmentType,
41 | description: description ?? this.description,
42 | location: location ?? this.location,
43 | workplace: workplace ?? this.workplace,
44 | );
45 |
46 | Map toJson() {
47 | final map = {};
48 | map['company_id'] = companyId;
49 | map['position'] = position;
50 | map['employment_type'] = employmentType;
51 | map['description'] = description;
52 | map['location'] = location;
53 | map['workplace'] = workplace;
54 | return map;
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/lib/app/data/remote/dto/search/search_out_dto.dart:
--------------------------------------------------------------------------------
1 | class SearchOutDto {
2 | SearchOutDto({
3 | this.id,
4 | this.name,
5 | this.image,
6 | });
7 |
8 | SearchOutDto.fromJson(dynamic json) {
9 | id = json['id'];
10 | name = json['name'];
11 | image = json['image'];
12 | }
13 |
14 | String? id;
15 | String? name;
16 | String? image;
17 |
18 | SearchOutDto copyWith({
19 | String? id,
20 | String? name,
21 | String? image,
22 | }) =>
23 | SearchOutDto(
24 | id: id ?? this.id,
25 | name: name ?? this.name,
26 | image: image ?? this.image,
27 | );
28 |
29 | Map toJson() {
30 | final map = {};
31 | map['id'] = id;
32 | map['name'] = name;
33 | map['image'] = image;
34 | return map;
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/lib/app/data/remote/exceptions/dio_exceptions.dart:
--------------------------------------------------------------------------------
1 | import 'package:dio/dio.dart';
2 |
3 | class DioExceptions implements Exception {
4 | late String message;
5 |
6 | static const Map _errorCodes = {
7 | '400': 'Bad Request',
8 | '401': 'Unauthorized',
9 | '403': 'Forbidden',
10 | '404': 'Not Found',
11 | '408': 'Request Timeout',
12 | '500': 'Internal Server Error',
13 | '502': 'Bad Gateway',
14 | '503': 'Service Unavailable',
15 | '504': 'Gateway Timeout',
16 | '505': 'HTTP Version Not Supported',
17 | '511': 'Network Authentication Required',
18 | '520': 'Unknown Error',
19 | '521': 'Web Server Is Down',
20 | '522': 'Connection Timed Out',
21 | '523': 'Origin Is Unreachable',
22 | '524': 'A Timeout Occurred',
23 | '525': 'SSL Handshake Failed',
24 | '526': 'Invalid SSL Certificate',
25 | '530': 'Origin DNS Error',
26 | '598': 'Network Read Timeout Error',
27 | '599': 'Network Connect Timeout Error',
28 | };
29 |
30 | static const Map _errorTypes = {
31 | 'cancel': 'Request to API server was cancelled',
32 | 'connectTimeout': 'Connection timeout with API server',
33 | 'default': 'Connection to API server failed due to internet connection',
34 | 'receiveTimeout': 'Receive timeout in connection with API server',
35 | 'sendTimeout': 'Send timeout in connection with API server',
36 | 'other': 'Connection to API server failed due to internet connection',
37 | };
38 |
39 | DioExceptions.fromDioError(DioError dioError) {
40 | message = _getErrorMessage(dioError);
41 | }
42 |
43 | String _getErrorMessage(DioError error) {
44 | String errorType = error.type.toString().split('.').last;
45 | String errorMessage = _errorTypes[errorType] ??
46 | error.response?.data['error'] ??
47 | _errorCodes[error.response?.statusCode.toString()] ??
48 | 'Something went wrong';
49 | return errorMessage;
50 | }
51 |
52 | @override
53 | String toString() => message;
54 | }
55 |
--------------------------------------------------------------------------------
/lib/app/data/remote/repositories/application/application_repository.dart:
--------------------------------------------------------------------------------
1 | import 'package:dio/dio.dart';
2 |
3 | import '../../base/idto.dart';
4 | import '../../base/status.dart';
5 | import '../../dto/application/application_out_dto.dart';
6 | import '../../exceptions/dio_exceptions.dart';
7 | import '../../services/application/i_application_service.dart';
8 | import 'i_application_repository.dart';
9 |
10 | class ApplicationRepository implements IApplicationRepository {
11 | final IApplicationService service;
12 |
13 | ApplicationRepository({required this.service});
14 |
15 | @override
16 | Future> create({required IDto dto}) async {
17 | try {
18 | await service.create(dto: dto);
19 | return const Status.success(data: true);
20 | } on DioError catch (e) {
21 | final errMsg = DioExceptions.fromDioError(e).toString();
22 | return Status.failure(reason: errMsg);
23 | }
24 | }
25 |
26 | @override
27 | Future> delete({required String applicationId}) async {
28 | try {
29 | await service.delete(applicationId: applicationId);
30 | return const Status.success(data: true);
31 | } on DioError catch (e) {
32 | final errMsg = DioExceptions.fromDioError(e).toString();
33 | return Status.failure(reason: errMsg);
34 | }
35 | }
36 |
37 | @override
38 | Future> get({required String applicationId}) async {
39 | try {
40 | final response = await service.get(applicationId: applicationId);
41 | return Status.success(data: ApplicationOutDto.fromJson(response.data));
42 | } on DioError catch (e) {
43 | final errMsg = DioExceptions.fromDioError(e).toString();
44 | return Status.failure(reason: errMsg);
45 | }
46 | }
47 |
48 | @override
49 | Future>> getAll({
50 | int? limit,
51 | int? offset,
52 | }) async {
53 | try {
54 | final response = await service.getAll(limit: limit, offset: offset);
55 | final applications = (response.data['items'] as List)
56 | .map((e) => ApplicationOutDto.fromJson(e))
57 | .toList();
58 | return Status.success(data: applications);
59 | } on DioError catch (e) {
60 | final errMsg = DioExceptions.fromDioError(e).toString();
61 | return Status.failure(reason: errMsg);
62 | }
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/lib/app/data/remote/repositories/application/i_application_repository.dart:
--------------------------------------------------------------------------------
1 | import '../../base/idto.dart';
2 | import '../../base/status.dart';
3 | import '../../dto/application/application_out_dto.dart';
4 |
5 | abstract class IApplicationRepository {
6 | Future> create({required IDto dto});
7 |
8 | Future>> getAll({int? limit, int? offset});
9 |
10 | Future> get({required String applicationId});
11 |
12 | Future> delete({required String applicationId});
13 | }
14 |
--------------------------------------------------------------------------------
/lib/app/data/remote/repositories/auth/i_auth_repository.dart:
--------------------------------------------------------------------------------
1 | import 'package:jobs_flutter_app/app/data/remote/base/idto.dart';
2 |
3 | import '../../../local/base/i_entity.dart';
4 |
5 | abstract class IAuthRepository {
6 | Future login({required IDto dto});
7 |
8 | Future registerCompany({required IDto dto});
9 |
10 | Future registerCustomer({required IDto dto});
11 |
12 | Future readStorage({required String key});
13 |
14 | Future writeStorage({required String key, required IEntity entity});
15 |
16 | Future removeStorage({required String key});
17 | }
18 |
--------------------------------------------------------------------------------
/lib/app/data/remote/repositories/company/company_repository.dart:
--------------------------------------------------------------------------------
1 | import 'package:dio/dio.dart';
2 |
3 | import '../../base/status.dart';
4 | import '../../dto/company/Company_out_dto.dart';
5 | import '../../exceptions/dio_exceptions.dart';
6 | import '../../services/company/i_company_service.dart';
7 | import 'i_company_repository.dart';
8 |
9 | class CompanyRepository implements ICompanyRepository {
10 | final ICompanyService service;
11 |
12 | CompanyRepository({required this.service});
13 |
14 | @override
15 | Future> get({required String uuid}) async {
16 | try {
17 | final response = await service.get(uuid: uuid);
18 | if (response.statusCode == 200) {
19 | final CompanyOutDto job = CompanyOutDto.fromJson(response.data);
20 | return Status.success(data: job);
21 | }
22 | return const Status.failure(reason: "Something went wrong!");
23 | } on DioError catch (e) {
24 | final errMsg = DioExceptions.fromDioError(e).toString();
25 | return Status.failure(reason: errMsg);
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/lib/app/data/remote/repositories/company/i_company_repository.dart:
--------------------------------------------------------------------------------
1 | import '../../base/status.dart';
2 |
3 | abstract class ICompanyRepository {
4 | Future> get({required String uuid});
5 | }
6 |
--------------------------------------------------------------------------------
/lib/app/data/remote/repositories/customer/i_customer_repository.dart:
--------------------------------------------------------------------------------
1 | import 'package:jobs_flutter_app/app/data/remote/base/idto.dart';
2 | import 'package:jobs_flutter_app/app/data/remote/base/status.dart';
3 |
4 | abstract class ICustomerRepository {
5 | Future> toggleSave({
6 | required String customerUuid,
7 | required String jobUuid,
8 | });
9 |
10 | Future>> getAllSavedJobs({
11 | int? limit,
12 | int? offset,
13 | required String customerUuid,
14 | });
15 |
16 | Future> getProfile({required String customerUuid});
17 |
18 | Future> getAvatar({required String customerUuid});
19 | }
20 |
--------------------------------------------------------------------------------
/lib/app/data/remote/repositories/job/i_job_repository.dart:
--------------------------------------------------------------------------------
1 | import '../../base/idto.dart';
2 | import '../../base/status.dart';
3 |
4 | abstract class IJobRepository {
5 | Future create({required IDto dto});
6 |
7 | Future delete({required String uuid});
8 |
9 | Future> get({required String uuid});
10 |
11 | Future>?> getAll({
12 | int? limit,
13 | int? offset,
14 | bool? isFeatured,
15 | String? position,
16 | String? companyId,
17 | });
18 |
19 | Future update({required String uuid, required IDto dto});
20 | }
21 |
--------------------------------------------------------------------------------
/lib/app/data/remote/repositories/position/i_choice_repository.dart:
--------------------------------------------------------------------------------
1 | import '../../base/status.dart';
2 |
3 | abstract class IChoiceRepository {
4 | Future>> getAll({int? limit, int? offset});
5 | }
6 |
--------------------------------------------------------------------------------
/lib/app/data/remote/repositories/position/position_repository.dart:
--------------------------------------------------------------------------------
1 | import 'package:dio/dio.dart';
2 |
3 | import '../../base/status.dart';
4 | import '../../dto/choices/Position_out_dto.dart';
5 | import '../../exceptions/dio_exceptions.dart';
6 | import '../../services/position/i_choice_service.dart';
7 | import 'i_choice_repository.dart';
8 |
9 | class PositionRepository extends IChoiceRepository {
10 | final IChoiceService service;
11 |
12 | PositionRepository({required this.service});
13 |
14 | @override
15 | Future>> getAll({int? limit, int? offset}) async {
16 | try {
17 | final response = await service.getAll(limit: limit, offset: offset);
18 | final positions = (response.data as List)
19 | .map((e) => PositionOutDto.fromJson(e))
20 | .toList();
21 | if (response.statusCode == 200) return Status.success(data: positions);
22 | return const Status.failure(reason: "Some thing wrong happen!");
23 | } on DioError catch (e) {
24 | final errMsg = DioExceptions.fromDioError(e).toString();
25 | return Status.failure(reason: errMsg);
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/lib/app/data/remote/repositories/search/i_search_repository.dart:
--------------------------------------------------------------------------------
1 | import '../../base/status.dart';
2 |
3 | abstract class ISearchRepository {
4 | Future>?> getAll({
5 | int? limit,
6 | int? offset,
7 | String? q,
8 | });
9 | }
10 |
--------------------------------------------------------------------------------
/lib/app/data/remote/repositories/search/search_repository.dart:
--------------------------------------------------------------------------------
1 | import 'package:dio/dio.dart';
2 |
3 | import '../../base/status.dart';
4 | import '../../dto/search/search_out_dto.dart';
5 | import '../../exceptions/dio_exceptions.dart';
6 | import '../../services/search/i_search_service.dart';
7 | import 'i_search_repository.dart';
8 |
9 | class SearchRepository extends ISearchRepository {
10 | final ISearchService service;
11 |
12 | SearchRepository({required this.service});
13 |
14 | @override
15 | Future>> getAll(
16 | {int? limit, int? offset, String? q}) async {
17 | try {
18 | final response = await service.getAll(limit: limit, offset: offset, q: q);
19 | final results =
20 | (response.data as List).map((e) => SearchOutDto.fromJson(e)).toList();
21 | if (response.statusCode == 200) return Status.success(data: results);
22 | return const Status.failure(reason: "Some thing wrong happen!");
23 | } on DioError catch (e) {
24 | final errMsg = DioExceptions.fromDioError(e).toString();
25 | return Status.failure(reason: errMsg);
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/lib/app/data/remote/services/application/application_service.dart:
--------------------------------------------------------------------------------
1 | import 'package:dio/src/response.dart';
2 |
3 | import '../../api/api_routes.dart';
4 | import '../../api/dio_client.dart';
5 | import '../../base/idto.dart';
6 | import 'i_application_service.dart';
7 |
8 | class ApplicationService implements IApplicationService {
9 | final DioClient dioClient;
10 |
11 | ApplicationService({required this.dioClient});
12 |
13 | @override
14 | Future delete({required String applicationId}) async {
15 | try {
16 | return await dioClient.delete("${ApiRoutes.APPLICATIONS}$applicationId");
17 | } catch (e) {
18 | rethrow;
19 | }
20 | }
21 |
22 | @override
23 | Future get({required String applicationId}) async {
24 | try {
25 | return await dioClient.get("${ApiRoutes.APPLICATIONS}$applicationId");
26 | } catch (e) {
27 | rethrow;
28 | }
29 | }
30 |
31 | @override
32 | Future getAll({int? limit, int? offset}) async {
33 | try {
34 | return await dioClient.get(ApiRoutes.APPLICATIONS, queryParameters: {
35 | "limit": limit ?? 20,
36 | "offset": offset ?? 0,
37 | });
38 | } catch (e) {
39 | rethrow;
40 | }
41 | }
42 |
43 | @override
44 | Future create({required IDto dto}) async {
45 | try {
46 | return await dioClient.post(
47 | ApiRoutes.JOB_APPLY,
48 | data: dto.toJson(),
49 | );
50 | } catch (e) {
51 | rethrow;
52 | }
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/lib/app/data/remote/services/application/i_application_service.dart:
--------------------------------------------------------------------------------
1 | import 'package:dio/dio.dart';
2 |
3 | import '../../base/idto.dart';
4 |
5 | abstract class IApplicationService {
6 | Future create({required IDto dto});
7 |
8 | Future getAll({int? limit, int? offset});
9 |
10 | Future get({required String applicationId});
11 |
12 | Future delete({required String applicationId});
13 | }
14 |
--------------------------------------------------------------------------------
/lib/app/data/remote/services/auth/auth_service.dart:
--------------------------------------------------------------------------------
1 | import 'package:dio/src/response.dart';
2 |
3 | import '../../api/api_routes.dart';
4 | import '../../api/dio_client.dart';
5 | import 'i_auth_service.dart';
6 | import '../../base/idto.dart';
7 |
8 | class AuthService implements IAuthService {
9 | final DioClient dioClient;
10 |
11 | AuthService({required this.dioClient});
12 |
13 | @override
14 | Future login({required IDto dto}) async {
15 | try {
16 | return await dioClient.post(ApiRoutes.LOGIN, data: dto.toJson());
17 | } catch (e) {
18 | rethrow;
19 | }
20 | }
21 |
22 | @override
23 | Future registerCompany({required IDto dto}) async {
24 | try {
25 | return await dioClient.post(ApiRoutes.COMPANY_REGISTER,
26 | data: dto.toJson());
27 | } catch (e) {
28 | rethrow;
29 | }
30 | }
31 |
32 | @override
33 | Future registerCustomer({required IDto dto}) async {
34 | try {
35 | return await dioClient.post(ApiRoutes.CUSTOMER_REGISTER,
36 | data: dto.toJson());
37 | } catch (e) {
38 | rethrow;
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/lib/app/data/remote/services/auth/i_auth_service.dart:
--------------------------------------------------------------------------------
1 | import 'package:dio/src/response.dart';
2 |
3 | abstract class IAuthService {
4 | Future registerCompany({required T dto});
5 |
6 | Future registerCustomer({required T dto});
7 |
8 | Future login({required T dto});
9 | }
10 |
--------------------------------------------------------------------------------
/lib/app/data/remote/services/company/comapny_service.dart:
--------------------------------------------------------------------------------
1 | import 'package:dio/src/response.dart';
2 |
3 | import '../../api/api_routes.dart';
4 | import '../../api/dio_client.dart';
5 | import 'i_company_service.dart';
6 |
7 | class CompanyService implements ICompanyService {
8 | final DioClient dioClient;
9 |
10 | CompanyService({required this.dioClient});
11 |
12 | @override
13 | Future get({required String uuid}) async {
14 | try {
15 | return await dioClient.get('${ApiRoutes.COMPANIES}/$uuid');
16 | } catch (e) {
17 | rethrow;
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/lib/app/data/remote/services/company/i_company_service.dart:
--------------------------------------------------------------------------------
1 | import 'package:dio/dio.dart';
2 |
3 | abstract class ICompanyService {
4 | Future get({required String uuid});
5 | }
6 |
--------------------------------------------------------------------------------
/lib/app/data/remote/services/customer/customer_service.dart:
--------------------------------------------------------------------------------
1 | import 'package:dio/src/response.dart';
2 |
3 | import '../../api/api_routes.dart';
4 | import '../../api/dio_client.dart';
5 | import 'i_customer_service.dart';
6 |
7 | class CustomerService implements ICustomerService {
8 | final DioClient dioClient;
9 |
10 | CustomerService({required this.dioClient});
11 |
12 | @override
13 | Future getAllSavedJobs({
14 | int? limit,
15 | int? offset,
16 | required String customerUuid,
17 | }) async {
18 | try {
19 | return await dioClient.get(ApiRoutes.SAVED_JOBS, queryParameters: {
20 | "limit": limit ?? 20,
21 | "offset": offset ?? 0,
22 | "customer_id": customerUuid,
23 | });
24 | } catch (e) {
25 | rethrow;
26 | }
27 | }
28 |
29 | @override
30 | Future toggleSave({
31 | required String customerUuid,
32 | required String jobUuid,
33 | }) async {
34 | try {
35 | return await dioClient.post(
36 | ApiRoutes.TOGGLE_SAVE,
37 | queryParameters: {
38 | 'customer_id': customerUuid,
39 | 'job_id': jobUuid,
40 | },
41 | );
42 | } catch (e) {
43 | rethrow;
44 | }
45 | }
46 |
47 | @override
48 | Future getProfile({required String customerUuid}) async {
49 | try {
50 | return await dioClient.get("${ApiRoutes.CUSTOMERS}/$customerUuid");
51 | } catch (e) {
52 | rethrow;
53 | }
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/lib/app/data/remote/services/customer/i_customer_service.dart:
--------------------------------------------------------------------------------
1 | import 'package:dio/src/response.dart';
2 |
3 | abstract class ICustomerService {
4 | Future toggleSave({
5 | required String customerUuid,
6 | required String jobUuid,
7 | });
8 |
9 | Future getAllSavedJobs({
10 | int? limit,
11 | int? offset,
12 | required String customerUuid,
13 | });
14 |
15 | Future getProfile({
16 | required String customerUuid,
17 | });
18 |
19 | }
20 |
--------------------------------------------------------------------------------
/lib/app/data/remote/services/job/i_job_service.dart:
--------------------------------------------------------------------------------
1 | import 'package:dio/src/response.dart';
2 |
3 | import '../../base/idto.dart';
4 |
5 | abstract class IJobService {
6 | Future create({required IDto dto});
7 |
8 | Future delete({required String uuid});
9 |
10 | Future get({required String uuid});
11 |
12 | Future getAll({
13 | int? limit,
14 | int? offset,
15 | bool? isFeatured,
16 | String? position,
17 | String? companyId,
18 | });
19 |
20 | Future update({required String uuid, required IDto dto});
21 | }
22 |
--------------------------------------------------------------------------------
/lib/app/data/remote/services/job/job_service.dart:
--------------------------------------------------------------------------------
1 | import 'package:dio/dio.dart';
2 |
3 | import '../../api/api_routes.dart';
4 | import '../../api/dio_client.dart';
5 | import '../../base/idto.dart';
6 | import 'i_job_service.dart';
7 |
8 | class JobService implements IJobService {
9 | final DioClient dioClient;
10 |
11 | JobService({required this.dioClient});
12 |
13 | @override
14 | Future get({required String uuid}) async {
15 | try {
16 | return await dioClient.get('${ApiRoutes.JOBS}/$uuid');
17 | } catch (e) {
18 | rethrow;
19 | }
20 | }
21 |
22 | @override
23 | Future getAll({
24 | int? limit,
25 | int? offset,
26 | bool? isFeatured,
27 | String? position,
28 | String? companyId,
29 | }) async {
30 | try {
31 | return await dioClient.get(ApiRoutes.JOBS, queryParameters: {
32 | "limit": limit ?? 20,
33 | "offset": offset ?? 0,
34 | if (isFeatured != null) "is_featured": isFeatured,
35 | if (position != null) "position": position,
36 | if (companyId != null) "company_id": companyId,
37 | });
38 | } catch (e) {
39 | rethrow;
40 | }
41 | }
42 |
43 | @override
44 | Future delete({required String uuid}) async {
45 | try {
46 | return await dioClient.delete('${ApiRoutes.JOBS}/$uuid');
47 | } catch (e) {
48 | rethrow;
49 | }
50 | }
51 |
52 | @override
53 | Future update({required String uuid, required IDto dto}) async {
54 | try {
55 | return await dioClient.put(
56 | '${ApiRoutes.JOBS}/$uuid',
57 | data: dto.toJson(),
58 | );
59 | } catch (e) {
60 | rethrow;
61 | }
62 | }
63 |
64 | @override
65 | Future create({required IDto dto}) async {
66 | try {
67 | return await dioClient.post(ApiRoutes.JOBS, data: dto.toJson());
68 | } catch (e) {
69 | rethrow;
70 | }
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/lib/app/data/remote/services/position/i_choice_service.dart:
--------------------------------------------------------------------------------
1 | import 'package:dio/dio.dart';
2 |
3 | abstract class IChoiceService {
4 | Future getAll({int? limit, int? offset, String? q});
5 | }
6 |
--------------------------------------------------------------------------------
/lib/app/data/remote/services/position/position_choice_service.dart:
--------------------------------------------------------------------------------
1 | import 'package:dio/src/response.dart';
2 |
3 | import '../../api/api_routes.dart';
4 | import '../../api/dio_client.dart';
5 | import 'i_choice_service.dart';
6 |
7 | class PositionChoiceService extends IChoiceService {
8 | final DioClient dioClient;
9 |
10 | PositionChoiceService({required this.dioClient});
11 |
12 | @override
13 | Future getAll({int? limit, int? offset, String? q}) async {
14 | try {
15 | return await dioClient.get(ApiRoutes.POSITIONS);
16 | } catch (e) {
17 | rethrow;
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/lib/app/data/remote/services/search/i_search_service.dart:
--------------------------------------------------------------------------------
1 | import 'package:dio/dio.dart';
2 |
3 | abstract class ISearchService {
4 | Future getAll({int? limit, int? offset, String? q});
5 | }
6 |
--------------------------------------------------------------------------------
/lib/app/data/remote/services/search/search_service.dart:
--------------------------------------------------------------------------------
1 | import 'package:dio/src/response.dart';
2 |
3 | import '../../api/api_routes.dart';
4 | import '../../api/dio_client.dart';
5 | import 'i_search_service.dart';
6 |
7 | class SearchService extends ISearchService {
8 | final DioClient dioClient;
9 |
10 | SearchService({required this.dioClient});
11 |
12 | @override
13 | Future getAll({int? limit, int? offset, String? q}) async {
14 | try {
15 | return await dioClient.get(
16 | ApiRoutes.SEARCH,
17 | queryParameters: {
18 | "company_name": q,
19 | },
20 | );
21 | } catch (e) {
22 | rethrow;
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/lib/app/domain/enums/user_type.dart:
--------------------------------------------------------------------------------
1 | enum RegisterType {
2 | COMPANY,
3 | CUSTOMER,
4 | NOTSELECTED,
5 | }
6 |
--------------------------------------------------------------------------------
/lib/app/icons.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/widgets.dart';
2 |
3 | class MyFlutterApp {
4 | MyFlutterApp._();
5 |
6 | static const _kFontFam = 'MyFlutterApp';
7 | static const String? _kFontPkg = null;
8 |
9 | static const IconData briefcase = IconData(0xe807, fontFamily: _kFontFam, fontPackage: _kFontPkg);
10 | }
11 |
--------------------------------------------------------------------------------
/lib/app/modules/JobDetails/bindings/job_details_binding.dart:
--------------------------------------------------------------------------------
1 | import 'package:get/get.dart';
2 |
3 | import '../controllers/job_details_controller.dart';
4 |
5 | class JobDetailsBinding extends Bindings {
6 | @override
7 | void dependencies() {
8 | Get.lazyPut(
9 | () => JobDetailsController(),
10 | );
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/lib/app/modules/JobDetails/views/job_details_view.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter/services.dart';
3 | import 'package:get/get.dart';
4 |
5 | import '../controllers/job_details_controller.dart';
6 | import 'widgets/body.dart';
7 | import 'widgets/details_bottom_nav_bar.dart';
8 |
9 | class JobDetailsView extends GetView {
10 | const JobDetailsView({Key? key}) : super(key: key);
11 |
12 | @override
13 | Widget build(BuildContext context) {
14 | return Scaffold(
15 | resizeToAvoidBottomInset: false,
16 | body: AnnotatedRegion(
17 | value: SystemUiOverlayStyle(
18 | statusBarColor: Get.theme.primaryColor,
19 | statusBarIconBrightness: Brightness.light,
20 | systemNavigationBarColor: Colors.white,
21 | systemNavigationBarIconBrightness: Brightness.dark,
22 | ),
23 | child: const SafeArea(
24 | child: Body(),
25 | ),
26 | ),
27 | bottomNavigationBar: const DetailsBottomNavBar(),
28 | );
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/lib/app/modules/JobDetails/views/widgets/apply_bottom_sheet.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_screenutil/flutter_screenutil.dart';
3 | import 'package:get/get.dart';
4 | import 'package:google_fonts/google_fonts.dart';
5 | import 'package:heroicons/heroicons.dart';
6 |
7 | import '../../../../widgets/custom_button.dart';
8 | import '../../../../widgets/custom_text_field.dart';
9 | import '../../controllers/job_details_controller.dart';
10 |
11 | class ApplyBottomSheetBody extends GetView {
12 | const ApplyBottomSheetBody(this.jobId, {Key? key}) : super(key: key);
13 | final String jobId;
14 |
15 | @override
16 | Widget build(BuildContext context) {
17 | return Column(
18 | children: [
19 | Text(
20 | "Why Are You Applying for This Position?",
21 | style: GoogleFonts.poppins(
22 | fontSize: 20.sp,
23 | fontWeight: FontWeight.w700,
24 | color: Get.theme.colorScheme.onBackground,
25 | ),
26 | ),
27 | const CustomTextField(
28 | minLines: 3,
29 | maxLines: 5,
30 | hintText: "Describe what you're looking for in this job...",
31 | ),
32 | SizedBox(height: 15.h),
33 | Row(
34 | children: [
35 | HeroIcon(
36 | HeroIcons.checkCircle,
37 | color: Get.theme.primaryColor,
38 | ),
39 | SizedBox(width: 5.w),
40 | Text(
41 | "Will take the resume from your profile.",
42 | style: GoogleFonts.poppins(
43 | fontSize: 13.sp,
44 | fontWeight: FontWeight.w400,
45 | color: Get.theme.colorScheme.primary,
46 | ),
47 | )
48 | ],
49 | ),
50 | SizedBox(height: 30.h),
51 | CustomButton(
52 | title: "SUBMIT",
53 | onTap: () => controller.applyToJob(jobId, "whyApply"),
54 | )
55 | ],
56 | );
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/lib/app/modules/JobDetails/views/widgets/body.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:get/get.dart';
3 |
4 | import '../../../../widgets/shimmer/job_details_shimmer.dart';
5 | import '../../controllers/job_details_controller.dart';
6 | import 'about_the_employer.dart';
7 | import 'description.dart';
8 | import 'details_sliver_app_bar.dart';
9 | import 'similar_jobs.dart';
10 |
11 | class Body extends GetView {
12 | const Body({Key? key}) : super(key: key);
13 |
14 | @override
15 | Widget build(BuildContext context) {
16 | return Obx(
17 | () => controller.job.when(
18 | idle: () => Container(),
19 | loading: () => const JobDetailsShimmer(),
20 | failure: (err) => const JobDetailsShimmer(),
21 | success: (job) => CustomScrollView(
22 | slivers: [
23 | DetailsSliverAppBar(job: job!),
24 | SliverToBoxAdapter(
25 | child: Column(
26 | children: [
27 | Description(job: job),
28 | AboutTheEmployer(job: job),
29 | const SimilarJobs(),
30 | ],
31 | ),
32 | )
33 | ],
34 | ),
35 | ),
36 | );
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/lib/app/modules/JobDetails/views/widgets/description.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_markdown/flutter_markdown.dart';
3 | import 'package:flutter_screenutil/flutter_screenutil.dart';
4 | import 'package:get/get.dart';
5 | import 'package:google_fonts/google_fonts.dart';
6 |
7 | import '../../../../data/remote/dto/job/job_out_dto.dart';
8 |
9 | class Description extends StatelessWidget {
10 | const Description({Key? key, required this.job}) : super(key: key);
11 | final JobOutDto job;
12 |
13 | @override
14 | Widget build(BuildContext context) {
15 | return Container(
16 | margin: EdgeInsets.all(16.w),
17 | decoration: BoxDecoration(
18 | color: Colors.white,
19 | borderRadius: BorderRadius.circular(14.r),
20 | ),
21 | child: Markdown(
22 | data: job.description!,
23 | selectable: true,
24 | shrinkWrap: true,
25 | physics: const NeverScrollableScrollPhysics(),
26 | styleSheet: MarkdownStyleSheet(
27 | p: GoogleFonts.poppins(
28 | fontSize: 13.sp,
29 | fontWeight: FontWeight.w400,
30 | color: Get.theme.colorScheme.onBackground,
31 | ),
32 | h2: GoogleFonts.poppins(
33 | fontSize: 14.sp,
34 | fontWeight: FontWeight.w700,
35 | color: Get.theme.colorScheme.onBackground,
36 | ),
37 | ),
38 | ),
39 | );
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/lib/app/modules/JobDetails/views/widgets/details_bottom_nav_bar.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_screenutil/flutter_screenutil.dart';
3 | import 'package:get/get.dart';
4 |
5 | import '../../../../data/remote/base/status.dart';
6 | import '../../../../utils/functions.dart';
7 | import '../../../../widgets/custom_button.dart';
8 | import '../../../JobDetails/controllers/job_details_controller.dart';
9 | import 'apply_bottom_sheet.dart';
10 |
11 | class DetailsBottomNavBar extends GetView {
12 | const DetailsBottomNavBar({Key? key}) : super(key: key);
13 |
14 | @override
15 | Widget build(BuildContext context) {
16 | return Obx(
17 | () => (controller.job is! Success)
18 | ? const SizedBox.shrink()
19 | : Container(
20 | height: 85.h,
21 | padding: EdgeInsets.all(16.w),
22 | decoration: BoxDecoration(
23 | color: Colors.white,
24 | borderRadius: BorderRadius.only(
25 | topLeft: Radius.circular(14.r),
26 | topRight: Radius.circular(14.r),
27 | ),
28 | boxShadow: [
29 | BoxShadow(
30 | color: Get.theme.colorScheme.secondary.withOpacity(.15),
31 | spreadRadius: 0,
32 | blurRadius: 159,
33 | offset: const Offset(0, 4), // changes position of shadow
34 | ),
35 | ],
36 | ),
37 | child: CustomButton(
38 | title: "APPLY NOW",
39 | onTap: () => popupBottomSheet(
40 | bottomSheetBody: ApplyBottomSheetBody(
41 | controller.job.whenOrNull(success: (job) => job!.id!)!,
42 | ),
43 | ),
44 | ),
45 | ),
46 | );
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/lib/app/modules/JobDetails/views/widgets/submit_bottom_sheet.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_screenutil/flutter_screenutil.dart';
3 | import 'package:get/get.dart';
4 | import 'package:google_fonts/google_fonts.dart';
5 | import 'package:heroicons/heroicons.dart';
6 |
7 | import '../../../../widgets/custom_button.dart';
8 |
9 | class SubmitBottomSheet extends StatelessWidget {
10 | const SubmitBottomSheet({Key? key}) : super(key: key);
11 |
12 | @override
13 | Widget build(BuildContext context) {
14 | return Column(
15 | children: [
16 | HeroIcon(
17 | HeroIcons.checkBadge,
18 | size: 100.w,
19 | color: Get.theme.primaryColor,
20 | style: HeroIconStyle.solid,
21 | ),
22 | SizedBox(height: 25.h),
23 | Text(
24 | "Thank You For Applying!",
25 | textAlign: TextAlign.center,
26 | style: GoogleFonts.poppins(
27 | fontSize: 20,
28 | fontWeight: FontWeight.w700,
29 | color: Get.theme.colorScheme.onBackground,
30 | ),
31 | ),
32 | SizedBox(height: 10.h),
33 | Text(
34 | "Your Application was successfully submitted.\nwe’ll contact you when a decision is made.",
35 | textAlign: TextAlign.center,
36 | style: GoogleFonts.poppins(
37 | fontSize: 13,
38 | fontWeight: FontWeight.w400,
39 | color: Get.theme.colorScheme.secondary,
40 | ),
41 | ),
42 | SizedBox(height: 50.h),
43 | CustomButton(
44 | title: "Back To Home",
45 | onTap: () async => Get.close(2),
46 | ),
47 | ],
48 | );
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/lib/app/modules/auth/bindings/auth_binding.dart:
--------------------------------------------------------------------------------
1 | import 'package:get/get.dart';
2 | import 'package:jobs_flutter_app/app/modules/home/controllers/home_controller.dart';
3 | import 'package:jobs_flutter_app/app/modules/root/controllers/root_controller.dart';
4 | import '../../saved/controllers/saved_controller.dart';
5 | import '../../search/controllers/search_controller.dart';
6 | import '../controllers/auth_controller.dart';
7 |
8 | class AuthBinding extends Bindings {
9 | @override
10 | void dependencies() {
11 | Get.lazyPut(() => AuthController());
12 | Get.lazyPut(() => RootController());
13 | Get.lazyPut(() => HomeController());
14 | Get.lazyPut(() => SearchController());
15 | Get.lazyPut(() => SavedController());
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/lib/app/modules/auth/views/login/login_view.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter/services.dart';
3 |
4 | import 'package:get/get.dart';
5 |
6 | import '../../controllers/auth_controller.dart';
7 | import 'widgets/body.dart';
8 |
9 | class LoginView extends GetView {
10 | const LoginView({Key? key}) : super(key: key);
11 |
12 | @override
13 | Widget build(BuildContext context) {
14 | return Scaffold(
15 | backgroundColor: Get.theme.backgroundColor,
16 | resizeToAvoidBottomInset: false,
17 | body: AnnotatedRegion(
18 | value: SystemUiOverlayStyle(
19 | statusBarColor: Get.theme.backgroundColor,
20 | statusBarIconBrightness: Brightness.dark,
21 | systemNavigationBarColor: Colors.white,
22 | systemNavigationBarIconBrightness: Brightness.dark,
23 | ),
24 | child: const SafeArea(child: Body()),
25 | ),
26 | );
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/lib/app/modules/auth/views/login/widgets/body.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_screenutil/flutter_screenutil.dart';
3 | import 'package:get/get.dart';
4 |
5 | import '../../../../../core/values/strings.dart';
6 | import '../../../controllers/auth_controller.dart';
7 | import '../../widgets/button_with_text.dart';
8 | import '../../widgets/header.dart';
9 | import 'login_form.dart';
10 |
11 | class Body extends GetView {
12 | const Body({Key? key}) : super(key: key);
13 |
14 | @override
15 | Widget build(BuildContext context) {
16 | return Padding(
17 | padding: EdgeInsets.symmetric(horizontal: 29.w),
18 | child: CustomScrollView(slivers: [
19 | SliverFillRemaining(
20 | child: Column(
21 | mainAxisAlignment: MainAxisAlignment.center,
22 | children: [
23 | const Header(title: AppStrings.welcomeBack),
24 | SizedBox(height: 30.h),
25 | const LoginForm(),
26 | SizedBox(height: 50.h),
27 | ButtonWithText(
28 | btnLabel: AppStrings.loginBtn,
29 | firstTextSpan: AppStrings.youDoNotHaveAnAccountYet,
30 | secondTextSpan: AppStrings.signup,
31 | onTap: controller.onLoginSubmit,
32 | onTextTap: controller.onSignUp,
33 | ),
34 | ],
35 | ),
36 | )
37 | ]),
38 | );
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/lib/app/modules/auth/views/login/widgets/choose_bottom_sheet.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_screenutil/flutter_screenutil.dart';
3 | import 'package:get/get.dart';
4 | import 'package:google_fonts/google_fonts.dart';
5 | import 'package:heroicons/heroicons.dart';
6 |
7 | import '../../../../../core/values/strings.dart';
8 | import '../../../../../domain/enums/user_type.dart';
9 | import '../../../controllers/auth_controller.dart';
10 | import 'custom_choose_button.dart';
11 |
12 | class ChooseBottomSheetBody extends GetView {
13 | const ChooseBottomSheetBody({Key? key}) : super(key: key);
14 |
15 | @override
16 | Widget build(BuildContext context) {
17 | return Column(
18 | children: [
19 | Text(
20 | AppStrings.whatAreYouLookingFor,
21 | style: GoogleFonts.poppins(
22 | fontSize: 20.sp,
23 | fontWeight: FontWeight.w700,
24 | color: Get.theme.colorScheme.onBackground,
25 | ),
26 | ),
27 | SizedBox(height: 42.h),
28 | FittedBox(
29 | child: Row(
30 | mainAxisAlignment: MainAxisAlignment.center,
31 | children: [
32 | CustomChooseButton(
33 | title: "Employee",
34 | icon: HeroIcons.user,
35 | onTap: () =>
36 | controller.onSelectRegisterType(RegisterType.COMPANY),
37 | ),
38 | SizedBox(width: 15.w),
39 | CustomChooseButton(
40 | title: "Job",
41 | icon: HeroIcons.briefcase,
42 | onTap: () =>
43 | controller.onSelectRegisterType(RegisterType.CUSTOMER),
44 | ),
45 | ],
46 | ),
47 | )
48 | ],
49 | );
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/lib/app/modules/auth/views/login/widgets/custom_choose_button.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_screenutil/flutter_screenutil.dart';
3 | import 'package:get/get.dart';
4 | import 'package:google_fonts/google_fonts.dart';
5 | import 'package:heroicons/heroicons.dart';
6 |
7 | class CustomChooseButton extends StatelessWidget {
8 | const CustomChooseButton({
9 | Key? key,
10 | required this.title,
11 | required this.icon,
12 | required this.onTap,
13 | }) : super(key: key);
14 |
15 | final String title;
16 | final HeroIcons icon;
17 | final void Function() onTap;
18 |
19 | @override
20 | Widget build(BuildContext context) {
21 | return SizedBox(
22 | width: 150.w,
23 | height: 95.h,
24 | child: ElevatedButton(
25 | onPressed: onTap,
26 | style: ElevatedButton.styleFrom(
27 | padding: EdgeInsets.all(10.w),
28 | backgroundColor: Colors.white,
29 | foregroundColor: Get.theme.colorScheme.primary,
30 | elevation: 0.0,
31 | side: BorderSide(
32 | color: Get.theme.colorScheme.primary,
33 | width: 1.5,
34 | ),
35 | ),
36 | child: Column(
37 | mainAxisAlignment: MainAxisAlignment.center,
38 | children: [
39 | Container(
40 | width: 40.w,
41 | height: 40.h,
42 | padding: EdgeInsets.all(8.w),
43 | decoration: BoxDecoration(
44 | borderRadius: BorderRadius.circular(50.r),
45 | color: Get.theme.colorScheme.primary.withOpacity(0.1),
46 | ),
47 | child: Center(
48 | child: HeroIcon(
49 | style: HeroIconStyle.solid,
50 | icon,
51 | ),
52 | ),
53 | ),
54 | SizedBox(height: 5.h),
55 | Text(
56 | title,
57 | style: GoogleFonts.poppins(
58 | fontSize: 13.sp,
59 | fontWeight: FontWeight.w700,
60 | color: Get.theme.colorScheme.primary),
61 | ),
62 | ],
63 | ),
64 | ),
65 | );
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/lib/app/modules/auth/views/login/widgets/login_form.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_screenutil/flutter_screenutil.dart';
3 | import 'package:get/get.dart';
4 | import 'package:heroicons/heroicons.dart';
5 | import 'package:jobs_flutter_app/app/core/values/strings.dart';
6 | import 'package:jobs_flutter_app/app/modules/auth/controllers/auth_controller.dart';
7 |
8 | import '../../../../../widgets/custom_text_field.dart';
9 |
10 | class LoginForm extends GetView {
11 | const LoginForm({Key? key}) : super(key: key);
12 |
13 | @override
14 | Widget build(BuildContext context) {
15 | return Form(
16 | key: controller.loginFormKey,
17 | child: Column(
18 | children: [
19 | CustomTextField(
20 | controller: controller.loginEmailController,
21 | hintText: AppStrings.emailHint,
22 | title: AppStrings.emailLabel,
23 | autofocus: false,
24 | maxLines: 1,
25 | ),
26 | SizedBox(height: 15.h),
27 | Obx(
28 | () => CustomTextField(
29 | controller: controller.loginPasswordController,
30 | hintText: AppStrings.password,
31 | title: AppStrings.password,
32 | autofocus: false,
33 | isPassword: true,
34 | suffixIcon:
35 | controller.isObscure ? HeroIcons.eyeSlash : HeroIcons.eye,
36 | obscureText: controller.isObscure,
37 | onSuffixTap: controller.toggleObscurePassword,
38 | ),
39 | ),
40 | ],
41 | ),
42 | );
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/lib/app/modules/auth/views/register/register_view.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter/services.dart';
3 |
4 | import 'package:get/get.dart';
5 |
6 | import 'widgets/body.dart';
7 |
8 | class RegisterView extends GetView {
9 | const RegisterView({Key? key}) : super(key: key);
10 |
11 | @override
12 | Widget build(BuildContext context) {
13 | return Scaffold(
14 | backgroundColor: Get.theme.backgroundColor,
15 | resizeToAvoidBottomInset: true,
16 | body: AnnotatedRegion(
17 | value: SystemUiOverlayStyle(
18 | statusBarColor: Get.theme.backgroundColor,
19 | statusBarIconBrightness: Brightness.dark,
20 | systemNavigationBarColor: Colors.white,
21 | systemNavigationBarIconBrightness: Brightness.dark,
22 | ),
23 | child: const SafeArea(child: Body()),
24 | ),
25 | );
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/lib/app/modules/auth/views/register/widgets/body.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_screenutil/flutter_screenutil.dart';
3 | import 'package:get/get.dart';
4 |
5 | import '../../../../../core/values/strings.dart';
6 | import '../../../../../domain/enums/user_type.dart';
7 | import '../../../../../routes/app_pages.dart';
8 | import '../../../controllers/auth_controller.dart';
9 | import '../../widgets/button_with_text.dart';
10 | import '../../widgets/header.dart';
11 | import 'employee_form.dart';
12 | import 'employer_form.dart';
13 |
14 | class Body extends GetView {
15 | const Body({Key? key}) : super(key: key);
16 |
17 | @override
18 | Widget build(BuildContext context) {
19 | return Padding(
20 | padding: EdgeInsets.symmetric(horizontal: 29.w),
21 | child: SingleChildScrollView(
22 | child: Column(
23 | children: [
24 | SizedBox(height: 50.h),
25 | const Header(title: AppStrings.createAnAccount),
26 | SizedBox(height: 30.h),
27 | if (controller.registerType == RegisterType.CUSTOMER)
28 | const EmployeeForm(),
29 | if (controller.registerType == RegisterType.COMPANY)
30 | const EmployerForm(),
31 | SizedBox(height: 50.h),
32 | ButtonWithText(
33 | btnLabel: AppStrings.signup.toUpperCase(),
34 | firstTextSpan: AppStrings.alreadyHaveAnAccount,
35 | secondTextSpan: AppStrings.signIn,
36 | onTap: controller.onRegisterSubmit,
37 | onTextTap: () => Get.offNamed(Routes.LOGIN),
38 | ),
39 | SizedBox(height: 50.h),
40 | ],
41 | ),
42 | ),
43 | );
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/lib/app/modules/auth/views/register/widgets/employee_form.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_screenutil/flutter_screenutil.dart';
3 | import 'package:get/get.dart';
4 | import 'package:heroicons/heroicons.dart';
5 |
6 | import '../../../../../core/values/strings.dart';
7 | import '../../../../../utils/validators.dart';
8 | import '../../../../../widgets/custom_text_field.dart';
9 | import '../../../controllers/auth_controller.dart';
10 |
11 | class EmployeeForm extends GetView {
12 | const EmployeeForm({Key? key}) : super(key: key);
13 |
14 | @override
15 | Widget build(BuildContext context) {
16 | return Form(
17 | key: controller.customerFormKey,
18 | child: Column(
19 | children: [
20 | CustomTextField(
21 | controller: controller.customerFullNameController,
22 | title: AppStrings.fullName,
23 | hintText: AppStrings.fullNameHint,
24 | autofocus: false,
25 | maxLines: 1,
26 | isRequired: true,
27 | validator: Validators.name,
28 | ),
29 | SizedBox(height: 15.h),
30 | CustomTextField(
31 | controller: controller.customerPhoneNumController,
32 | title: AppStrings.phoneNumber,
33 | hintText: AppStrings.phoneNumberHint,
34 | autofocus: false,
35 | maxLines: 1,
36 | isRequired: true,
37 | textInputType: TextInputType.phone,
38 | validator: Validators.phoneNumber,
39 | isPhoneNumber: true,
40 | onCountryChanged: controller.onCountryChanged,
41 | ),
42 | SizedBox(height: 15.h),
43 | CustomTextField(
44 | controller: controller.customerEmailController,
45 | title: AppStrings.email,
46 | hintText: AppStrings.emailHint,
47 | autofocus: false,
48 | maxLines: 1,
49 | isRequired: true,
50 | textInputType: TextInputType.emailAddress,
51 | validator: Validators.email,
52 | ),
53 | SizedBox(height: 15.h),
54 | Obx(
55 | () => CustomTextField(
56 | controller: controller.customerPasswordController,
57 | hintText: AppStrings.password,
58 | title: AppStrings.password,
59 | autofocus: false,
60 | isPassword: true,
61 | obscureText: controller.isObscure,
62 | onSuffixTap: controller.toggleObscurePassword,
63 | isRequired: true,
64 | validator: Validators.password,
65 | suffixIcon:
66 | controller.isObscure ? HeroIcons.eyeSlash : HeroIcons.eye,
67 | ),
68 | ),
69 | ],
70 | ),
71 | );
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/lib/app/modules/auth/views/widgets/button_with_text.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/gestures.dart';
2 | import 'package:flutter/material.dart';
3 | import 'package:flutter_screenutil/flutter_screenutil.dart';
4 | import 'package:google_fonts/google_fonts.dart';
5 |
6 | import '../../../../widgets/custom_button.dart';
7 |
8 | class ButtonWithText extends StatelessWidget {
9 | const ButtonWithText({
10 | Key? key,
11 | required this.btnLabel,
12 | required this.firstTextSpan,
13 | required this.secondTextSpan,
14 | required this.onTap,
15 | required this.onTextTap,
16 | }) : super(key: key);
17 | final String btnLabel;
18 | final String firstTextSpan;
19 | final String secondTextSpan;
20 | final Future Function() onTap;
21 | final void Function() onTextTap;
22 |
23 | @override
24 | Widget build(BuildContext context) {
25 | return Column(
26 | children: [
27 | CustomButton(
28 | title: btnLabel,
29 | onTap: onTap,
30 | ),
31 | SizedBox(height: 20.h),
32 | RichText(
33 | text: TextSpan(
34 | children: [
35 | TextSpan(
36 | text: firstTextSpan,
37 | style: GoogleFonts.poppins(
38 | fontSize: 12.sp,
39 | fontWeight: FontWeight.w400,
40 | color: const Color(0xff14171A),
41 | ),
42 | ),
43 | TextSpan(
44 | text: secondTextSpan,
45 | recognizer: TapGestureRecognizer()..onTap = onTextTap,
46 | style: GoogleFonts.poppins(
47 | fontSize: 12.sp,
48 | fontWeight: FontWeight.w400,
49 | color: const Color(0xff1DA1F2),
50 | decoration: TextDecoration.underline),
51 | ),
52 | ],
53 | ),
54 | ),
55 | ],
56 | );
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/lib/app/modules/auth/views/widgets/header.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_screenutil/flutter_screenutil.dart';
3 | import 'package:google_fonts/google_fonts.dart';
4 |
5 | class Header extends StatelessWidget {
6 | const Header({
7 | Key? key,
8 | required this.title,
9 | }) : super(key: key);
10 |
11 | final String title;
12 |
13 | @override
14 | Widget build(BuildContext context) {
15 | return Column(
16 | children: [
17 | Text(
18 | title,
19 | style: GoogleFonts.poppins(
20 | fontSize: 30.sp,
21 | fontWeight: FontWeight.w700,
22 | color: const Color(0xff14171A),
23 | ),
24 | ),
25 | ],
26 | );
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/lib/app/modules/companyProfile/bindings/company_profile_binding.dart:
--------------------------------------------------------------------------------
1 | import 'package:get/get.dart';
2 |
3 | import '../controllers/company_profile_controller.dart';
4 |
5 | class CompanyProfileBinding extends Bindings {
6 | @override
7 | void dependencies() {
8 | Get.lazyPut(
9 | () => CompanyProfileController(),
10 | );
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/lib/app/modules/companyProfile/views/company_profile_view.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter/services.dart';
3 | import 'package:get/get.dart';
4 |
5 | import '../controllers/company_profile_controller.dart';
6 | import 'widgets/body.dart';
7 |
8 | class CompanyProfileView extends GetView {
9 | const CompanyProfileView({Key? key}) : super(key: key);
10 |
11 | @override
12 | Widget build(BuildContext context) {
13 | return Scaffold(
14 | backgroundColor: Get.theme.backgroundColor,
15 | body: AnnotatedRegion(
16 | value: SystemUiOverlayStyle(
17 | statusBarColor: Get.theme.primaryColor,
18 | statusBarIconBrightness: Brightness.light,
19 | systemNavigationBarColor: Colors.white,
20 | systemNavigationBarIconBrightness: Brightness.dark,
21 | ),
22 | child: const SafeArea(child: Body())),
23 | );
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/lib/app/modules/companyProfile/views/widgets/body.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_screenutil/flutter_screenutil.dart';
3 | import 'package:get/get.dart';
4 | import 'package:google_fonts/google_fonts.dart';
5 |
6 | import '../../../../widgets/shimmer/company_profile_shimmer.dart';
7 | import '../../controllers/company_profile_controller.dart';
8 | import 'company_profile_sliver_app_bar.dart';
9 | import 'company_tab_view.dart';
10 | import 'sliverPersistentHeaderDelegateImp.dart';
11 |
12 | class Body extends GetView {
13 | const Body({Key? key}) : super(key: key);
14 |
15 | @override
16 | Widget build(BuildContext context) {
17 | return Obx(
18 | () => controller.rxCompany.when(
19 | idle: () => Container(),
20 | loading: () => const CompanyProfileShimmer(),
21 | failure: (err) => const CompanyProfileShimmer(),
22 | success: (company) => NestedScrollView(
23 | headerSliverBuilder: (
24 | BuildContext context,
25 | bool innerBoxIsScrolled,
26 | ) {
27 | return [
28 | CompanyProfileSliverAppBar(company: company!),
29 | SliverPersistentHeader(
30 | delegate: SliverPersistentHeaderDelegateImp(
31 | tabBar: TabBar(
32 | controller: controller.tabController,
33 | labelStyle: GoogleFonts.poppins(
34 | fontSize: 14.sp,
35 | fontWeight: FontWeight.w700,
36 | ),
37 | unselectedLabelStyle: GoogleFonts.poppins(
38 | fontSize: 14.sp,
39 | fontWeight: FontWeight.w700,
40 | ),
41 | labelColor: Get.theme.colorScheme.onPrimary,
42 | unselectedLabelColor: Get.theme.colorScheme.secondary,
43 | indicator: BoxDecoration(
44 | borderRadius: BorderRadius.circular(12.r),
45 | color: Get.theme.colorScheme.primary,
46 | ),
47 | tabs: const [
48 | Tab(text: "About us"),
49 | Tab(text: "Jobs"),
50 | ],
51 | ),
52 | ),
53 | pinned: true,
54 | ),
55 | ];
56 | },
57 | body: const CompanyTabView(),
58 | ),
59 | ),
60 | );
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/lib/app/modules/companyProfile/views/widgets/company_profile_sliver_app_bar.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_screenutil/flutter_screenutil.dart';
3 | import 'package:get/get.dart';
4 | import 'package:google_fonts/google_fonts.dart';
5 | import 'package:heroicons/heroicons.dart';
6 |
7 | import '../../../../data/remote/dto/company/Company_out_dto.dart';
8 | import '../../controllers/company_profile_controller.dart';
9 | import 'header.dart';
10 |
11 | class CompanyProfileSliverAppBar extends GetView {
12 | const CompanyProfileSliverAppBar({Key? key, required this.company})
13 | : super(key: key);
14 | final CompanyOutDto company;
15 |
16 | @override
17 | Widget build(BuildContext context) {
18 | return SliverAppBar(
19 | automaticallyImplyLeading: false,
20 | expandedHeight: 210.h,
21 | backgroundColor: Get.theme.primaryColor,
22 | pinned: true,
23 | leadingWidth: kToolbarHeight,
24 | toolbarHeight: kToolbarHeight,
25 | leading: Padding(
26 | padding: EdgeInsets.all(6.w),
27 | child: IconButton(
28 | onPressed: () => Get.back(),
29 | style: IconButton.styleFrom(
30 | backgroundColor: Colors.white.withOpacity(0.2),
31 | padding: EdgeInsets.zero,
32 | minimumSize: Size.zero,
33 | shape: RoundedRectangleBorder(
34 | borderRadius: BorderRadius.circular(8.r),
35 | ),
36 | ),
37 | icon: const HeroIcon(
38 | HeroIcons.chevronLeft,
39 | color: Colors.white,
40 | ),
41 | ),
42 | ),
43 | centerTitle: true,
44 | titleTextStyle: GoogleFonts.poppins(
45 | fontSize: 18.sp,
46 | fontWeight: FontWeight.w600,
47 | color: Get.theme.backgroundColor,
48 | ),
49 | title: Padding(
50 | padding: EdgeInsets.symmetric(vertical: 6.h),
51 | child: const Text(
52 | "Company Profile",
53 | ),
54 | ),
55 | flexibleSpace: FlexibleSpaceBar(
56 | background: Header(company: company),
57 | ),
58 | );
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/lib/app/modules/companyProfile/views/widgets/company_tab_view.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:get/get.dart';
3 |
4 | import '../../controllers/company_profile_controller.dart';
5 | import 'about_us.dart';
6 | import 'jobs_list.dart';
7 |
8 | class CompanyTabView extends GetView {
9 | const CompanyTabView({Key? key}) : super(key: key);
10 |
11 | @override
12 | Widget build(BuildContext context) {
13 | return TabBarView(
14 | controller: controller.tabController,
15 | children: const [
16 | AboutUs(),
17 | JobsList(),
18 | ],
19 | );
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/lib/app/modules/companyProfile/views/widgets/company_tap_bar.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_screenutil/flutter_screenutil.dart';
3 | import 'package:get/get.dart';
4 | import 'package:google_fonts/google_fonts.dart';
5 |
6 | import '../../controllers/company_profile_controller.dart';
7 |
8 | class CompanyTabBar extends GetView {
9 | const CompanyTabBar({Key? key}) : super(key: key);
10 |
11 | @override
12 | Widget build(BuildContext context) {
13 | return TabBar(
14 | controller: controller.tabController,
15 | labelStyle: GoogleFonts.poppins(
16 | fontSize: 14.sp,
17 | fontWeight: FontWeight.w700,
18 | ),
19 | unselectedLabelStyle: GoogleFonts.poppins(
20 | fontSize: 14.sp,
21 | fontWeight: FontWeight.w700,
22 | ),
23 | labelColor: Get.theme.colorScheme.onBackground,
24 | unselectedLabelColor: Get.theme.colorScheme.tertiary,
25 | tabs: const [
26 | Tab(text: "About us"),
27 | Tab(text: "Jobs"),
28 | ],
29 | );
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/lib/app/modules/companyProfile/views/widgets/header.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_screenutil/flutter_screenutil.dart';
3 | import 'package:flutter_svg_provider/flutter_svg_provider.dart';
4 | import 'package:get/get.dart';
5 | import 'package:google_fonts/google_fonts.dart';
6 |
7 | import '../../../../data/remote/api/api_routes.dart';
8 | import '../../../../data/remote/dto/company/Company_out_dto.dart';
9 | import '../../../../widgets/custom_avatar.dart';
10 | import '../../../JobDetails/controllers/job_details_controller.dart';
11 |
12 | class Header extends GetView {
13 | const Header({
14 | Key? key,
15 | required this.company,
16 | }) : super(key: key);
17 | final CompanyOutDto company;
18 |
19 | @override
20 | Widget build(BuildContext context) {
21 | return Container(
22 | padding: EdgeInsets.only(right: 16.w, left: 16.w, top: 50.h),
23 | decoration: const BoxDecoration(
24 | image: DecorationImage(
25 | image: Svg('assets/header_bg.svg', color: Colors.white),
26 | fit: BoxFit.cover,
27 | ),
28 | ),
29 | child: Column(
30 | crossAxisAlignment: CrossAxisAlignment.center,
31 | children: [
32 | CustomAvatar(
33 | imageUrl: "${ApiRoutes.BASE_URL}${company.image}",
34 | ),
35 | Text(
36 | company.name!,
37 | style: GoogleFonts.poppins(
38 | fontWeight: FontWeight.w600,
39 | fontSize: 20.sp,
40 | color: Get.theme.colorScheme.onPrimary,
41 | ),
42 | ),
43 | if (company.workType != null)
44 | Text(
45 | company.workType!,
46 | style: GoogleFonts.poppins(
47 | fontWeight: FontWeight.w400,
48 | fontSize: 13.sp,
49 | color: Get.theme.colorScheme.onPrimary,
50 | ),
51 | ),
52 | ],
53 | ),
54 | );
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/lib/app/modules/companyProfile/views/widgets/jobs_list.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:get/get.dart';
3 | import 'package:heroicons/heroicons.dart';
4 |
5 | import '../../../../data/remote/api/api_routes.dart';
6 | import '../../../../routes/app_pages.dart';
7 | import '../../../../widgets/custom_job_card.dart';
8 | import '../../../../widgets/custom_lottie.dart';
9 | import '../../../saved/controllers/saved_controller.dart';
10 | import '../../controllers/company_profile_controller.dart';
11 |
12 | class JobsList extends GetView {
13 | const JobsList({Key? key}) : super(key: key);
14 |
15 | @override
16 | Widget build(BuildContext context) {
17 | return Obx(() => controller.rxJobs.when(
18 | idle: () => Container(),
19 | loading: () => const CircularProgressIndicator(),
20 | success: (jobs) => jobs == null || jobs.isEmpty
21 | ? const CustomLottie(
22 | title: "This company has not jobs yet.",
23 | asset: "assets/empty.json",
24 | )
25 | : ListView.builder(
26 | itemCount: jobs.length,
27 | shrinkWrap: true,
28 | scrollDirection: Axis.vertical,
29 | itemBuilder: (context, index) => CustomJobCard(
30 | jobPosition: jobs[index].position,
31 | publishTime: jobs[index].createdAt!,
32 | companyName: jobs[index].company!.name!,
33 | employmentType: jobs[index].employmentType!,
34 | location: jobs[index].location!,
35 | workplace: jobs[index].workplace!,
36 | actionIcon: HeroIcons.bookmark,
37 | avatar:
38 | "${ApiRoutes.BASE_URL}${jobs[index].company!.image!}",
39 | description: jobs[index].description!,
40 | onTap: () => Get.toNamed(
41 | Routes.JOB_DETAILS,
42 | arguments: jobs[index].id,
43 | ),
44 | isSaved: SavedController.to.isJobSaved(jobs[index].id!),
45 | onActionTap: (isSaved) =>
46 | controller.onSaveButtonTapped(isSaved, jobs[index].id!),
47 | ),
48 | ),
49 | failure: (e) => Text(e!),
50 | ));
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/lib/app/modules/companyProfile/views/widgets/profile_header.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_screenutil/flutter_screenutil.dart';
3 | import 'package:get/get.dart';
4 | import 'package:google_fonts/google_fonts.dart';
5 |
6 | import '../../../../data/remote/api/api_routes.dart';
7 | import '../../../../widgets/custom_avatar.dart';
8 | import '../../controllers/company_profile_controller.dart';
9 |
10 | class ProfileHeader extends GetView {
11 | const ProfileHeader({
12 | Key? key,
13 | required this.imagePath,
14 | required this.name,
15 | }) : super(key: key);
16 | final String imagePath;
17 | final String name;
18 |
19 | @override
20 | Widget build(BuildContext context) {
21 | return Container(
22 | padding: EdgeInsets.symmetric(horizontal: 16.w),
23 | width: double.infinity,
24 | child: Column(
25 | children: [
26 | CustomAvatar(
27 | imageUrl: "${ApiRoutes.BASE_URL}$imagePath",
28 | ),
29 | SizedBox(height: 5.h),
30 | Text(
31 | name,
32 | style: GoogleFonts.poppins(
33 | fontWeight: FontWeight.w700,
34 | fontSize: 16.sp,
35 | color: Get.theme.colorScheme.onBackground,
36 | ),
37 | ),
38 | ],
39 | ),
40 | );
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/lib/app/modules/companyProfile/views/widgets/sliverPersistentHeaderDelegateImp.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_screenutil/flutter_screenutil.dart';
3 | import 'package:get/get.dart';
4 |
5 | class SliverPersistentHeaderDelegateImp extends SliverPersistentHeaderDelegate {
6 | final TabBar tabBar;
7 |
8 | const SliverPersistentHeaderDelegateImp({
9 | required this.tabBar,
10 | });
11 |
12 | @override
13 | Widget build(
14 | BuildContext context,
15 | double shrinkOffset,
16 | bool overlapsContent,
17 | ) {
18 | return Align(
19 | child: Container(
20 | padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 8.h),
21 | decoration: BoxDecoration(
22 | color: Get.theme.backgroundColor,
23 | ),
24 | child: Container(
25 | padding: EdgeInsets.all(5.w),
26 | decoration: BoxDecoration(
27 | color: Colors.white,
28 | borderRadius: BorderRadius.circular(14.r),
29 | boxShadow: [
30 | BoxShadow(
31 | color: Colors.grey.withOpacity(0.05),
32 | blurRadius: 20,
33 | offset: const Offset(0, 10),
34 | ),
35 | ],
36 | ),
37 | child: tabBar,
38 | ),
39 | ),
40 | );
41 | }
42 |
43 | @override
44 | double get maxExtent => tabBar.preferredSize.height * 1.5;
45 |
46 | @override
47 | double get minExtent => tabBar.preferredSize.height * 1.5;
48 |
49 | @override
50 | bool shouldRebuild(covariant SliverPersistentHeaderDelegate oldDelegate) {
51 | return false;
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/lib/app/modules/customerProfile/bindings/customer_profile_binding.dart:
--------------------------------------------------------------------------------
1 | import 'package:get/get.dart';
2 |
3 | import '../controllers/customer_profile_controller.dart';
4 |
5 | class CustomerProfileBinding extends Bindings {
6 | @override
7 | void dependencies() {
8 | Get.lazyPut(
9 | () => CustomerProfileController(),
10 | );
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/lib/app/modules/customerProfile/controllers/customer_profile_controller.dart:
--------------------------------------------------------------------------------
1 | import 'package:get/get.dart';
2 |
3 | import '../../../data/remote/base/status.dart';
4 | import '../../../data/remote/dto/customer/customer_profile_out_dto.dart';
5 | import '../../../data/remote/repositories/customer/customer_repository.dart';
6 | import '../../../di/locator.dart';
7 | import '../../../widgets/dialogs.dart';
8 | import '../../auth/controllers/auth_controller.dart';
9 |
10 | class CustomerProfileController extends GetxController {
11 | final customerRepository = getIt.get();
12 |
13 | final Rx> _rxProfile =
14 | Rx(const Status.loading());
15 |
16 | Status get profile => _rxProfile.value;
17 |
18 | @override
19 | void onInit() {
20 | super.onInit();
21 | loadPage();
22 | }
23 |
24 | @override
25 | void onReady() {
26 | super.onReady();
27 | }
28 |
29 | @override
30 | void onClose() {
31 | super.onClose();
32 | }
33 |
34 | getProfile() async {
35 | final state = await customerRepository.getProfile(
36 | customerUuid: AuthController.to.currentUser!.id!);
37 | _rxProfile.value = state;
38 | }
39 |
40 | void loadPage() async {
41 | await getProfile();
42 | showDialogOnFailure();
43 | }
44 |
45 | void onRetry() async {
46 | _rxProfile.value = const Status.loading();
47 | await getProfile();
48 | showDialogOnFailure();
49 | }
50 |
51 | void showDialogOnFailure() {
52 | if (profile is Failure) {
53 | Dialogs.spaceDialog(
54 | description: (profile as Failure).reason.toString(),
55 | btnOkOnPress: onRetry,
56 | dismissOnBackKeyPress: false,
57 | dismissOnTouchOutside: false,
58 | );
59 | }
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/lib/app/modules/customerProfile/views/customer_profile_view.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter/services.dart';
3 | import 'package:get/get.dart';
4 |
5 | import '../controllers/customer_profile_controller.dart';
6 | import 'widgets/body.dart';
7 |
8 | class CustomerProfileView extends GetView {
9 | const CustomerProfileView({Key? key}) : super(key: key);
10 |
11 | @override
12 | Widget build(BuildContext context) {
13 | return Scaffold(
14 | backgroundColor: Get.theme.backgroundColor,
15 | body: AnnotatedRegion(
16 | value: SystemUiOverlayStyle(
17 | statusBarColor: Get.theme.primaryColor,
18 | statusBarIconBrightness: Brightness.light,
19 | systemNavigationBarColor: Get.theme.backgroundColor,
20 | systemNavigationBarIconBrightness: Brightness.dark,
21 | ),
22 | child: const SafeArea(child: Body()),
23 | ),
24 | );
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/lib/app/modules/customerProfile/views/widgets/about_me.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_screenutil/flutter_screenutil.dart';
3 | import 'package:get/get.dart';
4 | import 'package:google_fonts/google_fonts.dart';
5 | import 'package:heroicons/heroicons.dart';
6 |
7 | import '../../../../widgets/custom_info_card.dart';
8 |
9 | class AboutMe extends StatelessWidget {
10 | const AboutMe({
11 | Key? key,
12 | required this.description,
13 | }) : super(key: key);
14 | final String? description;
15 |
16 | @override
17 | Widget build(BuildContext context) {
18 | return description == null
19 | ? const SizedBox()
20 | : CustomInfoCard(
21 | icon: HeroIcons.userCircle,
22 | title: "About me",
23 | child: Text(
24 | description!,
25 | style: GoogleFonts.poppins(
26 | fontSize: 13.sp,
27 | fontWeight: FontWeight.w400,
28 | color: Get.theme.colorScheme.secondary,
29 | ),
30 | ),
31 | );
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/lib/app/modules/customerProfile/views/widgets/body.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_screenutil/flutter_screenutil.dart';
3 | import 'package:get/get.dart';
4 |
5 | import '../../../../widgets/shimmer/customer_profile_shimmer.dart';
6 | import '../../controllers/customer_profile_controller.dart';
7 | import 'about_me.dart';
8 | import 'customer_profile_sliver_app_bar.dart';
9 | import 'education.dart';
10 | import 'experience.dart';
11 | import 'languages.dart';
12 | import 'skills.dart';
13 |
14 | class Body extends GetView {
15 | const Body({Key? key}) : super(key: key);
16 |
17 | @override
18 | Widget build(BuildContext context) {
19 | return Obx(
20 | () => controller.profile.when(
21 | idle: () => const SizedBox(),
22 | loading: () => const CustomerProfileShimmer(),
23 | failure: (err) => const CustomerProfileShimmer(),
24 | success: (profile) => CustomScrollView(
25 | slivers: [
26 | CustomerProfileSliverAppBar(profile: profile!),
27 | SliverToBoxAdapter(
28 | child: SingleChildScrollView(
29 | child: Padding(
30 | padding: EdgeInsets.only(top: 16.h),
31 | child: Column(
32 | children: [
33 | AboutMe(description: profile.description),
34 | Experience(experience: profile.workExperience),
35 | EducationCard(education: profile.education),
36 | Skills(skills: profile.skills),
37 | Languages(languages: profile.language),
38 | ],
39 | ),
40 | ),
41 | ),
42 | ),
43 | ],
44 | ),
45 | ),
46 | );
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/lib/app/modules/customerProfile/views/widgets/education.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_screenutil/flutter_screenutil.dart';
3 | import 'package:get/get.dart';
4 | import 'package:google_fonts/google_fonts.dart';
5 | import 'package:heroicons/heroicons.dart';
6 |
7 | import '../../../../data/remote/dto/customer/customer_profile_out_dto.dart';
8 | import '../../../../utils/extensions.dart';
9 | import '../../../../widgets/custom_info_card.dart';
10 |
11 | class EducationCard extends StatelessWidget {
12 | const EducationCard({
13 | Key? key,
14 | required this.education,
15 | }) : super(key: key);
16 | final List? education;
17 |
18 | @override
19 | Widget build(BuildContext context) {
20 | return education == null || education!.isEmpty
21 | ? const SizedBox()
22 | : CustomInfoCard(
23 | icon: HeroIcons.academicCap,
24 | title: "Education",
25 | child: Column(
26 | crossAxisAlignment: CrossAxisAlignment.start,
27 | children: List.generate(
28 | education!.length,
29 | (index) => Column(
30 | crossAxisAlignment: CrossAxisAlignment.start,
31 | children: [
32 | Text(
33 | education![index].degree!,
34 | style: GoogleFonts.poppins(
35 | fontSize: 13.sp,
36 | fontWeight: FontWeight.w600,
37 | color: Get.theme.colorScheme.onBackground,
38 | ),
39 | ),
40 | SizedBox(height: 5.h),
41 | Text(
42 | education![index].school!,
43 | style: GoogleFonts.poppins(
44 | fontSize: 13.sp,
45 | fontWeight: FontWeight.w400,
46 | color: Get.theme.colorScheme.secondary,
47 | ),
48 | ),
49 | SizedBox(height: 2.h),
50 | Text(
51 | "${education![index].startDate!.toShortDate()} - ${education![index].endDate!.toShortDate()}",
52 | style: GoogleFonts.poppins(
53 | fontSize: 13.sp,
54 | fontWeight: FontWeight.w400,
55 | color: Get.theme.colorScheme.secondary,
56 | ),
57 | ),
58 | if (index != education!.length - 1)
59 | Divider(
60 | color: Get.theme.colorScheme.background,
61 | thickness: 1.5,
62 | ),
63 | ],
64 | ),
65 | ),
66 | ),
67 | );
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/lib/app/modules/customerProfile/views/widgets/header.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_screenutil/flutter_screenutil.dart';
3 | import 'package:flutter_svg_provider/flutter_svg_provider.dart';
4 | import 'package:get/get.dart';
5 | import 'package:google_fonts/google_fonts.dart';
6 |
7 | import '../../../../data/remote/api/api_routes.dart';
8 | import '../../../../data/remote/dto/customer/customer_profile_out_dto.dart';
9 | import '../../../../widgets/custom_avatar.dart';
10 | import '../../../JobDetails/controllers/job_details_controller.dart';
11 |
12 | class Header extends GetView {
13 | const Header({
14 | Key? key,
15 | required this.profile,
16 | }) : super(key: key);
17 | final CustomerProfileOutDto profile;
18 |
19 | @override
20 | Widget build(BuildContext context) {
21 | return Container(
22 | padding: EdgeInsets.only(right: 16.w, left: 16.w, top: 30.h),
23 | decoration: const BoxDecoration(
24 | image: DecorationImage(
25 | image: Svg('assets/header_bg.svg', color: Colors.white),
26 | fit: BoxFit.cover,
27 | ),
28 | ),
29 | child: Padding(
30 | padding: EdgeInsets.only(top: 30.h),
31 | child: Column(
32 | children: [
33 | CustomAvatar(imageUrl: "${ApiRoutes.BASE_URL}${profile.image}"),
34 | SizedBox(height: 5.h),
35 | Text(
36 | profile.name!,
37 | style: GoogleFonts.poppins(
38 | fontSize: 16.sp,
39 | fontWeight: FontWeight.w600,
40 | color: Get.theme.colorScheme.onPrimary,
41 | ),
42 | ),
43 | Text(
44 | profile.jobTitle!,
45 | style: GoogleFonts.poppins(
46 | fontSize: 13.sp,
47 | fontWeight: FontWeight.w400,
48 | color: Get.theme.colorScheme.onPrimary,
49 | ),
50 | ),
51 | ],
52 | ),
53 | ),
54 | );
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/lib/app/modules/customerProfile/views/widgets/languages.dart:
--------------------------------------------------------------------------------
1 | import 'package:expandable/expandable.dart';
2 | import 'package:flutter/material.dart';
3 | import 'package:heroicons/heroicons.dart';
4 |
5 | import '../../../../widgets/custom_info_card.dart';
6 | import 'wrapped_chips.dart';
7 |
8 | class Languages extends StatelessWidget {
9 | const Languages({
10 | Key? key,
11 | required this.languages,
12 | }) : super(key: key);
13 | final List? languages;
14 |
15 | @override
16 | Widget build(BuildContext context) {
17 | final List shortLanguages = List.from(languages!);
18 | if (languages!.length > 6) {
19 | shortLanguages.removeRange(6, languages!.length);
20 | shortLanguages.add('+${languages!.length - shortLanguages.length} more');
21 | }
22 | return languages == null || languages!.isEmpty
23 | ? const SizedBox()
24 | : CustomInfoCard(
25 | icon: HeroIcons.language,
26 | title: "Languages",
27 | child: ExpandableNotifier(
28 | child: Expandable(
29 | collapsed: ExpandableButton(
30 | child: WrappedChips(list: shortLanguages),
31 | ),
32 | expanded: ExpandableButton(
33 | child: WrappedChips(list: languages!),
34 | ),
35 | ),
36 | ),
37 | );
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/lib/app/modules/customerProfile/views/widgets/skills.dart:
--------------------------------------------------------------------------------
1 | import 'package:expandable/expandable.dart';
2 | import 'package:flutter/material.dart';
3 | import 'package:heroicons/heroicons.dart';
4 |
5 | import '../../../../widgets/custom_info_card.dart';
6 | import 'wrapped_chips.dart';
7 |
8 | class Skills extends StatelessWidget {
9 | const Skills({
10 | Key? key,
11 | required this.skills,
12 | }) : super(key: key);
13 | final List? skills;
14 |
15 | @override
16 | Widget build(BuildContext context) {
17 | final List shortSkills = List.from(skills!);
18 | if (skills!.length > 4) {
19 | shortSkills.removeRange(4, skills!.length);
20 | shortSkills.add('+${skills!.length - shortSkills.length} more');
21 | }
22 | return skills == null || skills!.isEmpty
23 | ? const SizedBox()
24 | : CustomInfoCard(
25 | icon: HeroIcons.sparkles,
26 | title: "Skills",
27 | child: ExpandableNotifier(
28 | child: Expandable(
29 | collapsed: ExpandableButton(
30 | child: WrappedChips(list: shortSkills),
31 | ),
32 | expanded: ExpandableButton(
33 | child: WrappedChips(list: skills!),
34 | ),
35 | ),
36 | ),
37 | );
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/lib/app/modules/customerProfile/views/widgets/wrapped_chips.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_screenutil/flutter_screenutil.dart';
3 | import 'package:get/get.dart';
4 | import 'package:google_fonts/google_fonts.dart';
5 |
6 | class WrappedChips extends StatelessWidget {
7 | const WrappedChips({
8 | Key? key,
9 | required this.list,
10 | }) : super(key: key);
11 | final List list;
12 |
13 | @override
14 | Widget build(BuildContext context) {
15 | return Wrap(
16 | children: List.generate(
17 | list.length,
18 | (index) => Padding(
19 | padding: EdgeInsets.all(4.w),
20 | child: Chip(
21 | shape: RoundedRectangleBorder(
22 | borderRadius: BorderRadius.circular(10.r),
23 | ),
24 | backgroundColor: Get.theme.colorScheme.background,
25 | labelPadding: EdgeInsets.all(8.w),
26 | label: Text(
27 | list[index],
28 | style: GoogleFonts.poppins(
29 | fontSize: 13.sp,
30 | fontWeight: FontWeight.w400,
31 | color: Get.theme.colorScheme.secondary,
32 | ),
33 | ),
34 | ),
35 | ),
36 | ),
37 | );
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/lib/app/modules/home/bindings/home_binding.dart:
--------------------------------------------------------------------------------
1 | import 'package:get/get.dart';
2 |
3 | import '../controllers/home_controller.dart';
4 |
5 | class HomeBinding extends Bindings {
6 | @override
7 | void dependencies() {
8 | Get.lazyPut(
9 | () => HomeController(),
10 | );
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/lib/app/modules/home/views/home_view.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_screenutil/flutter_screenutil.dart';
3 | import 'package:get/get.dart';
4 |
5 | import '../../../data/remote/api/api_routes.dart';
6 | import '../../../widgets/custom_appbar.dart';
7 | import '../../../widgets/custom_avatar.dart';
8 | import '../controllers/home_controller.dart';
9 | import 'widgets/body.dart';
10 |
11 | class HomeView extends GetView {
12 | const HomeView({Key? key}) : super(key: key);
13 |
14 | @override
15 | Widget build(BuildContext context) {
16 | return SafeArea(
17 | child: Scaffold(
18 | backgroundColor: Get.theme.backgroundColor,
19 | appBar: CustomAppBar(
20 | leading: Padding(
21 | padding: EdgeInsets.only(left: 16.w, bottom: 8.w, top: 8.w),
22 | child: GestureDetector(
23 | onTap: () => Scaffold.of(context).openDrawer(),
24 | child: Obx(
25 | () => controller.customerAvatar.when(
26 | idle: () => const SizedBox(),
27 | loading: () => const SizedBox(),
28 | success: (data) => CustomAvatar(
29 | imageUrl: "${ApiRoutes.BASE_URL}$data",
30 | height: 46.h,
31 | ),
32 | failure: (error) => const SizedBox(),
33 | ),
34 | ),
35 | ),
36 | ),
37 | title: "Job Finder",
38 | ),
39 | body: const Body(),
40 | ),
41 | );
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/lib/app/modules/home/views/widgets/body.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_screenutil/flutter_screenutil.dart';
3 | import 'package:get/get.dart';
4 |
5 | import '../../controllers/home_controller.dart';
6 | import 'chips_list.dart';
7 | import 'featured_jobs.dart';
8 | import 'recent_jobs.dart';
9 |
10 | class Body extends GetView {
11 | const Body({Key? key}) : super(key: key);
12 |
13 | @override
14 | Widget build(BuildContext context) {
15 | return SingleChildScrollView(
16 | controller: controller.homeScrollController,
17 | child: Column(
18 | children: [
19 | SizedBox(height: 16.h),
20 | const ChipsList(),
21 | SizedBox(height: 16.h),
22 | const FeaturedJobs(),
23 | SizedBox(height: 16.h),
24 | const RecentJobs(),
25 | ],
26 | ),
27 | );
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/lib/app/modules/home/views/widgets/chips_list.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_screenutil/flutter_screenutil.dart';
3 | import 'package:get/get.dart';
4 |
5 | import '../../../../widgets/custom_chip.dart';
6 | import '../../../../widgets/shimmer/chips_shimmer.dart';
7 | import '../../controllers/home_controller.dart';
8 |
9 | class ChipsList extends GetView {
10 | const ChipsList({Key? key}) : super(key: key);
11 |
12 | @override
13 | Widget build(BuildContext context) {
14 | return SizedBox(
15 | height: 0.1.sw,
16 | child: Obx(
17 | () => controller.positions.when(
18 | idle: () => Container(),
19 | loading: () => const ChipsShimmer(),
20 | success: (positions) => ListView.builder(
21 | itemCount: positions!.length,
22 | padding: EdgeInsets.only(left: 16.w),
23 | scrollDirection: Axis.horizontal,
24 | shrinkWrap: true,
25 | itemBuilder: (context, index) => Obx(
26 | () => CustomChip(
27 | title: positions[index].jobTitle!,
28 | isActive: positions[index].jobTitle == controller.chipTitle,
29 | onPressed: () =>
30 | controller.updateChipTitle(positions[index].jobTitle!),
31 | ),
32 | ),
33 | ),
34 | failure: (e) => const ChipsShimmer(),
35 | ),
36 | ),
37 | );
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/lib/app/modules/root/bindings/root_binding.dart:
--------------------------------------------------------------------------------
1 | import 'package:get/get.dart';
2 |
3 | import '../../home/controllers/home_controller.dart';
4 | import '../../saved/controllers/saved_controller.dart';
5 | import '../../search/controllers/search_controller.dart';
6 | import '../controllers/root_controller.dart';
7 |
8 | class RootBinding extends Bindings {
9 | @override
10 | void dependencies() {
11 | Get.lazyPut(() => RootController());
12 | Get.put(HomeController());
13 | Get.put(SearchController());
14 | Get.put(SavedController());
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/lib/app/modules/root/controllers/root_controller.dart:
--------------------------------------------------------------------------------
1 | import 'package:get/get.dart';
2 | import 'package:persistent_bottom_nav_bar_v2/persistent-tab-view.dart';
3 |
4 | import '../../../widgets/dialogs.dart';
5 | import '../../auth/controllers/auth_controller.dart';
6 | import '../../home/controllers/home_controller.dart';
7 | import '../../saved/controllers/saved_controller.dart';
8 | import '../../search/controllers/search_controller.dart';
9 |
10 | class RootController extends GetxController {
11 | static RootController get to => Get.find();
12 | final persistentTabController = PersistentTabController(initialIndex: 0);
13 |
14 | @override
15 | void onInit() {
16 | super.onInit();
17 | }
18 |
19 | @override
20 | void onReady() {
21 | super.onReady();
22 | }
23 |
24 | @override
25 | void onClose() {
26 | super.onClose();
27 | persistentTabController.dispose();
28 | }
29 |
30 | void onHomeDoubleClick() {
31 | HomeController.to.animateToStart();
32 | }
33 |
34 | void onSearchDoubleClick() {
35 | SearchController.to.clearSearch();
36 | }
37 |
38 | void onSavedDoubleClick() {
39 | SavedController.to.animateToStart();
40 | }
41 |
42 | void logout() {
43 | Dialogs.warningDialog(
44 | title: "You are about to logout",
45 | btnOkText: "Logout",
46 | btnOkOnPress: AuthController.to.logout,
47 | );
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/lib/app/modules/saved/bindings/saved_binding.dart:
--------------------------------------------------------------------------------
1 | import 'package:get/get.dart';
2 |
3 | import '../controllers/saved_controller.dart';
4 |
5 | class SavedBinding extends Bindings {
6 | @override
7 | void dependencies() {
8 | Get.lazyPut(
9 | () => SavedController(),
10 | );
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/lib/app/modules/saved/views/saved_view.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:get/get.dart';
3 | import 'package:jobs_flutter_app/app/modules/saved/views/widgets/body.dart';
4 | import 'package:jobs_flutter_app/app/widgets/custom_appbar.dart';
5 | import '../controllers/saved_controller.dart';
6 |
7 | class SavedView extends GetView {
8 | const SavedView({Key? key}) : super(key: key);
9 |
10 | @override
11 | Widget build(BuildContext context) {
12 | return SafeArea(
13 | child: Scaffold(
14 | backgroundColor: Get.theme.backgroundColor,
15 | appBar: const CustomAppBar(title: "Saved Jobs"),
16 | body: const Body(),
17 | ),
18 | );
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/lib/app/modules/saved/views/widgets/body.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:get/get.dart';
3 |
4 | import '../../../../widgets/custom_lottie.dart';
5 | import '../../../../widgets/shimmer/recent_jobs_shimmer.dart';
6 | import '../../controllers/saved_controller.dart';
7 | import 'no_saving.dart';
8 | import 'saved_jobs.dart';
9 |
10 | class Body extends GetView {
11 | const Body({Key? key}) : super(key: key);
12 |
13 | @override
14 | Widget build(BuildContext context) {
15 | return Obx(
16 | () => Center(
17 | child: controller.savedJobs.when(
18 | idle: () => const RecentJobsShimmer(),
19 | loading: () => const RecentJobsShimmer(),
20 | success: (data) {
21 | if (data!.isEmpty) return const NoSaving();
22 | return SavedJobs(jobs: data);
23 | },
24 | failure: (e) => CustomLottie(
25 | asset: "assets/space.json",
26 | repeat: true,
27 | title: e!,
28 | onTryAgain: controller.onRetry,
29 | ),
30 | ),
31 | ),
32 | );
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/lib/app/modules/saved/views/widgets/no_saving.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/cupertino.dart';
2 | import 'package:flutter/material.dart';
3 | import 'package:flutter_screenutil/flutter_screenutil.dart';
4 | import 'package:flutter_svg/svg.dart';
5 | import 'package:get/get.dart';
6 | import 'package:google_fonts/google_fonts.dart';
7 |
8 | import '../../../../core/values/strings.dart';
9 | import '../../../../widgets/custom_button.dart';
10 | import '../../controllers/saved_controller.dart';
11 |
12 | class NoSaving extends GetView {
13 | const NoSaving({Key? key}) : super(key: key);
14 |
15 | @override
16 | Widget build(BuildContext context) {
17 | return Column(
18 | mainAxisAlignment: MainAxisAlignment.center,
19 | children: [
20 | Text(
21 | 'No Saving',
22 | style: GoogleFonts.poppins(
23 | fontSize: 24.sp,
24 | fontWeight: FontWeight.w700,
25 | color: Get.theme.colorScheme.onBackground,
26 | ),
27 | ),
28 | SizedBox(height: 6.h),
29 | Text(
30 | AppStrings.noSaved,
31 | style: GoogleFonts.poppins(
32 | fontWeight: FontWeight.w400,
33 | fontSize: 14.sp,
34 | color: Get.theme.colorScheme.secondary),
35 | textAlign: TextAlign.center,
36 | ),
37 | SizedBox(height: 23.h),
38 | SvgPicture.asset(
39 | 'assets/empty_save.svg',
40 | height: 208.h,
41 | ),
42 | SizedBox(height: 80.h),
43 | Padding(
44 | padding: EdgeInsets.symmetric(horizontal: 80.w),
45 | child: CustomButton(
46 | title: "FIND A JOB",
47 | onTap: controller.jumpToHome,
48 | ),
49 | )
50 | ],
51 | );
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/lib/app/modules/saved/views/widgets/saved_jobs.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/cupertino.dart';
2 | import 'package:get/get.dart';
3 | import 'package:heroicons/heroicons.dart';
4 |
5 | import '../../../../data/remote/api/api_routes.dart';
6 | import '../../../../data/remote/dto/job/job_out_dto.dart';
7 | import '../../../../routes/app_pages.dart';
8 | import '../../../../widgets/custom_job_card.dart';
9 | import '../../controllers/saved_controller.dart';
10 |
11 | class SavedJobs extends GetView {
12 | const SavedJobs({
13 | Key? key,
14 | required this.jobs,
15 | }) : super(key: key);
16 | final List jobs;
17 |
18 | @override
19 | Widget build(BuildContext context) {
20 | return AnimatedList(
21 | key: controller.animatedListKey,
22 | initialItemCount: jobs.length,
23 | controller: controller.savedScrollController,
24 | scrollDirection: Axis.vertical,
25 | physics: const BouncingScrollPhysics(),
26 | itemBuilder: (context, index, animation) => CustomJobCard(
27 | avatar: "${ApiRoutes.BASE_URL}${jobs[index].company!.image}",
28 | companyName: jobs[index].company!.name!,
29 | employmentType: jobs[index].employmentType,
30 | jobPosition: jobs[index].position,
31 | location: jobs[index].location,
32 | actionIcon: HeroIcons.bookmark,
33 | isSaved: true,
34 | publishTime: jobs[index].createdAt!,
35 | workplace: jobs[index].workplace,
36 | description: jobs[index].description,
37 | onActionTap: (isSaved) =>
38 | controller.onSaveButtonTapped(isSaved, jobs[index].id!),
39 | onAvatarTap: () => Get.toNamed(
40 | Routes.COMPANY_PROFILE,
41 | arguments: jobs[index].company!.id,
42 | ),
43 | onTap: () => Get.toNamed(
44 | Routes.JOB_DETAILS,
45 | arguments: jobs[index].id,
46 | ),
47 | ),
48 | );
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/lib/app/modules/search/bindings/search_binding.dart:
--------------------------------------------------------------------------------
1 | import 'package:get/get.dart';
2 |
3 | import '../controllers/search_controller.dart';
4 |
5 | class SearchBinding extends Bindings {
6 | @override
7 | void dependencies() {
8 | Get.lazyPut(
9 | () => SearchController(),
10 | );
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/lib/app/modules/search/controllers/search_controller.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:get/get.dart';
3 |
4 | import '../../../data/remote/base/status.dart';
5 | import '../../../data/remote/dto/search/search_out_dto.dart';
6 | import '../../../data/remote/repositories/search/search_repository.dart';
7 | import '../../../di/locator.dart';
8 |
9 | class SearchController extends GetxController {
10 | static SearchController get to => Get.find();
11 | final _searchRepository = getIt.get();
12 | final searchController = TextEditingController();
13 |
14 | final Rx>> _rxResults =
15 | Rx>>(const Status.idle());
16 |
17 | Status> get rxResults => _rxResults.value;
18 |
19 | @override
20 | void onInit() {
21 | super.onInit();
22 | }
23 |
24 | @override
25 | void onReady() {
26 | super.onReady();
27 | }
28 |
29 | @override
30 | void onClose() {
31 | super.onClose();
32 | searchController.dispose();
33 | }
34 |
35 | getSearchResult() async {
36 | if (!searchController.text.isBlank!) {
37 | final Status> results =
38 | await _searchRepository.getAll(q: searchController.text.trim());
39 | _rxResults.value = results;
40 | }
41 | }
42 |
43 | clearSearch() {
44 | searchController.clear();
45 | _rxResults.value = const Status.idle();
46 | }
47 |
48 | void onRetry() {
49 | getSearchResult();
50 | }
51 |
52 | }
53 |
--------------------------------------------------------------------------------
/lib/app/modules/search/views/search_view.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:get/get.dart';
3 |
4 | import '../controllers/search_controller.dart';
5 | import 'widgets/body.dart';
6 |
7 | class SearchView extends GetView {
8 | const SearchView({Key? key}) : super(key: key);
9 |
10 | @override
11 | Widget build(BuildContext context) {
12 | return SafeArea(
13 | child: Scaffold(
14 | backgroundColor: Get.theme.backgroundColor,
15 | resizeToAvoidBottomInset: true,
16 | body: const Body(),
17 | ),
18 | );
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/lib/app/modules/search/views/widgets/body.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_screenutil/flutter_screenutil.dart';
3 | import 'package:get/get.dart';
4 | import 'package:heroicons/heroicons.dart';
5 | import 'package:jobs_flutter_app/app/core/values/strings.dart';
6 |
7 | import '../../../../widgets/custom_text_field.dart';
8 | import '../../controllers/search_controller.dart';
9 | import 'search_items.dart';
10 |
11 | class Body extends GetView {
12 | const Body({Key? key}) : super(key: key);
13 |
14 | @override
15 | Widget build(BuildContext context) {
16 | return Padding(
17 | padding: EdgeInsets.symmetric(horizontal: 16.w),
18 | child: Column(
19 | children: [
20 | SizedBox(height: 30.h),
21 | CustomTextField(
22 | controller: controller.searchController,
23 | autofocus: false,
24 | hintText: AppStrings.SEARCH_HINT,
25 | isSearchBar: true,
26 | maxLines: 1,
27 | prefixIcon: HeroIcons.magnifyingGlass,
28 | suffixIcon: HeroIcons.xMark,
29 | onChanged: (_) => controller.getSearchResult(),
30 | onSuffixTap: () => controller.clearSearch(),
31 | ),
32 | SizedBox(height: 20.h),
33 | const Expanded(child: SearchResults()),
34 | ],
35 | ),
36 | );
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/lib/app/modules/search/views/widgets/items_card.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_screenutil/flutter_screenutil.dart';
3 | import 'package:get/get.dart';
4 | import 'package:google_fonts/google_fonts.dart';
5 | import 'package:jobs_flutter_app/app/widgets/custom_avatar.dart';
6 |
7 | class SearchItem extends StatelessWidget {
8 | const SearchItem({
9 | Key? key,
10 | required this.avatar,
11 | required this.title,
12 | required this.subtitle,
13 | required this.onTap,
14 | }) : super(key: key);
15 | final String avatar;
16 | final String title;
17 | final String subtitle;
18 | final void Function() onTap;
19 |
20 | @override
21 | Widget build(BuildContext context) {
22 | return GestureDetector(
23 | onTap: onTap,
24 | child: Container(
25 | padding: EdgeInsets.symmetric(horizontal: 8.w, vertical: 8.h),
26 | decoration: BoxDecoration(
27 | color: Colors.white,
28 | borderRadius: BorderRadius.circular(14.r),
29 | ),
30 | child: Row(
31 | children: [
32 | CustomAvatar(
33 | imageUrl: avatar,
34 | height: 35.h,
35 | ),
36 | Padding(
37 | padding: EdgeInsets.only(left: 10.w),
38 | child: Column(
39 | crossAxisAlignment: CrossAxisAlignment.start,
40 | children: [
41 | Text(
42 | title,
43 | style: GoogleFonts.poppins(
44 | fontSize: 14.sp,
45 | fontWeight: FontWeight.w400,
46 | ),
47 | ),
48 | Text(
49 | subtitle,
50 | style: GoogleFonts.poppins(
51 | fontSize: 13.sp,
52 | color: Get.theme.colorScheme.secondary.withOpacity(0.75),
53 | ),
54 | )
55 | ],
56 | ),
57 | )
58 | ],
59 | ),
60 | ),
61 | );
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/lib/app/modules/search/views/widgets/search_items.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_screenutil/flutter_screenutil.dart';
3 | import 'package:get/get.dart';
4 | import 'package:jobs_flutter_app/app/core/values/strings.dart';
5 |
6 | import '../../../../routes/app_pages.dart';
7 | import '../../../../data/remote/api/api_routes.dart';
8 | import '../../../../widgets/custom_lottie.dart';
9 | import '../../controllers/search_controller.dart';
10 | import 'items_card.dart';
11 |
12 | class SearchResults extends GetView {
13 | const SearchResults({Key? key}) : super(key: key);
14 |
15 | @override
16 | Widget build(BuildContext context) {
17 | return Obx(
18 | () => controller.rxResults.when(
19 | idle: () => Container(),
20 | loading: () => const Center(child: CircularProgressIndicator()),
21 | success: (results) => results!.isEmpty
22 | ? CustomLottie(
23 | title: AppStrings.NO_RESULT,
24 | asset: "assets/empty.json",
25 | description:AppStrings.NO_RESULT_DES,
26 | assetHeight: 200.h,
27 | )
28 | : ListView.builder(
29 | itemCount: results.length,
30 | shrinkWrap: true,
31 | scrollDirection: Axis.vertical,
32 | physics: const BouncingScrollPhysics(),
33 | itemBuilder: (context, index) => Padding(
34 | padding: EdgeInsets.only(bottom: 16.h),
35 | child: SearchItem(
36 | avatar: "${ApiRoutes.BASE_URL}${results[index].image}",
37 | title: results[index].name!,
38 | subtitle: "Internet company",
39 | onTap: () => Get.toNamed(Routes.COMPANY_PROFILE,
40 | arguments: results[index].id!),
41 | ),
42 | ),
43 | ),
44 | failure: (e) => CustomLottie(
45 | asset: "assets/space.json",
46 | title: e!,
47 | onTryAgain: controller.onRetry,
48 | ),
49 | ),
50 | );
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/lib/app/modules/waiting/bindings/waiting_binding.dart:
--------------------------------------------------------------------------------
1 | import 'package:get/get.dart';
2 |
3 | import '../controllers/waiting_controller.dart';
4 |
5 | class WaitingBinding extends Bindings {
6 | @override
7 | void dependencies() {
8 | Get.lazyPut(
9 | () => WaitingController(),
10 | );
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/lib/app/modules/waiting/controllers/waiting_controller.dart:
--------------------------------------------------------------------------------
1 | import 'package:get/get.dart';
2 |
3 | class WaitingController extends GetxController {
4 | //TODO: Implement WaitingController
5 |
6 | final count = 0.obs;
7 | @override
8 | void onInit() {
9 | super.onInit();
10 | }
11 |
12 | @override
13 | void onReady() {
14 | super.onReady();
15 | }
16 |
17 | @override
18 | void onClose() {
19 | super.onClose();
20 | }
21 |
22 | void increment() => count.value++;
23 | }
24 |
--------------------------------------------------------------------------------
/lib/app/modules/waiting/views/waiting_view.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | import 'package:get/get.dart';
4 |
5 | import '../controllers/waiting_controller.dart';
6 | import 'widgets/body.dart';
7 |
8 | class WaitingView extends GetView {
9 | const WaitingView({Key? key}) : super(key: key);
10 |
11 | @override
12 | Widget build(BuildContext context) {
13 | return SafeArea(
14 | child: Scaffold(
15 | backgroundColor: Get.theme.backgroundColor,
16 | body: const Body(),
17 | ),
18 | );
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/lib/app/modules/waiting/views/widgets/body.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter/services.dart';
3 | import 'package:flutter_screenutil/flutter_screenutil.dart';
4 | import 'package:get/get.dart';
5 | import 'package:google_fonts/google_fonts.dart';
6 |
7 | import '../../../../core/values/strings.dart';
8 | import '../../../../widgets/custom_button.dart';
9 |
10 | class Body extends StatelessWidget {
11 | const Body({Key? key}) : super(key: key);
12 |
13 | @override
14 | Widget build(BuildContext context) {
15 | return Padding(
16 | padding: EdgeInsets.all(29.w),
17 | child: Column(
18 | mainAxisAlignment: MainAxisAlignment.center,
19 | children: [
20 | Text(
21 | AppStrings.thankYou,
22 | style: GoogleFonts.poppins(
23 | fontSize: 40.sp,
24 | fontWeight: FontWeight.w700,
25 | color: Get.theme.colorScheme.onBackground,
26 | ),
27 | ),
28 | Text(
29 | AppStrings.forYourSubmission,
30 | style: GoogleFonts.poppins(
31 | fontWeight: FontWeight.w400,
32 | fontSize: 20.sp,
33 | color: Get.theme.colorScheme.secondary,
34 | ),
35 | ),
36 | SizedBox(height: 5.h),
37 | Text(
38 | AppStrings.willGetInTouch,
39 | style: GoogleFonts.poppins(
40 | fontSize: 14.sp,
41 | fontWeight: FontWeight.w400,
42 | color: Get.theme.colorScheme.secondary,
43 | ),
44 | ),
45 | SizedBox(height: 100.h),
46 | CustomButton(
47 | title: AppStrings.exit,
48 | onTap: () => SystemNavigator.pop(),
49 | ),
50 | ],
51 | ),
52 | );
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/lib/app/routes/app_pages.dart:
--------------------------------------------------------------------------------
1 | import 'package:get/get.dart';
2 |
3 | import '../modules/JobDetails/bindings/job_details_binding.dart';
4 | import '../modules/JobDetails/views/job_details_view.dart';
5 | import '../modules/auth/bindings/auth_binding.dart';
6 | import '../modules/auth/views/login/login_view.dart';
7 | import '../modules/auth/views/register/register_view.dart';
8 | import '../modules/companyProfile/bindings/company_profile_binding.dart';
9 | import '../modules/companyProfile/views/company_profile_view.dart';
10 | import '../modules/customerProfile/bindings/customer_profile_binding.dart';
11 | import '../modules/customerProfile/views/customer_profile_view.dart';
12 | import '../modules/home/bindings/home_binding.dart';
13 | import '../modules/home/views/home_view.dart';
14 | import '../modules/root/bindings/root_binding.dart';
15 | import '../modules/root/views/root_view.dart';
16 | import '../modules/saved/bindings/saved_binding.dart';
17 | import '../modules/saved/views/saved_view.dart';
18 | import '../modules/search/bindings/search_binding.dart';
19 | import '../modules/search/views/search_view.dart';
20 | import '../modules/waiting/bindings/waiting_binding.dart';
21 | import '../modules/waiting/views/waiting_view.dart';
22 |
23 | part 'app_routes.dart';
24 |
25 | class AppPages {
26 | AppPages._();
27 |
28 | static const INITIAL = Routes.LOGIN;
29 |
30 | static final routes = [
31 | GetPage(
32 | name: _Paths.HOME,
33 | page: () => const HomeView(),
34 | binding: HomeBinding(),
35 | ),
36 | GetPage(
37 | name: _Paths.LOGIN,
38 | page: () => const LoginView(),
39 | binding: AuthBinding(),
40 | ),
41 | GetPage(
42 | name: _Paths.REGISTER,
43 | page: () => const RegisterView(),
44 | binding: AuthBinding(),
45 | ),
46 | GetPage(
47 | name: _Paths.WAITTING,
48 | page: () => const WaitingView(),
49 | binding: WaitingBinding(),
50 | ),
51 | GetPage(
52 | name: _Paths.SEARCH,
53 | page: () => const SearchView(),
54 | binding: SearchBinding(),
55 | ),
56 | GetPage(
57 | name: _Paths.SAVED,
58 | page: () => const SavedView(),
59 | binding: SavedBinding(),
60 | ),
61 | GetPage(
62 | name: _Paths.COMPANY_PROFILE,
63 | page: () => const CompanyProfileView(),
64 | binding: CompanyProfileBinding(),
65 | ),
66 | GetPage(
67 | name: _Paths.JOB_DETAILS,
68 | page: () => const JobDetailsView(),
69 | binding: JobDetailsBinding(),
70 | ),
71 | GetPage(
72 | name: _Paths.ROOT,
73 | page: () => const RootView(),
74 | binding: RootBinding(),
75 | ),
76 | GetPage(
77 | name: _Paths.CUSTOMER_PROFILE,
78 | page: () => const CustomerProfileView(),
79 | binding: CustomerProfileBinding(),
80 | ),
81 | ];
82 | }
83 |
--------------------------------------------------------------------------------
/lib/app/routes/app_routes.dart:
--------------------------------------------------------------------------------
1 | part of 'app_pages.dart';
2 |
3 | abstract class Routes {
4 | Routes._();
5 |
6 | static const HOME = _Paths.HOME;
7 | static const LOGIN = _Paths.LOGIN;
8 | static const REGISTER = _Paths.REGISTER;
9 | static const WAITTING = _Paths.WAITTING;
10 | static const SEARCH = _Paths.SEARCH;
11 | static const SAVED = _Paths.SAVED;
12 | static const COMPANY_PROFILE = _Paths.COMPANY_PROFILE;
13 | static const JOB_DETAILS = _Paths.JOB_DETAILS;
14 | static const ROOT = _Paths.ROOT;
15 | static const CUSTOMER_PROFILE = _Paths.CUSTOMER_PROFILE;
16 | }
17 |
18 | abstract class _Paths {
19 | _Paths._();
20 |
21 | static const HOME = '/home';
22 | static const LOGIN = '/login';
23 | static const REGISTER = '/register';
24 | static const WAITTING = '/waiting';
25 | static const SEARCH = '/search';
26 | static const SAVED = '/saved';
27 | static const COMPANY_PROFILE = '/company-profile';
28 | static const JOB_DETAILS = '/job_details';
29 | static const ROOT = '/root';
30 | static const CUSTOMER_PROFILE = '/customer-profile';
31 | }
32 |
--------------------------------------------------------------------------------
/lib/app/utils/extensions.dart:
--------------------------------------------------------------------------------
1 | import 'package:intl/intl.dart';
2 |
3 | extension ToDataTime on String {
4 | DateTime toDateTime() {
5 | return DateTime.parse(this);
6 | }
7 | }
8 |
9 | extension ToShortDate on String {
10 | String toShortDate() {
11 | final format = DateFormat.yMMM().format(toDateTime());
12 | return format.toString();
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/lib/app/utils/functions.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter/services.dart';
3 | import 'package:flutter_screenutil/flutter_screenutil.dart';
4 | import 'package:get/get.dart';
5 |
6 | import '../widgets/custom_bottom_sheet.dart';
7 |
8 | popupBottomSheet({
9 | required Widget bottomSheetBody,
10 | bool? isDismissible,
11 | bool? enableDrag,
12 | }) {
13 | return Get.bottomSheet(
14 | CustomBottomSheet(body: bottomSheetBody),
15 | enableDrag: enableDrag ?? true,
16 | isDismissible: isDismissible ?? true,
17 | shape: RoundedRectangleBorder(
18 | borderRadius: BorderRadius.only(
19 | topRight: Radius.circular(22.r),
20 | topLeft: Radius.circular(22.r),
21 | ),
22 | ),
23 | isScrollControlled: true,
24 | backgroundColor: Colors.white,
25 | );
26 | }
27 |
28 | void setDefaultStatusBarColor() {
29 | SystemChrome.setSystemUIOverlayStyle(
30 | const SystemUiOverlayStyle(
31 | statusBarColor: Colors.transparent,
32 | statusBarIconBrightness: Brightness.dark,
33 | systemNavigationBarColor: Colors.white,
34 | systemNavigationBarIconBrightness: Brightness.dark,
35 | ),
36 | );
37 | }
38 |
--------------------------------------------------------------------------------
/lib/app/utils/validators.dart:
--------------------------------------------------------------------------------
1 | import 'package:form_field_validator/form_field_validator.dart';
2 |
3 | class Validators {
4 | static final name = MultiValidator([
5 | RequiredValidator(errorText: "This field is required!"),
6 | MaxLengthValidator(150, errorText: "Max length is 150"),
7 | MinLengthValidator(2, errorText: "Name is too short!")
8 | ]);
9 |
10 | static final phoneNumber = MultiValidator([
11 | RequiredValidator(errorText: "This field is required!"),
12 | ]);
13 |
14 | static final email = MultiValidator([
15 | RequiredValidator(errorText: "This field is required!"),
16 | EmailValidator(errorText: "Provide valid email.")
17 | ]);
18 |
19 | static final password = MultiValidator([
20 | RequiredValidator(errorText: "This field is required!"),
21 | MinLengthValidator(8, errorText: "Required 6 digitalis at least.")
22 | ]);
23 |
24 | static final address = MultiValidator([
25 | RequiredValidator(errorText: "This field is required!"),
26 | MinLengthValidator(3, errorText: "Address is too short!")
27 | ]);
28 | }
29 |
--------------------------------------------------------------------------------
/lib/app/widgets/custom_appbar.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter/services.dart';
3 | import 'package:flutter_screenutil/flutter_screenutil.dart';
4 | import 'package:get/get.dart';
5 | import 'package:google_fonts/google_fonts.dart';
6 |
7 | class CustomAppBar extends StatelessWidget with PreferredSizeWidget {
8 | const CustomAppBar({
9 | Key? key,
10 | this.leading,
11 | this.title,
12 | this.actions,
13 | this.backgroundColor,
14 | }) : super(key: key);
15 | final Widget? leading;
16 | final List? actions;
17 | final String? title;
18 | final Color? backgroundColor;
19 |
20 | @override
21 | Widget build(BuildContext context) {
22 | return AppBar(
23 | backgroundColor: backgroundColor ?? Colors.transparent,
24 | scrolledUnderElevation: 0,
25 | elevation: 0.0,
26 | leading: leading,
27 | title: title != null
28 | ? Text(
29 | title!,
30 | style: GoogleFonts.poppins(
31 | fontSize: 18.sp,
32 | fontWeight: FontWeight.w700,
33 | color: Get.theme.colorScheme.onBackground,
34 | ),
35 | )
36 | : null,
37 | centerTitle: true,
38 | actions: actions,
39 | );
40 | }
41 |
42 | @override
43 | Size get preferredSize => const Size.fromHeight(kToolbarHeight);
44 | }
45 |
--------------------------------------------------------------------------------
/lib/app/widgets/custom_avatar.dart:
--------------------------------------------------------------------------------
1 | import 'package:cached_network_image/cached_network_image.dart';
2 | import 'package:flutter/material.dart';
3 | import 'package:flutter_screenutil/flutter_screenutil.dart';
4 | import 'package:heroicons/heroicons.dart';
5 |
6 | class CustomAvatar extends StatelessWidget {
7 | const CustomAvatar({
8 | Key? key,
9 | required this.imageUrl,
10 | this.height,
11 | this.radius,
12 | }) : super(key: key);
13 | final String imageUrl;
14 | final double? height;
15 | final double? radius;
16 |
17 | @override
18 | Widget build(BuildContext context) {
19 | return CachedNetworkImage(
20 | imageUrl: imageUrl,
21 | height: height ?? 80.h,
22 | fit: BoxFit.contain,
23 | imageBuilder: (context, imageProvider) => ClipRRect(
24 | borderRadius: BorderRadius.circular(radius ?? 10000),
25 | child: Container(
26 | height: height ?? 80.h,
27 | width: height ?? 80.h,
28 | decoration: BoxDecoration(
29 | image: DecorationImage(
30 | image: imageProvider,
31 | fit: BoxFit.contain,
32 | ),
33 | ),
34 | ),
35 | ),
36 | placeholder: (context, url) => Container(
37 | height: height ?? 80.h,
38 | width: height ?? 80.h,
39 | decoration: BoxDecoration(
40 | shape: BoxShape.circle,
41 | color: Colors.grey[300],
42 | ),
43 | child: const Center(
44 | child: CircularProgressIndicator(),
45 | ),
46 | ),
47 | errorWidget: (context, url, error) => Container(
48 | height: height ?? 80.h,
49 | width: height ?? 80.h,
50 | decoration: BoxDecoration(
51 | shape: BoxShape.circle,
52 | color: Colors.grey[300],
53 | ),
54 | child: Center(
55 | child: HeroIcon(
56 | HeroIcons.exclamationCircle,
57 | color: Colors.grey[500],
58 | size: 0.5 * (height ?? 80.h),
59 | ),
60 | ),
61 | ),
62 | );
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/lib/app/widgets/custom_bottom_sheet.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_screenutil/flutter_screenutil.dart';
3 | import 'package:get/get.dart';
4 |
5 | class CustomBottomSheet extends StatelessWidget {
6 | const CustomBottomSheet({Key? key, required this.body}) : super(key: key);
7 | final Widget body;
8 |
9 | @override
10 | Widget build(BuildContext context) {
11 | return Padding(
12 | padding: EdgeInsets.only(
13 | bottom: Get.mediaQuery.viewInsets.bottom,
14 | left: 29.w,
15 | right: 29.w,
16 | ),
17 | child: Column(
18 | mainAxisSize: MainAxisSize.min,
19 | children: [
20 | Container(
21 | margin: EdgeInsets.only(top: 28.h, bottom: 50.h),
22 | width: 30.w,
23 | height: 4.h,
24 | decoration: BoxDecoration(
25 | borderRadius: BorderRadius.circular(22.r),
26 | color: Get.theme.colorScheme.onBackground,
27 | ),
28 | ),
29 | body,
30 | SizedBox(height: 50.h)
31 | ],
32 | ),
33 | );
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/lib/app/widgets/custom_button.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_screenutil/flutter_screenutil.dart';
3 | import 'package:get/get.dart';
4 |
5 | class CustomButton extends StatelessWidget {
6 | CustomButton({
7 | Key? key,
8 | required this.title,
9 | required this.onTap,
10 | }) : super(key: key);
11 | final String title;
12 | final Future Function() onTap;
13 |
14 | final RxBool _isLoading = false.obs;
15 |
16 | @override
17 | Widget build(BuildContext context) {
18 | return Obx(
19 | () => SizedBox(
20 | width: double.infinity,
21 | child: ElevatedButton(
22 | onPressed: _isLoading.value
23 | ? null
24 | : () async {
25 | _isLoading.value = true;
26 | await onTap();
27 | _isLoading.value = false;
28 | },
29 | style: Get.theme.elevatedButtonTheme.style,
30 | child: FittedBox(
31 | child: _isLoading.value
32 | ? SizedBox(
33 | height: 20.h,
34 | width: 20.h,
35 | child: const CircularProgressIndicator(color: Colors.white),
36 | )
37 | : Text(title),
38 | ),
39 | ),
40 | ),
41 | );
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/lib/app/widgets/custom_chip.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_screenutil/flutter_screenutil.dart';
3 | import 'package:get/get.dart';
4 | import 'package:google_fonts/google_fonts.dart';
5 |
6 | class CustomChip extends StatelessWidget {
7 | const CustomChip({
8 | Key? key,
9 | required this.title,
10 | this.isActive = false,
11 | required this.onPressed,
12 | }) : super(key: key);
13 | final String title;
14 | final bool isActive;
15 | final void Function() onPressed;
16 |
17 | @override
18 | Widget build(BuildContext context) {
19 | return Container(
20 | margin: EdgeInsets.only(right: 6.w),
21 | child: ActionChip(
22 | padding: EdgeInsets.all(6.w),
23 | label: Text(title),
24 | labelStyle: GoogleFonts.poppins(
25 | fontSize: 13.sp,
26 | fontWeight: FontWeight.w500,
27 | color: isActive ? Colors.white : Get.theme.colorScheme.secondary,
28 | ),
29 | elevation: 0.0,
30 | side: BorderSide(
31 | color: isActive
32 | ? Get.theme.colorScheme.primary
33 | : Get.theme.colorScheme.secondary,
34 | width: 1.w),
35 | labelPadding: EdgeInsets.symmetric(vertical: 1.w, horizontal: 15.w),
36 | shape: RoundedRectangleBorder(
37 | borderRadius: BorderRadius.circular(14.r),
38 | ),
39 | onPressed: onPressed,
40 | backgroundColor: isActive
41 | ? Get.theme.colorScheme.primary
42 | : Get.theme.backgroundColor,
43 | ),
44 | );
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/lib/app/widgets/custom_info_card.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_screenutil/flutter_screenutil.dart';
3 | import 'package:get/get.dart';
4 | import 'package:google_fonts/google_fonts.dart';
5 | import 'package:heroicons/heroicons.dart';
6 |
7 | class CustomInfoCard extends StatelessWidget {
8 | const CustomInfoCard({
9 | Key? key,
10 | required this.child,
11 | required this.icon,
12 | required this.title,
13 | this.action,
14 | this.onActionTap,
15 | }) : super(key: key);
16 | final Widget child;
17 | final HeroIcons icon;
18 | final HeroIcons? action;
19 | final String title;
20 | final void Function()? onActionTap;
21 |
22 | @override
23 | Widget build(BuildContext context) {
24 | return Container(
25 | padding: EdgeInsets.all(20.w),
26 | margin: EdgeInsets.only(bottom: 16.h, right: 16.w, left: 16.w),
27 | decoration: BoxDecoration(
28 | borderRadius: BorderRadius.circular(14.r),
29 | color: Colors.white,
30 | boxShadow: [
31 | BoxShadow(
32 | color: Colors.grey.withOpacity(0.05),
33 | blurRadius: 20,
34 | offset: const Offset(0, 10),
35 | ),
36 | ],
37 | ),
38 | child: Column(
39 | crossAxisAlignment: CrossAxisAlignment.start,
40 | children: [
41 | Row(
42 | children: [
43 | HeroIcon(
44 | icon,
45 | color: Get.theme.colorScheme.primary,
46 | ),
47 | SizedBox(width: 10.w),
48 | Text(
49 | title,
50 | style: GoogleFonts.poppins(
51 | fontSize: 13.sp,
52 | fontWeight: FontWeight.w700,
53 | color: Get.theme.colorScheme.onBackground,
54 | ),
55 | ),
56 | const Spacer(),
57 | if (action != null)
58 | GestureDetector(
59 | onTap: onActionTap,
60 | child: HeroIcon(action!),
61 | )
62 | ],
63 | ),
64 | SizedBox(height: 10.h),
65 | Divider(
66 | color: Get.theme.colorScheme.background,
67 | thickness: 1.5,
68 | ),
69 | SizedBox(height: 10.h),
70 | child,
71 | ],
72 | ),
73 | );
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/lib/app/widgets/custom_lottie.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_screenutil/flutter_screenutil.dart';
3 | import 'package:get/get.dart';
4 | import 'package:google_fonts/google_fonts.dart';
5 | import 'package:lottie/lottie.dart';
6 |
7 | class CustomLottie extends StatelessWidget {
8 | const CustomLottie({
9 | Key? key,
10 | required this.title,
11 | this.onTryAgain,
12 | required this.asset,
13 | this.repeat = false,
14 | this.description,
15 | this.assetHeight,
16 | this.padding,
17 | this.titleStyle,
18 | this.descriptionStyle,
19 | }) : super(key: key);
20 | final String title;
21 | final String? description;
22 | final String asset;
23 | final bool repeat;
24 | final void Function()? onTryAgain;
25 | final double? assetHeight;
26 | final EdgeInsetsGeometry? padding;
27 | final TextStyle? titleStyle;
28 | final TextStyle? descriptionStyle;
29 |
30 | @override
31 | Widget build(BuildContext context) {
32 | return Center(
33 | child: Padding(
34 | padding: padding ?? const EdgeInsets.only(bottom: kToolbarHeight),
35 | child: Column(
36 | mainAxisAlignment: MainAxisAlignment.center,
37 | mainAxisSize: MainAxisSize.min,
38 | children: [
39 | LottieBuilder.asset(
40 | asset,
41 | height: assetHeight ?? 250.h,
42 | fit: BoxFit.contain,
43 | repeat: repeat,
44 | ),
45 | Text(
46 | title,
47 | style: titleStyle ??
48 | GoogleFonts.poppins(
49 | fontSize: 13.sp,
50 | color: Get.theme.colorScheme.secondary,
51 | fontWeight: FontWeight.w500,
52 | ),
53 | ),
54 | if (description != null) SizedBox(height: 5.w),
55 | if (description != null)
56 | Text(
57 | description!,
58 | textAlign: TextAlign.center,
59 | style: descriptionStyle ??
60 | GoogleFonts.poppins(
61 | color: Get.theme.colorScheme.tertiary,
62 | fontSize: 13.sp,
63 | fontWeight: FontWeight.w400,
64 | ),
65 | ),
66 | if (onTryAgain != null)
67 | TextButton(
68 | onPressed: onTryAgain,
69 | child: Text(
70 | "Try again",
71 | style: GoogleFonts.poppins(
72 | fontSize: 13.sp,
73 | fontWeight: FontWeight.w700,
74 | color: Get.theme.colorScheme.primary,
75 | ),
76 | ),
77 | ),
78 | ],
79 | ),
80 | ),
81 | );
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/lib/app/widgets/custom_tag.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_screenutil/flutter_screenutil.dart';
3 | import 'package:get/get.dart';
4 | import 'package:google_fonts/google_fonts.dart';
5 | import 'package:heroicons/heroicons.dart';
6 |
7 | class CustomTag extends StatelessWidget {
8 | const CustomTag({
9 | Key? key,
10 | required this.icon,
11 | required this.title,
12 | this.isFeatured = false,
13 | required this.titleColor,
14 | required this.backgroundColor,
15 | }) : super(key: key);
16 | final HeroIcons icon;
17 | final String title;
18 | final bool isFeatured;
19 | final Color titleColor;
20 | final Color backgroundColor;
21 |
22 | @override
23 | Widget build(BuildContext context) {
24 | return Container(
25 | margin: EdgeInsets.only(right: 6.w , top: 6.h),
26 | padding: EdgeInsets.all(8.w),
27 | decoration: BoxDecoration(
28 | color: backgroundColor,
29 | borderRadius: BorderRadius.circular(10.r),
30 | ),
31 | child: Row(
32 | crossAxisAlignment: CrossAxisAlignment.center,
33 | mainAxisSize: MainAxisSize.min,
34 | children: [
35 | HeroIcon(
36 | icon,
37 | color: titleColor,
38 | size: 15.w,
39 | ),
40 | SizedBox(width: 5.w),
41 | Text(
42 | title.capitalize!,
43 | style: GoogleFonts.poppins(
44 | fontSize: 12.sp,
45 | fontWeight: FontWeight.w500,
46 | color: titleColor,
47 | ),
48 | )
49 | ],
50 | ),
51 | );
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/lib/app/widgets/section_header.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_screenutil/flutter_screenutil.dart';
3 | import 'package:get/get.dart';
4 | import 'package:google_fonts/google_fonts.dart';
5 |
6 | class SectionHeader extends StatelessWidget {
7 | const SectionHeader({
8 | Key? key,
9 | required this.title,
10 | this.actionTitle,
11 | }) : super(key: key);
12 | final String title;
13 | final String? actionTitle;
14 |
15 | @override
16 | Widget build(BuildContext context) {
17 | return Padding(
18 | padding: EdgeInsets.symmetric(horizontal: 16.w),
19 | child: Row(
20 | mainAxisAlignment: MainAxisAlignment.spaceBetween,
21 | children: [
22 | Text(
23 | title,
24 | style: GoogleFonts.poppins(
25 | fontSize: 16.sp,
26 | fontWeight: FontWeight.w600,
27 | color: Get.theme.colorScheme.onBackground,
28 | ),
29 | ),
30 | if (actionTitle != null)
31 | Text(
32 | actionTitle!,
33 | style: GoogleFonts.poppins(
34 | fontSize: 13.sp,
35 | fontWeight: FontWeight.w400,
36 | color: Get.theme.colorScheme.secondary,
37 | ),
38 | ),
39 | ],
40 | ),
41 | );
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/lib/app/widgets/shimmer/chips_shimmer.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_screenutil/flutter_screenutil.dart';
3 |
4 | import 'shimmer_widget.dart';
5 |
6 | class ChipsShimmer extends StatelessWidget {
7 | const ChipsShimmer({Key? key}) : super(key: key);
8 |
9 | @override
10 | Widget build(BuildContext context) {
11 | return ListView.builder(
12 | itemCount: 8,
13 | padding: EdgeInsets.only(left: 16.w),
14 | scrollDirection: Axis.horizontal,
15 | shrinkWrap: true,
16 | itemBuilder: (context, index) => Container(
17 | margin: EdgeInsets.only(right: 6.w),
18 | child: ShimmerWidget(
19 | width: 100.w,
20 | height: 0.0,
21 | ),
22 | ),
23 | );
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/lib/app/widgets/shimmer/company_profile_shimmer.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_screenutil/flutter_screenutil.dart';
3 |
4 | import 'shimmer_widget.dart';
5 |
6 | class CompanyProfileShimmer extends StatelessWidget {
7 | const CompanyProfileShimmer({Key? key}) : super(key: key);
8 |
9 | @override
10 | Widget build(BuildContext context) {
11 | return SingleChildScrollView(
12 | child: Column(
13 | crossAxisAlignment: CrossAxisAlignment.start,
14 | children: [
15 | ShimmerWidget(
16 | width: double.infinity,
17 | height: 210.h,
18 | radius: 0,
19 | ),
20 | Container(
21 | padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 8.h),
22 | child: ShimmerWidget(
23 | width: double.infinity,
24 | height: 60.h,
25 | ),
26 | ),
27 | Column(
28 | children: List.generate(
29 | 4,
30 | (index) => ShimmerWidget(
31 | width: double.infinity,
32 | height: 150.h,
33 | margin: EdgeInsets.only(right: 16.w, left: 16.w, bottom: 16.h),
34 | ),
35 | ),
36 | )
37 | ],
38 | ),
39 | );
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/lib/app/widgets/shimmer/customer_profile_shimmer.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_screenutil/flutter_screenutil.dart';
3 |
4 | import 'shimmer_widget.dart';
5 |
6 | class CustomerProfileShimmer extends StatelessWidget {
7 | const CustomerProfileShimmer({Key? key}) : super(key: key);
8 |
9 | @override
10 | Widget build(BuildContext context) {
11 | return SingleChildScrollView(
12 | child: Column(
13 | crossAxisAlignment: CrossAxisAlignment.start,
14 | children: [
15 | ShimmerWidget(
16 | width: double.infinity,
17 | height: 210.h,
18 | radius: 0,
19 | margin: EdgeInsets.only(bottom: 8.h),
20 | ),
21 | Column(
22 | children: List.generate(
23 | 4,
24 | (index) => ShimmerWidget(
25 | width: double.infinity,
26 | height: 200.h,
27 | margin: EdgeInsets.symmetric(horizontal: 16.w, vertical: 8.h),
28 | ),
29 | ),
30 | )
31 | ],
32 | ),
33 | );
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/lib/app/widgets/shimmer/featured_job_shimmer.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_screenutil/flutter_screenutil.dart';
3 |
4 | import 'shimmer_widget.dart';
5 |
6 | class FeaturedJobShimmer extends StatelessWidget {
7 | const FeaturedJobShimmer({Key? key}) : super(key: key);
8 |
9 | @override
10 | Widget build(BuildContext context) {
11 | return Container(
12 | padding: EdgeInsets.all(16.w),
13 | child: ShimmerWidget(
14 | width: double.infinity,
15 | height: 170.h,
16 | ),
17 | );
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/lib/app/widgets/shimmer/job_details_shimmer.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_screenutil/flutter_screenutil.dart';
3 |
4 | import 'shimmer_widget.dart';
5 |
6 | class JobDetailsShimmer extends StatelessWidget {
7 | const JobDetailsShimmer({Key? key}) : super(key: key);
8 |
9 | @override
10 | Widget build(BuildContext context) {
11 | return SingleChildScrollView(
12 | child: Column(
13 | crossAxisAlignment: CrossAxisAlignment.start,
14 | children: [
15 | ShimmerWidget(
16 | width: double.infinity,
17 | height: 225.h,
18 | radius: 0,
19 | ),
20 | SizedBox(height: 20.h),
21 | ShimmerWidget(
22 | width: double.infinity,
23 | height: 300.h,
24 | margin: EdgeInsets.symmetric(horizontal: 16.w),
25 | ),
26 | ShimmerWidget(
27 | width: double.infinity,
28 | height: 100.h,
29 | margin: EdgeInsets.all(16.w),
30 | ),
31 | ShimmerWidget(
32 | width: 200.w,
33 | height: 20.h,
34 | margin: EdgeInsets.symmetric(horizontal: 16.w),
35 | ),
36 | SizedBox(height: 16.h),
37 | Padding(
38 | padding: EdgeInsets.symmetric(horizontal: 16.w),
39 | child: Column(
40 | crossAxisAlignment: CrossAxisAlignment.start,
41 | children: [
42 | SingleChildScrollView(
43 | scrollDirection: Axis.horizontal,
44 | physics: const BouncingScrollPhysics(),
45 | child: Row(
46 | children: List.generate(
47 | 2,
48 | (index) => ShimmerWidget(
49 | width: 0.65.sw,
50 | height: 200.h,
51 | margin: EdgeInsets.only(right: 16.w),
52 | ),
53 | ),
54 | ),
55 | ),
56 | ],
57 | ),
58 | ),
59 | ],
60 | ),
61 | );
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/lib/app/widgets/shimmer/recent_jobs_shimmer.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_screenutil/flutter_screenutil.dart';
3 | import 'package:jobs_flutter_app/app/widgets/shimmer/shimmer_widget.dart';
4 |
5 | class RecentJobsShimmer extends StatelessWidget {
6 | const RecentJobsShimmer({Key? key}) : super(key: key);
7 |
8 | @override
9 | Widget build(BuildContext context) {
10 | return ListView.builder(
11 | itemCount: 3,
12 | shrinkWrap: true,
13 | physics: const NeverScrollableScrollPhysics(),
14 | itemBuilder: (context, index) => Container(
15 | padding: EdgeInsets.symmetric(horizontal: 16.w),
16 | margin: EdgeInsets.only(bottom: 16.w),
17 | child: ShimmerWidget(
18 | width: double.infinity,
19 | height: 200.h,
20 | ),
21 | ),
22 | );
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/lib/app/widgets/shimmer/shimmer_widget.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_screenutil/flutter_screenutil.dart';
3 | import 'package:get/get.dart';
4 | import 'package:shimmer/shimmer.dart';
5 |
6 | class ShimmerWidget extends StatelessWidget {
7 | const ShimmerWidget({
8 | Key? key,
9 | required this.width,
10 | required this.height,
11 | this.radius,
12 | this.child,
13 | this.margin,
14 | }) : super(key: key);
15 | final double width;
16 | final double height;
17 | final double? radius;
18 | final Widget? child;
19 | final EdgeInsetsGeometry? margin;
20 |
21 | @override
22 | Widget build(BuildContext context) {
23 | return Shimmer.fromColors(
24 | baseColor: Get.theme.primaryColor.withOpacity(0.38),
25 | highlightColor: Get.theme.colorScheme.background,
26 | child: Container(
27 | width: width,
28 | height: height,
29 | margin: margin ?? EdgeInsets.zero,
30 | decoration: BoxDecoration(
31 | shape: BoxShape.rectangle,
32 | borderRadius: BorderRadius.circular(radius ?? 14.r),
33 | color: Get.theme.primaryColor.withOpacity(0.38),
34 | ),
35 | child: child,
36 | ),
37 | );
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/lib/main.dart:
--------------------------------------------------------------------------------
1 | import 'package:country_codes/country_codes.dart';
2 | import 'package:flutter/material.dart';
3 | import 'package:flutter/services.dart';
4 | import 'package:flutter_screenutil/flutter_screenutil.dart';
5 | import 'package:get/get.dart';
6 | import 'package:get_storage/get_storage.dart';
7 |
8 | import 'app/core/theme/app_theme.dart';
9 | import 'app/di/locator.dart';
10 | import 'app/modules/auth/bindings/auth_binding.dart';
11 | import 'app/modules/auth/controllers/auth_controller.dart';
12 | import 'app/modules/auth/views/login/login_view.dart';
13 | import 'app/modules/root/views/root_view.dart';
14 | import 'app/routes/app_pages.dart';
15 |
16 | void main() async {
17 | setupLocator();
18 | await GetStorage.init();
19 | await CountryCodes.init();
20 | SystemChrome.setPreferredOrientations([
21 | DeviceOrientation.portraitUp,
22 | DeviceOrientation.portraitDown,
23 | ]);
24 | runApp(
25 | ScreenUtilInit(
26 | designSize: const Size(375, 812),
27 | minTextAdapt: true,
28 | splitScreenMode: true,
29 | builder: (_, child) => GetMaterialApp(
30 | locale: Get.locale,
31 | debugShowCheckedModeBanner: false,
32 | initialBinding: AuthBinding(),
33 | home: Obx(
34 | () => AuthController.to.currentUser != null
35 | ? const RootView()
36 | : const LoginView(),
37 | ),
38 | getPages: AppPages.routes,
39 | theme: AppTheme.lightTheme,
40 | defaultTransition: Transition.cupertino,
41 | ),
42 | ),
43 | );
44 | }
45 |
--------------------------------------------------------------------------------
/pubspec.yaml:
--------------------------------------------------------------------------------
1 | name: jobs_flutter_app
2 | version: 1.0.0+1
3 | publish_to: none
4 | description: A new Flutter project.
5 | environment:
6 | sdk: '>=2.17.6 <3.0.0'
7 |
8 | dependencies:
9 | cupertino_icons: ^1.0.2
10 | get: 4.6.5
11 | google_fonts: 3.0.1
12 | flutter_screenutil: 5.5.4
13 | cached_network_image: ^3.2.2
14 | flutter_svg: 1.1.5
15 | lottie: 1.4.2
16 | carousel_slider: 4.1.1
17 | flutter_markdown: 0.6.12
18 | persistent_bottom_nav_bar_v2: 4.2.5
19 | dio: 4.0.6
20 | get_it: 7.2.0
21 | freezed_annotation: ^2.1.0
22 | json_annotation: ^4.7.0
23 | intl: 0.17.0
24 | get_storage: 2.0.3
25 | heroicons: 0.7.0
26 | form_field_validator: 1.1.0
27 | intl_phone_field: 3.1.0
28 | shimmer: 2.0.0
29 | awesome_dialog: 3.0.2
30 | awesome_snackbar_content: 0.0.8
31 | country_codes: 2.2.0
32 | smooth_page_indicator: 1.0.0+2
33 | url_launcher: 6.1.6
34 | flutter_svg_provider: 1.0.3
35 | expandable: 5.0.1
36 | flutter:
37 | sdk: flutter
38 |
39 | dev_dependencies:
40 | build_runner: ^2.2.1
41 | flutter_lints: ^2.0.0
42 | freezed: ^2.1.1
43 | json_serializable: ^6.4.0
44 | flutter_native_splash: ^2.2.13
45 | logger: 1.1.0
46 | device_preview: ^1.1.0
47 | flutter_test:
48 | sdk: flutter
49 |
50 | flutter_native_splash:
51 | color: '#03A9F4'
52 | color_dark: '#23A9F4'
53 | android_12:
54 | color_dark: '#23A9F4'
55 | web: false
56 |
57 | flutter:
58 | assets:
59 | - assets/
60 | uses-material-design: true
61 |
62 |
--------------------------------------------------------------------------------