diff --git a/.github/workflows/PR-generate-goldens.yaml b/.github/workflows/PR-generate-goldens.yaml new file mode 100644 index 0000000..780f195 --- /dev/null +++ b/.github/workflows/PR-generate-goldens.yaml @@ -0,0 +1,43 @@ +name: Generate Updated Goldens +on: + push: + branches-ignore: [master, release, dev] # only run on feature branches + paths: + - '**/golden_tests/**.dart' + + workflow_dispatch: + +jobs: + generate-goldens: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + with: + persist-credentials: false # otherwise, the token used is the GITHUB_TOKEN, instead of your personal access token. + fetch-depth: 0 + - name: Setup Java JDK + uses: actions/setup-java@v2.2.0 + with: + distribution: 'adopt' + java-version: '12.x' + - name: Checkout Flutter Stable Channel + uses: subosito/flutter-action@v1.5.3 + with: + channel: 'stable' + - name: Get Pub Dependencies + run: flutter pub get + - name: Run Build Runner For Codegen Files + run: flutter packages pub run build_runner build --delete-conflicting-outputs + - name: Run tests + run: flutter test --update-goldens test/golden_tests + - name: Commit Updated Goldens + run: | + git config --global user.name 'arafaysaleem' + git config --global user.email 'arafaysaleem@users.noreply.github.com' + git add -A + git commit -m "test(Goldens): update generated goldens for new changes" + - name: GitHub Push To Repository + uses: ad-m/github-push-action@v0.6.0 + with: + github_token: ${{ secrets.EZ_TICKETS_APP_TOKEN }} + branch: ${{ github.ref }} \ No newline at end of file diff --git a/.github/workflows/PR-merge-build-release.yaml b/.github/workflows/PR-merge-build-release.yaml index d76e195..393341d 100644 --- a/.github/workflows/PR-merge-build-release.yaml +++ b/.github/workflows/PR-merge-build-release.yaml @@ -15,11 +15,13 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - - uses: actions/setup-java@v1 + - name: Setup Java JDK + uses: actions/setup-java@v2.2.0 with: + distribution: 'adopt' java-version: '12.x' - name: Checkout Flutter Stable Channel - uses: subosito/flutter-action@v1.5.1 + uses: subosito/flutter-action@v1.5.3 with: channel: 'stable' - name: Get Pub Dependencies diff --git a/.github/workflows/PR-open-test-build.yaml b/.github/workflows/PR-open-test-build.yaml index 467c87f..c4425c2 100644 --- a/.github/workflows/PR-open-test-build.yaml +++ b/.github/workflows/PR-open-test-build.yaml @@ -7,12 +7,20 @@ jobs: name: Test APK runs-on: ubuntu-latest steps: + - name: Wait For Generate Goldens Workflow To Complete + uses: fountainhead/action-wait-for-check@v1.0.0 + with: + token: ${{ secrets.GITHUB_TOKEN }} + checkName: generate-goldens + ref: ${{ github.event.pull_request.head.sha || github.sha }} - uses: actions/checkout@v2 - - uses: actions/setup-java@v1 + - name: Setup Java JDK + uses: actions/setup-java@v2.2.0 with: + distribution: 'adopt' java-version: '12.x' - name: Checkout Flutter Stable Channel - uses: subosito/flutter-action@v1 + uses: subosito/flutter-action@v1.5.3 with: channel: 'stable' - name: Get Pub Dependencies @@ -30,7 +38,7 @@ jobs: with: path: "./coverage/lcov.info" min_coverage: 4.5 - exclude: "**/*.freezed.dart **/*.g.dart **/*.gr.dart **/*.mocks.dart **/constants.dart **/custom_theme.dart **/assets_helper.dart" + exclude: "**/*.freezed.dart **/*.g.dart **/*.gr.dart **/*.mocks.dart **/constants.dart **/custom_theme.dart **/assets_helper.dart **/routes.dart" - name: Upload coverage to Codecov uses: codecov/codecov-action@v2.0.2 with: diff --git a/.gitignore b/.gitignore index 10cb6d6..c3099d1 100644 --- a/.gitignore +++ b/.gitignore @@ -45,7 +45,7 @@ app.*.map.json /android/app/profile /android/app/release -# Generated model files +# Generated files *.g.dart *.freezed.dart *.gr.dart @@ -53,3 +53,9 @@ app.*.map.json #keystore *.jks + +# don't check in golden failure output +**/failures/*.png + +# don't check in goldens since we are using Windows and CI uses Ubuntu +**/goldens_local/*.png diff --git a/analysis_options.yaml b/analysis_options.yaml index 96747c5..2e4a909 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -9,9 +9,8 @@ analyzer: errors: missing_required_param: error missing_return: error - prefer_const_constructors: error - prefer_const_constructors_in_immutables: error todo: ignore + invalid_annotation_target: ignore strong-mode: implicit-casts: false implicit-dynamic: false @@ -22,10 +21,13 @@ linter: directives_ordering: false prefer_double_quotes: false use_key_in_widget_constructors: false + prefer_const_constructors: true + prefer_const_constructors_in_immutables: true always_specify_types: false unnecessary_final: false public_member_api_docs: false prefer_expression_function_bodies: false avoid_classes_with_only_static_members: false prefer_const_literals_to_create_immutables: true - lines_longer_than_80_chars: false \ No newline at end of file + lines_longer_than_80_chars: false + prefer_relative_imports: true \ No newline at end of file diff --git a/build.yaml b/build.yaml index e47c946..195ed04 100644 --- a/build.yaml +++ b/build.yaml @@ -1,10 +1,6 @@ targets: $default: builders: - auto_route_generator:autoRouteGenerator: - generate_for: - include: - - lib/routes/**.dart json_serializable: options: explicit_to_json: true diff --git a/codecov.yml b/codecov.yml index c684ddb..031a932 100644 --- a/codecov.yml +++ b/codecov.yml @@ -4,6 +4,7 @@ ignore: - '**/*.freezed.dart' - "**/*.mocks.dart" - '**/constants.dart' + - '**/routes.dart' - '**/custom_theme.dart' - '**/assets_helper.dart' - '/android/' diff --git a/coverage/lcov.info b/coverage/lcov.info index 24b7b0c..8441543 100644 --- a/coverage/lcov.info +++ b/coverage/lcov.info @@ -1,19 +1,56 @@ SF:lib\enums\booking_status_enum.dart -DA:6,6 +DA:6,34 DA:14,4 DA:16,6 LF:3 LH:3 end_of_record +SF:lib\helper\utils\custom_theme.dart +DA:9,0 +DA:19,15 +DA:23,10 +DA:24,5 +DA:25,10 +DA:30,10 +DA:35,10 +DA:40,10 +DA:45,10 +DA:50,10 +DA:55,10 +DA:58,10 +DA:61,10 +DA:64,10 +DA:68,5 +DA:69,5 +LF:16 +LH:15 +end_of_record +SF:lib\helper\utils\constants.dart +DA:9,0 +DA:94,20 +DA:97,20 +DA:102,0 +DA:123,9 +DA:128,9 +DA:131,9 +DA:134,6 +DA:137,6 +DA:140,6 +DA:143,6 +DA:146,6 +DA:193,7 +LF:13 +LH:11 +end_of_record SF:lib\enums\movie_type_enum.dart -DA:6,3 +DA:6,24 DA:15,2 DA:17,3 LF:3 LH:3 end_of_record SF:lib\enums\payment_method_enum.dart -DA:8,17 +DA:8,27 DA:16,2 DA:17,3 DA:18,3 @@ -21,36 +58,21 @@ LF:4 LH:4 end_of_record SF:lib\helper\extensions\string_extension.dart -DA:7,3 -DA:10,3 -DA:13,3 -DA:16,3 -DA:19,3 -DA:22,3 -DA:25,3 -DA:28,12 -DA:31,2 -LF:9 -LH:9 -end_of_record -SF:lib\helper\utils\constants.dart -DA:9,0 -DA:94,0 -DA:97,0 -DA:102,0 -DA:123,3 -DA:128,3 -DA:131,3 -DA:134,3 -DA:137,3 -DA:140,3 -DA:143,3 -DA:190,7 -LF:12 -LH:8 +DA:7,9 +DA:10,9 +DA:13,9 +DA:16,6 +DA:19,6 +DA:22,6 +DA:25,6 +DA:28,6 +DA:31,12 +DA:34,2 +LF:10 +LH:10 end_of_record SF:lib\enums\role_type_enum.dart -DA:8,5 +DA:8,25 DA:16,4 DA:17,6 DA:18,3 @@ -58,7 +80,7 @@ LF:4 LH:4 end_of_record SF:lib\enums\show_status_enum.dart -DA:8,6 +DA:8,24 DA:16,2 DA:17,3 DA:18,4 @@ -66,7 +88,7 @@ LF:4 LH:4 end_of_record SF:lib\enums\show_type_enum.dart -DA:6,8 +DA:6,24 DA:13,2 DA:14,3 DA:15,2 @@ -74,232 +96,331 @@ LF:4 LH:4 end_of_record SF:lib\enums\theater_type_enum.dart -DA:6,4 +DA:6,24 DA:13,2 DA:15,3 LF:3 LH:3 end_of_record SF:lib\enums\user_role_enum.dart -DA:6,3 +DA:6,24 DA:14,2 DA:16,3 LF:3 LH:3 end_of_record -SF:lib\helper\utils\form_validator.dart -DA:12,0 -DA:15,1 -DA:16,1 -DA:18,1 -DA:25,1 -DA:26,1 -DA:31,1 -DA:32,2 -DA:37,1 -DA:38,1 +SF:lib\providers\all_providers.dart +DA:38,0 +DA:42,4 DA:43,1 -DA:44,1 -DA:47,1 +DA:46,1 +DA:49,4 +DA:50,2 +DA:52,1 DA:54,1 DA:55,1 -DA:60,1 -DA:61,1 +DA:56,1 +DA:57,1 +DA:62,4 +DA:63,2 +DA:64,1 +DA:68,4 +DA:69,2 +DA:70,1 +DA:73,0 +DA:78,0 +DA:83,0 +DA:88,0 +DA:93,0 +DA:99,9 +DA:100,0 +DA:101,0 +DA:102,0 +DA:103,0 +DA:109,3 +DA:110,1 +DA:111,2 +DA:112,1 +DA:119,0 +DA:124,0 +DA:129,0 +DA:134,0 +DA:142,0 +LF:36 +LH:21 +end_of_record +SF:lib\views\screens\change_password_screen.dart +DA:23,1 +DA:25,1 +DA:27,1 +DA:28,1 +DA:29,1 +DA:30,2 +DA:31,1 +DA:32,1 +DA:33,1 +DA:34,0 +DA:35,0 +DA:36,0 +DA:37,0 +DA:38,0 +DA:39,0 +DA:40,0 +DA:41,0 +DA:43,0 +DA:44,0 +DA:48,0 +DA:52,0 +DA:54,0 +DA:55,0 +DA:61,0 +DA:64,1 +DA:65,0 DA:66,1 DA:67,1 +DA:69,1 +DA:70,0 +DA:71,1 DA:72,1 -DA:73,1 -DA:78,1 -DA:79,2 -DA:84,1 -DA:85,1 -DA:90,1 -DA:91,1 -DA:96,1 +DA:74,1 +DA:77,2 +DA:83,1 +DA:95,1 DA:97,1 -DA:102,1 -DA:103,1 -LF:31 -LH:30 +DA:98,0 +DA:99,0 +DA:100,0 +DA:101,0 +DA:102,0 +DA:103,0 +LF:43 +LH:20 end_of_record -SF:lib\models\booking_model.g.dart +SF:lib\models\user_model.dart +DA:21,1 +DA:22,1 +LF:2 +LH:2 +end_of_record +SF:lib\models\user_model.g.dart DA:9,2 -DA:10,2 -DA:11,2 -DA:12,2 -DA:13,2 -DA:14,2 +DA:10,1 +DA:11,1 +DA:12,1 +DA:13,1 +DA:14,1 DA:15,2 -DA:16,4 -DA:17,4 -DA:18,4 -DA:19,4 -DA:23,2 -DA:24,2 -DA:26,2 +DA:18,1 +DA:19,1 +DA:21,1 +DA:23,1 +DA:27,2 DA:28,2 -DA:32,6 -DA:33,4 -DA:34,4 -DA:35,6 -DA:36,6 -DA:37,4 -DA:38,4 -DA:39,6 -DA:40,6 -DA:44,2 +DA:29,2 +DA:30,2 +DA:31,2 +DA:32,3 +DA:36,1 +DA:42,0 +DA:44,0 +DA:48,2 +DA:49,3 DA:50,0 DA:52,0 -DA:56,4 -DA:57,6 -DA:58,0 -DA:60,0 -DA:62,0 -DA:65,0 -DA:67,2 -LF:34 -LH:28 +DA:54,0 +DA:57,0 +DA:59,1 +LF:27 +LH:21 end_of_record -SF:lib\models\booking_model.freezed.dart -DA:10,1 -DA:12,0 -DA:15,2 -DA:16,2 -DA:21,3 -DA:23,0 -DA:39,0 +SF:lib\providers\auth_provider.dart +DA:18,3 +DA:19,1 +DA:29,3 +DA:36,3 +DA:37,3 +DA:40,0 +DA:42,0 +DA:44,0 +DA:46,0 +DA:48,0 +DA:50,0 DA:52,0 DA:53,0 -DA:62,0 -DA:63,0 -DA:64,0 +DA:56,0 +DA:57,0 +DA:58,0 +DA:61,3 +DA:62,6 +DA:63,9 +DA:64,12 DA:65,0 -DA:66,0 -DA:67,0 +DA:66,3 DA:68,0 -DA:69,0 -DA:70,0 -DA:71,0 DA:72,0 -DA:73,0 -DA:74,0 -DA:75,0 DA:76,0 -DA:78,0 +DA:77,0 DA:79,0 DA:81,0 -DA:103,1 +DA:83,0 +DA:84,0 +DA:85,0 +DA:86,0 +DA:87,0 +DA:91,0 +DA:99,0 +DA:100,0 +DA:101,0 DA:109,0 -DA:121,0 -DA:122,0 +DA:111,0 +DA:112,0 +DA:113,0 +DA:115,0 +DA:116,0 +DA:117,0 +DA:118,0 +DA:119,0 DA:123,0 +DA:124,0 +DA:125,0 DA:126,0 -DA:127,0 +DA:129,0 DA:130,0 -DA:131,0 +DA:132,0 +DA:133,0 DA:134,0 DA:135,0 -DA:138,0 -DA:139,0 +DA:136,0 +DA:140,0 +DA:141,0 DA:142,0 -DA:143,0 -DA:146,0 -DA:147,0 -DA:150,0 -DA:151,0 -DA:154,0 -DA:155,0 -DA:184,1 -DA:186,3 -DA:188,1 -DA:189,1 -DA:191,1 -DA:203,3 -DA:204,1 -DA:205,2 -DA:208,1 -DA:209,0 -DA:212,1 -DA:213,0 -DA:216,1 -DA:217,0 -DA:220,1 -DA:221,0 -DA:224,1 -DA:225,0 -DA:228,1 -DA:229,2 -DA:232,1 -DA:233,0 -DA:236,1 -DA:237,0 -DA:248,2 -DA:264,2 -DA:266,2 -DA:267,2 -DA:294,0 -DA:296,0 -DA:299,2 -DA:302,2 -DA:303,4 -DA:305,0 -DA:306,4 -DA:307,0 -DA:308,4 -DA:309,0 -DA:310,4 -DA:312,0 -DA:313,4 -DA:315,0 -DA:316,4 -DA:317,0 -DA:318,4 -DA:319,0 -DA:320,4 -DA:322,0 -DA:323,4 -DA:325,6 -DA:328,0 -DA:330,0 -DA:331,0 -DA:332,0 -DA:333,0 -DA:334,0 -DA:335,0 -DA:336,0 -DA:337,0 -DA:338,0 -DA:339,0 -DA:341,1 -DA:344,1 -DA:346,2 -DA:348,2 -DA:369,4 -DA:374,0 -DA:376,0 -DA:377,0 -DA:379,0 -DA:380,0 -DA:382,0 -DA:383,0 -DA:385,0 -DA:386,0 -DA:388,0 -DA:389,0 -DA:390,0 -DA:391,0 -DA:393,0 -DA:394,0 -DA:395,0 -DA:396,0 -DA:397,0 -DA:398,0 -DA:401,0 -LF:134 -LH:43 +DA:145,3 +DA:146,3 +DA:147,3 +DA:148,3 +DA:149,6 +LF:65 +LH:15 +end_of_record +SF:lib\services\local_storage\key_value_storage_service.dart +DA:35,0 +DA:36,0 +DA:40,0 +DA:41,0 +DA:45,0 +DA:46,0 +DA:48,0 +DA:52,0 +DA:53,0 +DA:59,0 +DA:60,0 +DA:66,0 +DA:67,0 +DA:68,0 +DA:75,0 +DA:76,0 +DA:82,0 +DA:83,0 +DA:89,0 +DA:90,0 +DA:91,0 +LF:21 +LH:0 +end_of_record +SF:lib\services\repositories\auth_repository.dart +DA:14,1 +DA:16,0 +DA:20,0 +DA:21,0 +DA:24,0 +DA:25,0 +DA:26,0 +DA:31,0 +DA:35,0 +DA:36,0 +DA:39,0 +DA:40,0 +DA:41,0 +DA:42,0 +DA:47,0 +DA:50,0 +DA:51,0 +DA:54,0 +DA:58,0 +DA:61,0 +DA:62,0 +DA:65,0 +DA:69,0 +DA:72,0 +DA:73,0 +DA:76,0 +DA:80,0 +DA:81,0 +DA:82,0 +DA:85,0 +LF:30 +LH:1 +end_of_record +SF:lib\helper\extensions\context_extensions.dart +DA:4,4 +DA:5,4 +DA:6,10 +DA:7,15 +DA:8,3 +DA:9,0 +DA:10,15 +DA:11,0 +DA:12,3 +DA:13,0 +DA:14,12 +DA:15,0 +LF:12 +LH:8 +end_of_record +SF:lib\helper\utils\exception_constants.dart +DA:8,0 +LF:1 +LH:0 +end_of_record +SF:lib\helper\utils\form_validator.dart +DA:12,0 +DA:15,2 +DA:16,2 +DA:18,2 +DA:25,1 +DA:26,1 +DA:31,1 +DA:32,2 +DA:37,1 +DA:38,1 +DA:43,1 +DA:44,1 +DA:47,1 +DA:54,2 +DA:55,2 +DA:60,2 +DA:61,2 +DA:66,2 +DA:67,2 +DA:72,1 +DA:73,1 +DA:78,1 +DA:79,2 +DA:84,1 +DA:85,1 +DA:90,1 +DA:91,1 +DA:96,1 +DA:97,1 +DA:102,1 +DA:103,1 +DA:108,1 +DA:109,1 +LF:33 +LH:32 end_of_record SF:lib\models\booking_model.dart -DA:12,2 +DA:13,2 DA:27,1 DA:43,2 DA:45,1 @@ -314,515 +435,218 @@ DA:55,2 LF:12 LH:11 end_of_record -SF:lib\models\genre_model.freezed.dart -DA:10,0 -DA:12,0 +SF:lib\models\booking_model.g.dart +DA:9,2 +DA:10,2 +DA:11,2 +DA:12,2 +DA:13,2 +DA:14,2 DA:15,2 -DA:16,2 -DA:21,2 -DA:23,0 -DA:24,0 -DA:30,0 -DA:31,0 -DA:40,0 -DA:41,0 -DA:43,0 -DA:44,0 -DA:46,0 -DA:59,0 +DA:16,4 +DA:17,4 +DA:19,4 +DA:20,4 +DA:23,2 +DA:24,2 +DA:26,2 +DA:28,2 +DA:32,6 +DA:33,4 +DA:34,4 +DA:35,6 +DA:36,6 +DA:37,4 +DA:38,4 +DA:39,6 +DA:40,6 +DA:44,2 +DA:50,0 +DA:52,0 +DA:56,4 +DA:57,6 +DA:58,0 +DA:60,0 +DA:62,0 DA:65,0 -DA:70,0 -DA:71,0 -DA:72,0 -DA:75,0 -DA:76,0 -DA:95,0 -DA:97,0 -DA:99,0 -DA:100,0 -DA:102,0 -DA:107,0 -DA:108,0 -DA:109,0 -DA:112,0 -DA:113,0 -DA:124,4 -DA:126,2 -DA:127,2 -DA:134,0 -DA:136,0 -DA:139,2 -DA:142,2 -DA:143,4 -DA:145,3 -DA:146,4 -DA:147,0 -DA:150,0 -DA:152,0 -DA:153,0 -DA:154,0 -DA:156,0 -DA:159,0 -DA:161,1 -DA:163,1 -DA:174,0 -DA:175,0 -DA:176,0 -DA:177,0 -DA:178,0 -DA:181,0 -LF:56 -LH:13 +DA:67,2 +LF:34 +LH:28 +end_of_record +SF:lib\models\genre_model.dart +DA:15,2 +DA:16,2 +LF:2 +LH:2 end_of_record SF:lib\models\genre_model.g.dart DA:9,2 DA:10,2 DA:11,2 DA:12,2 +DA:15,1 DA:16,1 DA:17,1 DA:18,1 -DA:19,1 LF:8 LH:8 end_of_record -SF:lib\models\genre_model.dart -DA:15,2 -DA:16,2 -LF:2 -LH:2 +SF:lib\models\movie_model.dart +DA:12,1 +DA:13,4 +DA:18,1 +DA:32,1 +DA:33,1 +DA:40,1 +DA:45,1 +DA:62,2 +DA:63,1 +DA:64,1 +DA:65,1 +DA:66,1 +DA:67,1 +DA:68,1 +DA:69,1 +DA:70,0 +DA:71,1 +DA:74,1 +DA:75,1 +DA:77,1 +DA:78,5 +LF:21 +LH:20 end_of_record -SF:lib\models\movie_model.freezed.dart +SF:lib\models\movie_model.g.dart +DA:9,1 DA:10,1 -DA:12,0 +DA:11,1 +DA:12,1 +DA:13,1 +DA:14,1 DA:15,1 DA:16,1 -DA:21,1 -DA:23,0 -DA:35,0 -DA:48,0 -DA:49,0 -DA:58,0 +DA:17,2 +DA:18,1 +DA:19,3 +DA:20,1 +DA:21,2 +DA:24,1 +DA:25,1 +DA:27,1 +DA:29,0 +DA:33,3 +DA:34,2 +DA:35,2 +DA:36,2 +DA:37,2 +DA:38,2 +DA:39,2 +DA:40,3 +DA:41,3 +DA:45,1 +DA:51,0 +DA:53,0 +DA:57,2 +DA:58,3 DA:59,0 -DA:60,0 DA:61,0 -DA:62,0 DA:63,0 -DA:64,0 -DA:65,0 DA:66,0 -DA:67,0 -DA:68,0 -DA:70,0 -DA:71,0 -DA:73,0 -DA:95,1 -DA:101,0 -DA:113,0 -DA:114,0 -DA:115,0 -DA:118,0 -DA:119,0 -DA:122,0 -DA:123,0 -DA:126,0 -DA:127,0 -DA:130,0 -DA:131,0 -DA:134,0 -DA:135,0 -DA:138,0 -DA:139,0 -DA:142,0 -DA:143,0 -DA:146,0 -DA:147,0 -DA:175,1 -DA:177,3 -DA:179,1 -DA:180,1 -DA:182,1 -DA:194,3 -DA:195,1 -DA:196,0 -DA:199,1 -DA:200,0 -DA:203,1 -DA:204,0 -DA:207,1 -DA:208,0 -DA:211,1 -DA:212,0 -DA:215,1 -DA:216,0 -DA:219,1 -DA:220,0 -DA:223,1 -DA:224,2 -DA:227,1 -DA:228,0 -DA:239,1 -DA:251,1 -DA:253,1 -DA:254,1 -DA:278,0 -DA:280,0 -DA:283,1 -DA:286,1 -DA:287,2 -DA:289,0 -DA:290,2 -DA:291,3 -DA:292,2 -DA:293,0 -DA:294,2 -DA:296,0 -DA:297,2 -DA:299,0 -DA:300,2 -DA:302,0 -DA:303,2 -DA:304,0 -DA:305,2 -DA:306,3 -DA:307,2 -DA:309,0 -DA:312,0 -DA:314,0 -DA:315,0 -DA:316,0 -DA:317,0 -DA:318,0 -DA:319,0 -DA:320,0 -DA:321,0 -DA:322,0 -DA:323,0 -DA:325,1 -DA:328,1 -DA:330,1 -DA:332,1 -DA:349,2 -DA:354,0 -DA:356,0 -DA:357,0 -DA:358,0 -DA:359,0 -DA:360,0 -DA:361,0 -DA:362,0 -DA:363,0 -DA:364,0 -DA:365,0 -DA:366,0 -DA:367,0 -DA:368,0 -DA:369,0 -DA:371,0 -DA:372,0 -DA:373,0 -DA:374,0 -DA:377,0 -LF:130 -LH:43 +DA:68,1 +LF:36 +LH:29 end_of_record -SF:lib\models\movie_model.g.dart +SF:lib\models\movie_role_model.dart +DA:15,1 +DA:23,1 +DA:24,1 +DA:26,1 +DA:27,1 +DA:28,2 +DA:29,2 +LF:7 +LH:7 +end_of_record +SF:lib\models\movie_role_model.g.dart DA:9,1 DA:10,1 DA:11,1 -DA:12,1 -DA:13,1 -DA:14,1 -DA:15,1 -DA:16,1 -DA:17,2 -DA:18,1 -DA:19,3 -DA:20,1 -DA:21,2 -DA:25,1 -DA:26,1 -DA:28,1 -DA:30,0 -DA:34,3 +DA:12,2 +DA:13,2 +DA:16,0 +DA:17,0 +DA:18,0 +DA:19,0 +DA:20,0 +DA:23,1 +DA:29,0 +DA:31,0 DA:35,2 -DA:36,2 -DA:37,2 -DA:38,2 -DA:39,2 -DA:40,2 -DA:41,3 -DA:42,3 +DA:36,3 +DA:37,0 +DA:39,0 +DA:41,0 +DA:44,0 DA:46,1 -DA:52,0 -DA:54,0 -DA:58,2 -DA:59,3 -DA:60,0 -DA:62,0 -DA:64,0 -DA:67,0 -DA:69,1 -LF:36 -LH:29 -end_of_record -SF:lib\models\movie_model.dart -DA:11,1 -DA:12,4 -DA:17,1 -DA:32,1 -DA:33,1 -DA:40,1 -DA:45,1 -DA:62,2 -DA:63,1 -DA:64,1 -DA:65,1 -DA:66,1 -DA:67,1 -DA:68,1 -DA:69,1 -DA:70,0 -DA:71,1 -DA:74,1 -DA:75,1 -DA:77,1 -DA:78,5 -LF:21 -LH:20 +LF:20 +LH:9 end_of_record SF:lib\models\role_model.dart -DA:17,2 DA:18,2 +DA:19,2 LF:2 LH:2 end_of_record -SF:lib\models\role_model.freezed.dart -DA:10,0 -DA:12,0 -DA:15,2 -DA:16,2 -DA:21,2 -DA:23,0 -DA:28,0 -DA:36,0 -DA:37,0 -DA:46,0 -DA:47,0 -DA:48,0 -DA:49,0 -DA:51,0 -DA:52,0 -DA:54,0 -DA:66,0 -DA:72,0 -DA:79,0 -DA:80,0 -DA:81,0 -DA:84,0 -DA:85,0 -DA:88,0 -DA:89,0 -DA:92,0 -DA:93,0 -DA:112,0 -DA:113,0 -DA:115,0 -DA:116,0 -DA:118,0 -DA:125,0 -DA:126,0 -DA:127,0 -DA:130,0 -DA:131,0 -DA:134,0 -DA:135,0 -DA:138,0 -DA:139,0 -DA:150,4 -DA:156,2 -DA:157,2 -DA:168,0 -DA:170,0 -DA:173,2 -DA:176,2 -DA:177,4 -DA:178,3 -DA:179,4 -DA:181,0 -DA:182,4 -DA:183,0 -DA:184,4 -DA:186,0 -DA:189,0 -DA:191,0 -DA:192,0 -DA:193,0 -DA:194,0 -DA:195,0 -DA:197,0 -DA:200,0 -DA:202,1 -DA:204,1 -DA:218,0 -DA:219,0 -DA:220,0 -DA:221,0 -DA:222,0 -DA:223,0 -DA:224,0 -DA:225,0 -DA:226,0 -DA:229,0 -LF:76 -LH:15 -end_of_record SF:lib\models\role_model.g.dart -DA:9,2 +DA:9,4 DA:10,2 DA:11,2 DA:12,2 DA:13,2 -DA:14,2 +DA:16,1 +DA:17,1 DA:18,1 DA:19,1 DA:20,1 DA:21,1 -DA:22,1 -DA:23,1 -LF:12 -LH:12 +LF:11 +LH:11 end_of_record -SF:lib\models\movie_role_model.dart -DA:14,3 -DA:23,1 -DA:24,1 +SF:lib\models\payment_model.dart +DA:13,1 DA:26,1 -DA:27,1 -DA:28,2 -DA:29,2 -LF:7 -LH:7 +DA:38,2 +DA:39,1 +DA:40,1 +DA:41,1 +DA:42,0 +DA:43,1 +DA:44,1 +DA:47,1 +DA:48,1 +LF:11 +LH:10 end_of_record -SF:lib\models\movie_role_model.g.dart +SF:lib\models\payment_model.g.dart DA:9,1 DA:10,1 DA:11,1 DA:12,2 -DA:13,2 -DA:17,0 -DA:18,0 -DA:19,0 -DA:20,0 -DA:21,0 +DA:13,1 +DA:14,1 +DA:15,2 +DA:17,2 +DA:18,2 +DA:21,1 +DA:22,1 DA:24,1 -DA:30,0 -DA:32,0 -DA:36,2 -DA:37,3 -DA:38,0 -DA:40,0 -DA:42,0 -DA:45,0 -DA:47,1 -LF:20 -LH:9 -end_of_record -SF:lib\models\movie_role_model.freezed.dart -DA:10,0 -DA:12,0 -DA:15,1 -DA:16,1 -DA:21,2 -DA:23,0 -DA:27,0 -DA:34,0 -DA:35,0 -DA:44,0 -DA:45,0 -DA:46,0 -DA:48,0 -DA:49,0 -DA:51,0 -DA:67,0 -DA:73,0 -DA:79,0 -DA:80,0 -DA:81,0 -DA:84,0 -DA:85,0 -DA:88,0 -DA:89,0 -DA:95,0 -DA:97,0 -DA:98,0 -DA:120,0 -DA:122,0 -DA:124,0 -DA:125,0 -DA:127,0 -DA:133,0 -DA:134,0 -DA:135,0 -DA:138,0 -DA:139,0 -DA:142,0 -DA:143,0 -DA:154,2 -DA:156,1 -DA:158,1 -DA:159,1 -DA:168,0 -DA:170,0 -DA:173,1 -DA:176,1 -DA:177,2 -DA:179,0 -DA:180,2 -DA:181,3 -DA:182,2 -DA:184,3 -DA:187,0 -DA:189,0 -DA:190,0 -DA:191,0 -DA:192,0 -DA:194,0 -DA:197,0 -DA:199,0 -DA:201,0 -DA:210,4 -DA:215,0 -DA:216,0 -DA:217,0 -DA:218,0 -DA:219,0 -DA:220,0 -DA:221,0 -DA:224,0 -LF:71 -LH:15 -end_of_record -SF:lib\models\payment_model.g.dart -DA:9,1 -DA:10,1 -DA:11,1 -DA:12,2 -DA:13,1 -DA:14,1 -DA:15,2 -DA:16,2 -DA:17,2 -DA:21,1 -DA:22,1 -DA:24,1 -DA:26,1 -DA:30,3 -DA:31,2 -DA:32,2 -DA:33,2 -DA:34,3 -DA:35,3 +DA:26,1 +DA:30,3 +DA:31,2 +DA:32,2 +DA:33,2 +DA:34,3 +DA:35,3 DA:36,2 DA:40,1 DA:46,0 @@ -837,1219 +661,3361 @@ DA:63,1 LF:30 LH:24 end_of_record -SF:lib\models\payment_model.freezed.dart -DA:10,1 -DA:12,0 -DA:15,1 -DA:16,1 +SF:lib\models\seat_model.dart +DA:15,4 +LF:1 +LH:1 +end_of_record +SF:lib\models\seat_model.g.dart +DA:9,4 +DA:10,2 +DA:11,2 +DA:14,2 +DA:15,2 +DA:16,2 +DA:17,2 +LF:7 +LH:7 +end_of_record +SF:lib\models\show_model.dart +DA:12,1 +DA:20,1 DA:21,1 -DA:23,0 -DA:33,0 -DA:44,0 +DA:22,2 +DA:28,1 +DA:29,1 +LF:6 +LH:6 +end_of_record +SF:lib\models\show_model.g.dart +DA:9,2 +DA:10,2 +DA:11,1 +DA:12,1 +DA:13,3 +DA:14,1 +DA:17,1 +DA:18,1 +DA:19,2 +DA:20,1 +DA:21,5 +LF:11 +LH:11 +end_of_record +SF:lib\models\show_time_model.dart +DA:14,3 +DA:26,1 +DA:27,2 +DA:28,1 +DA:37,2 +DA:38,2 +LF:6 +LH:6 +end_of_record +SF:lib\models\show_time_model.g.dart +DA:9,2 +DA:10,2 +DA:11,2 +DA:12,4 +DA:13,4 +DA:14,4 +DA:15,4 +DA:16,2 +DA:19,2 +DA:20,2 +DA:22,2 +DA:24,0 +DA:28,6 +DA:29,6 +DA:30,6 +DA:31,6 +DA:32,6 +DA:33,4 +DA:37,2 +DA:43,0 DA:45,0 -DA:54,0 +DA:49,4 +DA:50,6 +DA:51,0 +DA:53,0 DA:55,0 -DA:56,0 -DA:57,0 DA:58,0 -DA:59,0 -DA:60,0 -DA:61,0 -DA:62,0 -DA:64,0 -DA:65,0 -DA:67,0 -DA:89,1 -DA:95,0 -DA:105,0 -DA:106,0 -DA:107,0 -DA:110,0 -DA:111,0 -DA:114,0 -DA:115,0 -DA:118,0 -DA:119,0 -DA:122,0 -DA:123,0 -DA:126,0 -DA:127,0 -DA:130,0 -DA:131,0 -DA:160,1 -DA:162,3 -DA:164,1 -DA:165,1 -DA:167,1 -DA:177,3 -DA:178,1 -DA:179,0 -DA:182,1 -DA:183,0 -DA:186,1 -DA:187,2 -DA:190,1 -DA:191,0 -DA:194,1 -DA:195,0 -DA:198,1 -DA:199,0 -DA:202,1 -DA:203,2 -DA:214,1 -DA:224,1 -DA:226,1 -DA:227,1 -DA:246,0 -DA:248,0 -DA:251,1 -DA:254,1 -DA:255,2 -DA:257,0 -DA:258,2 -DA:259,0 -DA:260,2 -DA:261,0 -DA:262,2 -DA:263,0 -DA:264,2 -DA:266,3 -DA:267,2 -DA:269,0 -DA:270,2 -DA:272,3 -DA:275,0 -DA:277,0 -DA:278,0 -DA:279,0 -DA:280,0 -DA:281,0 -DA:282,0 -DA:283,0 -DA:284,0 -DA:286,1 -DA:289,1 -DA:291,1 -DA:293,1 -DA:308,2 -DA:313,0 -DA:315,0 -DA:316,0 -DA:317,0 -DA:318,0 -DA:319,0 -DA:320,0 -DA:321,0 -DA:322,0 -DA:323,0 -DA:324,0 -DA:325,0 -DA:326,0 -DA:328,0 -DA:329,0 -DA:332,0 -LF:110 -LH:40 +DA:60,2 +LF:28 +LH:21 end_of_record -SF:lib\models\payment_model.dart -DA:12,1 +SF:lib\models\theater_model.dart +DA:14,1 DA:26,1 -DA:38,2 -DA:39,1 -DA:40,1 -DA:41,1 -DA:42,0 +DA:41,2 +DA:42,1 DA:43,1 DA:44,1 +DA:45,0 +DA:46,1 DA:47,1 DA:48,1 -LF:11 -LH:10 +DA:51,1 +DA:52,1 +LF:12 +LH:11 end_of_record -SF:lib\models\seat_model.freezed.dart -DA:10,0 -DA:12,0 +SF:lib\models\theater_model.g.dart +DA:9,1 +DA:10,1 +DA:11,1 +DA:12,1 +DA:13,1 +DA:14,1 DA:15,2 -DA:16,2 -DA:21,3 -DA:23,0 -DA:24,0 -DA:30,0 -DA:31,0 -DA:40,0 -DA:41,0 -DA:43,0 -DA:44,0 -DA:46,0 -DA:58,0 +DA:16,1 +DA:17,3 +DA:18,1 +DA:19,1 +DA:20,3 +DA:21,1 +DA:24,1 +DA:25,1 +DA:27,1 +DA:29,0 +DA:33,3 +DA:34,2 +DA:35,2 +DA:36,2 +DA:37,3 +DA:38,6 +DA:39,6 +DA:43,1 +DA:49,0 +DA:51,0 +DA:55,2 +DA:56,3 +DA:57,0 +DA:59,0 +DA:61,0 DA:64,0 -DA:69,0 -DA:70,0 -DA:71,0 -DA:74,0 -DA:75,0 -DA:94,0 -DA:95,0 -DA:97,0 -DA:98,0 -DA:100,0 -DA:105,0 -DA:106,0 -DA:107,0 -DA:110,0 -DA:111,0 -DA:122,5 -DA:124,2 -DA:125,2 -DA:132,0 -DA:134,0 -DA:137,3 -DA:140,3 -DA:141,6 -DA:143,6 -DA:144,4 -DA:146,0 -DA:149,0 -DA:151,0 -DA:152,0 -DA:153,0 -DA:155,0 -DA:158,0 -DA:160,2 -DA:162,2 -DA:173,0 -DA:174,0 -DA:175,0 -DA:176,0 -DA:177,0 -DA:180,0 -LF:56 -LH:13 +DA:66,1 +LF:34 +LH:27 end_of_record -SF:lib\models\seat_model.g.dart +SF:lib\models\user_booking_model.dart +DA:19,2 +LF:1 +LH:1 +end_of_record +SF:lib\models\user_booking_model.g.dart +DA:9,1 +DA:10,1 +DA:11,1 +DA:12,1 +DA:13,2 +DA:14,1 +DA:15,3 +DA:16,1 +DA:19,1 +DA:20,1 +DA:21,1 +DA:22,1 +DA:23,2 +DA:24,5 +LF:14 +LH:14 +end_of_record +SF:lib\models\user_booking_show_model.dart +DA:17,4 +LF:1 +LH:1 +end_of_record +SF:lib\models\user_booking_show_model.g.dart DA:9,2 -DA:10,2 DA:11,2 DA:12,2 -DA:16,2 +DA:13,4 +DA:14,4 DA:17,2 -DA:18,2 DA:19,2 -LF:8 -LH:8 +DA:20,2 +DA:21,4 +DA:22,4 +DA:25,2 +DA:31,0 +DA:33,0 +DA:37,4 +DA:38,6 +DA:39,0 +DA:41,0 +DA:43,0 +DA:46,0 +DA:48,2 +LF:20 +LH:14 end_of_record -SF:lib\models\seat_model.dart -DA:14,4 -LF:1 -LH:1 +SF:lib\models\user_payment_model.dart +DA:19,2 +DA:30,2 +LF:2 +LH:2 +end_of_record +SF:lib\models\user_payment_model.g.dart +DA:9,1 +DA:10,1 +DA:11,1 +DA:12,2 +DA:13,2 +DA:15,2 +DA:17,2 +DA:20,1 +DA:21,1 +DA:22,1 +DA:23,1 +DA:24,2 +DA:25,2 +DA:26,2 +DA:29,1 +DA:35,0 +DA:37,0 +DA:41,2 +DA:42,3 +DA:43,0 +DA:45,0 +DA:47,0 +DA:50,0 +DA:52,1 +DA:61,1 +DA:63,1 +DA:64,1 +DA:65,1 +DA:68,1 +DA:70,1 +DA:71,1 +DA:72,1 +LF:32 +LH:26 end_of_record -SF:lib\models\show_model.freezed.dart +SF:lib\services\networking\api_endpoint.dart DA:10,0 -DA:12,0 -DA:15,1 -DA:16,1 -DA:21,4 -DA:23,0 DA:27,0 +DA:30,0 +DA:31,0 +DA:32,0 +DA:33,0 DA:34,0 DA:35,0 -DA:44,0 -DA:45,0 +DA:36,0 +DA:43,0 DA:46,0 +DA:47,0 DA:48,0 DA:49,0 -DA:51,0 +DA:57,0 +DA:60,0 +DA:61,0 +DA:62,0 DA:63,0 -DA:69,0 +DA:65,0 +DA:66,0 +DA:67,0 DA:75,0 -DA:76,0 -DA:77,0 +DA:78,0 +DA:79,0 DA:80,0 DA:81,0 +DA:83,0 DA:84,0 DA:85,0 -DA:104,0 -DA:105,0 -DA:107,0 +DA:93,0 +DA:96,0 +DA:97,0 +DA:98,0 +DA:99,0 +DA:100,0 DA:108,0 -DA:110,0 -DA:116,0 -DA:117,0 -DA:118,0 -DA:121,0 +DA:111,0 +DA:112,0 +DA:113,0 +DA:114,0 DA:122,0 DA:125,0 DA:126,0 -DA:137,1 -DA:139,1 -DA:141,1 -DA:142,1 +DA:127,0 +DA:128,0 +DA:129,0 +DA:131,0 +DA:132,0 +DA:133,0 +DA:135,0 +DA:136,0 +DA:137,0 +DA:145,0 +DA:148,0 +DA:149,0 +DA:150,0 DA:151,0 DA:153,0 -DA:156,1 -DA:159,1 -DA:160,2 -DA:161,3 -DA:162,2 -DA:164,0 -DA:165,2 -DA:167,3 -DA:170,0 -DA:172,0 -DA:173,0 -DA:174,0 -DA:175,0 -DA:177,0 -DA:180,0 -DA:182,1 -DA:184,1 -DA:193,2 -DA:198,0 -DA:199,0 -DA:200,0 -DA:201,0 -DA:202,0 -DA:203,0 -DA:204,0 -DA:207,0 -LF:68 -LH:17 -end_of_record -SF:lib\models\show_model.g.dart -DA:9,1 -DA:10,1 -DA:11,2 -DA:12,1 -DA:13,1 -DA:14,3 -DA:15,1 -DA:19,1 -DA:20,1 -DA:21,2 -DA:22,1 -DA:23,5 -LF:12 -LH:12 -end_of_record -SF:lib\models\show_model.dart -DA:11,1 -DA:20,1 -DA:21,1 -DA:22,2 -DA:28,1 -DA:29,1 -LF:6 -LH:6 +DA:154,0 +DA:155,0 +DA:162,22 +DA:180,22 +DA:190,22 +DA:198,22 +DA:208,22 +DA:218,22 +DA:226,22 +DA:240,22 +LF:69 +LH:8 end_of_record -SF:lib\models\show_time_model.g.dart -DA:9,2 -DA:10,2 -DA:11,2 -DA:12,4 -DA:13,4 -DA:14,4 -DA:15,4 -DA:16,2 -DA:20,2 -DA:21,2 -DA:23,2 -DA:25,0 -DA:29,6 -DA:30,6 -DA:31,6 -DA:32,6 -DA:33,6 -DA:34,4 -DA:38,2 -DA:44,0 +SF:lib\services\networking\api_service.dart +DA:18,1 +DA:38,0 DA:46,0 -DA:50,4 -DA:51,6 -DA:52,0 +DA:48,0 DA:54,0 -DA:56,0 -DA:59,0 -DA:61,2 -LF:28 -LH:21 +DA:57,0 +DA:78,0 +DA:86,0 +DA:89,0 +DA:94,0 +DA:114,0 +DA:122,0 +DA:125,0 +DA:129,0 +DA:149,0 +DA:157,0 +DA:160,0 +DA:164,0 +DA:184,0 +DA:192,0 +DA:195,0 +DA:199,0 +DA:206,0 +DA:208,0 +LF:24 +LH:1 end_of_record -SF:lib\models\show_time_model.dart -DA:13,3 +SF:lib\services\networking\dio_service.dart +DA:25,1 DA:26,1 -DA:27,2 -DA:28,1 -DA:37,2 -DA:38,2 -LF:6 -LH:6 -end_of_record -SF:lib\models\show_time_model.freezed.dart -DA:10,0 -DA:12,0 -DA:15,2 -DA:16,2 -DA:21,4 -DA:23,0 -DA:30,0 -DA:40,0 -DA:41,0 -DA:50,0 -DA:51,0 -DA:52,0 +DA:27,3 +DA:33,0 +DA:35,0 +DA:37,0 DA:53,0 -DA:54,0 -DA:55,0 -DA:56,0 -DA:58,0 -DA:59,0 -DA:61,0 -DA:81,0 -DA:87,0 -DA:96,0 +DA:60,0 +DA:64,0 +DA:66,0 +DA:67,0 +DA:68,0 +DA:84,0 +DA:91,0 +DA:95,0 DA:97,0 DA:98,0 -DA:101,0 -DA:102,0 -DA:105,0 -DA:106,0 -DA:109,0 -DA:110,0 -DA:113,0 -DA:114,0 -DA:117,0 -DA:118,0 -DA:145,0 -DA:147,0 -DA:149,0 -DA:150,0 -DA:152,0 +DA:99,0 +DA:115,0 +DA:122,0 +DA:126,0 +DA:128,0 +DA:129,0 +DA:130,0 +DA:146,0 +DA:153,0 +DA:157,0 +DA:159,0 +DA:160,0 DA:161,0 -DA:162,0 -DA:163,0 -DA:166,0 -DA:167,0 -DA:170,0 -DA:171,0 -DA:174,0 -DA:175,0 -DA:178,0 -DA:179,0 -DA:182,0 -DA:183,0 -DA:194,3 -DA:201,3 -DA:203,2 -DA:204,2 -DA:220,0 -DA:222,0 -DA:225,3 -DA:228,3 -DA:229,6 -DA:230,0 -DA:231,6 -DA:233,9 -DA:234,6 -DA:236,9 -DA:237,6 -DA:239,3 -DA:240,6 -DA:242,0 -DA:243,6 -DA:245,0 -DA:248,0 -DA:250,0 -DA:251,0 -DA:252,0 -DA:253,0 -DA:254,0 -DA:255,0 -DA:256,0 -DA:258,0 -DA:261,0 -DA:263,2 -DA:265,2 -DA:277,6 -DA:282,0 -DA:284,0 -DA:285,0 -DA:286,0 -DA:287,0 -DA:288,0 -DA:289,0 -DA:290,0 -DA:291,0 -DA:292,0 -DA:293,0 -DA:294,0 -DA:295,0 -DA:298,0 -LF:99 -LH:21 +LF:30 +LH:3 end_of_record -SF:lib\models\show_seating_model.freezed.dart -DA:10,0 -DA:12,0 -DA:17,2 -DA:19,0 -DA:23,0 -DA:36,0 -DA:37,0 -DA:38,0 +SF:lib\services\networking\interceptors\api_interceptor.dart +DA:16,2 +DA:35,0 +DA:39,0 DA:40,0 +DA:41,0 DA:42,0 -DA:62,0 -DA:68,0 -DA:74,0 +DA:45,0 +DA:47,0 DA:75,0 -DA:76,0 -DA:79,0 DA:80,0 -DA:83,0 +DA:82,0 +DA:85,0 +DA:86,0 +DA:87,0 +LF:14 +LH:1 +end_of_record +SF:lib\services\networking\interceptors\logging_interceptor.dart +DA:34,0 +DA:39,0 +DA:40,0 +DA:42,0 +DA:44,0 +DA:45,0 +DA:47,0 +DA:48,0 +DA:49,0 +DA:52,0 +DA:53,0 +DA:56,0 +DA:58,0 +DA:78,0 DA:84,0 +DA:86,0 +DA:88,0 DA:90,0 DA:92,0 -DA:93,0 -DA:97,0 -DA:99,0 -DA:100,0 +DA:117,0 +DA:122,0 +DA:123,0 +DA:124,0 +DA:125,0 +DA:126,0 DA:127,0 +DA:128,0 DA:129,0 +DA:130,0 DA:131,0 DA:132,0 +DA:133,0 DA:134,0 -DA:140,0 -DA:141,0 +DA:139,0 DA:142,0 +DA:144,0 DA:145,0 -DA:146,0 -DA:149,0 -DA:150,0 -DA:160,1 -DA:172,0 -DA:174,0 -DA:177,1 -DA:180,1 -DA:181,2 -DA:183,3 -DA:184,2 -DA:186,0 -DA:187,2 -DA:189,3 -DA:192,0 -DA:194,0 -DA:195,0 -DA:196,0 -DA:197,0 -DA:199,0 -DA:202,0 -DA:211,0 -DA:212,0 -DA:213,0 -DA:214,0 -DA:215,0 -DA:216,0 -DA:217,0 -DA:220,0 -LF:63 -LH:9 +DA:148,0 +DA:151,0 +DA:153,0 +LF:40 +LH:0 end_of_record -SF:lib\models\theater_model.freezed.dart -DA:10,1 -DA:12,0 -DA:15,1 -DA:16,1 -DA:21,2 -DA:23,0 -DA:32,0 -DA:43,0 -DA:44,0 -DA:53,0 +SF:lib\services\networking\interceptors\refresh_token_interceptor.dart +DA:21,1 +DA:28,0 +DA:45,0 +DA:49,0 +DA:50,0 +DA:51,0 DA:54,0 DA:55,0 -DA:56,0 DA:57,0 -DA:58,0 DA:59,0 DA:60,0 -DA:62,0 DA:63,0 +DA:64,0 DA:65,0 -DA:85,1 +DA:66,0 +DA:67,0 +DA:71,0 +DA:78,0 +DA:81,0 +DA:82,0 +DA:83,0 +DA:86,0 +DA:87,0 +DA:88,0 +DA:89,0 +DA:90,0 DA:91,0 -DA:101,0 -DA:102,0 -DA:103,0 -DA:106,0 -DA:107,0 -DA:110,0 -DA:111,0 +DA:94,0 +DA:100,0 +DA:108,0 DA:114,0 -DA:115,0 +DA:116,0 DA:118,0 DA:119,0 -DA:122,0 DA:123,0 -DA:126,0 +DA:124,0 DA:127,0 -DA:154,1 -DA:156,3 -DA:158,1 -DA:159,1 -DA:161,1 -DA:171,3 -DA:172,1 -DA:173,0 -DA:176,1 -DA:177,2 -DA:180,1 -DA:181,0 -DA:184,1 -DA:185,0 -DA:188,1 -DA:189,0 -DA:192,1 -DA:193,0 -DA:196,1 -DA:197,0 -DA:208,3 -DA:217,1 -DA:219,1 -DA:220,1 -DA:238,0 -DA:240,0 -DA:243,1 -DA:246,1 -DA:247,2 -DA:249,3 -DA:250,2 -DA:252,0 -DA:253,2 -DA:255,0 -DA:256,2 -DA:258,0 -DA:259,2 -DA:261,0 -DA:262,2 -DA:264,3 -DA:265,2 -DA:266,3 -DA:269,0 -DA:271,0 -DA:272,0 -DA:273,0 -DA:274,0 -DA:275,0 -DA:276,0 -DA:277,0 -DA:278,0 -DA:280,1 -DA:283,1 -DA:285,1 -DA:287,1 -DA:301,4 -DA:306,0 -DA:308,0 -DA:309,0 -DA:310,0 -DA:311,0 -DA:312,0 -DA:313,0 -DA:314,0 -DA:315,0 -DA:316,0 -DA:317,0 -DA:318,0 -DA:319,0 -DA:320,0 -DA:321,0 -DA:324,0 -LF:109 -LH:40 -end_of_record -SF:lib\models\theater_model.dart -DA:13,3 -DA:26,1 -DA:41,2 -DA:42,1 -DA:43,1 -DA:44,1 -DA:45,0 -DA:46,1 -DA:47,1 -DA:48,1 -DA:51,1 -DA:52,1 -LF:12 -LH:11 -end_of_record -SF:lib\models\theater_model.g.dart -DA:9,1 -DA:10,1 -DA:11,1 -DA:12,1 -DA:13,1 -DA:14,1 -DA:15,2 -DA:16,1 -DA:17,3 -DA:18,1 -DA:19,1 -DA:20,3 -DA:21,1 -DA:25,1 -DA:26,1 -DA:28,1 -DA:30,0 -DA:34,3 -DA:35,2 -DA:36,2 -DA:37,2 -DA:38,3 -DA:39,6 -DA:40,6 -DA:44,1 -DA:50,0 -DA:52,0 -DA:56,2 -DA:57,3 -DA:58,0 -DA:60,0 -DA:62,0 -DA:65,0 -DA:67,1 -LF:34 -LH:27 +DA:130,0 +DA:131,0 +DA:135,0 +DA:138,0 +DA:139,0 +DA:140,0 +DA:141,0 +DA:142,0 +DA:143,0 +DA:144,0 +DA:145,0 +DA:147,0 +DA:150,0 +DA:151,0 +DA:152,0 +DA:153,0 +DA:154,0 +DA:155,0 +LF:55 +LH:1 end_of_record -SF:lib\models\user_booking_model.freezed.dart -DA:10,0 -DA:12,0 -DA:15,1 -DA:16,1 -DA:21,2 -DA:23,0 +SF:lib\services\repositories\bookings_repository.dart +DA:19,0 +DA:25,0 +DA:26,0 +DA:27,0 DA:28,0 +DA:29,0 +DA:33,0 DA:36,0 DA:37,0 +DA:38,0 +DA:39,0 +DA:43,0 DA:46,0 DA:47,0 -DA:48,0 DA:49,0 -DA:51,0 -DA:52,0 +DA:50,0 DA:54,0 +DA:58,0 +DA:59,0 +DA:61,0 +DA:62,0 +DA:66,0 +DA:70,0 +DA:71,0 +DA:73,0 DA:74,0 -DA:80,0 +DA:78,0 +DA:81,0 +DA:82,0 +DA:83,0 +DA:84,0 +DA:85,0 +DA:86,0 DA:87,0 -DA:88,0 -DA:89,0 DA:92,0 -DA:93,0 +DA:95,0 DA:96,0 DA:97,0 -DA:100,0 -DA:101,0 -DA:107,0 +DA:98,0 +DA:102,0 +DA:105,0 +DA:106,0 +DA:108,0 DA:109,0 -DA:110,0 -DA:136,0 -DA:138,0 -DA:140,0 -DA:141,0 -DA:143,0 -DA:150,0 -DA:151,0 -DA:152,0 -DA:155,0 -DA:156,0 -DA:159,0 -DA:160,0 -DA:163,0 -DA:164,0 -DA:175,1 -DA:181,1 -DA:182,1 -DA:193,0 -DA:195,0 -DA:198,1 -DA:201,1 -DA:202,2 -DA:203,3 -DA:204,2 -DA:206,0 -DA:207,2 -DA:208,3 -DA:209,2 -DA:211,3 -DA:214,0 -DA:216,0 -DA:217,0 -DA:218,0 -DA:219,0 -DA:220,0 -DA:222,0 -DA:225,0 -DA:227,1 -DA:229,1 -DA:243,0 -DA:244,0 -DA:245,0 -DA:246,0 -DA:247,0 -DA:248,0 -DA:249,0 -DA:250,0 -DA:251,0 -DA:254,0 -LF:79 -LH:17 -end_of_record -SF:lib\models\user_booking_model.g.dart -DA:9,1 -DA:10,1 -DA:11,1 -DA:12,1 -DA:13,2 -DA:14,1 -DA:15,3 -DA:16,1 -DA:20,1 -DA:22,1 -DA:23,1 -DA:24,1 -DA:25,2 -DA:26,5 -LF:14 -LH:14 -end_of_record -SF:lib\models\user_booking_model.dart -DA:19,2 -LF:1 -LH:1 +DA:113,0 +DA:114,0 +LF:46 +LH:0 end_of_record -SF:lib\models\user_booking_show_model.g.dart -DA:9,2 -DA:11,2 -DA:12,2 -DA:13,4 -DA:14,4 -DA:18,2 -DA:20,2 -DA:21,2 -DA:22,4 -DA:23,4 -DA:26,2 -DA:32,0 -DA:34,0 -DA:38,4 -DA:39,6 +SF:lib\services\repositories\movies_repository.dart +DA:18,0 +DA:24,0 +DA:27,0 +DA:28,0 +DA:30,0 +DA:31,0 +DA:35,0 +DA:39,0 DA:40,0 DA:42,0 -DA:44,0 +DA:43,0 DA:47,0 -DA:49,2 -LF:20 -LH:14 +DA:51,0 +DA:52,0 +DA:54,0 +DA:55,0 +DA:59,0 +DA:62,0 +DA:63,0 +DA:65,0 +DA:66,0 +DA:70,0 +DA:73,0 +DA:74,0 +DA:75,0 +DA:76,0 +DA:80,0 +DA:83,0 +DA:84,0 +DA:85,0 +DA:86,0 +DA:90,0 +DA:91,0 +LF:33 +LH:0 end_of_record -SF:lib\models\user_booking_show_model.freezed.dart -DA:10,0 -DA:12,0 -DA:15,2 -DA:16,2 -DA:21,2 -DA:23,0 +SF:lib\services\repositories\payments_repository.dart +DA:18,0 +DA:24,0 DA:27,0 -DA:34,0 +DA:28,0 +DA:30,0 +DA:31,0 DA:35,0 -DA:44,0 +DA:38,0 +DA:39,0 +DA:40,0 +DA:41,0 DA:45,0 -DA:46,0 DA:48,0 DA:49,0 DA:51,0 -DA:65,0 -DA:71,0 -DA:77,0 -DA:78,0 -DA:79,0 -DA:82,0 +DA:52,0 +DA:56,0 +DA:60,0 +DA:61,0 +DA:63,0 +DA:64,0 +DA:68,0 +DA:72,0 +DA:73,0 +DA:75,0 +DA:76,0 +DA:80,0 DA:83,0 +DA:84,0 +DA:85,0 DA:86,0 -DA:87,0 -DA:108,0 -DA:110,0 -DA:112,0 -DA:113,0 -DA:115,0 -DA:121,0 +DA:90,0 +DA:91,0 +LF:33 +LH:0 +end_of_record +SF:lib\services\repositories\shows_repository.dart +DA:17,0 +DA:23,0 +DA:26,0 +DA:27,0 +DA:31,0 +DA:32,0 +DA:36,0 +DA:39,0 +DA:40,0 +DA:41,0 +DA:42,0 +DA:46,0 +DA:49,0 +DA:50,0 +DA:52,0 +DA:53,0 +DA:57,0 +DA:61,0 +DA:62,0 +DA:64,0 +DA:65,0 +DA:69,0 +DA:73,0 +DA:74,0 +DA:76,0 +DA:77,0 +DA:81,0 +DA:82,0 +LF:28 +LH:0 +end_of_record +SF:lib\services\repositories\theaters_repository.dart +DA:17,0 +DA:23,0 +DA:26,0 +DA:27,0 +DA:29,0 +DA:30,0 +DA:34,0 +DA:37,0 +DA:38,0 +DA:39,0 +DA:40,0 +DA:44,0 +DA:47,0 +DA:48,0 +DA:50,0 +DA:51,0 +DA:55,0 +DA:59,0 +DA:60,0 +DA:62,0 +DA:63,0 +DA:67,0 +DA:71,0 +DA:72,0 +DA:74,0 +DA:75,0 +DA:79,0 +DA:80,0 +LF:28 +LH:0 +end_of_record +SF:lib\providers\bookings_provider.dart +DA:23,0 +DA:33,0 +DA:38,0 +DA:40,0 +DA:41,0 +DA:44,0 +DA:50,0 +DA:51,0 +DA:52,0 +DA:53,0 +DA:54,0 +DA:56,0 +DA:60,0 +DA:63,0 +DA:66,0 +DA:69,0 +DA:72,0 +DA:75,0 +DA:78,0 +DA:79,0 +DA:80,0 +DA:81,0 +DA:82,0 +DA:83,0 +DA:84,0 +DA:87,0 +DA:88,0 +DA:91,0 +DA:93,0 +DA:99,0 +DA:108,0 +DA:112,0 +DA:117,0 +DA:119,0 +DA:148,0 +DA:151,0 +DA:154,0 +DA:155,0 +LF:38 +LH:0 +end_of_record +SF:lib\providers\forgot_password_provider.dart +DA:17,1 +DA:21,1 +DA:23,0 +DA:25,0 +DA:26,0 +DA:29,0 +DA:30,0 +DA:31,0 +DA:33,0 +DA:34,0 +DA:35,0 +DA:36,0 +DA:37,0 +DA:38,0 +DA:39,0 +DA:45,0 +DA:47,0 +DA:48,0 +DA:49,0 +DA:51,0 +DA:52,0 +DA:53,0 +DA:54,0 +DA:55,0 +DA:56,0 +DA:62,0 +DA:63,0 +DA:64,0 +DA:66,0 +DA:67,0 +DA:68,0 +DA:71,0 +DA:72,0 +DA:73,0 +DA:79,0 +DA:80,0 +LF:36 +LH:2 +end_of_record +SF:lib\providers\movies_provider.dart +DA:20,0 +DA:29,0 +DA:33,0 +DA:37,0 +DA:41,0 +DA:48,0 +DA:50,0 +DA:53,0 +DA:54,0 +DA:56,0 +DA:59,0 +DA:62,0 +DA:65,0 +DA:68,0 +DA:71,0 +DA:82,0 +DA:94,0 +DA:95,0 +DA:96,0 +DA:97,0 +DA:99,0 +DA:100,0 +DA:103,0 +DA:113,0 DA:122,0 DA:123,0 DA:126,0 -DA:127,0 -DA:130,0 -DA:131,0 -DA:142,2 -DA:147,2 -DA:148,2 -DA:157,0 -DA:159,0 -DA:162,2 -DA:165,2 -DA:166,4 -DA:167,0 -DA:168,4 -DA:170,3 -DA:171,4 -DA:173,6 -DA:176,0 -DA:178,0 -DA:179,0 +DA:129,0 +DA:132,0 +DA:133,0 +LF:30 +LH:0 +end_of_record +SF:lib\providers\payments_provider.dart +DA:26,0 +DA:30,0 +DA:39,0 +DA:44,0 +DA:46,0 +DA:49,0 +DA:50,0 +DA:52,0 +DA:55,0 +DA:58,0 +DA:61,0 +DA:64,0 +DA:67,0 +DA:68,0 +DA:69,0 +DA:70,0 +DA:71,0 +DA:73,0 +DA:76,0 +DA:77,0 +DA:78,0 +DA:79,0 +DA:81,0 +DA:82,0 +DA:83,0 +DA:84,0 +DA:88,0 +DA:89,0 +DA:90,0 +DA:118,0 +DA:119,0 +DA:120,0 +DA:121,0 +DA:122,0 +DA:123,0 +DA:124,0 +DA:125,0 +DA:129,0 +DA:135,0 +DA:143,0 +DA:152,0 +DA:154,0 +DA:177,0 DA:180,0 -DA:181,0 DA:183,0 -DA:186,0 -DA:189,2 -DA:191,2 -DA:204,0 -DA:205,0 -DA:206,0 -DA:207,0 -DA:208,0 -DA:209,0 -DA:210,0 -DA:213,0 -LF:66 -LH:15 +DA:184,0 +LF:46 +LH:0 end_of_record -SF:lib\models\user_booking_show_model.dart -DA:16,4 -LF:1 +SF:lib\providers\shows_provider.dart +DA:21,0 +DA:30,0 +DA:37,0 +DA:48,0 +DA:50,0 +DA:53,0 +DA:56,0 +DA:59,0 +DA:62,0 +DA:65,0 +DA:75,0 +DA:81,0 +DA:82,0 +DA:84,0 +DA:85,0 +DA:94,0 +DA:98,0 +DA:108,0 +DA:109,0 +DA:110,0 +DA:111,0 +DA:112,0 +DA:113,0 +DA:114,0 +DA:115,0 +DA:117,0 +DA:118,0 +DA:121,0 +DA:124,0 +DA:127,0 +DA:128,0 +LF:31 +LH:0 +end_of_record +SF:lib\providers\theaters_provider.dart +DA:23,0 +DA:27,0 +DA:55,0 +DA:56,0 +DA:58,0 +DA:59,0 +DA:60,0 +DA:62,0 +DA:64,0 +DA:66,0 +DA:68,0 +DA:70,0 +DA:73,0 +DA:75,0 +DA:78,0 +DA:79,0 +DA:81,0 +DA:82,0 +DA:83,0 +DA:88,0 +DA:92,0 +DA:95,0 +DA:96,0 +DA:100,0 +DA:108,0 +DA:117,0 +DA:119,0 +DA:122,0 +DA:131,0 +DA:139,0 +DA:140,0 +DA:141,0 +DA:144,0 +DA:147,0 +DA:150,0 +DA:151,0 +LF:36 +LH:0 +end_of_record +SF:lib\services\networking\network_exception.dart +DA:57,0 +DA:59,0 +DA:60,0 +DA:61,0 +DA:66,0 +DA:71,0 +DA:76,0 +DA:81,0 +DA:82,0 +DA:83,0 +DA:89,0 +DA:90,0 +DA:92,0 +DA:93,0 +DA:98,0 +DA:110,0 +DA:111,0 +DA:113,0 +DA:115,0 +LF:19 +LH:0 +end_of_record +SF:lib\services\local_storage\key_value_storage_base.dart +DA:22,22 +DA:25,0 +DA:31,0 +DA:32,0 +DA:37,0 +DA:40,0 +DA:41,0 +DA:42,0 +DA:43,0 +DA:44,0 +DA:46,0 +DA:52,0 +DA:54,0 +DA:55,0 +DA:56,0 +DA:61,0 +DA:63,0 +DA:64,0 +DA:65,0 +DA:66,0 +DA:67,0 +DA:72,0 +DA:74,0 +DA:75,0 +DA:76,0 +DA:77,0 +DA:82,0 +DA:85,0 +DA:87,0 +DA:89,0 +LF:30 +LH:1 +end_of_record +SF:lib\services\networking\api_interface.dart +DA:14,0 +LF:1 +LH:0 +end_of_record +SF:lib\views\widgets\common\custom_dialog.dart +DA:12,22 +DA:20,0 +DA:47,0 +DA:49,0 +DA:58,0 +DA:59,0 +DA:60,0 +DA:64,0 +DA:68,0 +DA:69,0 +DA:70,0 +DA:72,0 +DA:73,0 +DA:74,0 +DA:80,0 +DA:81,0 +DA:82,0 +DA:85,0 +DA:86,0 +DA:87,0 +DA:88,0 +DA:89,0 +DA:93,0 +DA:96,0 +DA:97,0 +DA:98,0 +DA:101,0 +DA:103,0 +DA:104,0 +DA:105,0 +DA:111,0 +DA:112,0 +DA:113,0 +DA:123,4 +DA:128,0 +DA:138,10 +DA:145,0 +LF:37 +LH:3 +end_of_record +SF:lib\views\widgets\common\scrollable_column.dart +DA:13,4 +DA:27,4 +DA:29,4 +DA:31,4 +DA:33,8 +DA:34,4 +DA:35,4 +DA:36,4 +DA:37,0 +DA:38,0 +DA:41,4 +DA:42,4 +DA:43,4 +DA:44,4 +DA:45,4 +DA:46,4 +DA:47,16 +DA:49,4 +DA:50,4 +DA:51,4 +DA:52,4 +DA:54,4 +DA:56,4 +DA:57,4 +LF:24 +LH:22 +end_of_record +SF:lib\views\widgets\common\rounded_bottom_container.dart +DA:12,4 +DA:17,4 +DA:19,4 +DA:21,4 +DA:30,4 +DA:33,4 +DA:35,4 +DA:44,4 +DA:47,4 +DA:48,4 +DA:49,4 +DA:51,4 +LF:12 +LH:12 +end_of_record +SF:lib\views\widgets\change_password\change_password_fields.dart +DA:18,1 +DA:24,1 +DA:26,3 +DA:27,1 +DA:29,1 +DA:31,1 +DA:34,1 +DA:37,0 +DA:39,0 +DA:46,1 +DA:49,1 +DA:52,0 +DA:54,0 +DA:61,1 +DA:64,1 +DA:67,0 +DA:69,0 +LF:17 +LH:11 +end_of_record +SF:lib\views\widgets\change_password\save_password_button.dart +DA:17,1 +DA:20,1 +DA:22,1 +DA:24,1 +DA:26,1 +DA:28,1 +DA:29,1 +DA:30,3 +DA:31,1 +DA:32,0 +DA:40,1 +LF:11 +LH:10 +end_of_record +SF:lib\views\widgets\common\custom_textfield.dart +DA:29,4 +DA:64,4 +DA:66,4 +DA:67,4 +DA:74,8 +DA:76,13 +DA:78,12 +DA:80,4 +DA:81,12 +DA:83,1 +DA:84,1 +DA:85,3 +DA:86,2 +DA:89,1 +DA:90,2 +DA:91,0 +DA:92,0 +DA:96,1 +DA:97,4 +DA:98,2 +DA:99,1 +DA:104,0 +DA:105,0 +DA:106,0 +DA:110,4 +DA:120,4 +DA:127,0 +DA:137,4 +DA:139,4 +DA:141,4 +DA:143,8 +DA:144,4 +DA:145,8 +DA:146,4 +DA:147,8 +DA:148,4 +DA:149,8 +DA:150,8 +DA:151,8 +DA:162,4 +DA:163,8 +DA:164,8 +DA:165,4 +DA:166,8 +DA:167,8 +DA:168,8 +DA:169,8 +DA:170,8 +DA:171,8 +DA:172,8 +DA:173,8 +DA:178,8 +DA:179,4 +DA:180,4 +DA:181,4 +DA:182,4 +DA:183,4 +DA:184,8 +DA:185,8 +DA:186,8 +DA:187,8 +DA:188,8 +DA:189,8 +DA:193,4 +DA:194,4 +DA:195,4 +DA:196,4 +DA:197,4 +DA:198,4 +DA:199,4 +DA:212,4 +DA:214,0 +DA:215,0 +DA:216,0 +DA:217,0 +DA:218,0 +DA:219,0 +DA:220,0 +LF:78 +LH:65 +end_of_record +SF:lib\views\widgets\common\custom_text_button.dart +DA:19,5 +DA:34,5 +DA:60,5 +DA:62,5 +DA:63,5 +DA:64,5 +DA:65,10 +DA:66,5 +DA:67,10 +DA:70,10 +DA:71,5 +DA:72,5 +DA:73,5 +DA:74,5 +DA:75,5 +DA:76,10 +DA:77,5 +DA:78,10 +DA:79,5 +DA:81,5 +DA:88,5 +DA:98,5 +DA:112,2 +DA:122,2 +LF:24 +LH:24 +end_of_record +SF:lib\views\screens\forgot_password_screen.dart +DA:26,1 +DA:28,0 +DA:29,0 +DA:32,0 +DA:40,0 +DA:43,1 +DA:48,2 +DA:49,1 +DA:50,1 +DA:51,1 +DA:52,0 +DA:53,0 +DA:54,0 +DA:55,0 +DA:56,0 +DA:57,0 +DA:58,0 +DA:60,0 +DA:61,0 +DA:70,0 +DA:72,0 +DA:73,0 +DA:77,0 +DA:78,0 +DA:79,0 +DA:83,0 +DA:85,1 +DA:86,0 +DA:87,1 +DA:88,1 +DA:90,1 +DA:91,0 +DA:92,0 +DA:93,1 +DA:95,1 +DA:102,1 +DA:103,0 +DA:104,0 +DA:105,0 +DA:127,1 +DA:128,0 +DA:129,0 +DA:130,0 +LF:43 +LH:14 +end_of_record +SF:lib\views\widgets\forgot_password\forgot_button_widget.dart +DA:20,1 +DA:25,1 +DA:27,1 +DA:28,1 +DA:34,0 +DA:39,0 +DA:40,0 +DA:41,0 +DA:43,0 +DA:45,0 +DA:47,0 +DA:48,0 +DA:54,1 +DA:56,2 +DA:57,1 +DA:59,1 +DA:60,1 +DA:61,2 +DA:63,0 +DA:77,1 +DA:79,1 +DA:80,2 +DA:82,0 +DA:94,1 +DA:96,1 +DA:97,2 +DA:99,0 +DA:113,1 +DA:115,0 +DA:117,0 +DA:128,0 +DA:129,0 +LF:32 +LH:17 +end_of_record +SF:lib\views\widgets\forgot_password\forgot_message_widget.dart +DA:13,4 +DA:15,0 +DA:17,1 +DA:18,1 +DA:21,2 +DA:28,1 +DA:30,2 +DA:31,1 +DA:32,2 +DA:36,2 +DA:37,2 +DA:38,0 +DA:39,0 +LF:13 +LH:10 +end_of_record +SF:lib\views\widgets\forgot_password\forgot_name_widget.dart +DA:12,4 +DA:14,0 +DA:16,1 +DA:17,1 +DA:23,1 +DA:24,1 +DA:26,3 +DA:30,1 +DA:32,2 +DA:33,1 +DA:34,1 +DA:35,2 +DA:36,1 +DA:38,1 +DA:39,2 +DA:40,1 +DA:42,1 +DA:43,2 +DA:44,1 +DA:46,0 +DA:47,0 +LF:21 +LH:18 +end_of_record +SF:lib\views\widgets\forgot_password\forgot_resend_widget.dart +DA:13,4 +DA:15,0 +DA:17,1 +DA:19,2 +DA:20,1 +DA:21,2 +DA:23,1 +DA:24,1 +DA:25,0 +DA:26,0 +DA:28,1 +DA:30,2 +DA:38,1 +LF:13 +LH:10 +end_of_record +SF:lib\views\widgets\forgot_password\forgot_text_fields.dart +DA:17,1 +DA:22,1 +DA:28,1 +DA:29,1 +DA:35,1 +DA:37,2 +DA:38,1 +DA:39,1 +DA:40,2 +DA:41,2 +DA:48,1 +DA:50,1 +DA:51,1 +DA:52,1 +DA:54,1 +DA:55,2 +DA:56,2 +DA:57,2 +DA:59,1 +DA:61,0 +DA:62,0 +LF:21 +LH:19 +end_of_record +SF:lib\views\widgets\forgot_password\reset_password_fields.dart +DA:13,1 +DA:17,1 +DA:19,1 +DA:21,1 +DA:22,1 +DA:24,1 +DA:27,1 +DA:36,1 +DA:39,1 +DA:42,0 +DA:44,0 +LF:11 +LH:9 +end_of_record +SF:lib\views\widgets\forgot_password\otp_code_fields.dart +DA:15,4 +DA:17,0 +DA:19,1 +DA:21,1 +DA:22,1 +DA:23,1 +DA:25,1 +DA:27,2 +DA:28,1 +DA:43,0 +DA:44,0 +DA:45,0 +DA:47,0 +DA:48,0 +DA:49,0 +DA:50,0 +DA:51,0 +LF:17 +LH:8 +end_of_record +SF:lib\views\screens\home_screen.dart +DA:17,4 +DA:19,1 +DA:21,1 +DA:23,1 +DA:25,1 +DA:27,1 +DA:29,1 +DA:31,2 +DA:37,1 +DA:39,1 +DA:45,1 +DA:47,2 +DA:57,1 +DA:59,1 +DA:61,1 +DA:62,1 +DA:64,0 +DA:65,0 +DA:85,1 +DA:87,0 +DA:89,1 +DA:91,1 +DA:100,1 +DA:102,0 +DA:103,0 +DA:105,1 +LF:26 +LH:21 +end_of_record +SF:lib\helper\utils\assets_helper.dart +DA:7,0 +LF:1 +LH:0 +end_of_record +SF:lib\routes\app_router.gr.dart +DA:26,0 +DA:27,0 +DA:31,0 +DA:33,0 +DA:34,0 +DA:36,0 +DA:38,0 +DA:39,0 +DA:41,0 +DA:43,0 +DA:44,0 +DA:46,0 +DA:48,0 +DA:49,0 +DA:51,0 +DA:53,0 +DA:54,0 +DA:56,0 +DA:58,0 +DA:59,0 +DA:61,0 +DA:63,0 +DA:64,0 +DA:66,0 +DA:68,0 +DA:69,0 +DA:71,0 +DA:73,0 +DA:74,0 +DA:76,0 +DA:78,0 +DA:79,0 +DA:81,0 +DA:83,0 +DA:86,0 +DA:88,0 +DA:91,0 +DA:92,0 +DA:94,0 +DA:95,0 +DA:97,0 +DA:98,0 +DA:100,0 +DA:101,0 +DA:105,0 +DA:106,0 +DA:107,0 +DA:108,0 +DA:109,0 +DA:110,0 +DA:111,0 +DA:113,0 +DA:114,0 +DA:115,0 +DA:116,0 +DA:118,0 +DA:119,0 +DA:121,0 +DA:123,0 +DA:125,0 +DA:131,0 +DA:137,3 +DA:143,3 +DA:149,3 +DA:155,3 +DA:161,3 +DA:167,3 +DA:173,3 +DA:179,3 +DA:180,0 +DA:186,3 +DA:192,3 +DA:198,3 +DA:204,3 +DA:205,0 +DA:211,3 +DA:212,0 +LF:77 +LH:13 +end_of_record +SF:lib\views\screens\app_startup_screen.dart +DA:13,0 +DA:15,0 +DA:17,0 +DA:18,0 +DA:19,0 +DA:20,0 +LF:6 +LH:0 +end_of_record +SF:lib\views\screens\confirmation_screen.dart +DA:16,3 +DA:18,0 +DA:20,0 +DA:22,0 +DA:23,0 +DA:24,0 +DA:29,0 +DA:30,0 +DA:31,0 +DA:32,0 +DA:35,0 +DA:36,0 +DA:37,0 +DA:62,0 +DA:63,0 +DA:88,0 +DA:89,0 +DA:116,0 +DA:117,0 +DA:118,0 +DA:119,0 +LF:21 +LH:1 +end_of_record +SF:lib\views\screens\login_screen.dart +DA:29,1 +DA:31,1 +DA:33,3 +DA:34,1 +DA:35,1 +DA:36,1 +DA:37,1 +DA:38,1 +DA:39,0 +DA:40,0 +DA:41,0 +DA:42,0 +DA:43,0 +DA:45,0 +DA:46,0 +DA:48,0 +DA:49,0 +DA:56,0 +DA:58,1 +DA:59,0 +DA:60,1 +DA:61,1 +DA:63,1 +DA:65,1 +DA:67,1 +DA:69,1 +DA:71,2 +DA:80,1 +DA:92,1 +DA:106,1 +DA:108,1 +DA:109,1 +DA:110,0 +DA:111,0 +DA:113,1 +DA:115,2 +DA:127,1 +DA:129,1 +DA:131,0 +DA:132,0 +DA:133,0 +DA:134,0 +DA:135,0 +DA:136,0 +DA:141,1 +DA:142,1 +DA:143,2 +DA:144,1 +DA:145,0 +DA:153,1 +LF:50 +LH:30 +end_of_record +SF:lib\views\screens\movie_details_screen.dart +DA:17,0 +DA:19,0 +DA:21,0 +DA:23,0 +DA:30,0 +DA:34,0 +DA:36,0 +DA:37,0 +DA:39,0 +DA:47,0 +DA:48,0 +DA:54,0 +DA:57,0 +DA:59,0 +DA:63,0 +DA:64,0 +LF:16 +LH:0 +end_of_record +SF:lib\views\screens\movies_screen.dart +DA:24,0 +DA:26,0 +DA:28,0 +DA:29,0 +DA:30,0 +DA:32,0 +DA:35,0 +DA:36,0 +DA:37,0 +DA:38,0 +DA:40,0 +DA:41,0 +DA:43,0 +DA:45,0 +DA:46,0 +DA:53,0 +DA:58,0 +DA:66,0 +DA:67,0 +DA:68,0 +DA:76,0 +DA:78,0 +DA:79,0 +DA:96,0 +DA:97,0 +DA:100,0 +DA:101,0 +DA:102,0 +DA:103,0 +LF:29 +LH:0 +end_of_record +SF:lib\views\screens\payment_screen.dart +DA:16,0 +DA:18,0 +DA:20,0 +DA:21,0 +DA:22,0 +DA:23,0 +DA:24,0 +DA:25,0 +DA:34,0 +DA:47,0 +DA:48,0 +DA:55,0 +DA:81,3 +DA:83,0 +DA:85,0 +DA:87,0 +DA:89,0 +DA:92,0 +DA:93,0 +DA:100,0 +DA:102,0 +LF:21 +LH:1 +end_of_record +SF:lib\views\screens\register_screen.dart +DA:27,1 +DA:29,1 +DA:30,1 +DA:35,2 +DA:37,0 +DA:38,0 +DA:39,0 +DA:40,0 +DA:42,0 +DA:49,0 +DA:51,0 +DA:54,1 +DA:55,1 +DA:57,1 +DA:58,3 +DA:59,3 +DA:60,1 +DA:64,1 +DA:65,1 +DA:89,1 +DA:96,1 +DA:98,0 +DA:99,0 +DA:100,0 +DA:101,0 +DA:111,1 +DA:112,1 +DA:113,2 +DA:114,1 +DA:141,1 +DA:142,1 +DA:145,1 +DA:146,2 +DA:149,0 +DA:150,0 +DA:151,0 +DA:152,0 +DA:153,0 +DA:154,0 +DA:163,1 +DA:165,1 +DA:166,1 +DA:167,1 +DA:168,1 +DA:169,1 +DA:170,1 +DA:171,1 +DA:173,0 +DA:174,0 +DA:175,0 +DA:176,0 +DA:177,0 +DA:178,0 +DA:179,0 +DA:180,0 +DA:181,0 +DA:184,1 +DA:185,1 +DA:186,1 +DA:187,0 +DA:189,0 +DA:190,0 +DA:192,1 +DA:193,0 +DA:194,1 +DA:195,1 +DA:197,1 +DA:198,1 +DA:199,1 +DA:200,1 +DA:201,1 +DA:202,1 +DA:203,1 +DA:205,1 +DA:207,2 +DA:215,1 +DA:216,1 +DA:223,1 +DA:234,1 +DA:241,1 +DA:244,1 +DA:245,1 +DA:246,1 +DA:247,1 +DA:248,1 +DA:249,1 +DA:250,1 +DA:251,1 +DA:269,1 +DA:276,1 +DA:278,1 +DA:279,1 +DA:281,1 +DA:282,1 +DA:293,1 +DA:294,1 +DA:305,1 +DA:306,1 +DA:317,1 +DA:318,1 +DA:324,1 +DA:326,1 +DA:327,1 +DA:329,1 +DA:354,1 +DA:359,1 +DA:361,1 +DA:362,1 +DA:364,1 +DA:365,1 +DA:377,1 +DA:378,1 +DA:383,0 +DA:385,0 +LF:114 +LH:82 +end_of_record +SF:lib\views\screens\shows_screen.dart +DA:29,0 +DA:31,0 +DA:33,0 +DA:34,0 +DA:35,0 +DA:36,0 +DA:37,0 +DA:41,0 +DA:43,0 +DA:45,0 +DA:48,0 +DA:49,0 +DA:56,0 +DA:57,0 +DA:58,0 +DA:59,0 +DA:60,0 +DA:65,0 +DA:78,0 +DA:79,0 +DA:82,0 +DA:83,0 +DA:85,0 +DA:87,0 +DA:89,0 +DA:99,0 +DA:110,0 +DA:116,0 +DA:118,0 +DA:128,0 +DA:145,0 +DA:147,0 +DA:162,0 +DA:164,0 +DA:165,0 +DA:166,0 +DA:167,0 +DA:168,0 +DA:169,0 +DA:171,0 +DA:172,0 +DA:173,0 +DA:195,0 +DA:196,0 +DA:197,0 +LF:45 +LH:0 +end_of_record +SF:lib\views\screens\theater_screen.dart +DA:28,0 +DA:33,0 +DA:34,0 +DA:37,0 +DA:38,0 +DA:41,0 +DA:43,0 +DA:44,0 +DA:45,0 +DA:46,0 +DA:48,0 +DA:50,0 +DA:59,0 +DA:60,0 +DA:63,0 +DA:64,0 +DA:65,0 +DA:66,0 +DA:67,0 +DA:68,0 +DA:69,0 +DA:71,0 +DA:72,0 +DA:74,0 +DA:75,0 +DA:82,0 +DA:87,0 +DA:88,0 +DA:89,0 +DA:90,0 +DA:91,0 +DA:92,0 +DA:103,0 +DA:105,0 +DA:106,0 +DA:108,0 +DA:109,0 +DA:111,0 +DA:121,0 +DA:135,0 +DA:136,0 +DA:138,0 +DA:153,3 +DA:155,0 +DA:157,0 +DA:159,0 +DA:161,0 +DA:162,0 +DA:163,0 +LF:49 +LH:1 +end_of_record +SF:lib\views\screens\ticket_summary_screen.dart +DA:12,0 +DA:14,0 +DA:16,0 +DA:18,0 +DA:19,0 +DA:43,3 +DA:45,0 +DA:47,0 +DA:49,0 +DA:51,0 +DA:54,0 +DA:55,0 +DA:62,0 +DA:65,0 +DA:66,0 +LF:15 +LH:1 +end_of_record +SF:lib\views\screens\trailer_screen.dart +DA:15,0 +DA:17,0 +DA:18,0 +DA:36,0 +DA:38,0 +DA:39,0 +DA:40,0 +DA:41,0 +DA:46,0 +DA:50,0 +DA:53,0 +DA:54,0 +DA:56,0 +DA:57,0 +DA:61,0 +DA:67,0 +DA:69,0 +DA:70,0 +DA:71,0 +DA:72,0 +DA:76,0 +DA:77,0 +DA:79,0 +DA:81,0 +DA:82,0 +DA:89,0 +DA:90,0 +DA:91,0 +DA:92,0 +DA:93,0 +DA:96,0 +DA:104,0 +DA:111,0 +DA:112,0 +LF:34 +LH:0 +end_of_record +SF:lib\views\screens\user_bookings_screen.dart +DA:11,3 +DA:13,0 +DA:15,0 +DA:16,0 +DA:17,0 +DA:18,0 +DA:22,0 +DA:24,0 +DA:26,0 +DA:29,0 +DA:30,0 +DA:37,0 +DA:38,0 +DA:43,0 +LF:14 +LH:1 +end_of_record +SF:lib\views\screens\welcome_screen.dart +DA:22,3 +DA:24,0 +DA:26,0 +DA:28,0 +DA:30,0 +DA:32,0 +DA:36,0 +DA:38,0 +DA:40,0 +DA:42,0 +DA:49,0 +DA:50,0 +DA:51,0 +DA:57,0 +DA:64,0 +DA:65,0 +DA:74,0 +DA:76,0 +LF:18 +LH:1 +end_of_record +SF:lib\views\widgets\confirmation\more_bookings_button.dart +DA:18,3 +DA:20,0 +DA:22,0 +DA:24,0 +DA:26,0 +DA:27,0 +DA:28,0 +LF:7 +LH:1 +end_of_record +SF:lib\views\widgets\confirmation\retry_payment_button.dart +DA:14,3 +DA:16,0 +DA:18,0 +DA:20,0 +DA:22,0 +DA:23,0 +LF:6 +LH:1 +end_of_record +SF:lib\views\widgets\movie_details\floating_movie_posters.dart +DA:16,3 +DA:18,0 +DA:19,0 +DA:25,0 +DA:27,0 +DA:28,0 +DA:29,0 +DA:30,0 +DA:35,0 +DA:37,0 +DA:39,0 +DA:41,0 +DA:42,0 +DA:52,0 +DA:53,0 +DA:74,0 +DA:75,0 +DA:88,3 +DA:90,0 +DA:92,0 +DA:94,0 +DA:95,0 +DA:96,0 +DA:105,3 +DA:107,0 +DA:109,0 +DA:111,0 +DA:112,0 +DA:113,0 +DA:122,3 +DA:124,0 +DA:126,0 +DA:128,0 +DA:129,0 +DA:131,0 +DA:132,0 +DA:133,0 +DA:134,0 +DA:135,0 +DA:140,0 +LF:40 +LH:4 +end_of_record +SF:lib\views\widgets\movie_details\movie_details_sheet.dart +DA:17,0 +DA:18,0 +DA:21,3 +DA:23,0 +DA:24,0 +DA:31,0 +DA:32,0 +DA:35,0 +DA:40,0 +DA:43,0 +DA:44,0 +DA:47,0 +DA:50,0 +DA:51,0 +DA:54,0 +DA:56,0 +DA:59,0 +DA:60,0 +DA:63,0 +DA:64,0 +DA:67,0 +DA:68,0 +DA:69,0 +DA:78,0 +DA:80,0 +DA:81,0 +DA:82,0 +DA:86,0 +DA:87,0 +DA:88,0 +DA:89,0 +DA:96,0 +DA:99,0 +DA:101,0 +DA:102,0 +DA:109,0 +DA:110,0 +DA:111,0 +DA:115,0 +DA:158,0 +DA:159,0 +DA:160,0 +DA:162,0 +DA:165,0 +LF:44 +LH:1 +end_of_record +SF:lib\views\skeletons\movies_skeleton_loader.dart +DA:11,3 +DA:13,0 +DA:15,0 +DA:16,0 +DA:19,0 +DA:21,0 +DA:32,0 +DA:34,0 +DA:36,0 +DA:37,0 +DA:38,0 +DA:62,0 +DA:63,0 +DA:64,0 +DA:74,0 +DA:151,0 +DA:152,0 +DA:153,0 +LF:18 +LH:1 +end_of_record +SF:lib\views\widgets\movies\movie_backdrop_view.dart +DA:12,0 +DA:16,0 +DA:21,0 +DA:23,0 +DA:26,0 +DA:27,0 +DA:28,0 +DA:29,0 +DA:31,0 +DA:37,0 +LF:10 +LH:0 +end_of_record +SF:lib\views\widgets\movies\movie_carousel.dart +DA:26,0 +DA:31,0 +DA:32,0 +DA:38,0 +DA:40,0 +DA:42,0 +DA:43,0 +DA:45,0 +DA:46,0 +DA:47,0 +DA:48,0 +DA:49,0 +DA:50,0 +DA:51,0 +DA:52,0 +DA:53,0 +DA:54,0 +DA:55,0 +DA:56,0 +DA:57,0 +DA:58,0 +DA:64,0 +DA:65,0 +DA:72,0 +DA:73,0 +DA:74,0 +DA:75,0 +DA:76,0 +DA:78,0 +LF:29 +LH:0 +end_of_record +SF:lib\views\widgets\movies\movie_icons_row.dart +DA:9,3 +DA:11,0 +DA:13,0 +DA:15,0 +DA:17,0 +DA:19,0 +DA:21,0 +DA:24,0 +LF:8 +LH:1 +end_of_record +SF:lib\views\widgets\common\error_response_handler.dart +DA:18,0 +DA:24,0 +DA:34,0 +DA:36,0 +DA:37,0 +DA:38,0 +DA:39,0 +DA:40,0 +DA:43,0 +DA:44,0 +DA:45,0 +DA:53,0 +DA:59,0 +DA:67,0 +DA:69,0 +DA:70,0 +DA:71,0 +DA:72,0 +LF:18 +LH:0 +end_of_record +SF:lib\views\widgets\payment\pay_button.dart +DA:18,3 +DA:20,0 +DA:22,0 +DA:24,0 +DA:26,0 +DA:27,0 +DA:28,0 +LF:7 +LH:1 +end_of_record +SF:lib\views\widgets\payment\billing_details.dart +DA:11,3 +DA:13,0 +DA:15,0 +DA:17,0 +DA:19,0 +DA:29,0 +DA:61,0 +DA:62,0 +DA:64,0 +DA:66,0 +DA:67,0 +DA:68,0 +DA:69,0 +DA:70,0 +DA:107,0 +DA:109,0 +DA:110,0 +DA:111,0 +DA:112,0 +DA:113,0 +DA:114,0 +LF:21 +LH:1 +end_of_record +SF:lib\views\widgets\payment\mode_details_input.dart +DA:18,3 +DA:20,0 +DA:21,0 +DA:28,0 +DA:29,0 +DA:30,0 +DA:31,0 +DA:33,0 +DA:40,0 +DA:42,0 +DA:45,0 +DA:46,0 +DA:49,0 +DA:51,0 +DA:52,0 +DA:53,0 +DA:54,0 +DA:55,0 +DA:56,0 +DA:57,0 +DA:58,0 +DA:59,0 +DA:61,0 +DA:62,0 +DA:63,0 +DA:64,0 +DA:65,0 +DA:69,0 +DA:70,0 +DA:75,0 +DA:76,0 +DA:81,0 +DA:96,0 +DA:101,0 +DA:103,0 +DA:105,0 +DA:108,0 +DA:112,0 +DA:113,0 +DA:124,0 +DA:125,0 +DA:136,0 +DA:137,0 +DA:157,0 +DA:161,0 +DA:163,0 +DA:165,0 +DA:168,0 +DA:172,0 +DA:173,0 +DA:184,0 +DA:185,0 +DA:206,0 +DA:211,0 +DA:213,0 +DA:215,0 +DA:218,0 +DA:222,0 +DA:223,0 +DA:235,0 +DA:236,0 +DA:248,0 +DA:249,0 +LF:63 +LH:1 +end_of_record +SF:lib\views\widgets\payment\payment_options.dart +DA:14,3 +DA:16,0 +DA:18,0 +DA:19,0 +DA:21,0 +DA:38,0 +DA:40,0 +DA:42,0 +DA:44,0 +DA:47,0 +DA:51,0 +DA:52,0 +DA:57,0 +DA:59,0 +DA:68,0 +DA:71,0 +DA:75,0 +DA:76,0 +DA:81,0 +DA:83,0 +DA:92,0 +DA:94,0 +DA:96,0 +DA:98,0 +DA:101,0 +DA:105,0 +DA:106,0 +DA:111,0 +DA:113,0 +LF:29 +LH:1 +end_of_record +SF:lib\views\skeletons\shows_skeleton_loader.dart +DA:11,3 +DA:13,0 +DA:15,0 +DA:16,0 +DA:18,0 +DA:20,0 +DA:22,0 +DA:32,0 +DA:33,0 +DA:44,0 +DA:46,0 +DA:47,0 +DA:48,0 +DA:59,0 +DA:80,0 +DA:82,0 +DA:92,0 +DA:93,0 +DA:104,0 +DA:106,0 +DA:121,0 +DA:122,0 +DA:140,0 +DA:142,0 +DA:152,0 +DA:153,0 +LF:26 +LH:1 +end_of_record +SF:lib\views\widgets\show_times\show_dates_list.dart +DA:18,0 +DA:20,0 +DA:21,0 +DA:27,0 +DA:33,0 +DA:36,0 +DA:38,0 +DA:40,0 +DA:41,0 +DA:43,0 +DA:46,0 +DA:47,0 +DA:48,0 +DA:49,0 +DA:52,0 +DA:53,0 +DA:54,0 +DA:55,0 +DA:56,0 +DA:57,0 +DA:60,0 +DA:61,0 +DA:74,0 +DA:80,0 +DA:82,0 +DA:84,0 +DA:85,0 +DA:86,0 +DA:90,0 +DA:91,0 +DA:92,0 +DA:95,0 +DA:97,0 +DA:99,0 +DA:100,0 +DA:102,0 +DA:111,0 +DA:112,0 +DA:114,0 +LF:39 +LH:0 +end_of_record +SF:lib\views\widgets\show_times\show_details_box.dart +DA:17,3 +DA:19,0 +DA:21,0 +DA:22,0 +DA:23,0 +DA:26,0 +DA:31,0 +DA:32,0 +DA:33,0 +DA:34,0 +DA:35,0 +DA:53,0 +DA:54,0 +DA:56,0 +DA:58,0 +DA:59,0 +DA:60,0 +DA:67,0 +DA:68,0 +DA:73,0 +DA:74,0 +DA:79,0 +DA:80,0 +LF:23 +LH:1 +end_of_record +SF:lib\views\widgets\show_times\show_times_list.dart +DA:14,3 +DA:16,0 +DA:25,0 +DA:28,0 +DA:30,0 +DA:31,0 +DA:32,0 +DA:33,0 +DA:35,0 +DA:39,0 +DA:40,0 +DA:41,0 +DA:42,0 +DA:45,0 +DA:46,0 +DA:47,0 +DA:48,0 +DA:50,0 +DA:63,0 +DA:68,0 +DA:70,0 +DA:72,0 +DA:73,0 +DA:74,0 +DA:78,0 +DA:79,0 +DA:80,0 +DA:83,0 +DA:84,0 +DA:85,0 +DA:87,0 +LF:31 +LH:1 +end_of_record +SF:lib\views\skeletons\theater_skeleton_loader.dart +DA:11,3 +DA:18,0 +DA:20,0 +DA:21,0 +DA:22,0 +DA:23,0 +DA:25,0 +DA:26,0 +DA:33,0 +DA:35,0 +DA:36,0 +DA:37,0 +DA:39,0 +DA:41,0 +DA:43,0 +DA:45,0 +DA:46,0 +DA:47,0 +DA:49,0 +DA:50,0 +DA:51,0 +DA:63,0 +DA:64,0 +DA:69,0 +DA:71,0 +DA:73,0 +DA:74,0 +DA:75,0 +DA:77,0 +DA:78,0 +DA:79,0 +DA:106,0 +DA:108,0 +DA:110,0 +DA:111,0 +DA:112,0 +DA:129,0 +DA:131,0 +DA:133,0 +DA:134,0 +DA:135,0 +DA:157,0 +DA:221,3 +DA:223,0 +DA:225,0 +DA:226,0 +DA:227,0 +DA:228,0 +DA:229,0 +DA:231,0 +DA:232,0 +DA:233,0 +DA:234,0 +DA:235,0 +DA:236,0 +DA:237,0 +DA:240,0 +DA:243,0 +LF:58 +LH:2 +end_of_record +SF:lib\views\widgets\common\custom_chips_list.dart +DA:15,0 +DA:28,0 +DA:30,0 +DA:32,0 +DA:33,0 +DA:34,0 +DA:35,0 +DA:38,0 +DA:39,0 +DA:40,0 +DA:42,0 +DA:44,0 +DA:45,0 +DA:46,0 +DA:47,0 +DA:48,0 +DA:55,0 +DA:56,0 +DA:57,0 +DA:59,0 +DA:60,0 +DA:62,0 +DA:64,0 +DA:65,0 +DA:66,0 +DA:67,0 +DA:68,0 +DA:69,0 +DA:71,0 +LF:29 +LH:0 +end_of_record +SF:lib\views\widgets\theater\curved_screen.dart +DA:8,0 +DA:13,0 +DA:15,0 +DA:16,0 +DA:19,0 +DA:20,0 +DA:21,0 +DA:22,0 +DA:31,3 +DA:33,0 +DA:35,0 +DA:36,0 +DA:37,0 +DA:38,0 +DA:39,0 +DA:41,0 +DA:42,0 +DA:43,0 +DA:44,0 +DA:45,0 +DA:46,0 +DA:47,0 +DA:50,0 +DA:52,0 +DA:53,0 +DA:54,0 +DA:55,0 +DA:57,0 +DA:58,0 +DA:59,0 +DA:64,0 +DA:65,0 +DA:66,0 +DA:67,0 +DA:68,0 +DA:69,0 +DA:70,0 +DA:72,0 +DA:73,0 +DA:74,0 +DA:75,0 +DA:76,0 +DA:77,0 +DA:78,0 +DA:80,0 +DA:81,0 +DA:82,0 +DA:83,0 +DA:84,0 +DA:86,0 +DA:87,0 +DA:89,0 +DA:92,0 +LF:53 +LH:1 +end_of_record +SF:lib\views\widgets\theater\purchase_seats_button.dart +DA:18,3 +DA:20,0 +DA:22,0 +DA:24,0 +DA:25,0 +DA:26,0 +DA:27,0 +DA:29,0 +DA:30,0 +DA:32,0 +DA:34,0 +DA:35,0 +DA:36,0 +LF:13 +LH:1 +end_of_record +SF:lib\views\widgets\theater\seat_color_indicators.dart +DA:10,3 +DA:14,3 +DA:22,0 +DA:24,0 +DA:26,0 +DA:28,0 +DA:29,0 +DA:30,0 +DA:32,0 +DA:34,0 +DA:37,0 +DA:38,0 +DA:39,0 +DA:47,0 +DA:48,0 +LF:15 +LH:2 +end_of_record +SF:lib\views\widgets\theater\seats_area.dart +DA:15,0 +DA:28,0 +DA:30,0 +DA:32,0 +DA:34,0 +DA:35,0 +DA:39,0 +DA:40,0 +DA:41,0 +DA:42,0 +DA:48,0 +DA:50,0 +DA:51,0 +DA:52,0 +DA:54,0 +DA:56,0 +DA:58,0 +DA:59,0 +DA:60,0 +DA:62,0 +DA:63,0 +DA:64,0 +DA:75,0 +DA:76,0 +DA:77,0 +DA:78,0 +DA:79,0 +DA:80,0 +DA:81,0 +DA:84,0 +DA:85,0 +DA:86,0 +DA:87,0 +DA:89,0 +DA:90,0 +DA:91,0 +DA:92,0 +DA:94,0 +DA:96,0 +DA:106,0 +LF:40 +LH:0 +end_of_record +SF:lib\views\widgets\ticket_summary\confirm_bookings_button.dart +DA:14,3 +DA:16,0 +DA:18,0 +DA:20,0 +DA:22,0 +DA:23,0 +LF:6 +LH:1 +end_of_record +SF:lib\views\widgets\ticket_summary\tickets_summary_box.dart +DA:21,3 +DA:23,0 +DA:25,0 +DA:26,0 +DA:27,0 +DA:33,0 +DA:34,0 +DA:36,0 +DA:37,0 +DA:38,0 +DA:39,0 +DA:40,0 +DA:65,0 +LF:13 +LH:1 +end_of_record +SF:lib\views\widgets\user_bookings\user_bookings_history.dart +DA:16,3 +DA:18,0 +DA:20,0 +DA:21,0 +DA:24,0 +DA:25,0 +DA:26,0 +DA:27,0 +DA:29,0 +LF:9 +LH:1 +end_of_record +SF:lib\views\widgets\welcome\user_profile_details.dart +DA:13,3 +DA:15,0 +DA:17,0 +DA:19,0 +DA:20,0 +DA:23,0 +DA:25,0 +DA:27,0 +DA:35,0 +DA:36,0 +DA:37,0 +DA:46,0 +DA:48,0 +DA:56,0 +DA:57,0 +DA:58,0 +DA:67,0 +DA:69,0 +DA:77,0 +DA:78,0 +DA:79,0 +DA:88,0 +DA:90,0 +DA:98,0 +DA:99,0 +DA:100,0 +LF:26 +LH:1 +end_of_record +SF:lib\views\widgets\welcome\view_bookings_button.dart +DA:14,3 +DA:16,0 +DA:18,0 +DA:20,0 +DA:21,0 +LF:5 +LH:1 +end_of_record +SF:lib\views\widgets\welcome\browse_movies_button.dart +DA:14,3 +DA:16,0 +DA:18,0 +DA:20,0 +DA:21,0 +LF:5 +LH:1 +end_of_record +SF:lib\views\skeletons\actor_picture_placeholder.dart +DA:6,3 +DA:8,0 +DA:10,0 +LF:3 +LH:1 +end_of_record +SF:lib\views\skeletons\movie_actors_skeleton_loader.dart +DA:10,3 +DA:12,0 +DA:14,0 +DA:15,0 +DA:17,0 +DA:18,0 +DA:21,0 +DA:22,0 +DA:24,0 +LF:9 +LH:1 +end_of_record +SF:lib\views\widgets\common\shimmer_loader.dart +DA:7,3 +DA:9,0 +DA:15,0 +DA:16,0 +DA:17,0 +DA:18,0 +DA:19,0 +DA:20,0 +DA:23,0 +DA:25,0 +DA:26,0 +DA:27,0 +LF:12 +LH:1 +end_of_record +SF:lib\views\skeletons\movie_poster_placeholder.dart +DA:12,15 +DA:25,0 +DA:27,0 +DA:29,0 +DA:30,0 +DA:31,0 +DA:32,0 +DA:34,0 +DA:36,0 +DA:37,0 +DA:38,0 +DA:41,0 +LF:12 +LH:1 +end_of_record +SF:lib\views\skeletons\user_bookings_skeleton_loader.dart +DA:10,3 +DA:12,0 +DA:14,0 +DA:15,0 +DA:18,0 +DA:19,0 +DA:26,3 +DA:28,0 +DA:30,0 +DA:32,0 +DA:34,0 +DA:36,0 +DA:38,0 +DA:40,0 +DA:93,3 +DA:95,0 +DA:97,0 +DA:99,0 +DA:100,0 +DA:109,0 +LF:20 +LH:3 +end_of_record +SF:lib\views\widgets\common\custom_error_widget.dart +DA:19,0 +DA:38,0 +DA:40,0 +DA:41,0 +DA:42,0 +DA:43,0 +DA:44,0 +DA:47,0 +DA:50,0 +DA:51,0 +DA:52,0 +DA:53,0 +DA:55,0 +DA:61,0 +DA:62,0 +DA:64,0 +DA:67,0 +DA:69,0 +DA:70,0 +DA:72,0 +DA:80,0 +DA:92,0 +DA:96,0 +DA:105,0 +DA:109,0 +LF:25 +LH:0 +end_of_record +SF:lib\views\widgets\common\custom_network_image.dart +DA:16,0 +DA:30,0 +DA:32,0 +DA:33,0 +DA:34,0 +DA:35,0 +DA:36,0 +DA:37,0 +DA:38,0 +DA:40,0 +DA:41,0 +DA:42,0 +DA:44,0 +DA:45,0 +DA:46,0 +DA:47,0 +DA:48,0 +DA:49,0 +DA:51,0 +LF:19 +LH:0 +end_of_record +SF:lib\views\widgets\common\ratings.dart +DA:10,0 +DA:13,0 +DA:15,0 +DA:18,0 +DA:19,0 +DA:22,0 +DA:24,0 +DA:25,0 +DA:27,0 +DA:29,0 +DA:30,0 +DA:31,0 +DA:40,0 +DA:41,0 +DA:42,0 +DA:53,0 +DA:54,0 +DA:55,0 +DA:58,0 +DA:61,0 +LF:20 +LH:0 +end_of_record +SF:lib\views\widgets\movie_details\movie_actors_list.dart +DA:29,0 +DA:43,3 +DA:45,0 +DA:54,0 +DA:56,0 +DA:57,0 +DA:59,0 +DA:60,0 +DA:61,0 +DA:63,0 +DA:65,0 +DA:67,0 +DA:69,0 +DA:80,0 +DA:83,0 +DA:84,0 +DA:85,0 +DA:86,0 +DA:89,0 +DA:90,0 +DA:91,0 +DA:92,0 +DA:93,0 +DA:94,0 +DA:95,0 +DA:96,0 +DA:97,0 +DA:98,0 +DA:99,0 +DA:100,0 +DA:106,0 +DA:107,0 +DA:110,0 +DA:120,0 +DA:125,0 +DA:129,0 +DA:131,0 +DA:132,0 +DA:134,0 +DA:135,0 +DA:147,0 +DA:148,0 +DA:149,0 +DA:150,0 +DA:162,0 +DA:163,0 +DA:164,0 +DA:165,0 +LF:48 +LH:1 +end_of_record +SF:lib\views\widgets\movie_details\movie_details_column.dart +DA:16,3 +DA:18,0 +DA:20,0 +DA:21,0 +DA:22,0 +DA:26,0 +DA:27,0 +DA:28,0 +DA:37,0 +DA:40,0 +DA:46,0 +DA:51,0 +DA:52,0 +DA:53,0 +LF:14 +LH:1 +end_of_record +SF:lib\views\widgets\movie_details\movie_summary_box.dart +DA:13,3 +DA:15,0 +DA:17,0 +DA:18,0 +DA:19,0 +DA:21,0 +DA:23,0 +DA:25,0 +DA:27,0 +DA:36,0 +DA:38,0 +DA:39,0 +DA:40,0 +LF:13 +LH:1 +end_of_record +SF:lib\views\widgets\movie_details\play_button_widget.dart +DA:13,3 +DA:15,0 +DA:17,0 +DA:19,0 +DA:20,0 +DA:21,0 +DA:22,0 +DA:24,0 +DA:26,0 +DA:33,0 +DA:35,0 +LF:11 +LH:1 +end_of_record +SF:lib\views\widgets\movies\white_movie_container.dart +DA:19,0 +DA:24,0 +DA:30,0 +DA:32,0 +DA:35,0 +DA:36,0 +DA:44,0 +DA:45,0 +DA:46,0 +DA:48,0 +DA:49,0 +DA:50,0 +DA:52,0 +DA:53,0 +DA:54,0 +DA:56,0 +DA:57,0 +DA:64,0 +DA:65,0 +DA:70,0 +DA:83,0 +LF:21 +LH:0 +end_of_record +SF:lib\views\widgets\movies\movie_type_popup_menu.dart +DA:16,3 +DA:18,0 +DA:20,0 +DA:21,0 +DA:29,0 +DA:31,0 +DA:33,0 +DA:34,0 +DA:35,0 +DA:40,0 +DA:42,0 +DA:43,0 +DA:44,0 +DA:49,0 +DA:51,0 +DA:52,0 +DA:53,0 +DA:58,0 +DA:59,0 +DA:60,0 +DA:61,0 +LF:21 +LH:1 +end_of_record +SF:lib\views\widgets\movies\movie_overview_column.dart +DA:14,0 +DA:17,0 +DA:21,0 +DA:23,0 +DA:24,0 +DA:26,0 +DA:27,0 +DA:30,0 +DA:39,0 +DA:42,0 +DA:48,0 +LF:11 +LH:0 +end_of_record +SF:lib\views\widgets\theater\seat_widget.dart +DA:17,0 +DA:20,0 +DA:22,0 +DA:23,0 +DA:29,0 +DA:30,0 +DA:31,0 +DA:33,0 +DA:34,0 +DA:37,0 +DA:39,0 +DA:42,0 +DA:43,0 +DA:48,0 +DA:49,0 +DA:50,0 +DA:53,0 +DA:54,0 +DA:55,0 +DA:56,0 +DA:58,0 +DA:59,0 +DA:62,0 +DA:63,0 +DA:64,0 +LF:25 +LH:0 +end_of_record +SF:lib\views\widgets\ticket_summary\dashed_ticket_separator.dart +DA:4,6 +DA:6,0 +DA:8,0 +DA:10,0 +DA:63,3 +DA:70,0 +DA:72,0 +DA:73,0 +DA:74,0 +DA:75,0 +DA:77,0 +DA:78,0 +DA:80,0 +DA:81,0 +DA:82,0 +DA:86,0 +LF:16 +LH:2 +end_of_record +SF:lib\views\widgets\ticket_summary\show_details_section.dart +DA:13,3 +DA:15,0 +DA:17,0 +DA:22,0 +DA:23,0 +DA:24,0 +DA:25,0 +DA:26,0 +DA:27,0 +DA:29,0 +DA:31,0 +DA:33,0 +DA:41,0 +DA:42,0 +DA:52,0 +DA:54,0 +DA:62,0 +DA:63,0 +DA:73,0 +DA:75,0 +DA:83,0 +LF:21 +LH:1 +end_of_record +SF:lib\views\widgets\ticket_summary\ticket_details_list.dart +DA:15,3 +DA:17,0 +DA:19,0 +DA:20,0 +DA:21,0 +DA:22,0 +DA:23,0 +DA:24,0 +DA:25,0 +DA:36,0 +DA:38,0 +DA:46,0 +DA:48,0 +DA:56,0 +DA:57,0 +DA:67,0 +LF:16 LH:1 end_of_record -SF:lib\models\user_model.freezed.dart -DA:10,0 -DA:12,0 -DA:15,1 -DA:16,1 -DA:21,1 -DA:23,0 +SF:lib\views\widgets\user_bookings\booking_details_dialog.dart +DA:22,0 +DA:26,0 +DA:28,0 DA:30,0 -DA:40,0 -DA:41,0 +DA:31,0 +DA:34,0 +DA:35,0 +DA:37,0 +DA:38,0 DA:50,0 DA:51,0 -DA:52,0 DA:53,0 -DA:54,0 DA:55,0 DA:56,0 DA:58,0 -DA:59,0 -DA:61,0 -DA:79,0 -DA:85,0 -DA:94,0 -DA:95,0 -DA:96,0 +DA:97,0 +DA:98,0 DA:99,0 -DA:100,0 +DA:101,0 +DA:102,0 DA:103,0 -DA:104,0 -DA:107,0 -DA:108,0 -DA:111,0 -DA:112,0 -DA:115,0 -DA:116,0 -DA:141,0 -DA:142,0 -DA:144,0 +DA:114,0 +DA:136,0 +DA:139,0 +DA:143,0 DA:145,0 -DA:147,0 -DA:156,0 -DA:157,0 -DA:158,0 +DA:146,0 +DA:148,0 +DA:150,0 +DA:151,0 +DA:160,0 DA:161,0 DA:162,0 -DA:165,0 -DA:166,0 -DA:169,0 -DA:170,0 +DA:171,0 DA:173,0 DA:174,0 +DA:176,0 DA:177,0 -DA:178,0 -DA:189,2 -DA:197,1 -DA:198,1 -DA:214,0 -DA:216,0 -DA:219,1 -DA:222,1 -DA:223,2 -DA:224,3 -DA:225,2 -DA:227,0 -DA:228,2 -DA:229,0 -DA:230,2 -DA:232,0 -DA:233,2 -DA:235,0 -DA:236,2 -DA:237,0 -DA:240,0 -DA:242,0 -DA:243,0 -DA:244,0 -DA:245,0 -DA:246,0 -DA:247,0 -DA:248,0 -DA:250,0 -DA:253,0 -DA:255,1 -DA:257,1 -DA:273,0 -DA:275,0 -DA:276,0 -DA:277,0 -DA:278,0 -DA:279,0 -DA:280,0 -DA:281,0 -DA:282,0 -DA:283,0 -DA:284,0 -DA:285,0 -DA:286,0 -DA:289,0 -LF:97 -LH:17 +DA:187,0 +DA:188,0 +DA:193,0 +DA:194,0 +DA:199,0 +DA:200,0 +LF:44 +LH:0 end_of_record -SF:lib\models\user_model.g.dart -DA:9,1 -DA:10,1 -DA:11,1 -DA:12,1 -DA:13,1 -DA:14,1 -DA:15,1 -DA:16,2 -DA:20,1 -DA:21,1 -DA:23,1 -DA:25,1 -DA:29,2 -DA:30,2 -DA:31,2 -DA:32,2 -DA:33,2 -DA:34,3 -DA:38,1 +SF:lib\views\widgets\user_bookings\booking_summary_row.dart +DA:15,0 +DA:22,0 +DA:24,0 +DA:26,0 +DA:28,0 +DA:30,0 +DA:32,0 +DA:33,0 +DA:42,0 DA:44,0 DA:46,0 -DA:50,2 -DA:51,3 -DA:52,0 -DA:54,0 -DA:56,0 -DA:59,0 -DA:61,1 -LF:28 -LH:22 -end_of_record -SF:lib\models\user_model.dart -DA:21,1 -DA:22,1 -LF:2 -LH:2 +DA:47,0 +DA:60,0 +DA:61,0 +DA:72,0 +DA:73,0 +DA:85,0 +DA:86,0 +DA:97,0 +DA:98,0 +DA:110,0 +DA:111,0 +DA:122,0 +DA:123,0 +DA:137,0 +DA:140,0 +DA:148,0 +DA:150,0 +DA:160,0 +DA:161,0 +LF:30 +LH:0 end_of_record -SF:lib\models\user_payment_model.freezed.dart -DA:10,0 -DA:12,0 -DA:15,1 -DA:16,1 -DA:21,1 -DA:23,0 -DA:29,0 +SF:lib\views\widgets\user_bookings\user_bookings_list.dart +DA:18,0 +DA:21,0 +DA:26,0 +DA:27,0 +DA:33,0 +DA:35,0 +DA:36,0 +DA:37,0 DA:38,0 -DA:39,0 +DA:41,0 +DA:42,0 +DA:43,0 DA:48,0 -DA:49,0 DA:50,0 -DA:51,0 DA:52,0 +DA:53,0 DA:54,0 DA:55,0 +DA:56,0 DA:57,0 +DA:58,0 +DA:60,0 +DA:61,0 +DA:62,0 +DA:64,0 +DA:66,0 +DA:69,0 +DA:70,0 +DA:71,0 +DA:75,0 DA:78,0 -DA:84,0 -DA:92,0 -DA:93,0 -DA:94,0 -DA:97,0 -DA:98,0 -DA:101,0 -DA:102,0 -DA:105,0 -DA:106,0 -DA:109,0 -DA:110,0 -DA:116,0 -DA:118,0 -DA:119,0 -DA:146,0 -DA:148,0 -DA:150,0 -DA:151,0 -DA:153,0 -DA:161,0 -DA:162,0 -DA:163,0 -DA:166,0 -DA:167,0 -DA:170,0 -DA:171,0 -DA:174,0 -DA:175,0 -DA:178,0 -DA:179,0 -DA:190,1 -DA:197,1 -DA:198,1 -DA:211,0 -DA:213,0 -DA:216,1 -DA:219,1 -DA:220,2 -DA:222,0 -DA:223,2 -DA:224,0 -DA:225,2 -DA:227,3 -DA:228,2 -DA:230,3 -DA:231,2 -DA:232,3 -DA:235,0 -DA:237,0 -DA:238,0 -DA:239,0 -DA:240,0 -DA:241,0 -DA:242,0 -DA:244,0 -DA:247,0 -DA:249,1 -DA:251,1 -DA:266,0 -DA:267,0 -DA:268,0 -DA:269,0 -DA:270,0 -DA:271,0 -DA:272,0 -DA:273,0 -DA:274,0 -DA:275,0 -DA:276,0 -DA:279,0 -DA:282,1 -DA:284,1 -DA:289,1 -DA:291,0 -DA:293,0 -DA:299,0 -DA:300,0 -DA:309,0 -DA:310,0 -DA:312,0 -DA:313,0 -DA:315,0 -DA:329,0 -DA:335,0 -DA:340,0 -DA:341,0 -DA:342,0 -DA:345,0 -DA:346,0 -DA:367,0 -DA:369,0 -DA:371,0 -DA:372,0 -DA:374,0 -DA:379,0 -DA:380,0 -DA:381,0 -DA:384,0 -DA:385,0 -DA:396,2 -DA:399,1 -DA:400,1 -DA:407,0 -DA:409,0 -DA:412,1 -DA:415,1 -DA:416,2 -DA:417,3 -DA:418,2 -DA:420,0 -DA:423,0 -DA:425,0 -DA:426,0 -DA:427,0 -DA:429,0 -DA:432,0 -DA:435,1 -DA:437,1 -DA:449,0 -DA:450,0 -DA:451,0 -DA:452,0 -DA:453,0 -DA:456,0 -LF:143 -LH:31 -end_of_record -SF:lib\models\user_payment_model.dart -DA:19,2 -DA:31,2 -LF:2 -LH:2 +DA:79,0 +DA:82,0 +LF:33 +LH:0 end_of_record -SF:lib\models\user_payment_model.g.dart -DA:9,1 -DA:10,1 -DA:11,1 +SF:lib\helper\extensions\int_extension.dart +DA:6,2 +DA:9,2 DA:12,2 -DA:13,2 -DA:14,2 -DA:16,2 -DA:20,1 -DA:22,1 -DA:23,1 -DA:24,1 -DA:25,2 -DA:26,2 -DA:27,2 -DA:30,1 -DA:36,0 -DA:38,0 -DA:42,2 -DA:43,3 -DA:44,0 -DA:46,0 -DA:48,0 -DA:51,0 -DA:53,1 -DA:62,1 -DA:64,1 -DA:65,1 -DA:66,1 -DA:70,1 -DA:72,1 -DA:73,1 -DA:74,1 -LF:32 -LH:26 +LF:3 +LH:3 end_of_record diff --git a/google_fonts/Lato-Bold.ttf b/google_fonts/Lato-Bold.ttf new file mode 100644 index 0000000..b63a14d Binary files /dev/null and b/google_fonts/Lato-Bold.ttf differ diff --git a/google_fonts/Lato-Light.ttf b/google_fonts/Lato-Light.ttf new file mode 100644 index 0000000..9c0a705 Binary files /dev/null and b/google_fonts/Lato-Light.ttf differ diff --git a/google_fonts/Lato-Regular.ttf b/google_fonts/Lato-Regular.ttf new file mode 100644 index 0000000..33eba8b Binary files /dev/null and b/google_fonts/Lato-Regular.ttf differ diff --git a/google_fonts/Poppins-Bold.ttf b/google_fonts/Poppins-Bold.ttf new file mode 100644 index 0000000..b94d47f Binary files /dev/null and b/google_fonts/Poppins-Bold.ttf differ diff --git a/google_fonts/Poppins-ExtraLight.ttf b/google_fonts/Poppins-ExtraLight.ttf new file mode 100644 index 0000000..ee62382 Binary files /dev/null and b/google_fonts/Poppins-ExtraLight.ttf differ diff --git a/google_fonts/Poppins-Light.ttf b/google_fonts/Poppins-Light.ttf new file mode 100644 index 0000000..2ab0221 Binary files /dev/null and b/google_fonts/Poppins-Light.ttf differ diff --git a/google_fonts/Poppins-Regular.ttf b/google_fonts/Poppins-Regular.ttf new file mode 100644 index 0000000..be06e7f Binary files /dev/null and b/google_fonts/Poppins-Regular.ttf differ diff --git a/google_fonts/Poppins-SemiBold.ttf b/google_fonts/Poppins-SemiBold.ttf new file mode 100644 index 0000000..dabf7c2 Binary files /dev/null and b/google_fonts/Poppins-SemiBold.ttf differ diff --git a/lib/helper/extensions/string_extension.dart b/lib/helper/extensions/string_extension.dart index f963307..d9e7152 100644 --- a/lib/helper/extensions/string_extension.dart +++ b/lib/helper/extensions/string_extension.dart @@ -3,26 +3,29 @@ import '../utils/constants.dart'; /// A utility with extensions for strings. extension StringExt on String { - /// An extension for validating String as an email. + /// An extension for validating String is an email. bool get isValidEmail => Constants.emailRegex.hasMatch(this); - /// An extension for validating String as a full name. + /// An extension for validating String is a full name. bool get isValidFullName => Constants.fullNameRegex.hasMatch(this); - /// An extension for validating String as a contact. + /// An extension for validating String is a contact. bool get isValidContact => Constants.contactRegex.hasMatch(this); - /// An extension for validating String as a zipcode. + /// An extension for validating String is a zipcode. bool get isValidZipCode => Constants.zipCodeRegex.hasMatch(this); - /// An extension for validating String as a credit card number. + /// An extension for validating String is a credit card number. bool get isValidCreditCardNumber => Constants.creditCardNumberRegex.hasMatch(this); - /// An extension for validating String as a credit card CVV. + /// An extension for validating String is a credit card CVV. bool get isValidCreditCardCVV => Constants.creditCardCVVRegex.hasMatch(this); - /// An extension for validating String as a credit card expiry. + /// An extension for validating String is a credit card expiry. bool get isValidCreditCardExpiry => Constants.creditCardExpiryRegex.hasMatch(this); + + /// An extension for validating String is a valid OTP digit + bool get isValidOtpDigit => Constants.otpDigitRegex.hasMatch(this); /// An extension for converting String to Capitalcase. String get capitalize => this[0].toUpperCase() + this.substring(1).toLowerCase(); diff --git a/lib/helper/typedefs.dart b/lib/helper/typedefs.dart index d620968..7a6a90f 100644 --- a/lib/helper/typedefs.dart +++ b/lib/helper/typedefs.dart @@ -1,2 +1,7 @@ +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import '../providers/states/future_state.dart'; + typedef JSON = Map; -typedef QueryParams = Map; \ No newline at end of file +typedef QueryParams = Map; +typedef StateListener = ProviderListener>; +typedef FutureStateListener = ProviderListener>>; \ No newline at end of file diff --git a/lib/helper/utils/constants.dart b/lib/helper/utils/constants.dart index 7c29bf3..8bbed86 100644 --- a/lib/helper/utils/constants.dart +++ b/lib/helper/utils/constants.dart @@ -142,6 +142,9 @@ class Constants { /// The regular expression for validating credit card expiry in the app. static RegExp creditCardExpiryRegex = RegExp(r'(0[1-9]|10|11|12)/20[0-9]{2}$'); + /// The regular expression for validating credit card expiry in the app. + static final RegExp otpDigitRegex = RegExp('^[0-9]{1}\$'); + /// The error message for invalid email input. static const invalidEmailError = 'Please enter a valid email address'; diff --git a/lib/helper/utils/custom_theme.dart b/lib/helper/utils/custom_theme.dart index 8a6d69c..adf5d64 100644 --- a/lib/helper/utils/custom_theme.dart +++ b/lib/helper/utils/custom_theme.dart @@ -38,7 +38,7 @@ class CustomTheme { height: 1.15, ), headline4: Constants.latoFont.copyWith( - fontWeight: FontWeight.w500, + fontWeight: FontWeight.w400, fontSize: 26, height: 1.15, ), diff --git a/lib/helper/utils/form_validator.dart b/lib/helper/utils/form_validator.dart index 4c0e560..4c3aae5 100644 --- a/lib/helper/utils/form_validator.dart +++ b/lib/helper/utils/form_validator.dart @@ -104,4 +104,10 @@ class FormValidator{ return Constants.invalidCreditCardExpiryError; } + /// A method containing validation logic for single otp digit input. + static String? otpDigitValidator(String? digit){ + if (digit != null && digit.isValidOtpDigit) return null; + return '!'; + } + } diff --git a/lib/main.dart b/lib/main.dart index 40e1e64..633f49b 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -7,8 +7,8 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; //Helper import 'helper/utils/custom_theme.dart'; -//Router -import 'routes/app_router.gr.dart'; +//Routers +import 'routes/app_router.dart'; //Services import 'services/local_storage/key_value_storage_base.dart'; @@ -36,17 +36,17 @@ void setDebugPrint(String? message, {int? wrapWidth}) { } class MyApp extends StatelessWidget { - final _appRouter = AppRouter(); @override Widget build(BuildContext context) { return ProviderScope( - child: MaterialApp.router( - routerDelegate: _appRouter.delegate(), - routeInformationParser: _appRouter.defaultRouteParser(), + child: MaterialApp( debugShowCheckedModeBanner: false, title: 'EZ Tickets', theme: CustomTheme.mainTheme, + initialRoute: AppRouter.initialRoute, + onGenerateRoute: AppRouter.generateRoute, + navigatorKey: AppRouter.navigatorKey, ), ); } diff --git a/lib/models/booking_model.dart b/lib/models/booking_model.dart index ed562e3..ee60e26 100644 --- a/lib/models/booking_model.dart +++ b/lib/models/booking_model.dart @@ -12,7 +12,6 @@ part 'booking_model.g.dart'; class BookingModel with _$BookingModel { const BookingModel._(); - @JsonSerializable() const factory BookingModel({ @JsonKey(toJson: Constants.toNull, includeIfNull: false) required int? bookingId, @JsonKey(includeIfNull: false) required int? userId, diff --git a/lib/models/genre_model.dart b/lib/models/genre_model.dart index 45a6e8f..c70c1aa 100644 --- a/lib/models/genre_model.dart +++ b/lib/models/genre_model.dart @@ -7,7 +7,6 @@ part 'genre_model.g.dart'; @freezed class GenreModel with _$GenreModel { - @JsonSerializable() const factory GenreModel({ required int genreId, required String genre, diff --git a/lib/models/movie_model.dart b/lib/models/movie_model.dart index f756891..91bf472 100644 --- a/lib/models/movie_model.dart +++ b/lib/models/movie_model.dart @@ -17,7 +17,6 @@ List toJsonGenres(List genres) { class MovieModel with _$MovieModel { MovieModel._(); - @JsonSerializable() factory MovieModel({ @JsonKey(toJson: Constants.toNull, includeIfNull: false) required int? movieId, required int year, diff --git a/lib/models/movie_role_model.dart b/lib/models/movie_role_model.dart index 252c9b6..c047ef7 100644 --- a/lib/models/movie_role_model.dart +++ b/lib/models/movie_role_model.dart @@ -14,7 +14,6 @@ part 'movie_role_model.g.dart'; class MovieRoleModel with _$MovieRoleModel { const MovieRoleModel._(); - @JsonSerializable() const factory MovieRoleModel({ required int movieId, required RoleModel role, diff --git a/lib/models/payment_model.dart b/lib/models/payment_model.dart index 6341f8c..9394f1a 100644 --- a/lib/models/payment_model.dart +++ b/lib/models/payment_model.dart @@ -12,7 +12,6 @@ part 'payment_model.g.dart'; class PaymentModel with _$PaymentModel { const PaymentModel._(); - @JsonSerializable() const factory PaymentModel({ @JsonKey(toJson: Constants.toNull, includeIfNull: false) required int? paymentId, required double amount, diff --git a/lib/models/role_model.dart b/lib/models/role_model.dart index c8abdb7..17323fa 100644 --- a/lib/models/role_model.dart +++ b/lib/models/role_model.dart @@ -8,7 +8,6 @@ part 'role_model.g.dart'; @freezed class RoleModel with _$RoleModel { - @JsonSerializable() const factory RoleModel({ required int roleId, required String fullName, diff --git a/lib/models/seat_model.dart b/lib/models/seat_model.dart index 5581e81..72b5a78 100644 --- a/lib/models/seat_model.dart +++ b/lib/models/seat_model.dart @@ -7,7 +7,6 @@ part 'seat_model.g.dart'; @freezed class SeatModel with _$SeatModel { - @JsonSerializable() const factory SeatModel({ required String seatRow, required int seatNumber, diff --git a/lib/models/show_model.dart b/lib/models/show_model.dart index f582d9d..405a9ef 100644 --- a/lib/models/show_model.dart +++ b/lib/models/show_model.dart @@ -11,7 +11,6 @@ part 'show_model.g.dart'; class ShowModel with _$ShowModel { const ShowModel._(); - @JsonSerializable() const factory ShowModel({ required DateTime date, required int movieId, diff --git a/lib/models/show_time_model.dart b/lib/models/show_time_model.dart index c53d7bb..c8cd6ac 100644 --- a/lib/models/show_time_model.dart +++ b/lib/models/show_time_model.dart @@ -13,7 +13,6 @@ part 'show_time_model.g.dart'; class ShowTimeModel with _$ShowTimeModel { const ShowTimeModel._(); - @JsonSerializable() const factory ShowTimeModel({ @JsonKey(toJson: Constants.toNull, includeIfNull: false) @Default(0) int showId, diff --git a/lib/models/theater_model.dart b/lib/models/theater_model.dart index a7f3a3d..cdb0cee 100644 --- a/lib/models/theater_model.dart +++ b/lib/models/theater_model.dart @@ -13,7 +13,6 @@ part 'theater_model.g.dart'; class TheaterModel with _$TheaterModel { const TheaterModel._(); - @JsonSerializable() const factory TheaterModel({ @JsonKey(toJson: Constants.toNull, includeIfNull: false) required int? theaterId, required String theaterName, diff --git a/lib/models/user_booking_model.dart b/lib/models/user_booking_model.dart index 3dba426..2a9f3ff 100644 --- a/lib/models/user_booking_model.dart +++ b/lib/models/user_booking_model.dart @@ -9,7 +9,6 @@ part 'user_booking_model.g.dart'; @freezed class UserBookingModel with _$UserBookingModel { - @JsonSerializable() const factory UserBookingModel({ required String title, required String posterUrl, diff --git a/lib/models/user_booking_show_model.dart b/lib/models/user_booking_show_model.dart index 79cb0b2..b7e500b 100644 --- a/lib/models/user_booking_show_model.dart +++ b/lib/models/user_booking_show_model.dart @@ -8,7 +8,6 @@ part 'user_booking_show_model.g.dart'; @freezed class UserBookingShowModel with _$UserBookingShowModel { - @JsonSerializable(fieldRename: FieldRename.snake) const factory UserBookingShowModel({ required int showId, required ShowType showType, diff --git a/lib/models/user_model.dart b/lib/models/user_model.dart index 5fd97e7..b0ba9b7 100644 --- a/lib/models/user_model.dart +++ b/lib/models/user_model.dart @@ -9,7 +9,6 @@ part 'user_model.g.dart'; @freezed class UserModel with _$UserModel { - @JsonSerializable() const factory UserModel({ @JsonKey(includeIfNull: false) required int? userId, required String fullName, diff --git a/lib/models/user_payment_model.dart b/lib/models/user_payment_model.dart index 566af90..f6e9e03 100644 --- a/lib/models/user_payment_model.dart +++ b/lib/models/user_payment_model.dart @@ -8,7 +8,6 @@ part 'user_payment_model.g.dart'; @freezed class UserPaymentModel with _$UserPaymentModel { - @JsonSerializable() const factory UserPaymentModel({ required int paymentId, required double amount, @@ -23,7 +22,6 @@ class UserPaymentModel with _$UserPaymentModel { @freezed @visibleForTesting class UserPaymentMovieModel with _$UserPaymentMovieModel { - @JsonSerializable() const factory UserPaymentMovieModel({ required String title, required String posterUrl, diff --git a/lib/providers/all_providers.dart b/lib/providers/all_providers.dart index 13d3979..09932ba 100644 --- a/lib/providers/all_providers.dart +++ b/lib/providers/all_providers.dart @@ -3,10 +3,10 @@ import 'package:flutter/foundation.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; //Service imports -import '../services/networking/dio_service.dart'; import '../services/local_storage/key_value_storage_service.dart'; -import '../services/networking/api_service.dart'; import '../services/networking/api_endpoint.dart'; +import '../services/networking/api_service.dart'; +import '../services/networking/dio_service.dart'; //Interceptor imports import '../services/networking/interceptors/api_interceptor.dart'; @@ -24,13 +24,15 @@ import '../services/repositories/theaters_repository.dart'; //Provider imports import 'auth_provider.dart'; import 'bookings_provider.dart'; +import 'forgot_password_provider.dart'; import 'movies_provider.dart'; import 'payments_provider.dart'; import 'shows_provider.dart'; +import 'theaters_provider.dart'; //State imports import 'states/auth_state.dart'; -import 'theaters_provider.dart'; +import 'states/forgot_password_state.dart'; //Services final keyValueStorageServiceProvider = Provider( @@ -104,6 +106,15 @@ final authProvider = StateNotifierProvider((ref) { ); }); +final forgotPasswordProvider = StateNotifierProvider.autoDispose< + ForgotPasswordProvider, ForgotPasswordState>((ref) { + final _authRepository = ref.watch(_authRepositoryProvider); + return ForgotPasswordProvider( + authRepository: _authRepository, + initialState: const ForgotPasswordState.email(), + ); +}); + //data providers final moviesProvider = Provider((ref) { final _moviesRepository = ref.watch(_moviesRepositoryProvider); diff --git a/lib/providers/auth_provider.dart b/lib/providers/auth_provider.dart index c8bcd93..2beb883 100644 --- a/lib/providers/auth_provider.dart +++ b/lib/providers/auth_provider.dart @@ -10,9 +10,9 @@ import '../models/user_model.dart'; import '../services/local_storage/key_value_storage_service.dart'; import '../services/networking/network_exception.dart'; import '../services/repositories/auth_repository.dart'; -import 'states/auth_state.dart'; //States +import 'states/auth_state.dart'; import 'states/future_state.dart'; final changePasswordStateProvider = StateProvider( @@ -120,21 +120,6 @@ class AuthProvider extends StateNotifier { } } - Future forgotPassword(String email) async { - final data = {'email': email}; - return await _authRepository.sendForgotPasswordData(data: data); - } - - Future resetPassword({ - required String email, - required String password, - }) async { - final data = {'email': email, 'password': password}; - final result = await _authRepository.sendResetPasswordData(data: data); - if (result) _updatePassword(password); - return result; - } - Future changePassword({required String newPassword}) async { final data = { 'email': currentUserEmail, @@ -152,14 +137,6 @@ class AuthProvider extends StateNotifier { } } - Future verifyOtp({required String email, required int otp}) async { - final data = { - 'email': email, - 'OTP': otp, - }; - return await _authRepository.sendOtpData(data: data); - } - void _updateAuthProfile() { _keyValueStorageService.setAuthState(state); _keyValueStorageService.setAuthUser(_currentUser!); diff --git a/lib/providers/forgot_password_provider.dart b/lib/providers/forgot_password_provider.dart new file mode 100644 index 0000000..af6736d --- /dev/null +++ b/lib/providers/forgot_password_provider.dart @@ -0,0 +1,82 @@ +import 'package:hooks_riverpod/hooks_riverpod.dart'; + +//Services +import '../services/networking/network_exception.dart'; + +//Repositories +import '../services/repositories/auth_repository.dart'; + +//States +import 'states/forgot_password_state.dart'; + +class ForgotPasswordProvider extends StateNotifier { + final _otpDigits = ['0', '0', '0', '0']; + final AuthRepository _authRepository; + String? _email; + + ForgotPasswordProvider({ + required AuthRepository authRepository, + required ForgotPasswordState initialState, + }) + : _authRepository = authRepository, super(initialState); + + String get _otpCode => _otpDigits.fold('', (otp, digit) => '$otp$digit'); + + void setOtpDigit(int i, String digit) { + _otpDigits[i] = digit; + } + + Future requestOtpCode(String email) async { + final lastState = state; + state = const ForgotPasswordState.loading(loading: 'Verifying user email'); + try { + final data = {'email': email}; + final result = await _authRepository.sendForgotPasswordData(data: data); + _email = email; + state = ForgotPasswordState.otp(otpSentMessage: result); + } on NetworkException catch (e) { + state = ForgotPasswordState.failed( + reason: e.message, + lastState: lastState, + ); + } + } + + Future resendOtpCode() async => requestOtpCode(_email!); + + Future verifyOtp() async { + final lastState = state; + state = const ForgotPasswordState.loading(loading: 'Verifying otp code'); + try { + final data = {'email': _email, 'OTP': _otpCode}; + final result = await _authRepository.sendOtpData(data: data); + state = ForgotPasswordState.resetPassword(otpVerifiedMessage: result); + } on NetworkException catch (e) { + state = ForgotPasswordState.failed( + reason: e.message, + lastState: lastState, + ); + } + } + + Future resetPassword({required String password}) async { + final lastState = state; + state = const ForgotPasswordState.loading(loading: 'Resetting password'); + try { + final data = {'email': _email, 'password': password}; + final result = await _authRepository.sendResetPasswordData(data: data); + state = ForgotPasswordState.success( + success: result, + ); + } on NetworkException catch (e) { + state = ForgotPasswordState.failed( + reason: e.message, + lastState: lastState, + ); + } + } + + void retryForgotPassword(ForgotPasswordState lastState) { + state = lastState; + } +} diff --git a/lib/providers/states/forgot_password_state.dart b/lib/providers/states/forgot_password_state.dart new file mode 100644 index 0000000..e30aa7b --- /dev/null +++ b/lib/providers/states/forgot_password_state.dart @@ -0,0 +1,29 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'forgot_password_state.freezed.dart'; + +@freezed +class ForgotPasswordState with _$ForgotPasswordState { + const factory ForgotPasswordState.email() = FORGOT_PW_EMAIL; + + const factory ForgotPasswordState.otp({ + required String otpSentMessage, + }) = FORGOT_PW_OTP; + + const factory ForgotPasswordState.resetPassword({ + required String otpVerifiedMessage, + }) = FORGOT_PW_RESET_PASSWORD; + + const factory ForgotPasswordState.loading({ + required String loading, + }) = LOADING; + + const factory ForgotPasswordState.failed({ + required String reason, + required ForgotPasswordState lastState, + }) = FORGOT_PW_FAILED; + + const factory ForgotPasswordState.success({ + String? success, + }) = FORGOT_PW_SUCCESS; +} diff --git a/lib/routes/app_router.dart b/lib/routes/app_router.dart index 0357e02..7aaba14 100644 --- a/lib/routes/app_router.dart +++ b/lib/routes/app_router.dart @@ -1,35 +1,170 @@ -import 'package:auto_route/annotations.dart'; +// ignore_for_file: constant_identifier_names import 'package:flutter/material.dart'; +//Screens import '../views/screens/app_startup_screen.dart'; +import '../views/screens/change_password_screen.dart'; +import '../views/screens/confirmation_screen.dart'; +import '../views/screens/forgot_password_screen.dart'; +import '../views/screens/home_screen.dart'; import '../views/screens/login_screen.dart'; -import '../views/screens/register_screen.dart'; -import '../views/screens/movies_screen.dart'; import '../views/screens/movie_details_screen.dart'; -import '../views/screens/trailer_screen.dart'; +import '../views/screens/movies_screen.dart'; +import '../views/screens/payment_screen.dart'; +import '../views/screens/register_screen.dart'; import '../views/screens/shows_screen.dart'; import '../views/screens/theater_screen.dart'; import '../views/screens/ticket_summary_screen.dart'; -import '../views/screens/payment_screen.dart'; -import '../views/screens/confirmation_screen.dart'; +import '../views/screens/trailer_screen.dart'; import '../views/screens/user_bookings_screen.dart'; -import '../views/screens/change_password_screen.dart'; +import '../views/screens/welcome_screen.dart'; + +//Routes +import 'routes.dart'; + +/// A utility class provides basic methods for navigation. +/// This class has no constructor and all variables are `static`. +@immutable +class AppRouter { + const AppRouter._(); + + /// The global key used to access navigator without context + static final GlobalKey navigatorKey = GlobalKey(); + + /// The name of the route that loads on app startup + static const String initialRoute = Routes.AppStartupScreenRoute; + + /// This method is used when the app is navigating using named routes. + /// + /// It maps each route name to a specific screen route. + /// + /// In case of unknown route name, it returns a route indicating error. + static Route? generateRoute(RouteSettings settings) { + // final args = settings.arguments; + switch (settings.name) { + case Routes.AppStartupScreenRoute: + return MaterialPageRoute( + builder: (_) => const AppStartupScreen(), + settings: const RouteSettings(name: Routes.AppStartupScreenRoute), + ); + case Routes.HomeScreenRoute: + return MaterialPageRoute( + builder: (_) => const HomeScreen(), + settings: const RouteSettings(name: Routes.HomeScreenRoute), + ); + case Routes.LoginScreenRoute: + return MaterialPageRoute( + builder: (_) => const LoginScreen(), + settings: const RouteSettings(name: Routes.LoginScreenRoute), + ); + case Routes.RegisterScreenRoute: + return MaterialPageRoute( + builder: (_) => const RegisterScreen(), + settings: const RouteSettings(name: Routes.RegisterScreenRoute), + ); + case Routes.ForgotPasswordScreenRoute: + return MaterialPageRoute( + builder: (_) => const ForgotPasswordScreen(), + settings: const RouteSettings(name: Routes.ForgotPasswordScreenRoute), + ); + case Routes.WelcomeScreenRoute: + return MaterialPageRoute( + builder: (_) => const WelcomeScreen(), + settings: const RouteSettings(name: Routes.WelcomeScreenRoute), + ); + case Routes.ChangePasswordScreenRoute: + return MaterialPageRoute( + builder: (_) => const ChangePasswordScreen(), + settings: const RouteSettings(name: Routes.ChangePasswordScreenRoute), + ); + case Routes.UserBookingsScreenRoute: + return MaterialPageRoute( + builder: (_) => const UserBookingsScreen(), + settings: const RouteSettings(name: Routes.UserBookingsScreenRoute), + ); + case Routes.MoviesScreenRoute: + return MaterialPageRoute( + builder: (_) => const MoviesScreen(), + settings: const RouteSettings(name: Routes.MoviesScreenRoute), + ); + case Routes.MovieDetailsScreenRoute: + return MaterialPageRoute( + builder: (_) => const MovieDetailsScreen(), + settings: const RouteSettings(name: Routes.MovieDetailsScreenRoute), + ); + case Routes.TrailerScreenRoute: + return MaterialPageRoute( + builder: (_) => const TrailerScreen(), + settings: const RouteSettings(name: Routes.TrailerScreenRoute), + ); + case Routes.ShowsScreenRoute: + return MaterialPageRoute( + builder: (_) => const ShowsScreen(), + settings: const RouteSettings(name: Routes.ShowsScreenRoute), + ); + case Routes.TheaterScreenRoute: + return MaterialPageRoute( + builder: (_) => const TheaterScreen(), + settings: const RouteSettings(name: Routes.TheaterScreenRoute), + ); + case Routes.TicketSummaryScreenRoute: + return MaterialPageRoute( + builder: (_) => const TicketSummaryScreen(), + settings: const RouteSettings(name: Routes.TicketSummaryScreenRoute), + ); + case Routes.PaymentScreenRoute: + return MaterialPageRoute( + builder: (_) => const PaymentScreen(), + settings: const RouteSettings(name: Routes.PaymentScreenRoute), + ); + case Routes.ConfirmationScreenRoute: + return MaterialPageRoute( + builder: (_) => const ConfirmationScreen(), + settings: const RouteSettings(name: Routes.ConfirmationScreenRoute), + ); + default: + return _errorRoute(); + } + } + + /// This method returns an error page to indicate redirection to an + /// unknown route. + static Route _errorRoute() { + return MaterialPageRoute( + builder: (_) => Scaffold( + appBar: AppBar( + title: const Text('Unknown Route'), + ), + body: const Center( + child: Text('Unknown Route'), + ), + ), + ); + } + + /// This method is used to navigate to a screen using it's name + static Future pushNamed(String routeName, {dynamic args}) { + return navigatorKey.currentState!.pushNamed(routeName, arguments: args); + } + + /// This method is used to navigate back to the previous screen. + /// + /// The [result] can contain any value that we want to return to the previous + /// screen. + static Future pop([dynamic result]) async { + navigatorKey.currentState!.pop(result); + } + + /// This method is used to navigate all the way back to a specific screen. + /// + /// The [routeName] is the name of the screen we want to go back to. + static void popUntil(String routeName) { + navigatorKey.currentState!.popUntil(ModalRoute.withName(routeName)); + } -@MaterialAutoRouter( - routes: [ - AutoRoute(page: AppStartupScreen, initial: true), - AutoRoute(page: RegisterScreen), - AutoRoute(page: LoginScreen), - AutoRoute(page: MoviesScreen), - AutoRoute(page: MovieDetailsScreen), - AutoRoute(page: TrailerScreen), - AutoRoute(page: ShowsScreen), - AutoRoute(page: TheaterScreen), - AutoRoute(page: TicketSummaryScreen), - AutoRoute(page: PaymentScreen), - AutoRoute(page: ConfirmationScreen), - AutoRoute(page: UserBookingsScreen), - AutoRoute(page: ChangePasswordScreen), - ], -) -class $AppRouter{} + /// This method is used to navigate all the way back to the first screen + /// shown on startup i.e. the [initialRoute]. + static void popUntilRoot() { + navigatorKey.currentState!.popUntil(ModalRoute.withName(initialRoute)); + } +} diff --git a/lib/routes/routes.dart b/lib/routes/routes.dart new file mode 100644 index 0000000..b670276 --- /dev/null +++ b/lib/routes/routes.dart @@ -0,0 +1,57 @@ +// ignore_for_file: constant_identifier_names +import 'package:flutter/material.dart'; + +/// A utility class that holds screen names for named navigation. +/// This class has no constructor and all variables are `static`. +@immutable +class Routes { + const Routes._(); + + /// The name of the route for app startup screen + static const String AppStartupScreenRoute = '/app-startup-screen'; + + /// The name of the route for home screen. + static const String HomeScreenRoute = '/home-screen'; + + /// The name of the route for login screen. + static const String LoginScreenRoute = '/login-screen'; + + /// The name of the route for home screen. + static const String RegisterScreenRoute = '/register-screen'; + + /// The name of the route for login screen. + static const String ForgotPasswordScreenRoute = '/forgot-password-screen'; + + /// The name of the route for home screen. + static const String WelcomeScreenRoute = '/welcome-screen'; + + /// The name of the route for login screen. + static const String ChangePasswordScreenRoute = '/change-password-screen'; + + /// The name of the route for user bookings screen. + static const String UserBookingsScreenRoute = '/user-bookings-screen'; + + /// The name of the route for movies screen. + static const String MoviesScreenRoute = '/movies-screen'; + + /// The name of the route for movie details screen. + static const String MovieDetailsScreenRoute = '/movie-details-screen'; + + /// The name of the route for trailer screen. + static const String TrailerScreenRoute = '/trailer-screen'; + + /// The name of the route for shows screen. + static const String ShowsScreenRoute = '/shows-screen'; + + /// The name of the route for theater map screen. + static const String TheaterScreenRoute = '/theater-screen'; + + /// The name of the route for ticket summary screen. + static const String TicketSummaryScreenRoute = '/ticket-summary-screen'; + + /// The name of the route for payment screen. + static const String PaymentScreenRoute = '/payment-screen'; + + /// The name of the route for payment/booking confirmation screen. + static const String ConfirmationScreenRoute = '/confirmation-screen'; +} diff --git a/lib/services/networking/network_exception.dart b/lib/services/networking/network_exception.dart index d1f2530..a137c24 100644 --- a/lib/services/networking/network_exception.dart +++ b/lib/services/networking/network_exception.dart @@ -1,8 +1,10 @@ // ignore_for_file: non_constant_identifier_names import 'package:dio/dio.dart'; -import 'package:ez_ticketz_app/helper/utils/exception_constants.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; +//Helpers +import '../../helper/utils/exception_constants.dart'; + part 'network_exception.freezed.dart'; @freezed diff --git a/lib/services/repositories/auth_repository.dart b/lib/services/repositories/auth_repository.dart index a3bb444..1554f6d 100644 --- a/lib/services/repositories/auth_repository.dart +++ b/lib/services/repositories/auth_repository.dart @@ -55,14 +55,14 @@ class AuthRepository { ); } - Future sendResetPasswordData({ + Future sendResetPasswordData({ required JSON data, }) async { - return await _apiService.setData( + return await _apiService.setData( endpoint: ApiEndpoint.auth(AuthEndpoint.RESET_PASSWORD), data: data, requiresAuthToken: false, - converter: (response) => response['headers']['success'] == 1, + converter: (response) => response['headers']['message'] as String, ); } @@ -77,12 +77,12 @@ class AuthRepository { ); } - Future sendOtpData({required JSON data}) async { - return await _apiService.setData( + Future sendOtpData({required JSON data}) async { + return await _apiService.setData( endpoint: ApiEndpoint.auth(AuthEndpoint.VERIFY_OTP), data: data, requiresAuthToken: false, - converter: (response) => response['headers']['success'] == 1, + converter: (response) => response['headers']['message'] as String, ); } } diff --git a/lib/views/screens/change_password_screen.dart b/lib/views/screens/change_password_screen.dart index a78a7ed..8372dea 100644 --- a/lib/views/screens/change_password_screen.dart +++ b/lib/views/screens/change_password_screen.dart @@ -5,11 +5,14 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; //Helpers import '../../helper/extensions/context_extensions.dart'; import '../../helper/utils/constants.dart'; +import '../../helper/typedefs.dart'; //Providers import '../../providers/all_providers.dart'; import '../../providers/auth_provider.dart'; -import '../../providers/states/future_state.dart'; + +//Routing +import '../../routes/app_router.dart'; //Widgets import '../widgets/common/custom_dialog.dart'; @@ -28,10 +31,10 @@ class ChangePasswordScreen extends HookWidget { final cNewPasswordController = useTextEditingController(); late final _formKey = useMemoized(() => GlobalKey()); return Scaffold( - body: ProviderListener>>( + body: FutureStateListener( provider: changePasswordStateProvider, - onChange: (_, changePasswordStateController) async { - final changePasswordState = changePasswordStateController.state; + onChange: (_, controller) async { + final changePasswordState = controller.state; changePasswordState.maybeWhen( data: (message) async { currentPasswordController.clear(); @@ -44,6 +47,7 @@ class ChangePasswordScreen extends HookWidget { title: 'Change Password Success', body: message, buttonText: 'Okay', + onButtonPressed: () => AppRouter.pop(), ), ); }, @@ -70,7 +74,7 @@ class ChangePasswordScreen extends HookWidget { children: [ //Page name Text( - 'Your profile', + 'Change password', textAlign: TextAlign.center, style: context.headline3.copyWith(fontSize: 22), ), diff --git a/lib/views/screens/forgot_password_screen.dart b/lib/views/screens/forgot_password_screen.dart new file mode 100644 index 0000000..aa8d0a2 --- /dev/null +++ b/lib/views/screens/forgot_password_screen.dart @@ -0,0 +1,140 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +//Helpers +import '../../helper/utils/constants.dart'; + +//Providers +import '../../providers/all_providers.dart'; + +//Routing +import '../../routes/app_router.dart'; + +//States +import '../../providers/states/forgot_password_state.dart'; + +//Widgets +import '../widgets/common/custom_dialog.dart'; +import '../widgets/common/rounded_bottom_container.dart'; +import '../widgets/common/scrollable_column.dart'; +import '../widgets/forgot_password/forgot_button_widget.dart'; +import '../widgets/forgot_password/forgot_message_widget.dart'; +import '../widgets/forgot_password/forgot_name_widget.dart'; +import '../widgets/forgot_password/forgot_resend_widget.dart'; +import '../widgets/forgot_password/forgot_text_fields.dart'; + +class ForgotPasswordScreen extends HookWidget { + const ForgotPasswordScreen(); + + Future _showConfirmDialog(BuildContext context) async { + final doPop = await showDialog( + context: context, + barrierColor: Constants.barrierColor, + builder: (ctx) => const CustomDialog.confirm( + title: 'Are you sure?', + body: 'Do you want to go back without resetting your password?', + trueButtonText: 'Yes', + falseButtonText: 'No', + ), + ); + final popTheScreen = doPop != null && doPop; + return Future.value(popTheScreen); + } + + @override + Widget build(BuildContext context) { + late final emailController = useTextEditingController(); + late final newPasswordController = useTextEditingController(); + late final cNewPasswordController = useTextEditingController(); + late final _formKey = useMemoized(() => GlobalKey()); + return Scaffold( + body: ProviderListener( + provider: forgotPasswordProvider, + onChange: (context, forgotPwState) async => forgotPwState.maybeWhen( + success: (_) async { + emailController.clear(); + newPasswordController.clear(); + cNewPasswordController.clear(); + AppRouter.pop().then((_) async { + return await showDialog( + context: context, + barrierColor: Constants.barrierColor.withOpacity(0.75), + builder: (ctx) => const CustomDialog.alert( + title: 'Password Reset Successful', + body: "In order to proceed, you'll have to login again with " + 'your new password', + buttonText: 'Okay', + ), + ); + }); + }, + failed: (reason, lastState) async => await showDialog( + context: context, + barrierColor: Constants.barrierColor.withOpacity(0.75), + builder: (ctx) => CustomDialog.alert( + title: 'Password Reset Failure', + body: reason, + buttonText: 'Retry', + onButtonPressed: (){ + final forgotProv = context.read(forgotPasswordProvider.notifier); + forgotProv.retryForgotPassword(lastState); + }, + ), + ), + orElse: () {}, + ), + child: GestureDetector( + onTap: () => FocusScope.of(context).unfocus(), + child: ScrollableColumn( + children: [ + //Input card + Form( + key: _formKey, + onWillPop: () => _showConfirmDialog(context), + child: RoundedBottomContainer( + padding: const EdgeInsets.fromLTRB(25.0, 28, 25.0, 20), + children: [ + //Relevant Page Name + const ForgotNameWidget(), + + const SizedBox(height: 20), + + //Relevant Input Fields + ForgotTextFields( + emailController: emailController, + newPasswordController: newPasswordController, + cNewPasswordController: cNewPasswordController, + ), + + const SizedBox(height: 10), + + //Resend message + const ForgotResendWidget(), + ], + ), + ), + + const SizedBox(height: 20), + + //Relevant Response Message + const Padding( + padding: EdgeInsets.symmetric(horizontal: 25), + child: ForgotMessageWidget(), + ), + + const Spacer(), + + //Reset Password Button + ForgotButtonWidget( + emailController: emailController, + newPasswordController: newPasswordController, + formKey: _formKey, + ), + ], + ), + ), + ), + ); + } +} diff --git a/lib/views/screens/home_screen.dart b/lib/views/screens/home_screen.dart index 50d8840..78dfa2d 100644 --- a/lib/views/screens/home_screen.dart +++ b/lib/views/screens/home_screen.dart @@ -1,4 +1,3 @@ -import 'package:auto_route/auto_route.dart'; import 'package:flutter/material.dart'; import '../../helper/utils/assets_helper.dart'; @@ -7,8 +6,9 @@ import '../../helper/utils/assets_helper.dart'; import '../../helper/utils/constants.dart'; import '../../helper/extensions/context_extensions.dart'; -//Routes -import '../../routes/app_router.gr.dart'; +//Routing +import '../../routes/routes.dart'; +import '../../routes/app_router.dart'; //Widgets import '../widgets/common/custom_text_button.dart'; @@ -62,7 +62,7 @@ class HomeScreen extends StatelessWidget { child: CustomTextButton.gradient( width: double.infinity, onPressed: () { - context.router.push(const LoginScreenRoute()); + AppRouter.pushNamed(Routes.LoginScreenRoute); }, gradient: Constants.buttonGradientRed, child: const Center( @@ -100,7 +100,7 @@ class HomeScreen extends StatelessWidget { CustomTextButton.outlined( width: double.infinity, onPressed: () { - context.router.push(const RegisterScreenRoute()); + AppRouter.pushNamed(Routes.RegisterScreenRoute); }, border: Border.all(color: Constants.primaryColor, width: 4), child: const Center( diff --git a/lib/views/screens/login_screen.dart b/lib/views/screens/login_screen.dart index ddabc79..a7bf3db 100644 --- a/lib/views/screens/login_screen.dart +++ b/lib/views/screens/login_screen.dart @@ -1,4 +1,3 @@ -import 'package:auto_route/auto_route.dart'; import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:flutter_spinkit/flutter_spinkit.dart'; @@ -12,6 +11,10 @@ import '../../helper/utils/form_validator.dart'; //Providers import '../../providers/all_providers.dart'; +//Routing +import '../../routes/routes.dart'; +import '../../routes/app_router.dart'; + //States import '../../providers/states/auth_state.dart'; @@ -27,18 +30,17 @@ class LoginScreen extends HookWidget { @override Widget build(BuildContext context) { - final formKey = useMemoized(()=>GlobalKey()); + final formKey = useMemoized(() => GlobalKey()); final emailController = useTextEditingController(text: ''); final passwordController = useTextEditingController(text: ''); return Scaffold( - body: ProviderListener( + body: ProviderListener( provider: authProvider, - onChange: (context, authState) async => - (authState as AuthState).maybeWhen( + onChange: (context, authState) async => authState.maybeWhen( authenticated: (_) { emailController.clear(); passwordController.clear(); - context.router.popUntilRoot(); + AppRouter.popUntilRoot(); }, failed: (reason) async { await showDialog( @@ -61,6 +63,7 @@ class LoginScreen extends HookWidget { Form( key: formKey, child: RoundedBottomContainer( + padding: const EdgeInsets.fromLTRB(25.0, 28, 25.0, 20), children: [ //Page name Text( @@ -76,7 +79,6 @@ class LoginScreen extends HookWidget { //Email CustomTextField( controller: emailController, - autofocus: true, floatingText: 'Email', hintText: 'Type your email address', keyboardType: TextInputType.emailAddress, @@ -99,6 +101,26 @@ class LoginScreen extends HookWidget { ), ), + const SizedBox(height: 20), + + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + GestureDetector( + onTap: () { + AppRouter.pushNamed(Routes.ForgotPasswordScreenRoute); + }, + child: Text( + 'Forgot your password?', + style: context.headline3.copyWith( + fontSize: 17, + color: Constants.primaryColor, + ), + ), + ), + ], + ), + const Spacer(), //Login button diff --git a/lib/views/screens/movie_details_screen.dart b/lib/views/screens/movie_details_screen.dart index 641e584..2a4608b 100644 --- a/lib/views/screens/movie_details_screen.dart +++ b/lib/views/screens/movie_details_screen.dart @@ -1,12 +1,12 @@ import 'package:flutter/material.dart'; -import 'package:auto_route/auto_route.dart'; //Helper import '../../helper/utils/constants.dart'; import '../../helper/extensions/context_extensions.dart'; -//Routes -import '../../routes/app_router.gr.dart'; +//Routing +import '../../routes/routes.dart'; +import '../../routes/app_router.dart'; //Widgets import '../widgets/movie_details/floating_movie_posters.dart'; @@ -14,6 +14,8 @@ import '../widgets/common/custom_text_button.dart'; import '../widgets/movie_details/movie_details_sheet.dart'; class MovieDetailsScreen extends StatelessWidget{ + const MovieDetailsScreen({Key? key}) : super(key: key); + @override Widget build(BuildContext context) { return Scaffold( @@ -45,7 +47,7 @@ class MovieDetailsScreen extends StatelessWidget{ ), ), onPressed: () { - context.router.push(const ShowsScreenRoute()); + AppRouter.pushNamed(Routes.ShowsScreenRoute); }, ), ), @@ -61,7 +63,7 @@ class MovieDetailsScreen extends StatelessWidget{ icon: const Icon(Icons.close_rounded, size: 25), padding: const EdgeInsets.all(0), onPressed: () { - context.router.pop(); + AppRouter.pop(); }, ), ), diff --git a/lib/views/screens/movies_screen.dart b/lib/views/screens/movies_screen.dart index 3b74fff..5494e1e 100644 --- a/lib/views/screens/movies_screen.dart +++ b/lib/views/screens/movies_screen.dart @@ -1,4 +1,3 @@ -import 'package:auto_route/auto_route.dart'; import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; @@ -11,6 +10,9 @@ import '../../helper/utils/constants.dart'; import '../../providers/all_providers.dart'; import '../../providers/movies_provider.dart'; +//Routing +import '../../routes/app_router.dart'; + //Skeletons import '../skeletons/movies_skeleton_loader.dart'; @@ -100,7 +102,7 @@ class MoviesScreen extends HookWidget { retryCallback: () => context.refresh(moviesFuture), onError: () { context.read(authProvider.notifier).logout(); - context.router.popUntilRoot(); + AppRouter.popUntilRoot(); }, ), ), diff --git a/lib/views/screens/payment_screen.dart b/lib/views/screens/payment_screen.dart index 9240d23..b96f42d 100644 --- a/lib/views/screens/payment_screen.dart +++ b/lib/views/screens/payment_screen.dart @@ -1,10 +1,12 @@ -import 'package:auto_route/auto_route.dart'; import 'package:flutter/material.dart'; //Helpers import '../../helper/utils/constants.dart'; import '../../helper/extensions/context_extensions.dart'; +//Routing +import '../../routes/app_router.dart'; + //Widgets import '../widgets/common/scrollable_column.dart'; import '../widgets/payment/pay_button.dart'; @@ -90,7 +92,7 @@ class _BackIconRow extends StatelessWidget { radius: 25, child: const Icon(Icons.arrow_back_sharp, size: 26), onTap: () { - context.router.pop(); + AppRouter.pop(); }, ), diff --git a/lib/views/screens/register_screen.dart b/lib/views/screens/register_screen.dart index d750022..c352f57 100644 --- a/lib/views/screens/register_screen.dart +++ b/lib/views/screens/register_screen.dart @@ -1,4 +1,3 @@ -import 'package:auto_route/auto_route.dart'; import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:flutter_spinkit/flutter_spinkit.dart'; @@ -13,6 +12,9 @@ import '../../helper/utils/form_validator.dart'; //Providers import '../../providers/all_providers.dart'; +//Routing +import '../../routes/app_router.dart'; + //States import '../../providers/states/auth_state.dart'; @@ -178,13 +180,13 @@ class _RegisterScreenState extends State { cPasswordController.clear(); contactController.clear(); _formHasData = false; - context.router.popUntilRoot(); + AppRouter.popUntilRoot(); } return Scaffold( - body: ProviderListener( + body: ProviderListener( provider: authProvider, - onChange: (_, authState) async => (authState as AuthState).maybeWhen( + onChange: (_, authState) async => authState.maybeWhen( authenticated: onAuthStateAuthenticated, failed: onAuthStateFailed, orElse: () {}, @@ -280,7 +282,6 @@ class _UserDetailFields extends StatelessWidget { //Full name CustomTextField( controller: fullNameController, - autofocus: true, floatingText: 'Full name', hintText: 'Type your full name', keyboardType: TextInputType.name, diff --git a/lib/views/screens/shows_screen.dart b/lib/views/screens/shows_screen.dart index 7c759ff..8654217 100644 --- a/lib/views/screens/shows_screen.dart +++ b/lib/views/screens/shows_screen.dart @@ -1,4 +1,3 @@ -import 'package:auto_route/auto_route.dart'; import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; @@ -12,8 +11,9 @@ import '../../helper/utils/constants.dart'; import '../../providers/movies_provider.dart'; import '../../providers/shows_provider.dart'; -//Routes -import '../../routes/app_router.gr.dart'; +//Routing +import '../../routes/routes.dart'; +import '../../routes/app_router.dart'; //Skeletons import '../skeletons/shows_skeleton_loader.dart'; @@ -46,7 +46,7 @@ class ShowsScreen extends HookWidget { radius: 25, child: const Icon(Icons.arrow_back_sharp, size: 26), onTap: () { - context.router.pop(); + AppRouter.pop(); }, ), @@ -170,7 +170,7 @@ class ShowsScreen extends HookWidget { width: double.infinity, disabled: showStatus == ShowStatus.FULL, onPressed: () { - context.router.push(const TheaterScreenRoute()); + AppRouter.pushNamed(Routes.TheaterScreenRoute); }, gradient: Constants.buttonGradientOrange, child: const Center( diff --git a/lib/views/screens/theater_screen.dart b/lib/views/screens/theater_screen.dart index f77d855..1d2606e 100644 --- a/lib/views/screens/theater_screen.dart +++ b/lib/views/screens/theater_screen.dart @@ -1,6 +1,5 @@ import 'dart:math'; -import 'package:auto_route/auto_route.dart'; import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; @@ -13,6 +12,9 @@ import '../../providers/all_providers.dart'; //Providers import '../../providers/theaters_provider.dart'; +//Routing +import '../../routes/app_router.dart'; + //Skeletons import '../skeletons/theater_skeleton_loader.dart'; @@ -160,7 +162,7 @@ class _BackIcon extends StatelessWidget { radius: 25, onTap: () { context.read(theatersProvider).clearSelectedSeats(); - context.router.pop(); + AppRouter.pop(); }, child: const DecoratedBox( decoration: BoxDecoration( diff --git a/lib/views/screens/ticket_summary_screen.dart b/lib/views/screens/ticket_summary_screen.dart index b0fd1f4..90b89a5 100644 --- a/lib/views/screens/ticket_summary_screen.dart +++ b/lib/views/screens/ticket_summary_screen.dart @@ -1,9 +1,11 @@ -import 'package:auto_route/auto_route.dart'; import 'package:flutter/material.dart'; //Helpers import '../../helper/extensions/context_extensions.dart'; +//Routing +import '../../routes/app_router.dart'; + //Widgets import '../widgets/ticket_summary/confirm_bookings_button.dart'; import '../widgets/ticket_summary/tickets_summary_box.dart'; @@ -52,7 +54,7 @@ class _BackIconRow extends StatelessWidget { radius: 25, child: const Icon(Icons.arrow_back_sharp, size: 26), onTap: () { - context.router.pop(); + AppRouter.pop(); }, ), diff --git a/lib/views/screens/trailer_screen.dart b/lib/views/screens/trailer_screen.dart index 7f538ab..9327e44 100644 --- a/lib/views/screens/trailer_screen.dart +++ b/lib/views/screens/trailer_screen.dart @@ -1,4 +1,3 @@ -import 'package:auto_route/auto_route.dart'; import 'package:better_player/better_player.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; @@ -8,6 +7,9 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../../helper/utils/constants.dart'; import '../../helper/extensions/context_extensions.dart'; +//Routing +import '../../routes/app_router.dart'; + //Providers import '../../providers/movies_provider.dart'; @@ -79,7 +81,7 @@ class _TrailerScreenState extends State { GestureDetector( child: const Icon(Icons.arrow_back_sharp, size: 26), onTap: () { - context.router.pop(); + AppRouter.pop(); }, ), diff --git a/lib/views/screens/user_bookings_screen.dart b/lib/views/screens/user_bookings_screen.dart index 4a64857..9ba7d18 100644 --- a/lib/views/screens/user_bookings_screen.dart +++ b/lib/views/screens/user_bookings_screen.dart @@ -1,9 +1,11 @@ -import 'package:auto_route/auto_route.dart'; import 'package:flutter/material.dart'; //Helpers import '../../helper/extensions/context_extensions.dart'; +//Routing +import '../../routes/app_router.dart'; + //Widgets import '../widgets/user_bookings/user_bookings_history.dart'; @@ -27,7 +29,7 @@ class UserBookingsScreen extends StatelessWidget { radius: 25, child: const Icon(Icons.arrow_back_sharp, size: 26), onTap: () { - context.router.pop(); + AppRouter.pop(); }, ), diff --git a/lib/views/screens/welcome_screen.dart b/lib/views/screens/welcome_screen.dart index 3dc50ff..bec32f3 100644 --- a/lib/views/screens/welcome_screen.dart +++ b/lib/views/screens/welcome_screen.dart @@ -1,4 +1,3 @@ -import 'package:auto_route/auto_route.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; @@ -10,8 +9,9 @@ import '../../helper/utils/constants.dart'; //Providers import '../../providers/all_providers.dart'; -//Routes -import '../../routes/app_router.gr.dart'; +//Routing +import '../../routes/routes.dart'; +import '../../routes/app_router.dart'; //Widgets import '../widgets/welcome/user_profile_details.dart'; @@ -48,7 +48,7 @@ class WelcomeScreen extends StatelessWidget { ), onTap: () { context.read(authProvider.notifier).logout(); - context.router.popUntilRoot(); + AppRouter.popUntilRoot(); }, ), ), @@ -62,7 +62,7 @@ class WelcomeScreen extends StatelessWidget { size: 30, ), onTap: () { - context.router.push(const ChangePasswordScreenRoute()); + AppRouter.pushNamed(Routes.ChangePasswordScreenRoute); }, ) ], diff --git a/lib/views/widgets/common/custom_dialog.dart b/lib/views/widgets/common/custom_dialog.dart index 568e5c2..c17eade 100644 --- a/lib/views/widgets/common/custom_dialog.dart +++ b/lib/views/widgets/common/custom_dialog.dart @@ -1,10 +1,12 @@ import 'package:flutter/material.dart'; -import 'package:auto_route/auto_route.dart'; //Helpers import '../../../helper/utils/constants.dart'; import '../../../helper/extensions/context_extensions.dart'; +//Routing +import '../../../routes/app_router.dart'; + //Widgets import 'custom_text_button.dart'; @@ -15,11 +17,14 @@ class CustomDialog extends StatelessWidget { final String title, body; final String? buttonText, falseButtonText, trueButtonText; final CustomDialogType _type; + final VoidCallback? falseButtonPressed, trueButtonPressed; const CustomDialog._({ this.buttonText, this.falseButtonText, this.trueButtonText, + this.falseButtonPressed, + this.trueButtonPressed, required this.title, required this.body, required CustomDialogType type, @@ -29,6 +34,7 @@ class CustomDialog extends StatelessWidget { required String title, required String body, required String buttonText, + VoidCallback? onButtonPressed, }) = _CustomDialogWithAlert; const factory CustomDialog.confirm({ @@ -36,6 +42,8 @@ class CustomDialog extends StatelessWidget { required String body, required String falseButtonText, required String trueButtonText, + VoidCallback? falseButtonPressed, + VoidCallback? trueButtonPressed, }) = _CustomDialogWithConfirm; @override @@ -72,7 +80,8 @@ class CustomDialog extends StatelessWidget { height: 40, width: 60, onPressed: () { - context.router.pop(); + trueButtonPressed?.call(); + AppRouter.pop(); }, ) else if (_type == CustomDialogType.CONFIRM) ...[ @@ -87,7 +96,8 @@ class CustomDialog extends StatelessWidget { height: 40, width: 60, onPressed: () { - context.router.pop(true); + trueButtonPressed?.call(); + AppRouter.pop(true); }, ), CustomTextButton.gradient( @@ -101,7 +111,8 @@ class CustomDialog extends StatelessWidget { height: 40, width: 60, onPressed: () { - context.router.pop(false); + falseButtonPressed?.call(); + AppRouter.pop(false); }, ), ] @@ -115,10 +126,12 @@ class _CustomDialogWithAlert extends CustomDialog { required String title, required String body, required String buttonText, + VoidCallback? onButtonPressed, }) : super._( title: title, body: body, buttonText: buttonText, + trueButtonPressed: onButtonPressed, type: CustomDialogType.ALERT, ); } @@ -129,11 +142,15 @@ class _CustomDialogWithConfirm extends CustomDialog { required String body, required String falseButtonText, required String trueButtonText, + VoidCallback? falseButtonPressed, + VoidCallback? trueButtonPressed, }) : super._( title: title, body: body, falseButtonText: falseButtonText, trueButtonText: trueButtonText, + falseButtonPressed: falseButtonPressed, + trueButtonPressed: trueButtonPressed, type: CustomDialogType.CONFIRM, ); } diff --git a/lib/views/widgets/common/custom_textfield.dart b/lib/views/widgets/common/custom_textfield.dart index 11398e4..41ddda9 100644 --- a/lib/views/widgets/common/custom_textfield.dart +++ b/lib/views/widgets/common/custom_textfield.dart @@ -7,28 +7,44 @@ import '../../../helper/extensions/context_extensions.dart'; import '../../../helper/utils/constants.dart'; class CustomTextField extends StatefulWidget { - final String? floatingText, hintText; - final TextInputType keyboardType; - final TextInputAction textInputAction; - final TextEditingController controller; - final String? Function(String? value) validator; - final void Function(String? value)? onSaved; - final AlignmentGeometry errorTextAlign; - final Widget? prefix; - final bool autofocus; + final TextEditingController? controller; + final double? width, height; final int? maxLength; + final String? floatingText, hintText; final TextStyle hintStyle, errorStyle, inputStyle; final TextStyle? floatingStyle; + final EdgeInsets? contentPadding; + final void Function(String? value)? onSaved, onChanged; + final Widget? prefix; + final bool showCursor; + final bool autofocus; + final bool showErrorBorder; + final TextAlign textAlign; + final Alignment errorAlign, floatingAlign; final Color fillColor; + final TextInputType keyboardType; + final TextInputAction textInputAction; + final String? Function(String? value) validator; const CustomTextField({ Key? key, - this.onSaved, - this.prefix, + this.controller, + this.width, + this.height = 47, this.maxLength, + this.floatingText, this.floatingStyle, - this.errorTextAlign = Alignment.centerRight, + this.onSaved, + this.onChanged, + this.prefix, + this.showCursor = true, + this.showErrorBorder = false, this.autofocus = false, + this.textAlign = TextAlign.start, + this.errorAlign = Alignment.centerRight, + this.floatingAlign = Alignment.centerLeft, + this.fillColor = Constants.scaffoldColor, + this.hintText, this.hintStyle = const TextStyle( fontSize: 17, color: Constants.textWhite80Color, @@ -41,10 +57,7 @@ class CustomTextField extends StatefulWidget { fontSize: 17, color: Constants.textWhite80Color, ), - this.fillColor = Constants.scaffoldColor, - this.floatingText, - this.hintText, - required this.controller, + this.contentPadding = const EdgeInsets.fromLTRB(17, 10, 1, 10), required this.keyboardType, required this.textInputAction, required this.validator, @@ -58,25 +71,29 @@ class _CustomTextFieldState extends State { String? errorText; bool hidePassword = true; - bool get hasErrorText => errorText != null; + bool get hasError => errorText != null; + + bool get showErrorBorder => widget.showErrorBorder && hasError; + + bool get hasFloatingText => widget.floatingText != null; bool get isPasswordField => widget.keyboardType == TextInputType.visiblePassword; void _onSaved(String? value) { value = value!.trim(); - widget.controller.text = value; - if (widget.onSaved != null) widget.onSaved!(value); + widget.controller?.text = value; + widget.onSaved?.call(value); } - void _onFieldSubmitted(String value) { - final error = widget.validator(value.trim()); - setState(() { - errorText = error; - }); + void _onChanged(String value) { + if(widget.onChanged != null){ + _runValidator(value); + widget.onChanged!(value); + } } - String? _onValidate(String? value) { + String? _runValidator(String? value) { final error = widget.validator(value!.trim()); setState(() { errorText = error; @@ -84,6 +101,12 @@ class _CustomTextFieldState extends State { return error; } + void _togglePasswordVisibility() { + setState(() { + hidePassword = !hidePassword; + }); + } + OutlineInputBorder _focusedBorder() { return const OutlineInputBorder( borderRadius: BorderRadius.all(Radius.circular(9)), @@ -101,63 +124,79 @@ class _CustomTextFieldState extends State { ); } + OutlineInputBorder _errorBorder() { + return const OutlineInputBorder( + borderRadius: BorderRadius.all(Radius.circular(9)), + borderSide: BorderSide( + color: Constants.redColor, + width: 1, + ), + ); + } + @override Widget build(BuildContext context) { return Column( - crossAxisAlignment: CrossAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.center, children: [ //Floating text - if (widget.floatingText != null) - Text( - widget.floatingText!, - style: widget.floatingStyle ?? - context.bodyText1.copyWith( - color: Constants.textGreyColor, - fontSize: 17, - ), + if (hasFloatingText) ...[ + SizedBox( + width: widget.width, + child: Align( + alignment: widget.floatingAlign, + child: Text( + widget.floatingText!, + style: widget.floatingStyle ?? + context.bodyText1.copyWith( + color: Constants.textGreyColor, + fontSize: 17, + ), + ), + ), ), - - if (widget.floatingText != null) const SizedBox(height: 2), + const SizedBox(height: 2), + ], //TextField SizedBox( - height: 47, + height: widget.height, + width: widget.width, child: TextFormField( controller: widget.controller, + textAlign: widget.textAlign, autofocus: widget.autofocus, maxLength: widget.maxLength, keyboardType: widget.keyboardType, textInputAction: widget.textInputAction, style: widget.inputStyle, + showCursor: widget.showCursor, maxLengthEnforcement: MaxLengthEnforcement.enforced, textAlignVertical: TextAlignVertical.center, autovalidateMode: AutovalidateMode.disabled, cursorColor: Colors.white, obscureText: isPasswordField && hidePassword, - showCursor: true, - validator: _onValidate, + validator: _runValidator, + onFieldSubmitted: _runValidator, onSaved: _onSaved, - onFieldSubmitted: _onFieldSubmitted, + onChanged: _onChanged, decoration: InputDecoration( hintText: widget.hintText, hintStyle: widget.hintStyle, errorStyle: widget.errorStyle, fillColor: widget.fillColor, prefixIcon: widget.prefix, - contentPadding: const EdgeInsets.fromLTRB(17, 10, 1, 10), + contentPadding: widget.contentPadding, isDense: true, filled: true, counterText: '', border: _normalBorder(), focusedBorder: _focusedBorder(), focusedErrorBorder: _focusedBorder(), + errorBorder: showErrorBorder ? _errorBorder() : null, suffixIcon: isPasswordField ? InkWell( - onTap: () { - setState(() { - hidePassword = !hidePassword; - }); - }, + onTap: _togglePasswordVisibility, child: const Icon( Icons.remove_red_eye_sharp, color: Constants.textGreyColor, @@ -169,17 +208,19 @@ class _CustomTextFieldState extends State { ), ), - if (hasErrorText) ...[ + //Error text + if (hasError) ...[ const SizedBox(height: 2), - - //Error text - Align( - alignment: widget.errorTextAlign, - child: Text( - errorText!, - style: context.bodyText1.copyWith( - fontSize: 16, - color: Constants.primaryColor, + SizedBox( + width: widget.width, + child: Align( + alignment: widget.errorAlign, + child: Text( + errorText!, + style: context.bodyText1.copyWith( + fontSize: 16, + color: Constants.primaryColor, + ), ), ), ), diff --git a/lib/views/widgets/common/error_response_handler.dart b/lib/views/widgets/common/error_response_handler.dart index e0231e3..bc5c645 100644 --- a/lib/views/widgets/common/error_response_handler.dart +++ b/lib/views/widgets/common/error_response_handler.dart @@ -40,7 +40,7 @@ class ErrorResponseHandler extends StatelessWidget { height: context.screenHeight * 0.5, ); } - if (onError != null) onError!(); + onError?.call(); debugPrint(error.toString()); debugPrint(stackTrace?.toString()); return const SizedBox.shrink(); @@ -67,7 +67,7 @@ class _ErrorResponseHandlerWithBuilder extends ErrorResponseHandler { @override Widget build(BuildContext context) { if (error is NetworkException) return builder(error as NetworkException); - if (onError != null) onError!(); + onError?.call(); debugPrint(error.toString()); debugPrint(stackTrace?.toString()); return const SizedBox.shrink(); diff --git a/lib/views/widgets/common/rounded_bottom_container.dart b/lib/views/widgets/common/rounded_bottom_container.dart index 24e65b1..daaacbd 100644 --- a/lib/views/widgets/common/rounded_bottom_container.dart +++ b/lib/views/widgets/common/rounded_bottom_container.dart @@ -1,17 +1,21 @@ -import 'package:auto_route/auto_route.dart'; import 'package:flutter/material.dart'; +//Routing +import '../../../routes/app_router.dart'; + //Helpers import '../../../helper/utils/constants.dart'; class RoundedBottomContainer extends StatelessWidget { final List children; final VoidCallback? onBackTap; + final EdgeInsets? padding; const RoundedBottomContainer({ Key? key, required this.children, this.onBackTap, + this.padding, }) : super(key: key); @override @@ -39,11 +43,11 @@ class RoundedBottomContainer extends StatelessWidget { color: Colors.white, ), ), - onTap: onBackTap ?? () => context.router.pop(), + onTap: onBackTap ?? () => AppRouter.pop(), ), Padding( - padding: const EdgeInsets.fromLTRB(25.0, 28, 25.0, 27), + padding: padding ?? const EdgeInsets.fromLTRB(25.0, 28, 25.0, 27), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: children, diff --git a/lib/views/widgets/confirmation/more_bookings_button.dart b/lib/views/widgets/confirmation/more_bookings_button.dart index 8aac0fc..4bb66f4 100644 --- a/lib/views/widgets/confirmation/more_bookings_button.dart +++ b/lib/views/widgets/confirmation/more_bookings_button.dart @@ -1,12 +1,12 @@ import 'package:flutter/material.dart'; -import 'package:auto_route/auto_route.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; //Helpers import '../../../helper/utils/constants.dart'; -//Routes -import '../../../routes/app_router.gr.dart'; +//Routing +import '../../../routes/routes.dart'; +import '../../../routes/app_router.dart'; //Providers import '../../../providers/all_providers.dart'; @@ -25,7 +25,7 @@ class MoreBookingsButton extends StatelessWidget { width: double.infinity, onPressed: () { context.read(theatersProvider).clearSelectedSeats(); - context.router.popUntilRouteWithName(MoviesScreenRoute.name); + AppRouter.popUntil(Routes.MoviesScreenRoute); }, color: Constants.textWhite80Color, child: const Center( diff --git a/lib/views/widgets/forgot_password/forgot_button_widget.dart b/lib/views/widgets/forgot_password/forgot_button_widget.dart new file mode 100644 index 0000000..caa7a22 --- /dev/null +++ b/lib/views/widgets/forgot_password/forgot_button_widget.dart @@ -0,0 +1,133 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:flutter_spinkit/flutter_spinkit.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; + +//Helpers +import '../../../helper/utils/constants.dart'; + +//Providers +import '../../../providers/all_providers.dart'; + +//Widgets +import '../common/custom_text_button.dart'; + +class ForgotButtonWidget extends StatefulHookWidget { + final TextEditingController emailController; + final TextEditingController newPasswordController; + final GlobalKey formKey; + + const ForgotButtonWidget({ + Key? key, + required this.emailController, + required this.newPasswordController, + required this.formKey, + }) : super(key: key); + + @override + _PageButtonWidgetState createState() => _PageButtonWidgetState(); +} + +class _PageButtonWidgetState extends State { + late Widget _currentPageButton; + + void _onPressed({ + bool isEmail = false, + bool isOtp = false, + bool isReset = false, + }) { + if (widget.formKey.currentState!.validate()) { + widget.formKey.currentState!.save(); + final _forgotPasswordProv = context.read(forgotPasswordProvider.notifier); + if (isEmail) { + _forgotPasswordProv.requestOtpCode(widget.emailController.text); + } else if (isOtp) { + _forgotPasswordProv.verifyOtp(); + } else if (isReset) { + _forgotPasswordProv.resetPassword( + password: widget.newPasswordController.text, + ); + } + } + } + + @override + Widget build(BuildContext context) { + final _forgotPasswordState = useProvider(forgotPasswordProvider); + return Padding( + padding: const EdgeInsets.fromLTRB(20, 40, 20, Constants.bottomInsets), + child: _forgotPasswordState.when( + email: () { + _currentPageButton = CustomTextButton.gradient( + width: double.infinity, + onPressed: () => _onPressed(isEmail: true), + gradient: Constants.buttonGradientOrange, + child: const Center( + child: Text( + 'SEND OTP', + style: TextStyle( + color: Colors.white, + fontSize: 15, + letterSpacing: 0.7, + fontWeight: FontWeight.w600, + ), + ), + ), + ); + return _currentPageButton; + }, + otp: (_) { + _currentPageButton = CustomTextButton.gradient( + width: double.infinity, + onPressed: () => _onPressed(isOtp: true), + gradient: Constants.buttonGradientOrange, + child: const Center( + child: Text('VERIFY OTP', + style: TextStyle( + color: Colors.white, + fontSize: 15, + letterSpacing: 0.7, + fontWeight: FontWeight.w600, + )), + ), + ); + return _currentPageButton; + }, + resetPassword: (_) { + _currentPageButton = CustomTextButton.gradient( + width: double.infinity, + onPressed: () => _onPressed(isReset: true), + gradient: Constants.buttonGradientOrange, + child: const Center( + child: Text( + 'RESET PASSWORD', + style: TextStyle( + color: Colors.white, + fontSize: 15, + letterSpacing: 0.7, + fontWeight: FontWeight.w600, + ), + ), + ), + ); + return _currentPageButton; + }, + loading: (_) => CustomTextButton.gradient( + width: double.infinity, + onPressed: () {}, + gradient: Constants.buttonGradientOrange, + child: const Center( + child: SpinKitRing( + color: Colors.white, + size: 30, + lineWidth: 4, + duration: Duration(milliseconds: 1100), + ), + ), + ), + failed: (_, __) => _currentPageButton, + success: (_) => const SizedBox.shrink(), + ), + ); + } +} diff --git a/lib/views/widgets/forgot_password/forgot_message_widget.dart b/lib/views/widgets/forgot_password/forgot_message_widget.dart new file mode 100644 index 0000000..24da0f7 --- /dev/null +++ b/lib/views/widgets/forgot_password/forgot_message_widget.dart @@ -0,0 +1,42 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; + +//Helpers +import '../../../helper/extensions/context_extensions.dart'; +import '../../../helper/utils/constants.dart'; + +//Providers +import '../../../providers/all_providers.dart'; + +class ForgotMessageWidget extends HookWidget { + const ForgotMessageWidget({ + Key? key, + }) : super(key: key); + + Text _buildMessageText(BuildContext ctx, String message) { + return Text( + message, + textAlign: TextAlign.center, + style: ctx.bodyText1.copyWith( + color: Constants.textGreyColor, + fontSize: 16, + ), + ); + } + + @override + Widget build(BuildContext context) { + final _forgotPasswordState = useProvider(forgotPasswordProvider); + return _forgotPasswordState.maybeWhen( + email: () => _buildMessageText( + context, + 'A 4 digit OTP will be sent to this email once verified', + ), + otp: (message) => _buildMessageText(context, message), + resetPassword: (message) => _buildMessageText(context, message), + loading: (message) => _buildMessageText(context, message), + orElse: () => const SizedBox.shrink(), + ); + } +} diff --git a/lib/views/widgets/forgot_password/forgot_name_widget.dart b/lib/views/widgets/forgot_password/forgot_name_widget.dart new file mode 100644 index 0000000..6dcb535 --- /dev/null +++ b/lib/views/widgets/forgot_password/forgot_name_widget.dart @@ -0,0 +1,50 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; + +//Helpers +import '../../../helper/extensions/context_extensions.dart'; + +//Providers +import '../../../providers/all_providers.dart'; + +class ForgotNameWidget extends StatefulHookWidget { + const ForgotNameWidget({ + Key? key, + }) : super(key: key); + + @override + _PageNameWidgetState createState() => _PageNameWidgetState(); +} + +class _PageNameWidgetState extends State { + late Text currentPageText; + + Text _buildText(String pageName) { + return Text( + pageName, + style: context.headline3.copyWith(fontSize: 22), + ); + } + + @override + Widget build(BuildContext context) { + final _forgotPasswordState = useProvider(forgotPasswordProvider); + return _forgotPasswordState.maybeWhen( + email: () { + currentPageText = _buildText('Forgot Password'); + return currentPageText; + }, + otp: (_) { + currentPageText = _buildText('Verify Otp'); + return currentPageText; + }, + resetPassword: (_) { + currentPageText = _buildText('Reset Password'); + return currentPageText; + }, + success: (_) => const SizedBox.shrink(), + orElse: () => currentPageText, + ); + } +} diff --git a/lib/views/widgets/forgot_password/forgot_resend_widget.dart b/lib/views/widgets/forgot_password/forgot_resend_widget.dart new file mode 100644 index 0000000..117b162 --- /dev/null +++ b/lib/views/widgets/forgot_password/forgot_resend_widget.dart @@ -0,0 +1,41 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; + +//Providers +import '../../../providers/all_providers.dart'; + +//Helpers +import '../../../helper/extensions/context_extensions.dart'; +import '../../../helper/utils/constants.dart'; + +class ForgotResendWidget extends HookWidget { + const ForgotResendWidget({ + Key? key, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + final _forgotPasswordState = useProvider(forgotPasswordProvider); + return _forgotPasswordState.maybeWhen( + otp: (_) => Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + GestureDetector( + onTap: () { + context.read(forgotPasswordProvider.notifier).resendOtpCode(); + }, + child: Text( + 'Resend OTP', + style: context.headline3.copyWith( + fontSize: 17, + color: Constants.primaryColor + ), + ), + ), + ], + ), + orElse: () => const SizedBox.shrink(), + ); + } +} diff --git a/lib/views/widgets/forgot_password/forgot_text_fields.dart b/lib/views/widgets/forgot_password/forgot_text_fields.dart new file mode 100644 index 0000000..920abba --- /dev/null +++ b/lib/views/widgets/forgot_password/forgot_text_fields.dart @@ -0,0 +1,65 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; + +//Helpers +import '../../../helper/utils/form_validator.dart'; + +//Providers +import '../../../providers/all_providers.dart'; + +//Widgets +import '../common/custom_textfield.dart'; +import 'reset_password_fields.dart'; +import 'otp_code_fields.dart'; + +class ForgotTextFields extends StatefulHookWidget { + const ForgotTextFields({ + Key? key, + required this.emailController, + required this.newPasswordController, + required this.cNewPasswordController, + }) : super(key: key); + + final TextEditingController emailController; + final TextEditingController newPasswordController; + final TextEditingController cNewPasswordController; + + @override + _ForgotPasswordFieldsState createState() => _ForgotPasswordFieldsState(); +} + +class _ForgotPasswordFieldsState extends State { + late Widget currentTextFields; + + @override + Widget build(BuildContext context) { + final _forgotPasswordState = useProvider(forgotPasswordProvider); + return _forgotPasswordState.maybeWhen( + email: () { + currentTextFields = CustomTextField( + controller: widget.emailController, + floatingText: 'Email', + hintText: 'Type your email address', + keyboardType: TextInputType.emailAddress, + textInputAction: TextInputAction.next, + validator: FormValidator.emailValidator, + ); + return currentTextFields; + }, + otp: (_) { + currentTextFields = const OtpCodeFields(); + return currentTextFields; + }, + resetPassword: (_) { + currentTextFields = ResetPasswordFields( + newPasswordController: widget.newPasswordController, + cNewPasswordController: widget.cNewPasswordController, + ); + return currentTextFields; + }, + success: (_) => const SizedBox.shrink(), + orElse: () => currentTextFields, + ); + } +} diff --git a/lib/views/widgets/forgot_password/otp_code_fields.dart b/lib/views/widgets/forgot_password/otp_code_fields.dart new file mode 100644 index 0000000..01eb319 --- /dev/null +++ b/lib/views/widgets/forgot_password/otp_code_fields.dart @@ -0,0 +1,60 @@ +import 'package:flutter/material.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; + +//Helpers +import '../../../helper/utils/constants.dart'; +import '../../../helper/utils/form_validator.dart'; + +//Providers +import '../../../providers/all_providers.dart'; + +//Widgets +import '../common/custom_textfield.dart'; + +class OtpCodeFields extends StatelessWidget { + const OtpCodeFields({ + Key? key, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return Column( + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + //Digit 1-4 + for (int i = 0; i < 4; i++) + CustomTextField( + maxLength: 1, + width: 60, + height: 60, + contentPadding: const EdgeInsets.only(bottom: 10), + inputStyle: const TextStyle( + fontSize: 35, + color: Constants.textWhite80Color, + ), + showErrorBorder: true, + textAlign: TextAlign.center, + errorAlign: Alignment.topCenter, + keyboardType: TextInputType.phone, + textInputAction: TextInputAction.next, + validator: FormValidator.otpDigitValidator, + onSaved: (digit) { + final forgotProv = context.read(forgotPasswordProvider.notifier); + forgotProv.setOtpDigit(i, digit!); + }, + onChanged: (digit) { + if (digit!.length == 1) { + FocusScope.of(context).nextFocus(); + } else if (digit.isEmpty) { + FocusScope.of(context).previousFocus(); + } + }, + ), + ], + ), + ], + ); + } +} diff --git a/lib/views/widgets/forgot_password/reset_password_fields.dart b/lib/views/widgets/forgot_password/reset_password_fields.dart new file mode 100644 index 0000000..65471c8 --- /dev/null +++ b/lib/views/widgets/forgot_password/reset_password_fields.dart @@ -0,0 +1,50 @@ +import 'package:flutter/material.dart'; + +//Helper +import '../../../helper/utils/form_validator.dart'; + +//Widget +import '../common/custom_textfield.dart'; + +class ResetPasswordFields extends StatelessWidget { + final TextEditingController newPasswordController; + final TextEditingController cNewPasswordController; + + const ResetPasswordFields({ + Key? key, + required this.newPasswordController, + required this.cNewPasswordController, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return Column( + children: [ + //New Password Field + CustomTextField( + hintText: 'Type your password', + floatingText: 'New Password', + controller: newPasswordController, + keyboardType: TextInputType.visiblePassword, + textInputAction: TextInputAction.next, + validator: FormValidator.passwordValidator, + ), + + const SizedBox(height: 25), + + //Confirm New Password Field + CustomTextField( + hintText: 'Retype your password', + floatingText: 'Confirm Password', + controller: cNewPasswordController, + keyboardType: TextInputType.visiblePassword, + textInputAction: TextInputAction.done, + validator: (confirmPw) => FormValidator.confirmPasswordValidator( + confirmPw, + newPasswordController.text, + ), + ), + ], + ); + } +} diff --git a/lib/views/widgets/movie_details/floating_movie_posters.dart b/lib/views/widgets/movie_details/floating_movie_posters.dart index b434f2f..2b3fc96 100644 --- a/lib/views/widgets/movie_details/floating_movie_posters.dart +++ b/lib/views/widgets/movie_details/floating_movie_posters.dart @@ -43,7 +43,7 @@ class _FloatingMoviePostersState extends State { left: 0, height: 250, width: 150, - duration: const Duration(milliseconds: 650), + duration: const Duration(milliseconds: 850), curve: Curves.easeInOutBack, child: const _LeftMoviePoster(), ), @@ -54,7 +54,7 @@ class _FloatingMoviePostersState extends State { right: 0, height: 250, width: 150, - duration: const Duration(milliseconds: 650), + duration: const Duration(milliseconds: 850), curve: Curves.easeInOutBack, child: const _RightMoviePoster(), ), @@ -75,7 +75,7 @@ class _FloatingMoviePostersState extends State { top: topGap - 65, height: 250, width: 190, - duration: const Duration(milliseconds: 500), + duration: const Duration(milliseconds: 650), curve: Curves.easeInOutBack, child: const _MainMoviePoster(), ), diff --git a/lib/views/widgets/movie_details/play_button_widget.dart b/lib/views/widgets/movie_details/play_button_widget.dart index b646e45..fec6be3 100644 --- a/lib/views/widgets/movie_details/play_button_widget.dart +++ b/lib/views/widgets/movie_details/play_button_widget.dart @@ -1,13 +1,13 @@ import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; -import 'package:auto_route/auto_route.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; //Providers import 'movie_details_sheet.dart' show btnScaleRatioProvider; -//Routes -import '../../../routes/app_router.gr.dart'; +//Routing +import '../../../routes/routes.dart'; +import '../../../routes/app_router.dart'; class PlayButtonWidget extends HookWidget { const PlayButtonWidget({ @@ -19,7 +19,7 @@ class PlayButtonWidget extends HookWidget { final btnScaleRatio = useProvider(btnScaleRatioProvider).state; return ElevatedButton( onPressed: () { - context.router.push(const TrailerScreenRoute()); + AppRouter.pushNamed(Routes.TrailerScreenRoute); }, style: ElevatedButton.styleFrom( elevation: 5, diff --git a/lib/views/widgets/movies/movie_carousel.dart b/lib/views/widgets/movies/movie_carousel.dart index d88acf9..dc9f119 100644 --- a/lib/views/widgets/movies/movie_carousel.dart +++ b/lib/views/widgets/movies/movie_carousel.dart @@ -1,4 +1,3 @@ -import 'package:auto_route/auto_route.dart'; import 'package:carousel_slider/carousel_slider.dart'; import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; @@ -13,8 +12,9 @@ import '../../../models/movie_model.dart'; //Providers import '../../../providers/movies_provider.dart'; -//Router -import '../../../routes/app_router.gr.dart'; +//Routing +import '../../../routes/routes.dart'; +import '../../../routes/app_router.dart'; //Widgets import 'white_movie_container.dart'; @@ -55,7 +55,7 @@ class __MoviesCarouselState extends State { context.read(selectedMovieProvider).state = movies[i]; context.read(leftMovieProvider).state = movies[leftIndex]; context.read(rightMovieProvider).state = movies[rightIndex]; - context.router.push(const MovieDetailsScreenRoute()); + AppRouter.pushNamed(Routes.MovieDetailsScreenRoute); }, ), ); diff --git a/lib/views/widgets/movies/movie_icons_row.dart b/lib/views/widgets/movies/movie_icons_row.dart index 29e719f..cf40aa1 100644 --- a/lib/views/widgets/movies/movie_icons_row.dart +++ b/lib/views/widgets/movies/movie_icons_row.dart @@ -1,7 +1,9 @@ -import 'package:auto_route/auto_route.dart'; import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; +//Routing +import '../../../routes/app_router.dart'; + //Widgets import 'movie_type_popup_menu.dart'; @@ -21,7 +23,7 @@ class MoviesIconsRow extends HookWidget { IconButton( icon: const Icon(Icons.arrow_back_rounded), padding: const EdgeInsets.all(0), - onPressed: () => context.router.pop(), + onPressed: () => AppRouter.pop(), ), //Filter diff --git a/lib/views/widgets/payment/pay_button.dart b/lib/views/widgets/payment/pay_button.dart index a9f6181..21c4e7a 100644 --- a/lib/views/widgets/payment/pay_button.dart +++ b/lib/views/widgets/payment/pay_button.dart @@ -1,12 +1,12 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:auto_route/auto_route.dart'; //Helpers import '../../../helper/utils/constants.dart'; -//Routes -import '../../../routes/app_router.gr.dart'; +//Routing +import '../../../routes/routes.dart'; +import '../../../routes/app_router.dart'; //Providers import '../../../providers/all_providers.dart'; @@ -25,7 +25,7 @@ class PayButton extends StatelessWidget { width: double.infinity, onPressed: () { context.read(paymentsProvider).makePayment(); - context.router.push(const ConfirmationScreenRoute()); + AppRouter.pushNamed(Routes.ConfirmationScreenRoute); }, gradient: Constants.buttonGradientOrange, child: const Center( diff --git a/lib/views/widgets/theater/purchase_seats_button.dart b/lib/views/widgets/theater/purchase_seats_button.dart index 28a3b3d..ab8deed 100644 --- a/lib/views/widgets/theater/purchase_seats_button.dart +++ b/lib/views/widgets/theater/purchase_seats_button.dart @@ -1,4 +1,3 @@ -import 'package:auto_route/auto_route.dart'; import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; @@ -8,8 +7,9 @@ import '../../../helper/utils/constants.dart'; //Providers import '../../../providers/all_providers.dart'; -//Routes -import '../../../routes/app_router.gr.dart'; +//Routing +import '../../../routes/routes.dart'; +import '../../../routes/app_router.dart'; //Widgets import '../common/custom_text_button.dart'; @@ -27,7 +27,7 @@ class PurchaseSeatsButton extends StatelessWidget { return CustomTextButton.gradient( width: double.infinity, onPressed: () { - context.router.push(const TicketSummaryScreenRoute()); + AppRouter.pushNamed(Routes.TicketSummaryScreenRoute); }, disabled: theaterSeats == 0, gradient: Constants.buttonGradientOrange, diff --git a/lib/views/widgets/ticket_summary/confirm_bookings_button.dart b/lib/views/widgets/ticket_summary/confirm_bookings_button.dart index 0feed8e..866db82 100644 --- a/lib/views/widgets/ticket_summary/confirm_bookings_button.dart +++ b/lib/views/widgets/ticket_summary/confirm_bookings_button.dart @@ -1,11 +1,11 @@ import 'package:flutter/material.dart'; -import 'package:auto_route/auto_route.dart'; //Helpers import '../../../helper/utils/constants.dart'; -//Routes -import '../../../routes/app_router.gr.dart'; +//Routing +import '../../../routes/routes.dart'; +import '../../../routes/app_router.dart'; //Widgets import '../common/custom_text_button.dart'; @@ -20,7 +20,7 @@ class ConfirmBookingsButton extends StatelessWidget { child: CustomTextButton.gradient( width: double.infinity, onPressed: () { - context.router.push(const PaymentScreenRoute()); + AppRouter.pushNamed(Routes.PaymentScreenRoute); }, gradient: Constants.buttonGradientOrange, child: const Center( diff --git a/lib/views/widgets/welcome/browse_movies_button.dart b/lib/views/widgets/welcome/browse_movies_button.dart index ea35499..bae6fcd 100644 --- a/lib/views/widgets/welcome/browse_movies_button.dart +++ b/lib/views/widgets/welcome/browse_movies_button.dart @@ -1,11 +1,11 @@ import 'package:flutter/material.dart'; -import 'package:auto_route/auto_route.dart'; //Helpers import '../../../helper/utils/constants.dart'; -//Routes -import '../../../../routes/app_router.gr.dart'; +//Routing +import '../../../routes/routes.dart'; +import '../../../routes/app_router.dart'; //Widgets import '../common/custom_text_button.dart'; @@ -18,7 +18,7 @@ class BrowseMoviesButton extends StatelessWidget { return CustomTextButton.gradient( width: double.infinity, onPressed: () { - context.router.push(const MoviesScreenRoute()); + AppRouter.pushNamed(Routes.MoviesScreenRoute); }, gradient: Constants.buttonGradientOrange, child: const Center( diff --git a/lib/views/widgets/welcome/view_bookings_button.dart b/lib/views/widgets/welcome/view_bookings_button.dart index 08924a6..ac53597 100644 --- a/lib/views/widgets/welcome/view_bookings_button.dart +++ b/lib/views/widgets/welcome/view_bookings_button.dart @@ -1,11 +1,11 @@ import 'package:flutter/material.dart'; -import 'package:auto_route/auto_route.dart'; //Helpers import '../../../helper/utils/constants.dart'; -//Routes -import '../../../routes/app_router.gr.dart'; +//Routing +import '../../../routes/routes.dart'; +import '../../../routes/app_router.dart'; //Widgets import '../common/custom_text_button.dart'; @@ -17,7 +17,7 @@ class ViewBookingsButton extends StatelessWidget { Widget build(BuildContext context) { return CustomTextButton.outlined( width: double.infinity, - onPressed: () => context.router.push(const UserBookingsScreenRoute()), + onPressed: () => AppRouter.pushNamed(Routes.UserBookingsScreenRoute), border: Border.all(color: Constants.primaryColor,width: 4), child: const Center( child: Text( diff --git a/pubspec.lock b/pubspec.lock index 6c64693..071d830 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -7,14 +7,14 @@ packages: name: _fe_analyzer_shared url: "https://pub.dartlang.org" source: hosted - version: "22.0.0" + version: "23.0.0" analyzer: - dependency: transitive + dependency: "direct overridden" description: name: analyzer url: "https://pub.dartlang.org" source: hosted - version: "1.7.1" + version: "2.0.0" archive: dependency: transitive description: @@ -36,20 +36,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.6.1" - auto_route: - dependency: "direct main" - description: - name: auto_route - url: "https://pub.dartlang.org" - source: hosted - version: "2.2.0" - auto_route_generator: - dependency: "direct dev" - description: - name: auto_route_generator - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.0" better_player: dependency: "direct main" description: @@ -70,7 +56,7 @@ packages: name: build url: "https://pub.dartlang.org" source: hosted - version: "2.0.3" + version: "2.1.0" build_config: dependency: transitive description: @@ -98,14 +84,14 @@ packages: name: build_runner url: "https://pub.dartlang.org" source: hosted - version: "2.0.6" + version: "2.1.1" build_runner_core: dependency: transitive description: name: build_runner_core url: "https://pub.dartlang.org" source: hosted - version: "7.0.1" + version: "7.1.0" built_collection: dependency: transitive description: @@ -238,7 +224,7 @@ packages: name: dartdoc url: "https://pub.dartlang.org" source: hosted - version: "1.0.0" + version: "1.0.2" dio: dependency: "direct main" description: @@ -320,7 +306,7 @@ packages: name: flutter_native_splash url: "https://pub.dartlang.org" source: hosted - version: "1.2.0" + version: "1.2.1" flutter_riverpod: dependency: transitive description: @@ -365,14 +351,14 @@ packages: name: freezed url: "https://pub.dartlang.org" source: hosted - version: "0.14.2" + version: "0.14.5" freezed_annotation: dependency: "direct main" description: name: freezed_annotation url: "https://pub.dartlang.org" source: hosted - version: "0.14.2" + version: "0.14.3" frontend_server_client: dependency: transitive description: @@ -387,6 +373,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.0.1" + golden_toolkit: + dependency: "direct main" + description: + name: golden_toolkit + url: "https://pub.dartlang.org" + source: hosted + version: "0.9.0" google_fonts: dependency: "direct main" description: @@ -470,14 +463,14 @@ packages: name: json_annotation url: "https://pub.dartlang.org" source: hosted - version: "4.0.1" + version: "4.1.0" json_serializable: dependency: "direct dev" description: name: json_serializable url: "https://pub.dartlang.org" source: hosted - version: "4.1.4" + version: "5.0.0" lints: dependency: transitive description: @@ -507,12 +500,12 @@ packages: source: hosted version: "0.12.10" meta: - dependency: transitive + dependency: "direct overridden" description: name: meta url: "https://pub.dartlang.org" source: hosted - version: "1.3.0" + version: "1.7.0" mime: dependency: transitive description: @@ -526,7 +519,7 @@ packages: name: mockito url: "https://pub.dartlang.org" source: hosted - version: "5.0.13" + version: "5.0.14" octo_image: dependency: transitive description: @@ -727,7 +720,14 @@ packages: name: source_gen url: "https://pub.dartlang.org" source: hosted - version: "1.0.3" + version: "1.0.5" + source_helper: + dependency: transitive + description: + name: source_helper + url: "https://pub.dartlang.org" + source: hosted + version: "1.2.1" source_span: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 56d1ed3..a46f238 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -8,11 +8,10 @@ environment: dependencies: flutter: sdk: flutter - auto_route: ^2.2.0 cupertino_icons: ^1.0.3 time: ^2.0.0 cached_network_image: ^3.1.0 - freezed_annotation: ^0.14.2 + freezed_annotation: ^0.14.3 google_fonts: ^2.1.0 flutter_hooks: ^0.17.0 hooks_riverpod: ^0.14.0+4 @@ -22,25 +21,29 @@ dependencies: shared_preferences: ^2.0.6 sliding_up_panel: ^2.0.0+1 intl: ^0.17.0 - dartdoc: ^1.0.0 + dartdoc: ^1.0.2 better_player: ^0.0.72 flutter_spinkit: 5.0.0 flutter_secure_storage: ^4.2.1 clock: ^1.1.0 - mockito: ^5.0.13 + mockito: ^5.0.14 + golden_toolkit: ^0.9.0 dev_dependencies: flutter_test: sdk: flutter - auto_route_generator: ^2.1.0 - freezed: ^0.14.2 - json_serializable: ^4.1.3 + freezed: ^0.14.4 + json_serializable: ^5.0.0 build_runner: null - flutter_native_splash: ^1.2.0 + flutter_native_splash: ^1.2.1 flutter_lints: ^1.0.4 +dependency_overrides: + analyzer: '2.0.0' + meta: '1.7.0' flutter: uses-material-design: true assets: - assets/ + - google_fonts/ flutter_icons: android: true ios: false diff --git a/test/flutter_test_config.dart b/test/flutter_test_config.dart new file mode 100644 index 0000000..f1e7dd6 --- /dev/null +++ b/test/flutter_test_config.dart @@ -0,0 +1,37 @@ +import 'dart:async'; +import 'dart:io'; + +import 'package:golden_toolkit/golden_toolkit.dart'; + +//Theme +import 'package:ez_ticketz_app/helper/utils/custom_theme.dart'; + +Future testExecutable(FutureOr Function() testMain) async { + return GoldenToolkit.runWithConfiguration( + () async { + await loadAppFonts(); + await testMain(); + }, + config: GoldenToolkitConfiguration( + defaultDevices: const [GoldensGlobalConfig.defaultDevice], + fileNameFactory: (name) { + if(Platform.isWindows) { + return 'goldens_local/$name.png'; + } + else { + return 'goldens/$name.png'; + } + } + ), + ); +} + +abstract class GoldensGlobalConfig { + static final globalAppWrapper = materialAppWrapper( + theme: CustomTheme.mainTheme, + ); + + static const defaultDevice = Device.iphone11; + + static final defaultSurfaceSize = defaultDevice.size; +} diff --git a/test/golden_tests/change_password_screen_golden_test.dart b/test/golden_tests/change_password_screen_golden_test.dart new file mode 100644 index 0000000..52bb5da --- /dev/null +++ b/test/golden_tests/change_password_screen_golden_test.dart @@ -0,0 +1,39 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:golden_toolkit/golden_toolkit.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; + +//Providers +import 'package:ez_ticketz_app/providers/all_providers.dart'; +import 'common_mocked_providers.dart'; + +//Screens +import 'package:ez_ticketz_app/views/screens/change_password_screen.dart'; + +//Config +import '../flutter_test_config.dart'; + +void main() { + group('ChangePasswordScreen', () { + testGoldens( + 'GIVEN the change password icon is pressed ' + 'WHEN the change password screen is shown ' + 'THEN it looks like change_password_screen_golden.png', + (tester) async { + //when + await tester.pumpWidgetBuilder( + ProviderScope( + overrides: [ + authProvider.overrideWithProvider(mockAuthProvider) + ], + child: const ChangePasswordScreen(), + ), + surfaceSize: GoldensGlobalConfig.defaultSurfaceSize, + wrapper: GoldensGlobalConfig.globalAppWrapper, + ); + + //then + await screenMatchesGolden(tester, 'change_password_screen_golden'); + }, + ); + }); +} diff --git a/test/golden_tests/common_mocked_providers.dart b/test/golden_tests/common_mocked_providers.dart new file mode 100644 index 0000000..a0c52a9 --- /dev/null +++ b/test/golden_tests/common_mocked_providers.dart @@ -0,0 +1,44 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:mockito/mockito.dart'; + +//Models +import 'package:ez_ticketz_app/models/user_model.dart'; + +//Providers +import 'package:ez_ticketz_app/providers/auth_provider.dart'; + +//States +import 'package:ez_ticketz_app/providers/states/auth_state.dart'; + +//Services +import 'package:ez_ticketz_app/services/local_storage/key_value_storage_service.dart'; +import 'package:ez_ticketz_app/services/repositories/auth_repository.dart'; + +//Mocks +class _MockKVStorageService extends Mock implements KeyValueStorageService { + @override + bool getAuthState() => false; + + @override + UserModel? getAuthUser() => null; + + @override + Future getAuthPassword() => SynchronousFuture(''); + + @override + void resetKeys() {} +} + +//Fakes +class MockAuthRepository extends Fake implements AuthRepository {} + +//Providers +final mockAuthProvider = StateNotifierProvider((ref) { + return AuthProvider( + reader: ref.read, + authRepository: MockAuthRepository(), + keyValueStorageService: _MockKVStorageService(), + ); +}); diff --git a/test/golden_tests/forgot_password_screen_golden_test.dart b/test/golden_tests/forgot_password_screen_golden_test.dart new file mode 100644 index 0000000..ec6481e --- /dev/null +++ b/test/golden_tests/forgot_password_screen_golden_test.dart @@ -0,0 +1,118 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:golden_toolkit/golden_toolkit.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; + +//Providers +import 'package:ez_ticketz_app/providers/all_providers.dart'; +import 'package:ez_ticketz_app/providers/forgot_password_provider.dart'; +import 'package:ez_ticketz_app/providers/states/forgot_password_state.dart'; +import 'common_mocked_providers.dart'; + +//Screens +import 'package:ez_ticketz_app/views/screens/forgot_password_screen.dart'; + +//Config +import '../flutter_test_config.dart'; + +void main() { + group( + 'ForgotPasswordScreen', + () { + const forgotPasswordScreen = ForgotPasswordScreen(); + + testGoldens( + 'GIVEN the forgot password link is pressed ' + 'WHEN the forgot password screen is shown ' + 'THEN it looks like forgot_password_screen_email_golden.png', + (tester) async { + //when + await tester.pumpWidgetBuilder( + const ProviderScope( + child: forgotPasswordScreen, + ), + surfaceSize: GoldensGlobalConfig.defaultSurfaceSize, + wrapper: GoldensGlobalConfig.globalAppWrapper, + ); + + //then + await screenMatchesGolden( + tester, + 'forgot_password_screen_email_golden', + ); + }, + ); + + testGoldens( + 'GIVEN we are on forgot password screen ' + 'AND the otp has been sent ' + 'WHEN the screen is rebuilt ' + 'THEN it looks like forgot_password_screen_otp_golden.png', + (tester) async { + //given + await tester.pumpWidgetBuilder( + ProviderScope( + overrides: [ + forgotPasswordProvider.overrideWithValue( + ForgotPasswordProvider( + authRepository: MockAuthRepository(), + initialState: const ForgotPasswordState.otp( + otpSentMessage: 'otpSentMessage', + ), + ), + ) + ], + child: forgotPasswordScreen, + ), + surfaceSize: GoldensGlobalConfig.defaultSurfaceSize, + wrapper: GoldensGlobalConfig.globalAppWrapper, + ); + + //rebuild screen + await tester.pump(); + + //then + await screenMatchesGolden( + tester, + 'forgot_password_screen_otp_golden', + ); + }, + ); + + testGoldens( + 'GIVEN we are on forgot password screen ' + 'AND the otp has been verified ' + 'WHEN the screen is rebuilt ' + 'THEN it looks like forgot_password_screen_resetPw_golden.png', + (tester) async { + //given + await tester.pumpWidgetBuilder( + ProviderScope( + overrides: [ + forgotPasswordProvider.overrideWithValue( + ForgotPasswordProvider( + authRepository: MockAuthRepository(), + initialState: const ForgotPasswordState.resetPassword( + otpVerifiedMessage: 'otpVerifiedMessage', + ), + ), + ) + ], + child: forgotPasswordScreen, + ), + surfaceSize: GoldensGlobalConfig.defaultSurfaceSize, + wrapper: GoldensGlobalConfig.globalAppWrapper, + ); + + //rebuild screen + await tester.pump(); + + //then + await screenMatchesGolden( + tester, + 'forgot_password_screen_resetPw_golden', + ); + }, + ); + }, + ); +} diff --git a/test/golden_tests/goldens/change_password_screen_golden.png b/test/golden_tests/goldens/change_password_screen_golden.png new file mode 100644 index 0000000..68e6ba0 Binary files /dev/null and b/test/golden_tests/goldens/change_password_screen_golden.png differ diff --git a/test/golden_tests/goldens/forgot_password_screen_email_golden.png b/test/golden_tests/goldens/forgot_password_screen_email_golden.png new file mode 100644 index 0000000..608418e Binary files /dev/null and b/test/golden_tests/goldens/forgot_password_screen_email_golden.png differ diff --git a/test/golden_tests/goldens/forgot_password_screen_otp_golden.png b/test/golden_tests/goldens/forgot_password_screen_otp_golden.png new file mode 100644 index 0000000..c47a17e Binary files /dev/null and b/test/golden_tests/goldens/forgot_password_screen_otp_golden.png differ diff --git a/test/golden_tests/goldens/forgot_password_screen_resetPw_golden.png b/test/golden_tests/goldens/forgot_password_screen_resetPw_golden.png new file mode 100644 index 0000000..f4942ca Binary files /dev/null and b/test/golden_tests/goldens/forgot_password_screen_resetPw_golden.png differ diff --git a/test/golden_tests/goldens/home_screen_golden.png b/test/golden_tests/goldens/home_screen_golden.png new file mode 100644 index 0000000..357d388 Binary files /dev/null and b/test/golden_tests/goldens/home_screen_golden.png differ diff --git a/test/golden_tests/goldens/login_screen_golden.png b/test/golden_tests/goldens/login_screen_golden.png new file mode 100644 index 0000000..d1c194a Binary files /dev/null and b/test/golden_tests/goldens/login_screen_golden.png differ diff --git a/test/golden_tests/goldens/register_screen_2_golden.png b/test/golden_tests/goldens/register_screen_2_golden.png new file mode 100644 index 0000000..5d2599f Binary files /dev/null and b/test/golden_tests/goldens/register_screen_2_golden.png differ diff --git a/test/golden_tests/goldens/register_screen_golden.png b/test/golden_tests/goldens/register_screen_golden.png new file mode 100644 index 0000000..ff75b8d Binary files /dev/null and b/test/golden_tests/goldens/register_screen_golden.png differ diff --git a/test/golden_tests/home_screen_golden_test.dart b/test/golden_tests/home_screen_golden_test.dart new file mode 100644 index 0000000..bba1629 --- /dev/null +++ b/test/golden_tests/home_screen_golden_test.dart @@ -0,0 +1,29 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:golden_toolkit/golden_toolkit.dart'; + +//Screens +import 'package:ez_ticketz_app/views/screens/home_screen.dart'; + +//Config +import '../flutter_test_config.dart'; + +void main() { + group('HomeScreen', () { + testGoldens( + 'GIVEN the app is started ' + 'WHEN the home screen is shown ' + 'THEN it looks like home_screen_golden.png', + (tester) async { + //when + await tester.pumpWidgetBuilder( + const HomeScreen(), + surfaceSize: GoldensGlobalConfig.defaultSurfaceSize, + wrapper: GoldensGlobalConfig.globalAppWrapper, + ); + + //then + await screenMatchesGolden(tester, 'home_screen_golden'); + }, + ); + }); +} diff --git a/test/golden_tests/login_screen_golden_test.dart b/test/golden_tests/login_screen_golden_test.dart new file mode 100644 index 0000000..adf69b2 --- /dev/null +++ b/test/golden_tests/login_screen_golden_test.dart @@ -0,0 +1,39 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:golden_toolkit/golden_toolkit.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; + +//Providers +import 'package:ez_ticketz_app/providers/all_providers.dart'; +import 'common_mocked_providers.dart'; + +//Screens +import 'package:ez_ticketz_app/views/screens/login_screen.dart'; + +//Config +import '../flutter_test_config.dart'; + +void main() { + group('LoginScreen', () { + testGoldens( + 'GIVEN the login button is pressed ' + 'WHEN the login screen is shown ' + 'THEN it looks like login_screen_golden.png', + (tester) async { + //when + await tester.pumpWidgetBuilder( + ProviderScope( + overrides: [ + authProvider.overrideWithProvider(mockAuthProvider), + ], + child: const LoginScreen(), + ), + surfaceSize: GoldensGlobalConfig.defaultSurfaceSize, + wrapper: GoldensGlobalConfig.globalAppWrapper, + ); + + //then + await screenMatchesGolden(tester, 'login_screen_golden'); + }, + ); + }); +} diff --git a/test/golden_tests/register_screen_golden_test.dart b/test/golden_tests/register_screen_golden_test.dart new file mode 100644 index 0000000..21e87aa --- /dev/null +++ b/test/golden_tests/register_screen_golden_test.dart @@ -0,0 +1,103 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:golden_toolkit/golden_toolkit.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; + +//Providers +import 'package:ez_ticketz_app/providers/all_providers.dart'; +import 'common_mocked_providers.dart'; + +//Screens +import 'package:ez_ticketz_app/views/screens/register_screen.dart'; +import 'package:ez_ticketz_app/views/widgets/common/custom_text_button.dart'; +import 'package:ez_ticketz_app/views/widgets/common/custom_textfield.dart'; + +//Config +import '../flutter_test_config.dart'; + +void main() { + group('RegisterScreen', () { + late Widget registerScreen; + + setUp((){ + registerScreen = ProviderScope( + overrides: [ + authProvider.overrideWithProvider(mockAuthProvider), + ], + child: const RegisterScreen(), + ); + }); + + testGoldens( + 'GIVEN the register button is pressed ' + 'WHEN the register screen is shown ' + 'THEN it looks like register_screen_golden.png', + (tester) async { + //when + await tester.pumpWidgetBuilder( + registerScreen, + surfaceSize: GoldensGlobalConfig.defaultSurfaceSize, + wrapper: GoldensGlobalConfig.globalAppWrapper, + ); + + //then + await screenMatchesGolden(tester, 'register_screen_golden'); + }, + ); + + testGoldens( + 'GIVEN we are on register screen ' + 'AND the user details are filled ' + 'WHEN Next button is pressed ' + 'AND the screen is rebuilt ' + 'THEN it looks like register_screen_2_golden.png', + (tester) async { + //given + await tester.pumpWidgetBuilder( + registerScreen, + surfaceSize: GoldensGlobalConfig.defaultSurfaceSize, + wrapper: GoldensGlobalConfig.globalAppWrapper, + ); + + //and fill the fullName field + final fullNameField = find.widgetWithText(CustomTextField, 'Full name'); + await tester.pumpAndSettle(); + await tester.enterText(fullNameField, 'Test User'); + + //and fill the email field + final emailField = find.widgetWithText(CustomTextField, 'Email'); + await tester.enterText(emailField, 'test.user@gmail.com'); + + //and fill the address field + final addressField = find.widgetWithText(CustomTextField, 'Address'); + await tester.enterText(addressField, '123-E Street'); + + //and fill the contact field + final contactField = find.widgetWithText(CustomTextField, 'Contact'); + await tester.enterText(contactField, '3001234567'); + + //and dismiss keyboard + await tester.testTextInput.receiveAction(TextInputAction.done); + await tester.pump(); + + //when + //find a CustomTextButton having descendant Text('Next') + final nextButton = find.ancestor( + of: find.text('Next'), + matching: find.byWidgetPredicate( + (widget) => widget is CustomTextButton, + ), + ); + + //tap button next + await tester.tap(nextButton); + + //rebuild screen + await tester.pump(); + + //then + await screenMatchesGolden(tester, 'register_screen_2_golden'); + }, + ); + }); +} diff --git a/test/helper/extensions/string_extension_test.dart b/test/helper/extensions/string_extension_test.dart index f33935f..a130eb9 100644 --- a/test/helper/extensions/string_extension_test.dart +++ b/test/helper/extensions/string_extension_test.dart @@ -1,5 +1,5 @@ -import 'package:ez_ticketz_app/helper/extensions/string_extension.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:ez_ticketz_app/helper/extensions/string_extension.dart'; void main() { group('StringExt', () { @@ -86,7 +86,7 @@ void main() { }, ); }); - + group('isValidContact', () { test( 'GIVEN a valid contact ' @@ -112,6 +112,7 @@ void main() { expect(isValid, true); }, ); + test( 'GIVEN an invalid contact ' 'WHEN extension method `.isValidContact is called ' @@ -146,7 +147,7 @@ void main() { }, ); }); - + group('isValidZipCode', () { test( 'GIVEN a valid zip code ' @@ -163,6 +164,7 @@ void main() { expect(isValid, true); }, ); + test( 'GIVEN an invalid zip code ' 'WHEN extension method `.isValidZipCode is called ' @@ -188,7 +190,7 @@ void main() { }, ); }); - + group('isValidCreditCardNumber', () { test( 'GIVEN a valid credit card number ' @@ -214,6 +216,7 @@ void main() { expect(isValid, true); }, ); + test( 'GIVEN an invalid credit card number ' 'WHEN extension method `.isValidCreditCardNumber is called ' @@ -239,7 +242,7 @@ void main() { }, ); }); - + group('isValidCreditCardCVV', () { test( 'GIVEN a valid credit card cvv ' @@ -281,7 +284,7 @@ void main() { }, ); }); - + group('isValidCreditCardExpiry', () { test( 'GIVEN a valid credit card expiry ' @@ -332,5 +335,57 @@ void main() { }, ); }); + + group('isValidOtpDigit', () { + test( + 'GIVEN a valid otp code ' + 'WHEN extension method `.isValidOtpDigit is called ' + 'THEN true is returned', + () { + //given + const otpDigit = '4'; + + //when + final isValid = otpDigit.isValidOtpDigit; + + //then + expect(isValid, true); + }, + ); + + test( + 'GIVEN an invalid otp digit ' + 'WHEN extension method `.isValidOtpDigit is called ' + 'THEN false is returned', + () { + //given + var otpDigit = '14'; + + //when + var isValid = otpDigit.isValidOtpDigit; + + //then + expect(isValid, false); + + //given + otpDigit = '#'; + + //when + isValid = otpDigit.isValidOtpDigit; + + //then + expect(isValid, false); + + //given + otpDigit = 'abc'; + + //when + isValid = otpDigit.isValidOtpDigit; + + //then + expect(isValid, false); + }, + ); + }); }); } diff --git a/test/helper/utils/form_validator_test.dart b/test/helper/utils/form_validator_test.dart index 65806e8..896d787 100644 --- a/test/helper/utils/form_validator_test.dart +++ b/test/helper/utils/form_validator_test.dart @@ -238,5 +238,17 @@ void main(){ expect(result, Constants.invalidCreditCardExpiryError); }); }); + + group("otp inputs' validations",(){ + test('a valid otp digit returns null', (){ + final result = FormValidator.otpDigitValidator('3'); + expect(result, null); + }); + + test('invalid otp digit returns error string', (){ + final result = FormValidator.otpDigitValidator('ab3'); + expect(result, '!'); + }); + }); }); }