├── .env-example ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md └── workflows │ └── main.yaml ├── .gitignore ├── .metadata ├── HiSchool!.png ├── LICENSE ├── README.md ├── analysis_options.yaml ├── android ├── .gitignore ├── app │ ├── build.gradle │ ├── google-services.json │ ├── proguard-rules.pro │ └── src │ │ ├── debug │ │ └── AndroidManifest.xml │ │ ├── main │ │ ├── AndroidManifest.xml │ │ ├── kotlin │ │ │ └── com │ │ │ │ └── example │ │ │ │ └── flutter_mobile_2school │ │ │ │ └── MainActivity.kt │ │ └── res │ │ │ ├── drawable-v21 │ │ │ └── launch_background.xml │ │ │ ├── drawable │ │ │ └── launch_background.xml │ │ │ ├── mipmap-hdpi │ │ │ ├── ic_launcher.png │ │ │ └── launcher_icon.png │ │ │ ├── mipmap-mdpi │ │ │ ├── ic_launcher.png │ │ │ └── launcher_icon.png │ │ │ ├── mipmap-xhdpi │ │ │ ├── ic_launcher.png │ │ │ └── launcher_icon.png │ │ │ ├── mipmap-xxhdpi │ │ │ ├── ic_launcher.png │ │ │ └── launcher_icon.png │ │ │ ├── mipmap-xxxhdpi │ │ │ ├── ic_launcher.png │ │ │ └── launcher_icon.png │ │ │ ├── values-night │ │ │ └── styles.xml │ │ │ └── values │ │ │ └── styles.xml │ │ └── profile │ │ └── AndroidManifest.xml ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ └── gradle-wrapper.properties ├── settings.gradle └── settings_aar.gradle ├── assets ├── fonts │ ├── Allison-Regular.ttf │ ├── DancingScript.ttf │ └── Lato-Regular.ttf ├── icons │ └── launcher_icon.png └── lottie │ ├── cat_sleeping.json │ └── splash.json ├── build.sh ├── compile.sh ├── init.sh ├── ios ├── .gitignore ├── Flutter │ ├── AppFrameworkInfo.plist │ ├── Debug.xcconfig │ ├── Flutter 2.podspec │ ├── Generated 2.xcconfig │ └── Release.xcconfig ├── Podfile ├── Podfile.lock ├── Runner.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ ├── IDEWorkspaceChecks.plist │ │ │ └── WorkspaceSettings.xcsettings │ └── xcshareddata │ │ └── xcschemes │ │ └── Runner.xcscheme ├── Runner.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist ├── Runner │ ├── AppDelegate.swift │ ├── Assets 2.xcassets │ │ ├── AppIcon.appiconset │ │ │ ├── Contents.json │ │ │ ├── HiSchool!-1024.png │ │ │ ├── HiSchool!-20.png │ │ │ ├── HiSchool!-20@2x.png │ │ │ ├── HiSchool!-20@3x.png │ │ │ ├── HiSchool!-29.png │ │ │ ├── HiSchool!-29@2x.png │ │ │ ├── HiSchool!-29@3x.png │ │ │ ├── HiSchool!-40.png │ │ │ ├── HiSchool!-40@2x.png │ │ │ ├── HiSchool!-40@3x.png │ │ │ ├── HiSchool!-60@2x.png │ │ │ ├── HiSchool!-60@3x.png │ │ │ ├── HiSchool!-76.png │ │ │ ├── HiSchool!-76@2x.png │ │ │ └── HiSchool!-83.5@2x.png │ │ └── LaunchImage.imageset │ │ │ ├── Contents.json │ │ │ ├── LaunchImage.png │ │ │ ├── LaunchImage@2x.png │ │ │ ├── LaunchImage@3x.png │ │ │ └── README.md │ ├── Assets.xcassets │ │ ├── AppIcon.appiconset │ │ │ ├── Contents.json │ │ │ ├── HiSchool!-1024.png │ │ │ ├── HiSchool!-20.png │ │ │ ├── HiSchool!-20@2x.png │ │ │ ├── HiSchool!-20@3x.png │ │ │ ├── HiSchool!-29.png │ │ │ ├── HiSchool!-29@2x.png │ │ │ ├── HiSchool!-29@3x.png │ │ │ ├── HiSchool!-40.png │ │ │ ├── HiSchool!-40@2x.png │ │ │ ├── HiSchool!-40@3x.png │ │ │ ├── HiSchool!-60@2x.png │ │ │ ├── HiSchool!-60@3x.png │ │ │ ├── HiSchool!-76.png │ │ │ ├── HiSchool!-76@2x.png │ │ │ └── HiSchool!-83.5@2x.png │ │ └── LaunchImage.imageset │ │ │ ├── Contents.json │ │ │ ├── LaunchImage.png │ │ │ ├── LaunchImage@2x.png │ │ │ ├── LaunchImage@3x.png │ │ │ └── README.md │ ├── Base.lproj │ │ ├── LaunchScreen.storyboard │ │ └── Main.storyboard │ ├── GoogleService-Info.plist │ ├── Info.plist │ ├── Runner-Bridging-Header.h │ └── Runner.entitlements ├── build │ └── XCBuildData │ │ ├── 63dc6ff226954aff1defa2bc5b630bc5-buildRequest.json │ │ ├── 63dc6ff226954aff1defa2bc5b630bc5-targetGraph.txt │ │ ├── BuildDescriptionCacheIndex-14f1afe95d2361a2bb30c2a7ffd2414e │ │ ├── b09b6a9e6e7a242bc3f5302f5e3c06fb-buildRequest.json │ │ ├── b09b6a9e6e7a242bc3f5302f5e3c06fb-desc.xcbuild │ │ ├── b09b6a9e6e7a242bc3f5302f5e3c06fb-manifest.xcbuild │ │ ├── b09b6a9e6e7a242bc3f5302f5e3c06fb-targetGraph 2.txt │ │ ├── b09b6a9e6e7a242bc3f5302f5e3c06fb-targetGraph.txt │ │ ├── build.db │ │ ├── d87afb5e48aa690e3bd8be2cf84600bf-buildRequest 2.json │ │ ├── d87afb5e48aa690e3bd8be2cf84600bf-buildRequest.json │ │ ├── d87afb5e48aa690e3bd8be2cf84600bf-desc.xcbuild │ │ ├── d87afb5e48aa690e3bd8be2cf84600bf-manifest.xcbuild │ │ ├── d87afb5e48aa690e3bd8be2cf84600bf-targetGraph.txt │ │ ├── dff818068802d9c42a73f2c8aacbe41d-buildRequest.json │ │ ├── dff818068802d9c42a73f2c8aacbe41d-desc.xcbuild │ │ ├── dff818068802d9c42a73f2c8aacbe41d-manifest.xcbuild │ │ ├── dff818068802d9c42a73f2c8aacbe41d-targetGraph 2.txt │ │ ├── dff818068802d9c42a73f2c8aacbe41d-targetGraph.txt │ │ ├── fbc6cd67855b3fa763c4f0085931aa2c-buildRequest.json │ │ ├── fbc6cd67855b3fa763c4f0085931aa2c-desc.xcbuild │ │ ├── fbc6cd67855b3fa763c4f0085931aa2c-manifest.xcbuild │ │ ├── fbc6cd67855b3fa763c4f0085931aa2c-targetGraph 2.txt │ │ └── fbc6cd67855b3fa763c4f0085931aa2c-targetGraph.txt └── clean-pods.sh ├── lib ├── main.dart └── src │ ├── app.dart │ ├── blocs │ ├── app_bloc.dart │ ├── app_state │ │ ├── app_state_bloc 2.dart │ │ ├── app_state_bloc.dart │ │ ├── app_state_event 2.dart │ │ ├── app_state_event.dart │ │ ├── app_state_state.dart │ │ └── bloc.dart │ ├── application │ │ ├── application_bloc.dart │ │ ├── application_event.dart │ │ ├── application_state.dart │ │ └── bloc.dart │ ├── authentication │ │ ├── authentication_bloc.dart │ │ ├── authentication_event.dart │ │ ├── authentication_state.dart │ │ └── bloc.dart │ ├── bloc.dart │ ├── bloc │ │ ├── transaction_bloc.dart │ │ ├── transaction_event.dart │ │ └── transaction_state.dart │ ├── conversation │ │ ├── conversation_bloc.dart │ │ ├── conversation_event.dart │ │ └── conversation_state.dart │ ├── count_down │ │ ├── count_down_bloc.dart │ │ ├── count_down_event 2.dart │ │ ├── count_down_event.dart │ │ └── count_down_state.dart │ ├── message │ │ ├── message_bloc.dart │ │ ├── message_event.dart │ │ └── message_state.dart │ ├── post_class │ │ ├── post_class_bloc.dart │ │ ├── post_class_event.dart │ │ └── post_class_state.dart │ ├── post_home │ │ ├── post_home_bloc.dart │ │ ├── post_home_event.dart │ │ └── post_home_state.dart │ ├── schedules │ │ ├── schedules_bloc.dart │ │ ├── schedules_event.dart │ │ └── schedules_state.dart │ ├── share_exam │ │ ├── share_exam_bloc.dart │ │ ├── share_exam_event.dart │ │ └── share_exam_state.dart │ └── theme │ │ ├── bloc.dart │ │ ├── theme_bloc.dart │ │ ├── theme_event.dart │ │ └── theme_state.dart │ ├── configs │ ├── application.dart │ └── language.dart │ ├── helpers │ ├── audio_helper.dart │ ├── date_time_helper.dart │ ├── device_helper.dart │ ├── export_excel.dart │ ├── int.dart │ ├── members_helpers.dart │ ├── path_helper.dart │ ├── picker │ │ └── custom_image_picker.dart │ ├── role_helper.dart │ ├── string.dart │ └── validators │ │ ├── login_validator 2.dart │ │ └── login_validator.dart │ ├── lang │ ├── language_service.dart │ └── localization.dart │ ├── models │ ├── activity.dart │ ├── assignment_firestore_model.dart │ ├── class_model.dart │ ├── conversation_model.dart │ ├── device_model.dart │ ├── exam.dart │ ├── exam_model.dart │ ├── history_quiz_model.dart │ ├── message_model.dart │ ├── notification_model.dart │ ├── post_model.dart │ ├── question.dart │ ├── question_mode.dart │ ├── question_type_enum.dart │ ├── road_map_content_model.dart │ ├── road_map_content_type.dart │ ├── road_map_model.dart │ ├── slide_mode.dart │ ├── statistic_model.dart │ ├── transaction_model.dart │ ├── upload_response_model.dart │ └── user.dart │ ├── public │ ├── api_gateway.dart │ ├── constants.dart │ └── sockets.dart │ ├── resources │ ├── base_repository.dart │ ├── hard │ │ ├── hard_activities.dart │ │ ├── hard_attended.dart │ │ ├── hard_chat.dart │ │ ├── hard_exam_post.dart │ │ ├── hard_normal_post.dart │ │ ├── hard_post.dart │ │ └── hard_schedule.dart │ ├── local │ │ └── user_local.dart │ └── remote │ │ ├── authentication_repository.dart │ │ ├── class_repository.dart │ │ ├── conversation_repository.dart │ │ ├── exam_repository.dart │ │ ├── history_quiz_repository.dart │ │ ├── member_repository.dart │ │ ├── message_repository.dart │ │ ├── notification_repository.dart │ │ ├── post_repository.dart │ │ ├── question_repository.dart │ │ ├── road_map_content_repository.dart │ │ ├── road_map_repository.dart │ │ ├── share_exam_repository.dart │ │ ├── transaction_repository.dart │ │ ├── upload_repository.dart │ │ └── user_repository.dart │ ├── routes │ ├── app_pages.dart │ ├── app_routes.dart │ ├── scaffold_wrapper.dart │ └── slides │ │ ├── fade_route.dart │ │ ├── slide_from_bottom_route.dart │ │ ├── slide_from_left_route.dart │ │ ├── slide_from_right_route.dart │ │ └── slide_from_top_route.dart │ ├── services │ ├── firebase_firestore │ │ ├── attendance_firestore.dart │ │ └── post_firestore.dart │ ├── firebase_messaging │ │ └── handle_messaging.dart │ ├── firebase_storage │ │ └── upload_file.dart │ ├── payment │ │ └── momo_payment.dart │ └── socket │ │ ├── socket.dart │ │ └── socket_emit.dart │ ├── themes │ ├── app_colors.dart │ ├── app_decorations.dart │ ├── font_family.dart │ ├── theme_service.dart │ └── themes.dart │ ├── ui │ ├── authentication │ │ ├── authentication_screen.dart │ │ └── screens │ │ │ ├── login_screen.dart │ │ │ └── register_screen.dart │ ├── calendar │ │ ├── calendar_screen.dart │ │ └── widgets │ │ │ └── dot_below_date.dart │ ├── chats │ │ ├── chat_screen.dart │ │ └── widgets │ │ │ └── message_card.dart │ ├── classes │ │ ├── blocs │ │ │ ├── class │ │ │ │ ├── class_bloc.dart │ │ │ │ ├── class_event.dart │ │ │ │ └── class_state.dart │ │ │ ├── do_exam │ │ │ │ ├── do_exam_bloc.dart │ │ │ │ ├── do_exam_event.dart │ │ │ │ └── do_exam_state.dart │ │ │ ├── exam │ │ │ │ ├── exam_bloc.dart │ │ │ │ ├── exam_event.dart │ │ │ │ └── exam_state.dart │ │ │ ├── history_quiz │ │ │ │ ├── history_quiz_bloc.dart │ │ │ │ ├── history_quiz_event.dart │ │ │ │ └── history_quiz_state.dart │ │ │ ├── member │ │ │ │ ├── member_bloc.dart │ │ │ │ ├── member_event.dart │ │ │ │ └── member_state.dart │ │ │ ├── question │ │ │ │ ├── question_bloc.dart │ │ │ │ ├── question_event.dart │ │ │ │ └── question_state.dart │ │ │ ├── road_map │ │ │ │ ├── road_map_bloc.dart │ │ │ │ ├── road_map_event.dart │ │ │ │ └── road_map_state.dart │ │ │ └── road_map_content │ │ │ │ ├── road_map_content_bloc.dart │ │ │ │ ├── road_map_content_event.dart │ │ │ │ └── road_map_content_state.dart │ │ ├── classes_screen.dart │ │ ├── screens │ │ │ ├── class_information_screen.dart │ │ │ ├── create_class_screen.dart │ │ │ ├── create_deadline_screen.dart │ │ │ ├── create_exam_screen.dart │ │ │ ├── create_question_screen.dart │ │ │ ├── create_road_map_content_screen.dart │ │ │ ├── create_roadmap_screen.dart │ │ │ ├── details_history_screen.dart │ │ │ ├── do_exam_screen.dart │ │ │ ├── history_quiz_screen.dart │ │ │ ├── list_exam_screen.dart │ │ │ ├── list_questions_screen.dart │ │ │ ├── list_request_screen.dart │ │ │ ├── lobby_screen.dart │ │ │ ├── members_screen.dart │ │ │ ├── new_post_screen.dart │ │ │ ├── road_map_content_screen.dart │ │ │ ├── road_map_screen.dart │ │ │ ├── share_exam_screen.dart │ │ │ ├── statistic_final_screen.dart │ │ │ ├── statistic_in_exam_screen.dart │ │ │ └── submit_deadline_screen.dart │ │ └── widgets │ │ │ ├── bottom_option_exam.dart │ │ │ ├── bottom_option_question.dart │ │ │ ├── bottom_option_road_map.dart │ │ │ ├── character_counter.dart │ │ │ ├── class_card.dart │ │ │ ├── dialog_add_answer.dart │ │ │ ├── dialog_add_dad.dart │ │ │ ├── drawer_option.dart │ │ │ ├── exam_card.dart │ │ │ ├── history_quiz_item.dart │ │ │ ├── lobby_user_card.dart │ │ │ ├── question_card.dart │ │ │ ├── recommend_class_card.dart │ │ │ ├── transaction_card.dart │ │ │ ├── user_request_card.dart │ │ │ └── user_score_card.dart │ ├── common │ │ ├── dialogs │ │ │ ├── dialog_confirm.dart │ │ │ ├── dialog_loading.dart │ │ │ └── dialog_notice.dart │ │ ├── network_cached.dart │ │ ├── screens │ │ │ └── loading_screen.dart │ │ └── widgets │ │ │ ├── animated_fade.dart │ │ │ ├── custom_date_picker.dart │ │ │ ├── fade_shimmer.dart │ │ │ ├── get_snack_bar.dart │ │ │ ├── indicator.dart │ │ │ └── pie_chart.dart │ ├── conversation │ │ ├── conversation_screen.dart │ │ └── widgets │ │ │ ├── input_message.dart │ │ │ └── message_conversation_card.dart │ ├── home │ │ ├── home_screen.dart │ │ └── widgets │ │ │ ├── active_friend_card.dart │ │ │ ├── attendance_in_post.dart │ │ │ ├── bottom_sheet_assignment.dart │ │ │ ├── bottom_sheet_attendance.dart │ │ │ ├── bottom_sheet_comment.dart │ │ │ ├── bottom_sheet_pick_class.dart │ │ │ ├── comment_card.dart │ │ │ ├── date_bar.dart │ │ │ ├── deadline_in_post.dart │ │ │ ├── exam_in_post.dart │ │ │ ├── image_body_post.dart │ │ │ ├── input_comment_post.dart │ │ │ ├── new_post.dart │ │ │ ├── post_card.dart │ │ │ ├── post_shimmer_card.dart │ │ │ ├── post_shimmer_list.dart │ │ │ └── user_assignment_done.dart │ ├── navigation │ │ ├── navigation.dart │ │ └── widgets │ │ │ └── notification_card.dart │ ├── notification │ │ ├── blocs │ │ │ ├── notification_bloc.dart │ │ │ ├── notification_event.dart │ │ │ └── notification_state.dart │ │ └── notification_screen.dart │ ├── profile │ │ ├── profile_screen.dart │ │ └── screens │ │ │ └── edit_profile_screen.dart │ └── splash │ │ └── splash_screen.dart │ └── utils │ ├── blurhash.dart │ ├── logger.dart │ ├── sizer_custom │ ├── extension.dart │ ├── sizer.dart │ ├── util.dart │ └── widget.dart │ └── stack_avatar.dart ├── pubspec.lock ├── pubspec.yaml ├── screenshots ├── class.png ├── details_class.png ├── home.png └── profile.png └── test └── main_test.dart /.env-example: -------------------------------------------------------------------------------- 1 | BASE_URL=domain 2 | SOCKET_URL=domain -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/workflows/main.yaml: -------------------------------------------------------------------------------- 1 | name: Test, Build, Release apk 2 | 3 | on: 4 | push: 5 | tags: 6 | - "*" 7 | 8 | jobs: 9 | test: 10 | name: Unit Test 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v1 14 | - uses: actions/setup-java@v1 15 | with: 16 | java-version: "12.x" 17 | - uses: subosito/flutter-action@v1 18 | with: 19 | flutter-version: "3.7.9" 20 | - run: flutter pub get 21 | - run: flutter test 22 | 23 | build: 24 | needs: [test] 25 | name: Build APK 26 | runs-on: ubuntu-latest 27 | steps: 28 | - uses: actions/checkout@v1 29 | - uses: actions/setup-java@v1 30 | with: 31 | java-version: "12.x" 32 | - uses: subosito/flutter-action@v1 33 | with: 34 | flutter-version: "3.7.9" 35 | - run: flutter pub get 36 | - run: flutter build apk --release 37 | - name: Create a Release APK 38 | uses: ncipollo/release-action@v1 39 | with: 40 | artifacts: "build/app/outputs/apk/release/*.apk" 41 | token: ${{ secrets.TOKEN }} 42 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | 12 | # IntelliJ related 13 | *.iml 14 | *.ipr 15 | *.iws 16 | .idea/ 17 | 18 | # The .vscode folder contains launch configuration and tasks you configure in 19 | # VS Code which you may wish to be included in version control, so this line 20 | # is commented out by default. 21 | #.vscode/ 22 | 23 | # Flutter/Dart/Pub related 24 | **/doc/api/ 25 | **/ios/Flutter/.last_build_id 26 | .dart_tool/ 27 | .flutter-plugins 28 | .flutter-plugins-dependencies 29 | .packages 30 | .pub-cache/ 31 | .pub/ 32 | /build/ 33 | 34 | # Web related 35 | lib/generated_plugin_registrant.dart 36 | 37 | # Symbolication related 38 | app.*.symbols 39 | 40 | # Obfuscation related 41 | app.*.map.json 42 | 43 | # Android Studio will place build artifacts here 44 | /android/app/debug 45 | /android/app/profile 46 | /android/app/release 47 | lib/src/secret_key.dart -------------------------------------------------------------------------------- /.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: f4abaa0735eba4dfd8f33f73363911d63931fe03 8 | channel: stable 9 | 10 | project_type: app 11 | -------------------------------------------------------------------------------- /HiSchool!.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Py-Ec/cloudmate-classroom-flutter/d1d241a3416e19b192dfd9743e4ce12e0d05357f/HiSchool!.png -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 lambiengcode 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /analysis_options.yaml: -------------------------------------------------------------------------------- 1 | # include: package:pedantic/analysis_options.1.9.0.yaml 2 | # linter: 3 | # rules: 4 | # prefer_single_quotes: false 5 | -------------------------------------------------------------------------------- /android/.gitignore: -------------------------------------------------------------------------------- 1 | gradle-wrapper.jar 2 | /.gradle 3 | /captures/ 4 | /gradlew 5 | /gradlew.bat 6 | /local.properties 7 | GeneratedPluginRegistrant.java 8 | 9 | # Remember to never publicly share your keystore. 10 | # See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app 11 | key.properties 12 | /app/hischool-keystore.jks -------------------------------------------------------------------------------- /android/app/google-services.json: -------------------------------------------------------------------------------- 1 | { 2 | "project_info": { 3 | "project_number": "346586327036", 4 | "project_id": "cloudmate-243bf", 5 | "storage_bucket": "cloudmate-243bf.appspot.com" 6 | }, 7 | "client": [ 8 | { 9 | "client_info": { 10 | "mobilesdk_app_id": "1:346586327036:android:22508e54c1752947f77479", 11 | "android_client_info": { 12 | "package_name": "com.wanted.cloudmate" 13 | } 14 | }, 15 | "oauth_client": [ 16 | { 17 | "client_id": "346586327036-fjps5ntuml5676862ju5eljav2qoq8sr.apps.googleusercontent.com", 18 | "client_type": 3 19 | } 20 | ], 21 | "api_key": [ 22 | { 23 | "current_key": "AIzaSyDwdoptIa5nvx6rZp_Jia_6dS7c0nYF_9I" 24 | } 25 | ], 26 | "services": { 27 | "appinvite_service": { 28 | "other_platform_oauth_client": [ 29 | { 30 | "client_id": "346586327036-fjps5ntuml5676862ju5eljav2qoq8sr.apps.googleusercontent.com", 31 | "client_type": 3 32 | }, 33 | { 34 | "client_id": "346586327036-cukqoq8teu58v3eb35rdugq1sjq7va0t.apps.googleusercontent.com", 35 | "client_type": 2, 36 | "ios_info": { 37 | "bundle_id": "com.wanted.cloudmate" 38 | } 39 | } 40 | ] 41 | } 42 | } 43 | } 44 | ], 45 | "configuration_version": "1" 46 | } -------------------------------------------------------------------------------- /android/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | ## Flutter wrapper 2 | -keep class io.flutter.app.** { *; } 3 | -keep class io.flutter.plugin.** { *; } 4 | -keep class io.flutter.util.** { *; } 5 | -keep class io.flutter.view.** { *; } 6 | -keep class io.flutter.** { *; } 7 | -keep class io.flutter.plugins.** { *; } 8 | -dontwarn io.flutter.embedding.** -------------------------------------------------------------------------------- /android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /android/app/src/main/kotlin/com/example/flutter_mobile_2school/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.wanted.cloudmate 2 | 3 | import io.flutter.embedding.android.FlutterActivity 4 | 5 | class MainActivity: FlutterActivity() { 6 | } 7 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-v21/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Py-Ec/cloudmate-classroom-flutter/d1d241a3416e19b192dfd9743e4ce12e0d05357f/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/launcher_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Py-Ec/cloudmate-classroom-flutter/d1d241a3416e19b192dfd9743e4ce12e0d05357f/android/app/src/main/res/mipmap-hdpi/launcher_icon.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Py-Ec/cloudmate-classroom-flutter/d1d241a3416e19b192dfd9743e4ce12e0d05357f/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/launcher_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Py-Ec/cloudmate-classroom-flutter/d1d241a3416e19b192dfd9743e4ce12e0d05357f/android/app/src/main/res/mipmap-mdpi/launcher_icon.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Py-Ec/cloudmate-classroom-flutter/d1d241a3416e19b192dfd9743e4ce12e0d05357f/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/launcher_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Py-Ec/cloudmate-classroom-flutter/d1d241a3416e19b192dfd9743e4ce12e0d05357f/android/app/src/main/res/mipmap-xhdpi/launcher_icon.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Py-Ec/cloudmate-classroom-flutter/d1d241a3416e19b192dfd9743e4ce12e0d05357f/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/launcher_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Py-Ec/cloudmate-classroom-flutter/d1d241a3416e19b192dfd9743e4ce12e0d05357f/android/app/src/main/res/mipmap-xxhdpi/launcher_icon.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Py-Ec/cloudmate-classroom-flutter/d1d241a3416e19b192dfd9743e4ce12e0d05357f/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/launcher_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Py-Ec/cloudmate-classroom-flutter/d1d241a3416e19b192dfd9743e4ce12e0d05357f/android/app/src/main/res/mipmap-xxxhdpi/launcher_icon.png -------------------------------------------------------------------------------- /android/app/src/main/res/values-night/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext.kotlin_version = '1.8.22' 3 | repositories { 4 | google() 5 | jcenter() 6 | } 7 | 8 | dependencies { 9 | classpath 'com.android.tools.build:gradle:7.4.2' 10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 11 | classpath 'com.google.gms:google-services:4.3.15' 12 | } 13 | } 14 | 15 | allprojects { 16 | repositories { 17 | google() 18 | jcenter() 19 | } 20 | } 21 | 22 | rootProject.buildDir = '../build' 23 | subprojects { 24 | project.buildDir = "${rootProject.buildDir}/${project.name}" 25 | project.evaluationDependsOn(':app') 26 | } 27 | 28 | tasks.register("clean", Delete) { 29 | delete rootProject.buildDir 30 | } 31 | -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | # android.enableR8=true 3 | android.useAndroidX=true 4 | android.enableJetifier=true -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri Jun 23 08:50:38 CEST 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip 7 | -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | 3 | def localPropertiesFile = new File(rootProject.projectDir, "local.properties") 4 | def properties = new Properties() 5 | 6 | assert localPropertiesFile.exists() 7 | localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } 8 | 9 | def flutterSdkPath = properties.getProperty("flutter.sdk") 10 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties" 11 | apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" 12 | -------------------------------------------------------------------------------- /android/settings_aar.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | -------------------------------------------------------------------------------- /assets/fonts/Allison-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Py-Ec/cloudmate-classroom-flutter/d1d241a3416e19b192dfd9743e4ce12e0d05357f/assets/fonts/Allison-Regular.ttf -------------------------------------------------------------------------------- /assets/fonts/DancingScript.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Py-Ec/cloudmate-classroom-flutter/d1d241a3416e19b192dfd9743e4ce12e0d05357f/assets/fonts/DancingScript.ttf -------------------------------------------------------------------------------- /assets/fonts/Lato-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Py-Ec/cloudmate-classroom-flutter/d1d241a3416e19b192dfd9743e4ce12e0d05357f/assets/fonts/Lato-Regular.ttf -------------------------------------------------------------------------------- /assets/icons/launcher_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Py-Ec/cloudmate-classroom-flutter/d1d241a3416e19b192dfd9743e4ce12e0d05357f/assets/icons/launcher_icon.png -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | echo "1. APK" 2 | echo "2. AppBundle" 3 | while : 4 | do 5 | read -p "Build to: " input 6 | case $input in 7 | 1) 8 | flutter build apk --target-platform android-arm,android-arm64 --release -v 9 | break 10 | ;; 11 | 2) 12 | flutter build appbundle --target-platform android-arm,android-arm64 --release -v 13 | break 14 | ;; 15 | *) 16 | ;; 17 | esac 18 | done 19 | echo "Build successfully!" -------------------------------------------------------------------------------- /compile.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | SCRIPTPATH="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" 4 | echo "Use path: $SCRIPTPATH/" 5 | cd $SCRIPTPATH 6 | 7 | case "$(uname -s)" in 8 | Linux*) windows=0;mac=0;; 9 | Darwin*) windows=0;mac=1;; 10 | CYGWIN*) windows=1;mac=0;; 11 | MINGW*) windows=1;mac=0;; 12 | *) windows=0;mac=0 13 | esac 14 | 15 | if [ -e ./build ]; then 16 | rm -rf ./build 17 | fi 18 | 19 | flutter format modules lib test 20 | flutter clean 21 | flutter pub get 22 | clear 23 | 24 | # Analyze before build 25 | flutter analyze 26 | if [ ! $? -eq 0 ]; then 27 | exit 1 28 | fi 29 | 30 | # Generate app icons & splash screen 31 | flutter pub run flutter_launcher_icons:main 32 | 33 | # Remove ununsed icons 34 | rm -f ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png 35 | rm -f ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@2x.png 36 | rm -f ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png 37 | rm -f ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png 38 | rm -f ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png 39 | rm -f ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png 40 | 41 | if [ "$1" == "run" ]; then 42 | # Run on all devices 43 | flutter run -d all 44 | else 45 | # Android App Bundle 46 | # Support app bundles with 32-bit and 64-bit binaries 47 | # https://github.com/flutter/flutter/issues/3192# 48 | # brew cask install java 49 | # brew install gradle 50 | flutter build appbundle --release --shrink --split-debug-info=build/debug_info $@ 51 | 52 | if [ "$mac" == "1" ]; then 53 | # Short pause 54 | sleep 3 55 | 56 | # iOS Build 57 | flutter build ios --release --obfuscate --split-debug-info=build/debug_info $@ 58 | if [ $? -eq 0 ]; then 59 | du -sh build/ios/iphoneos/Runner.app 60 | rm -Rf build/ios/iphoneos/Runner.app 61 | fi 62 | fi 63 | fi 64 | -------------------------------------------------------------------------------- /init.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | SCRIPTPATH="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" 4 | echo "Use path: $SCRIPTPATH/" 5 | cd $SCRIPTPATH 6 | 7 | case "$(uname -s)" in 8 | Linux*) windows=0;mac=0;; 9 | Darwin*) windows=0;mac=1;; 10 | CYGWIN*) windows=1;mac=0;; 11 | MINGW*) windows=1;mac=0;; 12 | *) windows=0;mac=0 13 | esac 14 | 15 | # Remove all pub caches 16 | if [ "$windows" != "1" ]; then 17 | rm -Rf ~/.pub-cache/ 18 | 19 | if [ "$mac" == "1" ]; then 20 | rm -Rf ~/Library/Developer/Xcode/DerivedData 21 | rm -Rf ~/.cocoapods/ 22 | fi 23 | else 24 | rm -Rf ~/AppData/Local/Pub/Cache 25 | rm -Rf ~/AppData/Roaming/Pub/Cache 26 | fi 27 | 28 | # Remove all logs and temp files 29 | rm -Rf .dart_tool/ 30 | rm -Rf .flutter-plugins 31 | rm -Rf .flutter-plugins-dependencies 32 | rm -Rf *.iml 33 | rm -Rf *.lock 34 | rm -Rf *.log 35 | rm -Rf android/.gradle/ 36 | rm -Rf android/.idea/ 37 | rm -Rf build/ 38 | 39 | if [ "$mac" == "1" ]; then 40 | rm -Rf ios/.symlinks/ 41 | rm -Rf ios/Flutter/Flutter.framework 42 | rm -Rf ios/Flutter/Flutter.podspec 43 | rm -Rf ios/Pods/ 44 | rm -Rf ios/Runner.xcworkspace 45 | fi 46 | 47 | # Upgrade the framework (only works on mac) bash configbash 48 | if [ "$windows" != "1" ]; then 49 | flutter channel stable 50 | flutter upgrade --force 51 | fi 52 | 53 | # Get pub packages 54 | if [ ! -e .packages ]; then 55 | flutter pub get 56 | else 57 | flutter clean 58 | flutter pub cache repair 59 | flutter pub upgrade 60 | fi 61 | 62 | # Install ios packages (only works on mac) 63 | if [ "$mac" == "1" ]; then 64 | cd ios 65 | pod deintegrate 66 | pod install --clean-install 67 | cd .. 68 | fi 69 | 70 | # Get packages for sub modules 71 | get_modules() { 72 | local root=$(pwd) 73 | local path="$1" 74 | cd $path 75 | flutter packages get 76 | cd $root 77 | } 78 | for folder in modules/*; do 79 | if [ -d "$folder" ]; then get_modules "$folder"; fi 80 | done 81 | 82 | # Get the flutter packages 83 | flutter config --no-analytics 84 | flutter doctor --android-licenses 85 | flutter packages get 86 | 87 | # Run flutter doctor 88 | clear ; flutter doctor -v 89 | -------------------------------------------------------------------------------- /ios/.gitignore: -------------------------------------------------------------------------------- 1 | *.mode1v3 2 | *.mode2v3 3 | *.moved-aside 4 | *.pbxuser 5 | *.perspectivev3 6 | **/*sync/ 7 | .sconsign.dblite 8 | .tags* 9 | **/.vagrant/ 10 | **/DerivedData/ 11 | Icon? 12 | **/Pods/ 13 | **/.symlinks/ 14 | profile 15 | xcuserdata 16 | **/.generated/ 17 | Flutter/App.framework 18 | Flutter/Flutter.framework 19 | Flutter/Flutter.podspec 20 | Flutter/Generated.xcconfig 21 | Flutter/ephemeral/ 22 | Flutter/app.flx 23 | Flutter/app.zip 24 | Flutter/flutter_assets/ 25 | Flutter/flutter_export_environment.sh 26 | ServiceDefinitions.json 27 | Runner/GeneratedPluginRegistrant.* 28 | 29 | # Exceptions to above rules. 30 | !default.mode1v3 31 | !default.mode2v3 32 | !default.pbxuser 33 | !default.perspectivev3 34 | -------------------------------------------------------------------------------- /ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | App 9 | CFBundleIdentifier 10 | io.flutter.flutter.app 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | App 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.0 23 | MinimumOSVersion 24 | 11.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /ios/Flutter/Flutter 2.podspec: -------------------------------------------------------------------------------- 1 | # 2 | # NOTE: This podspec is NOT to be published. It is only used as a local source! 3 | # This is a generated file; do not edit or check into version control. 4 | # 5 | 6 | Pod::Spec.new do |s| 7 | s.name = 'Flutter' 8 | s.version = '1.0.0' 9 | s.summary = 'High-performance, high-fidelity mobile apps.' 10 | s.homepage = 'https://flutter.io' 11 | s.license = { :type => 'MIT' } 12 | s.author = { 'Flutter Dev Team' => 'flutter-dev@googlegroups.com' } 13 | s.source = { :git => 'https://github.com/flutter/engine', :tag => s.version.to_s } 14 | s.ios.deployment_target = '9.0' 15 | # Framework linking is handled by Flutter tooling, not CocoaPods. 16 | # Add a placeholder to satisfy `s.dependency 'Flutter'` plugin podspecs. 17 | s.vendored_frameworks = 'path/to/nothing' 18 | end 19 | -------------------------------------------------------------------------------- /ios/Flutter/Generated 2.xcconfig: -------------------------------------------------------------------------------- 1 | // This is a generated file; do not edit or check into version control. 2 | FLUTTER_ROOT=/Applications/flutter 3 | FLUTTER_APPLICATION_PATH=/Users/lambiengcode/Documents/lambiengcode/opensource_hi_school 4 | COCOAPODS_PARALLEL_CODE_SIGN=true 5 | FLUTTER_TARGET=/Users/lambiengcode/Documents/lambiengcode/opensource_hi_school/lib/main.dart 6 | FLUTTER_BUILD_DIR=build 7 | FLUTTER_BUILD_NAME=1.0.0 8 | FLUTTER_BUILD_NUMBER=1 9 | EXCLUDED_ARCHS[sdk=iphonesimulator*]=i386 arm64 10 | DART_DEFINES=RkxVVFRFUl9XRUJfQVVUT19ERVRFQ1Q9dHJ1ZQ== 11 | DART_OBFUSCATION=false 12 | TRACK_WIDGET_CREATION=true 13 | TREE_SHAKE_ICONS=false 14 | PACKAGE_CONFIG=/Users/lambiengcode/Documents/lambiengcode/opensource_hi_school/.dart_tool/package_config.json 15 | -------------------------------------------------------------------------------- /ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /ios/Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment this line to define a global platform for your project 2 | platform :ios, '11.0' 3 | 4 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency. 5 | ENV['COCOAPODS_DISABLE_STATS'] = 'true' 6 | 7 | project 'Runner', { 8 | 'Debug' => :debug, 9 | 'Profile' => :release, 10 | 'Release' => :release, 11 | } 12 | 13 | def flutter_root 14 | generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) 15 | unless File.exist?(generated_xcode_build_settings_path) 16 | raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" 17 | end 18 | 19 | File.foreach(generated_xcode_build_settings_path) do |line| 20 | matches = line.match(/FLUTTER_ROOT\=(.*)/) 21 | return matches[1].strip if matches 22 | end 23 | raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" 24 | end 25 | 26 | require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) 27 | 28 | flutter_ios_podfile_setup 29 | 30 | target 'Runner' do 31 | use_frameworks! 32 | use_modular_headers! 33 | flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) 34 | end 35 | 36 | post_install do |installer| 37 | installer.pods_project.targets.each do |target| 38 | flutter_additional_ios_build_settings(target) 39 | end 40 | installer.pods_project.build_configurations.each do |config| 41 | config.build_settings['IPHONE_DEPLOYMENT_TARGET']='11.0' 42 | config.build_settings["EXCLUDED_ARCHS[sdk=iphonesimulator*]"] = "arm64 i386" 43 | end 44 | end 45 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import Flutter 3 | import Firebase 4 | import momo_vn 5 | 6 | @UIApplicationMain 7 | @objc class AppDelegate: FlutterAppDelegate { 8 | override func application( 9 | _ application: UIApplication, 10 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? 11 | ) -> Bool { 12 | FirebaseApp.configure() 13 | GeneratedPluginRegistrant.register(with: self) 14 | return super.application(application, didFinishLaunchingWithOptions: launchOptions) 15 | } 16 | 17 | override func application(_ application: UIApplication, open url: URL, sourceApplication: String?, annotation: Any) -> Bool { 18 | MoMoPayment.handleOpenUrl(url: url, sourceApp: sourceApplication!) 19 | return true 20 | } 21 | 22 | override func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any]) -> Bool { 23 | MoMoPayment.handleOpenUrl(url: url, sourceApp: "") 24 | return true 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /ios/Runner/Assets 2.xcassets/AppIcon.appiconset/HiSchool!-1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Py-Ec/cloudmate-classroom-flutter/d1d241a3416e19b192dfd9743e4ce12e0d05357f/ios/Runner/Assets 2.xcassets/AppIcon.appiconset/HiSchool!-1024.png -------------------------------------------------------------------------------- /ios/Runner/Assets 2.xcassets/AppIcon.appiconset/HiSchool!-20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Py-Ec/cloudmate-classroom-flutter/d1d241a3416e19b192dfd9743e4ce12e0d05357f/ios/Runner/Assets 2.xcassets/AppIcon.appiconset/HiSchool!-20.png -------------------------------------------------------------------------------- /ios/Runner/Assets 2.xcassets/AppIcon.appiconset/HiSchool!-20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Py-Ec/cloudmate-classroom-flutter/d1d241a3416e19b192dfd9743e4ce12e0d05357f/ios/Runner/Assets 2.xcassets/AppIcon.appiconset/HiSchool!-20@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets 2.xcassets/AppIcon.appiconset/HiSchool!-20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Py-Ec/cloudmate-classroom-flutter/d1d241a3416e19b192dfd9743e4ce12e0d05357f/ios/Runner/Assets 2.xcassets/AppIcon.appiconset/HiSchool!-20@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets 2.xcassets/AppIcon.appiconset/HiSchool!-29.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Py-Ec/cloudmate-classroom-flutter/d1d241a3416e19b192dfd9743e4ce12e0d05357f/ios/Runner/Assets 2.xcassets/AppIcon.appiconset/HiSchool!-29.png -------------------------------------------------------------------------------- /ios/Runner/Assets 2.xcassets/AppIcon.appiconset/HiSchool!-29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Py-Ec/cloudmate-classroom-flutter/d1d241a3416e19b192dfd9743e4ce12e0d05357f/ios/Runner/Assets 2.xcassets/AppIcon.appiconset/HiSchool!-29@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets 2.xcassets/AppIcon.appiconset/HiSchool!-29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Py-Ec/cloudmate-classroom-flutter/d1d241a3416e19b192dfd9743e4ce12e0d05357f/ios/Runner/Assets 2.xcassets/AppIcon.appiconset/HiSchool!-29@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets 2.xcassets/AppIcon.appiconset/HiSchool!-40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Py-Ec/cloudmate-classroom-flutter/d1d241a3416e19b192dfd9743e4ce12e0d05357f/ios/Runner/Assets 2.xcassets/AppIcon.appiconset/HiSchool!-40.png -------------------------------------------------------------------------------- /ios/Runner/Assets 2.xcassets/AppIcon.appiconset/HiSchool!-40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Py-Ec/cloudmate-classroom-flutter/d1d241a3416e19b192dfd9743e4ce12e0d05357f/ios/Runner/Assets 2.xcassets/AppIcon.appiconset/HiSchool!-40@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets 2.xcassets/AppIcon.appiconset/HiSchool!-40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Py-Ec/cloudmate-classroom-flutter/d1d241a3416e19b192dfd9743e4ce12e0d05357f/ios/Runner/Assets 2.xcassets/AppIcon.appiconset/HiSchool!-40@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets 2.xcassets/AppIcon.appiconset/HiSchool!-60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Py-Ec/cloudmate-classroom-flutter/d1d241a3416e19b192dfd9743e4ce12e0d05357f/ios/Runner/Assets 2.xcassets/AppIcon.appiconset/HiSchool!-60@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets 2.xcassets/AppIcon.appiconset/HiSchool!-60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Py-Ec/cloudmate-classroom-flutter/d1d241a3416e19b192dfd9743e4ce12e0d05357f/ios/Runner/Assets 2.xcassets/AppIcon.appiconset/HiSchool!-60@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets 2.xcassets/AppIcon.appiconset/HiSchool!-76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Py-Ec/cloudmate-classroom-flutter/d1d241a3416e19b192dfd9743e4ce12e0d05357f/ios/Runner/Assets 2.xcassets/AppIcon.appiconset/HiSchool!-76.png -------------------------------------------------------------------------------- /ios/Runner/Assets 2.xcassets/AppIcon.appiconset/HiSchool!-76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Py-Ec/cloudmate-classroom-flutter/d1d241a3416e19b192dfd9743e4ce12e0d05357f/ios/Runner/Assets 2.xcassets/AppIcon.appiconset/HiSchool!-76@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets 2.xcassets/AppIcon.appiconset/HiSchool!-83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Py-Ec/cloudmate-classroom-flutter/d1d241a3416e19b192dfd9743e4ce12e0d05357f/ios/Runner/Assets 2.xcassets/AppIcon.appiconset/HiSchool!-83.5@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets 2.xcassets/LaunchImage.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "LaunchImage.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "LaunchImage@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "LaunchImage@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /ios/Runner/Assets 2.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Py-Ec/cloudmate-classroom-flutter/d1d241a3416e19b192dfd9743e4ce12e0d05357f/ios/Runner/Assets 2.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /ios/Runner/Assets 2.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Py-Ec/cloudmate-classroom-flutter/d1d241a3416e19b192dfd9743e4ce12e0d05357f/ios/Runner/Assets 2.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets 2.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Py-Ec/cloudmate-classroom-flutter/d1d241a3416e19b192dfd9743e4ce12e0d05357f/ios/Runner/Assets 2.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets 2.xcassets/LaunchImage.imageset/README.md: -------------------------------------------------------------------------------- 1 | # Launch Screen Assets 2 | 3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory. 4 | 5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/HiSchool!-1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Py-Ec/cloudmate-classroom-flutter/d1d241a3416e19b192dfd9743e4ce12e0d05357f/ios/Runner/Assets.xcassets/AppIcon.appiconset/HiSchool!-1024.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/HiSchool!-20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Py-Ec/cloudmate-classroom-flutter/d1d241a3416e19b192dfd9743e4ce12e0d05357f/ios/Runner/Assets.xcassets/AppIcon.appiconset/HiSchool!-20.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/HiSchool!-20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Py-Ec/cloudmate-classroom-flutter/d1d241a3416e19b192dfd9743e4ce12e0d05357f/ios/Runner/Assets.xcassets/AppIcon.appiconset/HiSchool!-20@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/HiSchool!-20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Py-Ec/cloudmate-classroom-flutter/d1d241a3416e19b192dfd9743e4ce12e0d05357f/ios/Runner/Assets.xcassets/AppIcon.appiconset/HiSchool!-20@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/HiSchool!-29.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Py-Ec/cloudmate-classroom-flutter/d1d241a3416e19b192dfd9743e4ce12e0d05357f/ios/Runner/Assets.xcassets/AppIcon.appiconset/HiSchool!-29.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/HiSchool!-29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Py-Ec/cloudmate-classroom-flutter/d1d241a3416e19b192dfd9743e4ce12e0d05357f/ios/Runner/Assets.xcassets/AppIcon.appiconset/HiSchool!-29@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/HiSchool!-29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Py-Ec/cloudmate-classroom-flutter/d1d241a3416e19b192dfd9743e4ce12e0d05357f/ios/Runner/Assets.xcassets/AppIcon.appiconset/HiSchool!-29@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/HiSchool!-40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Py-Ec/cloudmate-classroom-flutter/d1d241a3416e19b192dfd9743e4ce12e0d05357f/ios/Runner/Assets.xcassets/AppIcon.appiconset/HiSchool!-40.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/HiSchool!-40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Py-Ec/cloudmate-classroom-flutter/d1d241a3416e19b192dfd9743e4ce12e0d05357f/ios/Runner/Assets.xcassets/AppIcon.appiconset/HiSchool!-40@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/HiSchool!-40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Py-Ec/cloudmate-classroom-flutter/d1d241a3416e19b192dfd9743e4ce12e0d05357f/ios/Runner/Assets.xcassets/AppIcon.appiconset/HiSchool!-40@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/HiSchool!-60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Py-Ec/cloudmate-classroom-flutter/d1d241a3416e19b192dfd9743e4ce12e0d05357f/ios/Runner/Assets.xcassets/AppIcon.appiconset/HiSchool!-60@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/HiSchool!-60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Py-Ec/cloudmate-classroom-flutter/d1d241a3416e19b192dfd9743e4ce12e0d05357f/ios/Runner/Assets.xcassets/AppIcon.appiconset/HiSchool!-60@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/HiSchool!-76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Py-Ec/cloudmate-classroom-flutter/d1d241a3416e19b192dfd9743e4ce12e0d05357f/ios/Runner/Assets.xcassets/AppIcon.appiconset/HiSchool!-76.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/HiSchool!-76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Py-Ec/cloudmate-classroom-flutter/d1d241a3416e19b192dfd9743e4ce12e0d05357f/ios/Runner/Assets.xcassets/AppIcon.appiconset/HiSchool!-76@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/HiSchool!-83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Py-Ec/cloudmate-classroom-flutter/d1d241a3416e19b192dfd9743e4ce12e0d05357f/ios/Runner/Assets.xcassets/AppIcon.appiconset/HiSchool!-83.5@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "LaunchImage.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "LaunchImage@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "LaunchImage@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Py-Ec/cloudmate-classroom-flutter/d1d241a3416e19b192dfd9743e4ce12e0d05357f/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Py-Ec/cloudmate-classroom-flutter/d1d241a3416e19b192dfd9743e4ce12e0d05357f/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Py-Ec/cloudmate-classroom-flutter/d1d241a3416e19b192dfd9743e4ce12e0d05357f/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md: -------------------------------------------------------------------------------- 1 | # Launch Screen Assets 2 | 3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory. 4 | 5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. -------------------------------------------------------------------------------- /ios/Runner/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /ios/Runner/GoogleService-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CLIENT_ID 6 | 346586327036-vg1kj72ndm3pmul858lcs7qm9q4c0nij.apps.googleusercontent.com 7 | REVERSED_CLIENT_ID 8 | com.googleusercontent.apps.346586327036-vg1kj72ndm3pmul858lcs7qm9q4c0nij 9 | API_KEY 10 | AIzaSyCMAwsOQIix9eFm_QquAQaFSq2-W59K968 11 | GCM_SENDER_ID 12 | 346586327036 13 | PLIST_VERSION 14 | 1 15 | BUNDLE_ID 16 | com.wanted.hischool 17 | PROJECT_ID 18 | cloudmate-243bf 19 | STORAGE_BUCKET 20 | cloudmate-243bf.appspot.com 21 | IS_ADS_ENABLED 22 | 23 | IS_ANALYTICS_ENABLED 24 | 25 | IS_APPINVITE_ENABLED 26 | 27 | IS_GCM_ENABLED 28 | 29 | IS_SIGNIN_ENABLED 30 | 31 | GOOGLE_APP_ID 32 | 1:346586327036:ios:9148ba5bdf1ce85cf77479 33 | 34 | -------------------------------------------------------------------------------- /ios/Runner/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "GeneratedPluginRegistrant.h" 2 | -------------------------------------------------------------------------------- /ios/Runner/Runner.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | aps-environment 6 | development 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/build/XCBuildData/63dc6ff226954aff1defa2bc5b630bc5-buildRequest.json: -------------------------------------------------------------------------------- 1 | { 2 | "buildCommand" : "build", 3 | "configuredTargets" : [ 4 | { 5 | "guid" : "3111b870364814bc5334e9082f29c72f88a783a885d8b0b3beb2e9f90bde3f49" 6 | } 7 | ], 8 | "continueBuildingAfterErrors" : false, 9 | "enableIndexBuildArena" : false, 10 | "hideShellScriptEnvironment" : false, 11 | "parameters" : { 12 | "action" : "build", 13 | "configurationName" : "Debug", 14 | "overrides" : { 15 | "commandLine" : { 16 | "table" : { 17 | "COMPILER_INDEX_STORE_ENABLE" : "NO", 18 | "FLUTTER_SUPPRESS_ANALYTICS" : "true", 19 | "SDKROOT" : "iphonesimulator14.5" 20 | } 21 | }, 22 | "synthesized" : { 23 | "table" : { 24 | "ACTION" : "build", 25 | "ENABLE_PREVIEWS" : "NO" 26 | } 27 | } 28 | } 29 | }, 30 | "schemeCommand" : "launch", 31 | "shouldCollectMetrics" : false, 32 | "showNonLoggedProgress" : true, 33 | "useDryRun" : false, 34 | "useImplicitDependencies" : false, 35 | "useLegacyBuildLocations" : false, 36 | "useParallelTargets" : false 37 | } -------------------------------------------------------------------------------- /ios/build/XCBuildData/63dc6ff226954aff1defa2bc5b630bc5-targetGraph.txt: -------------------------------------------------------------------------------- 1 | Target dependency graph (1 target) 2 | Runner in Runner -------------------------------------------------------------------------------- /ios/build/XCBuildData/BuildDescriptionCacheIndex-14f1afe95d2361a2bb30c2a7ffd2414e: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Py-Ec/cloudmate-classroom-flutter/d1d241a3416e19b192dfd9743e4ce12e0d05357f/ios/build/XCBuildData/BuildDescriptionCacheIndex-14f1afe95d2361a2bb30c2a7ffd2414e -------------------------------------------------------------------------------- /ios/build/XCBuildData/b09b6a9e6e7a242bc3f5302f5e3c06fb-buildRequest.json: -------------------------------------------------------------------------------- 1 | { 2 | "buildCommand" : "build", 3 | "configuredTargets" : [ 4 | { 5 | "guid" : "3111b870364814bc5334e9082f29c72f88a783a885d8b0b3beb2e9f90bde3f49" 6 | } 7 | ], 8 | "continueBuildingAfterErrors" : false, 9 | "enableIndexBuildArena" : false, 10 | "hideShellScriptEnvironment" : false, 11 | "parameters" : { 12 | "action" : "build", 13 | "configurationName" : "Debug", 14 | "overrides" : { 15 | "commandLine" : { 16 | "table" : { 17 | "COMPILER_INDEX_STORE_ENABLE" : "NO", 18 | "FLUTTER_SUPPRESS_ANALYTICS" : "true", 19 | "SCRIPT_OUTPUT_STREAM_FILE" : "/var/folders/85/b90cyd197q98d8fd834f2mkr0000gn/T/flutter_tools.f0qZO2/flutter_build_log_pipe.2Oc7mJ/pipe_to_stdout", 20 | "SDKROOT" : "iphonesimulator14.5" 21 | } 22 | }, 23 | "synthesized" : { 24 | "table" : { 25 | "ACTION" : "build", 26 | "ENABLE_PREVIEWS" : "NO" 27 | } 28 | } 29 | } 30 | }, 31 | "schemeCommand" : "launch", 32 | "shouldCollectMetrics" : false, 33 | "showNonLoggedProgress" : true, 34 | "useDryRun" : false, 35 | "useImplicitDependencies" : false, 36 | "useLegacyBuildLocations" : false, 37 | "useParallelTargets" : false 38 | } -------------------------------------------------------------------------------- /ios/build/XCBuildData/b09b6a9e6e7a242bc3f5302f5e3c06fb-desc.xcbuild: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Py-Ec/cloudmate-classroom-flutter/d1d241a3416e19b192dfd9743e4ce12e0d05357f/ios/build/XCBuildData/b09b6a9e6e7a242bc3f5302f5e3c06fb-desc.xcbuild -------------------------------------------------------------------------------- /ios/build/XCBuildData/b09b6a9e6e7a242bc3f5302f5e3c06fb-targetGraph 2.txt: -------------------------------------------------------------------------------- 1 | Target dependency graph (1 target) 2 | Runner in Runner -------------------------------------------------------------------------------- /ios/build/XCBuildData/b09b6a9e6e7a242bc3f5302f5e3c06fb-targetGraph.txt: -------------------------------------------------------------------------------- 1 | Target dependency graph (1 target) 2 | Runner in Runner -------------------------------------------------------------------------------- /ios/build/XCBuildData/build.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Py-Ec/cloudmate-classroom-flutter/d1d241a3416e19b192dfd9743e4ce12e0d05357f/ios/build/XCBuildData/build.db -------------------------------------------------------------------------------- /ios/build/XCBuildData/d87afb5e48aa690e3bd8be2cf84600bf-buildRequest 2.json: -------------------------------------------------------------------------------- 1 | { 2 | "buildCommand" : "build", 3 | "configuredTargets" : [ 4 | { 5 | "guid" : "3111b870364814bc5334e9082f29c72f88a783a885d8b0b3beb2e9f90bde3f49" 6 | } 7 | ], 8 | "continueBuildingAfterErrors" : false, 9 | "enableIndexBuildArena" : false, 10 | "hideShellScriptEnvironment" : false, 11 | "parameters" : { 12 | "action" : "build", 13 | "configurationName" : "Debug", 14 | "overrides" : { 15 | "commandLine" : { 16 | "table" : { 17 | "COMPILER_INDEX_STORE_ENABLE" : "NO", 18 | "FLUTTER_SUPPRESS_ANALYTICS" : "true", 19 | "SDKROOT" : "iphonesimulator14.5" 20 | } 21 | }, 22 | "synthesized" : { 23 | "table" : { 24 | "ACTION" : "build", 25 | "ENABLE_PREVIEWS" : "NO" 26 | } 27 | } 28 | } 29 | }, 30 | "schemeCommand" : "launch", 31 | "shouldCollectMetrics" : false, 32 | "showNonLoggedProgress" : true, 33 | "useDryRun" : false, 34 | "useImplicitDependencies" : false, 35 | "useLegacyBuildLocations" : false, 36 | "useParallelTargets" : false 37 | } -------------------------------------------------------------------------------- /ios/build/XCBuildData/d87afb5e48aa690e3bd8be2cf84600bf-buildRequest.json: -------------------------------------------------------------------------------- 1 | { 2 | "buildCommand" : "build", 3 | "configuredTargets" : [ 4 | { 5 | "guid" : "3111b870364814bc5334e9082f29c72f88a783a885d8b0b3beb2e9f90bde3f49" 6 | } 7 | ], 8 | "continueBuildingAfterErrors" : false, 9 | "enableIndexBuildArena" : false, 10 | "hideShellScriptEnvironment" : false, 11 | "parameters" : { 12 | "action" : "build", 13 | "configurationName" : "Debug", 14 | "overrides" : { 15 | "commandLine" : { 16 | "table" : { 17 | "COMPILER_INDEX_STORE_ENABLE" : "NO", 18 | "FLUTTER_SUPPRESS_ANALYTICS" : "true", 19 | "SDKROOT" : "iphonesimulator14.5" 20 | } 21 | }, 22 | "synthesized" : { 23 | "table" : { 24 | "ACTION" : "build", 25 | "ENABLE_PREVIEWS" : "NO" 26 | } 27 | } 28 | } 29 | }, 30 | "schemeCommand" : "launch", 31 | "shouldCollectMetrics" : false, 32 | "showNonLoggedProgress" : true, 33 | "useDryRun" : false, 34 | "useImplicitDependencies" : false, 35 | "useLegacyBuildLocations" : false, 36 | "useParallelTargets" : false 37 | } -------------------------------------------------------------------------------- /ios/build/XCBuildData/d87afb5e48aa690e3bd8be2cf84600bf-desc.xcbuild: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Py-Ec/cloudmate-classroom-flutter/d1d241a3416e19b192dfd9743e4ce12e0d05357f/ios/build/XCBuildData/d87afb5e48aa690e3bd8be2cf84600bf-desc.xcbuild -------------------------------------------------------------------------------- /ios/build/XCBuildData/d87afb5e48aa690e3bd8be2cf84600bf-targetGraph.txt: -------------------------------------------------------------------------------- 1 | Target dependency graph (1 target) 2 | Runner in Runner -------------------------------------------------------------------------------- /ios/build/XCBuildData/dff818068802d9c42a73f2c8aacbe41d-buildRequest.json: -------------------------------------------------------------------------------- 1 | { 2 | "buildCommand" : "build", 3 | "configuredTargets" : [ 4 | { 5 | "guid" : "3111b870364814bc5334e9082f29c72f88a783a885d8b0b3beb2e9f90bde3f49" 6 | } 7 | ], 8 | "continueBuildingAfterErrors" : false, 9 | "enableIndexBuildArena" : false, 10 | "hideShellScriptEnvironment" : false, 11 | "parameters" : { 12 | "action" : "build", 13 | "configurationName" : "Debug", 14 | "overrides" : { 15 | "commandLine" : { 16 | "table" : { 17 | "COMPILER_INDEX_STORE_ENABLE" : "NO", 18 | "FLUTTER_SUPPRESS_ANALYTICS" : "true", 19 | "SDKROOT" : "iphonesimulator14.5" 20 | } 21 | }, 22 | "synthesized" : { 23 | "table" : { 24 | "ACTION" : "build", 25 | "ENABLE_PREVIEWS" : "NO" 26 | } 27 | } 28 | } 29 | }, 30 | "schemeCommand" : "launch", 31 | "shouldCollectMetrics" : false, 32 | "showNonLoggedProgress" : true, 33 | "useDryRun" : false, 34 | "useImplicitDependencies" : false, 35 | "useLegacyBuildLocations" : false, 36 | "useParallelTargets" : false 37 | } -------------------------------------------------------------------------------- /ios/build/XCBuildData/dff818068802d9c42a73f2c8aacbe41d-desc.xcbuild: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Py-Ec/cloudmate-classroom-flutter/d1d241a3416e19b192dfd9743e4ce12e0d05357f/ios/build/XCBuildData/dff818068802d9c42a73f2c8aacbe41d-desc.xcbuild -------------------------------------------------------------------------------- /ios/build/XCBuildData/dff818068802d9c42a73f2c8aacbe41d-targetGraph 2.txt: -------------------------------------------------------------------------------- 1 | Target dependency graph (1 target) 2 | Runner in Runner -------------------------------------------------------------------------------- /ios/build/XCBuildData/dff818068802d9c42a73f2c8aacbe41d-targetGraph.txt: -------------------------------------------------------------------------------- 1 | Target dependency graph (1 target) 2 | Runner in Runner -------------------------------------------------------------------------------- /ios/build/XCBuildData/fbc6cd67855b3fa763c4f0085931aa2c-buildRequest.json: -------------------------------------------------------------------------------- 1 | { 2 | "buildCommand" : "build", 3 | "configuredTargets" : [ 4 | { 5 | "guid" : "3111b870364814bc5334e9082f29c72f88a783a885d8b0b3beb2e9f90bde3f49" 6 | } 7 | ], 8 | "continueBuildingAfterErrors" : false, 9 | "enableIndexBuildArena" : false, 10 | "hideShellScriptEnvironment" : false, 11 | "parameters" : { 12 | "action" : "build", 13 | "configurationName" : "Debug", 14 | "overrides" : { 15 | "commandLine" : { 16 | "table" : { 17 | "COMPILER_INDEX_STORE_ENABLE" : "NO", 18 | "FLUTTER_SUPPRESS_ANALYTICS" : "true", 19 | "SCRIPT_OUTPUT_STREAM_FILE" : "/var/folders/85/b90cyd197q98d8fd834f2mkr0000gn/T/flutter_tools.UBotKS/flutter_build_log_pipe.wMS0DJ/pipe_to_stdout", 20 | "SDKROOT" : "iphonesimulator14.5" 21 | } 22 | }, 23 | "synthesized" : { 24 | "table" : { 25 | "ACTION" : "build", 26 | "ENABLE_PREVIEWS" : "NO" 27 | } 28 | } 29 | } 30 | }, 31 | "schemeCommand" : "launch", 32 | "shouldCollectMetrics" : false, 33 | "showNonLoggedProgress" : true, 34 | "useDryRun" : false, 35 | "useImplicitDependencies" : false, 36 | "useLegacyBuildLocations" : false, 37 | "useParallelTargets" : false 38 | } -------------------------------------------------------------------------------- /ios/build/XCBuildData/fbc6cd67855b3fa763c4f0085931aa2c-desc.xcbuild: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Py-Ec/cloudmate-classroom-flutter/d1d241a3416e19b192dfd9743e4ce12e0d05357f/ios/build/XCBuildData/fbc6cd67855b3fa763c4f0085931aa2c-desc.xcbuild -------------------------------------------------------------------------------- /ios/build/XCBuildData/fbc6cd67855b3fa763c4f0085931aa2c-targetGraph 2.txt: -------------------------------------------------------------------------------- 1 | Target dependency graph (1 target) 2 | Runner in Runner -------------------------------------------------------------------------------- /ios/build/XCBuildData/fbc6cd67855b3fa763c4f0085931aa2c-targetGraph.txt: -------------------------------------------------------------------------------- 1 | Target dependency graph (1 target) 2 | Runner in Runner -------------------------------------------------------------------------------- /ios/clean-pods.sh: -------------------------------------------------------------------------------- 1 | rm -rf Pods 2 | rm -rf Podfile.lock 3 | flutter clean 4 | flutter pub get 5 | # pod install --repo-update 6 | arch -x86_64 pod install 7 | -------------------------------------------------------------------------------- /lib/main.dart: -------------------------------------------------------------------------------- 1 | import 'package:firebase_core/firebase_core.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:flutter/services.dart'; 4 | import 'package:flutter_bloc/flutter_bloc.dart'; 5 | import 'package:cloudmate/src/app.dart'; 6 | import 'package:cloudmate/src/utils/logger.dart'; 7 | 8 | void main() async { 9 | WidgetsFlutterBinding.ensureInitialized(); 10 | await Firebase.initializeApp(); 11 | Bloc.observer = AppBlocObserver(); 12 | SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle( 13 | statusBarColor: Colors.transparent, 14 | statusBarBrightness: Brightness.dark, 15 | statusBarIconBrightness: Brightness.dark, 16 | )); 17 | runApp(MyApp()); 18 | } 19 | 20 | class MyApp extends StatelessWidget { 21 | @override 22 | Widget build(BuildContext context) { 23 | return App(); 24 | } 25 | } 26 | 27 | class AppBlocObserver extends BlocObserver { 28 | @override 29 | void onEvent(Bloc bloc, Object? event) { 30 | UtilLogger.log('BLOC EVENT', event); 31 | super.onEvent(bloc, event); 32 | } 33 | 34 | @override 35 | void onError(BlocBase bloc, Object error, StackTrace stackTrace) { 36 | UtilLogger.log('BLOC ERROR', error); 37 | super.onError(bloc, error, stackTrace); 38 | } 39 | 40 | @override 41 | void onTransition(Bloc bloc, Transition transition) { 42 | UtilLogger.log('BLOC TRANSITION', transition.event); 43 | super.onTransition(bloc, transition); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /lib/src/blocs/app_state/app_state_bloc 2.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:bloc/bloc.dart'; 4 | import 'bloc.dart'; 5 | 6 | class AppStateBloc extends Bloc { 7 | AppStateBloc() : super(AppStateInitial()); 8 | 9 | @override 10 | Stream mapEventToState(AppStateEvent event) async* { 11 | if (event is OnResume) { 12 | yield Active(); 13 | 14 | ///More Task 15 | } 16 | if (event is OnBackground) { 17 | yield Background(); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /lib/src/blocs/app_state/app_state_bloc.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:bloc/bloc.dart'; 4 | import 'bloc.dart'; 5 | 6 | class AppStateBloc extends Bloc { 7 | AppStateBloc() : super(AppStateInitial()); 8 | 9 | @override 10 | Stream mapEventToState(AppStateEvent event) async* { 11 | if (event is OnResume) { 12 | yield Active(); 13 | 14 | ///More Task 15 | } 16 | if (event is OnBackground) { 17 | yield Background(); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /lib/src/blocs/app_state/app_state_event 2.dart: -------------------------------------------------------------------------------- 1 | abstract class AppStateEvent {} 2 | 3 | class OnResume extends AppStateEvent {} 4 | 5 | class OnBackground extends AppStateEvent {} 6 | 7 | class OnUpdateDatabase extends AppStateEvent {} 8 | -------------------------------------------------------------------------------- /lib/src/blocs/app_state/app_state_event.dart: -------------------------------------------------------------------------------- 1 | abstract class AppStateEvent {} 2 | 3 | class OnResume extends AppStateEvent {} 4 | 5 | class OnBackground extends AppStateEvent {} 6 | 7 | class OnUpdateDatabase extends AppStateEvent {} 8 | -------------------------------------------------------------------------------- /lib/src/blocs/app_state/app_state_state.dart: -------------------------------------------------------------------------------- 1 | abstract class AppState {} 2 | 3 | class AppStateInitial extends AppState {} 4 | 5 | class Active extends AppState {} 6 | 7 | class Background extends AppState {} 8 | -------------------------------------------------------------------------------- /lib/src/blocs/app_state/bloc.dart: -------------------------------------------------------------------------------- 1 | export 'app_state_bloc.dart'; 2 | export 'app_state_event.dart'; 3 | export 'app_state_state.dart'; 4 | -------------------------------------------------------------------------------- /lib/src/blocs/application/application_bloc.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | import 'package:bloc/bloc.dart'; 3 | import 'package:cloudmate/src/blocs/authentication/bloc.dart'; 4 | import 'package:flutter/material.dart'; 5 | import 'package:cloudmate/src/blocs/app_bloc.dart'; 6 | import 'package:cloudmate/src/blocs/bloc.dart'; 7 | import 'package:cloudmate/src/configs/application.dart'; 8 | import 'package:cloudmate/src/themes/theme_service.dart'; 9 | 10 | class ApplicationBloc extends Bloc { 11 | ApplicationBloc() : super(InitialApplicationState()); 12 | 13 | @override 14 | Stream mapEventToState(event) async* { 15 | if (event is OnSetupApplication) { 16 | // Get themeMode 17 | await Application().initialAppLication(); 18 | AppBloc.themeBloc.add( 19 | InitialTheme( 20 | themeMode: ThemeService().isSavedDarkMode() ? ThemeMode.dark : ThemeMode.light, 21 | ), 22 | ); 23 | 24 | AppBloc.authBloc.add(OnAuthCheck()); 25 | 26 | yield ApplicationCompleted(); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /lib/src/blocs/application/application_event.dart: -------------------------------------------------------------------------------- 1 | abstract class ApplicationEvent {} 2 | 3 | ///Event setup application 4 | class OnSetupApplication extends ApplicationEvent {} 5 | -------------------------------------------------------------------------------- /lib/src/blocs/application/application_state.dart: -------------------------------------------------------------------------------- 1 | abstract class ApplicationState {} 2 | 3 | class InitialApplicationState extends ApplicationState {} 4 | 5 | class ApplicationCompleted extends ApplicationState {} 6 | -------------------------------------------------------------------------------- /lib/src/blocs/application/bloc.dart: -------------------------------------------------------------------------------- 1 | export 'application_bloc.dart'; 2 | export 'application_event.dart'; 3 | export 'application_state.dart'; 4 | -------------------------------------------------------------------------------- /lib/src/blocs/authentication/authentication_event.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | abstract class AuthEvent {} 4 | 5 | class OnAuthCheck extends AuthEvent {} 6 | 7 | class OnAuthProcess extends AuthEvent { 8 | final String username; 9 | final String password; 10 | OnAuthProcess({required this.username, required this.password}); 11 | } 12 | 13 | class OnClear extends AuthEvent {} 14 | 15 | class RegisterEvent extends AuthEvent { 16 | final String firstName; 17 | final String lastName; 18 | final String username; 19 | final String password; 20 | RegisterEvent({ 21 | required this.username, 22 | required this.password, 23 | required this.firstName, 24 | required this.lastName, 25 | }); 26 | } 27 | 28 | class LoginEvent extends AuthEvent { 29 | final String username; 30 | final String password; 31 | LoginEvent({required this.username, required this.password}); 32 | } 33 | 34 | class LogOutEvent extends AuthEvent {} 35 | 36 | class GetInfoUser extends AuthEvent {} 37 | 38 | class UpdateInfoUser extends AuthEvent { 39 | final String firstName; 40 | final String lastName; 41 | final String intro; 42 | final String phone; 43 | UpdateInfoUser({ 44 | required this.firstName, 45 | required this.lastName, 46 | required this.intro, 47 | required this.phone, 48 | }); 49 | } 50 | 51 | class UpdateAvatarUser extends AuthEvent { 52 | final File avatar; 53 | UpdateAvatarUser({required this.avatar}); 54 | } 55 | 56 | class DeleteAccount extends AuthEvent {} 57 | -------------------------------------------------------------------------------- /lib/src/blocs/authentication/authentication_state.dart: -------------------------------------------------------------------------------- 1 | import 'package:cloudmate/src/models/user.dart'; 2 | 3 | abstract class AuthState {} 4 | 5 | class InitialAuthenticationState extends AuthState {} 6 | 7 | class AuthenticationSuccess extends AuthState { 8 | UserModel? userModel; 9 | AuthenticationSuccess({this.userModel}); 10 | } 11 | 12 | class AuthenticationFail extends AuthState {} 13 | 14 | class Authenticating extends AuthState {} 15 | -------------------------------------------------------------------------------- /lib/src/blocs/authentication/bloc.dart: -------------------------------------------------------------------------------- 1 | export 'authentication_bloc.dart'; 2 | export 'authentication_event.dart'; 3 | export 'authentication_state.dart'; 4 | -------------------------------------------------------------------------------- /lib/src/blocs/bloc.dart: -------------------------------------------------------------------------------- 1 | export 'app_state/bloc.dart'; 2 | export 'application/bloc.dart'; 3 | export 'theme/bloc.dart'; 4 | -------------------------------------------------------------------------------- /lib/src/blocs/bloc/transaction_bloc.dart: -------------------------------------------------------------------------------- 1 | import 'package:bloc/bloc.dart'; 2 | import 'package:cloudmate/src/models/transaction_model.dart'; 3 | import 'package:cloudmate/src/resources/remote/transaction_repository.dart'; 4 | import 'package:meta/meta.dart'; 5 | 6 | part 'transaction_event.dart'; 7 | part 'transaction_state.dart'; 8 | 9 | class TransactionBloc extends Bloc { 10 | TransactionBloc() : super(TransactionInitial()); 11 | 12 | List transactions = []; 13 | 14 | @override 15 | Stream mapEventToState(TransactionEvent event) async* { 16 | if (event is GetTransactionEvent) { 17 | transactions.clear(); 18 | yield TransactionInitial(); 19 | await _getTransactions(); 20 | yield GetDoneTransaction(transactions: transactions); 21 | } 22 | } 23 | 24 | // MARK: Private methods 25 | Future _getTransactions() async { 26 | List _transactions = await TransactionRepository().getTransactions(); 27 | 28 | transactions.addAll(_transactions); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /lib/src/blocs/bloc/transaction_event.dart: -------------------------------------------------------------------------------- 1 | part of 'transaction_bloc.dart'; 2 | 3 | abstract class TransactionEvent {} 4 | 5 | class GetTransactionEvent extends TransactionEvent {} 6 | -------------------------------------------------------------------------------- /lib/src/blocs/bloc/transaction_state.dart: -------------------------------------------------------------------------------- 1 | part of 'transaction_bloc.dart'; 2 | 3 | @immutable 4 | abstract class TransactionState {} 5 | 6 | class TransactionInitial extends TransactionState {} 7 | 8 | class GetDoneTransaction extends TransactionState { 9 | final List transactions; 10 | GetDoneTransaction({required this.transactions}); 11 | } 12 | -------------------------------------------------------------------------------- /lib/src/blocs/conversation/conversation_bloc.dart: -------------------------------------------------------------------------------- 1 | import 'package:bloc/bloc.dart'; 2 | import 'package:cloudmate/src/models/conversation_model.dart'; 3 | import 'package:cloudmate/src/models/message_model.dart'; 4 | import 'package:cloudmate/src/resources/remote/conversation_repository.dart'; 5 | import 'package:meta/meta.dart'; 6 | 7 | part 'conversation_event.dart'; 8 | part 'conversation_state.dart'; 9 | 10 | class ConversationBloc extends Bloc { 11 | ConversationBloc() : super(ConversationInitial()); 12 | 13 | List conversations = []; 14 | bool isOver = false; 15 | 16 | @override 17 | Stream mapEventToState(ConversationEvent event) async* { 18 | if (event is OnConversationEvent) { 19 | conversations.clear(); 20 | if (conversations.isEmpty) { 21 | yield ConversationInitial(); 22 | await _getConversations(); 23 | } 24 | yield _getDoneConversation; 25 | } 26 | 27 | if (event is GetConversationEvent) { 28 | if (!isOver) { 29 | yield _gettingConversation; 30 | await _getConversations(); 31 | yield _getDoneConversation; 32 | } 33 | } 34 | 35 | if (event is UpdateLatestMessageEvent) { 36 | int indexOfConversation = 37 | conversations.indexWhere((element) => element.idClass.id == event.message.idClass); 38 | 39 | if (indexOfConversation != -1) { 40 | conversations[indexOfConversation].latestMessage = 41 | LatestMessage.fromMessageModel(event.message); 42 | 43 | yield _getDoneConversation; 44 | } 45 | } 46 | } 47 | 48 | // MARK: Private methods 49 | GettingConversation get _gettingConversation => GettingConversation(conversations: conversations); 50 | GetDoneConversation get _getDoneConversation => GetDoneConversation(conversations: conversations); 51 | 52 | Future _getConversations() async { 53 | List _conversations = await ConversationRepository().getListClasses( 54 | skip: conversations.length, 55 | ); 56 | 57 | if (_conversations.length < 10) { 58 | isOver = true; 59 | } 60 | 61 | conversations.addAll(_conversations); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /lib/src/blocs/conversation/conversation_event.dart: -------------------------------------------------------------------------------- 1 | part of 'conversation_bloc.dart'; 2 | 3 | @immutable 4 | abstract class ConversationEvent {} 5 | 6 | class OnConversationEvent extends ConversationEvent {} 7 | 8 | class GetConversationEvent extends ConversationEvent {} 9 | 10 | class UpdateLatestMessageEvent extends ConversationEvent { 11 | final MessageModel message; 12 | UpdateLatestMessageEvent({required this.message}); 13 | } 14 | -------------------------------------------------------------------------------- /lib/src/blocs/conversation/conversation_state.dart: -------------------------------------------------------------------------------- 1 | part of 'conversation_bloc.dart'; 2 | 3 | @immutable 4 | abstract class ConversationState { 5 | List get props => []; 6 | } 7 | 8 | class ConversationInitial extends ConversationState {} 9 | 10 | class GettingConversation extends ConversationState { 11 | final List conversations; 12 | GettingConversation({required this.conversations}); 13 | 14 | @override 15 | List get props => [conversations]; 16 | } 17 | 18 | class GetDoneConversation extends ConversationState { 19 | final List conversations; 20 | GetDoneConversation({required this.conversations}); 21 | 22 | @override 23 | List get props => [conversations]; 24 | } 25 | -------------------------------------------------------------------------------- /lib/src/blocs/count_down/count_down_bloc.dart: -------------------------------------------------------------------------------- 1 | import 'package:bloc/bloc.dart'; 2 | import 'package:cloudmate/src/blocs/app_bloc.dart'; 3 | import 'package:cloudmate/src/ui/classes/blocs/do_exam/do_exam_bloc.dart'; 4 | import 'package:meta/meta.dart'; 5 | 6 | part 'count_down_event.dart'; 7 | part 'count_down_state.dart'; 8 | 9 | class CountDownBloc extends Bloc { 10 | CountDownBloc() : super(CountDownInitial()); 11 | 12 | int duration = 30; 13 | bool flagTimer = false; 14 | 15 | @override 16 | Stream mapEventToState(CountDownEvent event) async* { 17 | if (event is StartCountDownEvent) { 18 | flagTimer = false; 19 | await _onStart(); 20 | yield _inProgress; 21 | } 22 | 23 | if (event is ResetCountDownEvent) { 24 | flagTimer = false; 25 | duration = 30; 26 | yield _inProgress; 27 | await _onStart(); 28 | } 29 | 30 | if (event is UpdateCountDownEvent) { 31 | await _onStart(); 32 | yield _inProgress; 33 | } 34 | 35 | if (event is EndCountDownEvent) { 36 | flagTimer = true; 37 | duration = 30; 38 | yield CountDownInitial(); 39 | } 40 | } 41 | 42 | // MARK: Private methods 43 | InProgressCountDown get _inProgress => InProgressCountDown(duration: duration); 44 | 45 | Future _onStart() async { 46 | if (!flagTimer) { 47 | await Future.delayed(Duration(seconds: 1), () { 48 | if (duration > 0) { 49 | duration--; 50 | } 51 | if (duration == 0) { 52 | if (AppBloc.doExamBloc.users 53 | .indexWhere((user) => user.id == AppBloc.authBloc.userModel?.id) == 54 | -1) { 55 | AppBloc.doExamBloc.add(StartQuizEvent()); 56 | } else { 57 | add(EndCountDownEvent()); 58 | } 59 | } else { 60 | add(UpdateCountDownEvent()); 61 | } 62 | }); 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /lib/src/blocs/count_down/count_down_event 2.dart: -------------------------------------------------------------------------------- 1 | part of 'count_down_bloc.dart'; 2 | 3 | abstract class CountDownEvent {} 4 | 5 | class StartCountDownEvent extends CountDownEvent {} 6 | 7 | class ResetCountDownEvent extends CountDownEvent {} 8 | 9 | class UpdateCountDownEvent extends CountDownEvent {} 10 | 11 | class EndCountDownEvent extends CountDownEvent {} 12 | -------------------------------------------------------------------------------- /lib/src/blocs/count_down/count_down_event.dart: -------------------------------------------------------------------------------- 1 | part of 'count_down_bloc.dart'; 2 | 3 | abstract class CountDownEvent {} 4 | 5 | class StartCountDownEvent extends CountDownEvent {} 6 | 7 | class ResetCountDownEvent extends CountDownEvent {} 8 | 9 | class UpdateCountDownEvent extends CountDownEvent {} 10 | 11 | class EndCountDownEvent extends CountDownEvent {} 12 | -------------------------------------------------------------------------------- /lib/src/blocs/count_down/count_down_state.dart: -------------------------------------------------------------------------------- 1 | part of 'count_down_bloc.dart'; 2 | 3 | @immutable 4 | abstract class CountDownState {} 5 | 6 | class CountDownInitial extends CountDownState {} 7 | 8 | class InProgressCountDown extends CountDownState { 9 | final int duration; 10 | InProgressCountDown({required this.duration}); 11 | } 12 | -------------------------------------------------------------------------------- /lib/src/blocs/message/message_event.dart: -------------------------------------------------------------------------------- 1 | part of 'message_bloc.dart'; 2 | 3 | @immutable 4 | abstract class MessageEvent {} 5 | 6 | class OnMessageEvent extends MessageEvent { 7 | final ConversationModel conversation; 8 | OnMessageEvent({required this.conversation}); 9 | } 10 | 11 | class GetMessageEvent extends MessageEvent {} 12 | 13 | class SendMessageEvent extends MessageEvent { 14 | final String message; 15 | SendMessageEvent({required this.message}); 16 | } 17 | 18 | class InsertMessageEvent extends MessageEvent { 19 | final MessageModel message; 20 | InsertMessageEvent({required this.message}); 21 | } 22 | -------------------------------------------------------------------------------- /lib/src/blocs/message/message_state.dart: -------------------------------------------------------------------------------- 1 | part of 'message_bloc.dart'; 2 | 3 | @immutable 4 | abstract class MessageState { 5 | List get props => []; 6 | } 7 | 8 | class MessageInitial extends MessageState {} 9 | 10 | class GettingMessage extends MessageState { 11 | final List messages; 12 | GettingMessage({required this.messages}); 13 | 14 | @override 15 | List get props => [messages]; 16 | } 17 | 18 | class GetDoneMessage extends MessageState { 19 | final List messages; 20 | GetDoneMessage({required this.messages}); 21 | 22 | @override 23 | List get props => [messages]; 24 | } 25 | -------------------------------------------------------------------------------- /lib/src/blocs/post_class/post_class_bloc.dart: -------------------------------------------------------------------------------- 1 | import 'package:bloc/bloc.dart'; 2 | import 'package:cloudmate/src/models/post_model.dart'; 3 | import 'package:cloudmate/src/resources/remote/post_repository.dart'; 4 | import 'package:meta/meta.dart'; 5 | 6 | part 'post_class_event.dart'; 7 | part 'post_class_state.dart'; 8 | 9 | class PostClassBloc extends Bloc { 10 | PostClassBloc() : super(PostClassInitial()); 11 | 12 | Map> postsClass = {}; 13 | String currentClassId = ''; 14 | 15 | @override 16 | Stream mapEventToState(PostClassEvent event) async* { 17 | if (event is GetPostClassEvent) { 18 | currentClassId = event.classId; 19 | await _getPosts(); 20 | yield _getDonePostClass; 21 | } 22 | 23 | if (event is CleanPostClassEvent) { 24 | postsClass = {}; 25 | yield PostClassInitial(); 26 | } 27 | } 28 | 29 | // MARK: Private methods 30 | // GettingPostClass get _gettingPostClass => GettingPostClass( 31 | // posts: postsClass[currentClassId] ?? [], 32 | // ); 33 | GetDonePostClass get _getDonePostClass => GetDonePostClass( 34 | posts: postsClass[currentClassId] ?? [], 35 | ); 36 | 37 | Future _getPosts() async { 38 | List _posts = await PostRepository().getListPostClass(classId: currentClassId); 39 | 40 | postsClass[currentClassId] = _posts; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /lib/src/blocs/post_class/post_class_event.dart: -------------------------------------------------------------------------------- 1 | part of 'post_class_bloc.dart'; 2 | 3 | @immutable 4 | abstract class PostClassEvent {} 5 | 6 | class GetPostClassEvent extends PostClassEvent { 7 | final String classId; 8 | GetPostClassEvent({required this.classId}); 9 | } 10 | 11 | class CleanPostClassEvent extends PostClassEvent {} 12 | -------------------------------------------------------------------------------- /lib/src/blocs/post_class/post_class_state.dart: -------------------------------------------------------------------------------- 1 | part of 'post_class_bloc.dart'; 2 | 3 | @immutable 4 | abstract class PostClassState { 5 | List get props => []; 6 | } 7 | 8 | class PostClassInitial extends PostClassState { 9 | @override 10 | List get props => [[]]; 11 | } 12 | 13 | class GettingPostClass extends PostClassState { 14 | final List posts; 15 | GettingPostClass({required this.posts}); 16 | 17 | @override 18 | List get props => [posts]; 19 | } 20 | 21 | class GetDonePostClass extends PostClassState { 22 | final List posts; 23 | GetDonePostClass({required this.posts}); 24 | 25 | @override 26 | List get props => [posts]; 27 | } 28 | -------------------------------------------------------------------------------- /lib/src/blocs/post_home/post_home_bloc.dart: -------------------------------------------------------------------------------- 1 | import 'package:bloc/bloc.dart'; 2 | import 'package:cloudmate/src/models/post_model.dart'; 3 | import 'package:cloudmate/src/resources/remote/post_repository.dart'; 4 | import 'package:cloudmate/src/routes/app_pages.dart'; 5 | import 'package:meta/meta.dart'; 6 | 7 | part 'post_home_event.dart'; 8 | part 'post_home_state.dart'; 9 | 10 | class PostHomeBloc extends Bloc { 11 | PostHomeBloc() : super(PostHomeInitial()); 12 | 13 | List posts = []; 14 | bool isOver = false; 15 | 16 | @override 17 | Stream mapEventToState(PostHomeEvent event) async* { 18 | if (event is OnPostHomeEvent) { 19 | posts = []; 20 | isOver = false; 21 | if (posts.isEmpty) { 22 | await _getPosts(); 23 | yield _getDonePostHome; 24 | } 25 | } 26 | 27 | if (event is GetPostHomeEvent) { 28 | if (!isOver) { 29 | yield _gettingPostHome; 30 | await _getPosts(); 31 | yield _getDonePostHome; 32 | } 33 | } 34 | 35 | if (event is CreatePostHomeEvent) { 36 | for (int index = 0; index < event.classChooses.length; index++) { 37 | PostModel? post = await PostRepository().createPost( 38 | content: event.content, 39 | classId: event.classChooses[index], 40 | ); 41 | 42 | if (post != null) { 43 | posts.insert(0, post); 44 | yield _getDonePostHome; 45 | } 46 | } 47 | 48 | AppNavigator.pop(); 49 | } 50 | 51 | if (event is CleanPostHomeEvent) { 52 | yield PostHomeInitial(); 53 | } 54 | } 55 | 56 | // MARK: Private methods 57 | GettingPostHome get _gettingPostHome => GettingPostHome(posts: posts); 58 | GetDonePostHome get _getDonePostHome => GetDonePostHome(posts: posts); 59 | 60 | Future _getPosts() async { 61 | List _posts = await PostRepository().getListPostHome(); 62 | 63 | if (_posts.length < 15) { 64 | isOver = true; 65 | } 66 | 67 | posts.addAll(_posts); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /lib/src/blocs/post_home/post_home_event.dart: -------------------------------------------------------------------------------- 1 | part of 'post_home_bloc.dart'; 2 | 3 | @immutable 4 | abstract class PostHomeEvent {} 5 | 6 | class OnPostHomeEvent extends PostHomeEvent {} 7 | 8 | class GetPostHomeEvent extends PostHomeEvent {} 9 | 10 | class CreatePostHomeEvent extends PostHomeEvent { 11 | final List classChooses; 12 | final String content; 13 | CreatePostHomeEvent({required this.classChooses, required this.content}); 14 | } 15 | 16 | class CleanPostHomeEvent extends PostHomeEvent {} 17 | -------------------------------------------------------------------------------- /lib/src/blocs/post_home/post_home_state.dart: -------------------------------------------------------------------------------- 1 | part of 'post_home_bloc.dart'; 2 | 3 | @immutable 4 | abstract class PostHomeState { 5 | List get props => []; 6 | } 7 | 8 | class PostHomeInitial extends PostHomeState { 9 | @override 10 | List get props => [[]]; 11 | } 12 | 13 | class GettingPostHome extends PostHomeState { 14 | final List posts; 15 | GettingPostHome({required this.posts}); 16 | 17 | @override 18 | List get props => [posts]; 19 | } 20 | 21 | class GetDonePostHome extends PostHomeState { 22 | final List posts; 23 | GetDonePostHome({required this.posts}); 24 | 25 | @override 26 | List get props => [posts]; 27 | } 28 | -------------------------------------------------------------------------------- /lib/src/blocs/schedules/schedules_bloc.dart: -------------------------------------------------------------------------------- 1 | import 'package:bloc/bloc.dart'; 2 | import 'package:cloudmate/src/helpers/date_time_helper.dart'; 3 | import 'package:cloudmate/src/models/road_map_content_model.dart'; 4 | import 'package:cloudmate/src/resources/remote/road_map_content_repository.dart'; 5 | import 'package:intl/intl.dart'; 6 | import 'package:meta/meta.dart'; 7 | 8 | part 'schedules_event.dart'; 9 | part 'schedules_state.dart'; 10 | 11 | class SchedulesBloc extends Bloc { 12 | SchedulesBloc() : super(SchedulesInitial()); 13 | 14 | Map> roadmapContentMap = {}; 15 | DateTime _currentDate = DateTime.now(); 16 | 17 | @override 18 | Stream mapEventToState(SchedulesEvent event) async* { 19 | if (event is GetScheduleEvent) { 20 | _currentDate = event.currentDate; 21 | String date = DateFormat('MM/yyyy').format(event.currentDate); 22 | 23 | if (roadmapContentMap[date] == null || roadmapContentMap[date]!.isEmpty) { 24 | List _roadmapContent = await RoadMapContentRepository().getSchedules( 25 | month: event.currentDate.month.toString(), 26 | year: event.currentDate.year.toString(), 27 | ); 28 | 29 | roadmapContentMap[date] = _roadmapContent; 30 | } 31 | 32 | yield GetScheduleDone(roadmapContent: getByDate()); 33 | } 34 | 35 | if (event is CleanScheduleEvent) { 36 | roadmapContentMap = {}; 37 | yield SchedulesInitial(); 38 | } 39 | } 40 | 41 | List getByDate() { 42 | List roadMapContents = 43 | roadmapContentMap[DateFormat('MM/yyyy').format(_currentDate)] ?? []; 44 | 45 | return roadMapContents 46 | .where((request) => isEqualTwoDate(_currentDate, request.endTime)) 47 | .toList(); 48 | } 49 | 50 | int quantityPerDate(DateTime date) { 51 | List roadMapContents = 52 | roadmapContentMap[DateFormat('MM/yyyy').format(date)] ?? []; 53 | int quantity = 54 | roadMapContents.where((request) => isEqualTwoDate(date, request.endTime)).toList().length; 55 | return quantity >= 3 ? 3 : quantity; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /lib/src/blocs/schedules/schedules_event.dart: -------------------------------------------------------------------------------- 1 | part of 'schedules_bloc.dart'; 2 | 3 | @immutable 4 | abstract class SchedulesEvent {} 5 | 6 | class GetScheduleEvent extends SchedulesEvent { 7 | final DateTime currentDate; 8 | GetScheduleEvent({required this.currentDate}); 9 | } 10 | 11 | class CleanScheduleEvent extends SchedulesEvent {} 12 | -------------------------------------------------------------------------------- /lib/src/blocs/schedules/schedules_state.dart: -------------------------------------------------------------------------------- 1 | part of 'schedules_bloc.dart'; 2 | 3 | @immutable 4 | abstract class SchedulesState {} 5 | 6 | class SchedulesInitial extends SchedulesState {} 7 | 8 | class GetScheduleDone extends SchedulesState { 9 | final List roadmapContent; 10 | GetScheduleDone({required this.roadmapContent}); 11 | } 12 | -------------------------------------------------------------------------------- /lib/src/blocs/share_exam/share_exam_bloc.dart: -------------------------------------------------------------------------------- 1 | import 'package:bloc/bloc.dart'; 2 | import 'package:cloudmate/src/models/exam_model.dart'; 3 | import 'package:cloudmate/src/resources/remote/share_exam_repository.dart'; 4 | import 'package:cloudmate/src/routes/app_pages.dart'; 5 | import 'package:flutter/material.dart'; 6 | part 'share_exam_event.dart'; 7 | part 'share_exam_state.dart'; 8 | 9 | class ShareExamBloc extends Bloc { 10 | ShareExamBloc() : super(ShareExamInitial()); 11 | 12 | List exams = []; 13 | 14 | @override 15 | Stream mapEventToState(ShareExamEvent event) async* { 16 | if (event is GetShareExamEvent) { 17 | if (exams.isEmpty) { 18 | await _getExams(); 19 | yield _getDoneShareExam; 20 | } 21 | } 22 | 23 | if (event is CreateShareExamEvent) { 24 | await _createExam(event); 25 | yield _getDoneShareExam; 26 | } 27 | } 28 | 29 | // MARK: Private methods 30 | GetDoneShareExam get _getDoneShareExam => GetDoneShareExam(exams: exams); 31 | 32 | Future _getExams() async { 33 | List _exams = await ShareExamRepository().getListExam(); 34 | 35 | exams.addAll(_exams); 36 | } 37 | 38 | Future _createExam(CreateShareExamEvent event) async { 39 | ExamModel? _exam = await ShareExamRepository().createExam( 40 | name: event.name, 41 | description: event.description, 42 | ); 43 | 44 | AppNavigator.pop(); 45 | 46 | if (_exam != null) { 47 | exams.add(_exam); 48 | AppNavigator.pop(); 49 | } else { 50 | // Show dialog failure 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /lib/src/blocs/share_exam/share_exam_event.dart: -------------------------------------------------------------------------------- 1 | part of 'share_exam_bloc.dart'; 2 | 3 | @immutable 4 | abstract class ShareExamEvent {} 5 | 6 | class GetShareExamEvent extends ShareExamEvent {} 7 | 8 | class CreateShareExamEvent extends ShareExamEvent { 9 | final BuildContext context; 10 | final String name; 11 | final String description; 12 | CreateShareExamEvent({ 13 | required this.context, 14 | required this.name, 15 | required this.description, 16 | }); 17 | } 18 | -------------------------------------------------------------------------------- /lib/src/blocs/share_exam/share_exam_state.dart: -------------------------------------------------------------------------------- 1 | part of 'share_exam_bloc.dart'; 2 | 3 | @immutable 4 | abstract class ShareExamState {} 5 | 6 | class ShareExamInitial extends ShareExamState {} 7 | 8 | class GetDoneShareExam extends ShareExamState { 9 | final List exams; 10 | GetDoneShareExam({required this.exams}); 11 | } 12 | -------------------------------------------------------------------------------- /lib/src/blocs/theme/bloc.dart: -------------------------------------------------------------------------------- 1 | export 'theme_bloc.dart'; 2 | export 'theme_event.dart'; 3 | export 'theme_state.dart'; 4 | -------------------------------------------------------------------------------- /lib/src/blocs/theme/theme_bloc.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | import 'package:bloc/bloc.dart'; 3 | import 'package:cloudmate/src/themes/theme_service.dart'; 4 | import 'bloc.dart'; 5 | 6 | class ThemeBloc extends Bloc { 7 | ThemeBloc() : super(InitialThemeState()); 8 | 9 | @override 10 | Stream mapEventToState(event) async* { 11 | if (event is InitialTheme) { 12 | yield ThemeUpdating(); 13 | ThemeService.currentTheme = event.themeMode ?? ThemeService.currentTheme; 14 | ThemeService().switchStatusColor(); 15 | yield ThemeUpdated(); 16 | } 17 | 18 | if (event is OnChangeTheme) { 19 | yield ThemeUpdating(); 20 | ThemeService.currentTheme = event.themeMode ?? ThemeService.currentTheme; 21 | ThemeService().changeThemeMode(); 22 | yield ThemeUpdated(); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /lib/src/blocs/theme/theme_event.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | abstract class ThemeEvent {} 4 | 5 | class InitialTheme extends ThemeEvent { 6 | final ThemeMode? themeMode; 7 | 8 | InitialTheme({ 9 | this.themeMode, 10 | }); 11 | } 12 | 13 | class OnChangeTheme extends ThemeEvent { 14 | final ThemeMode? themeMode; 15 | 16 | OnChangeTheme({ 17 | this.themeMode, 18 | }); 19 | } 20 | -------------------------------------------------------------------------------- /lib/src/blocs/theme/theme_state.dart: -------------------------------------------------------------------------------- 1 | abstract class ThemeState {} 2 | 3 | class InitialThemeState extends ThemeState {} 4 | 5 | class ThemeUpdating extends ThemeState {} 6 | 7 | class ThemeUpdated extends ThemeState {} 8 | -------------------------------------------------------------------------------- /lib/src/configs/application.dart: -------------------------------------------------------------------------------- 1 | import 'package:cloudmate/src/services/firebase_messaging/handle_messaging.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:get_storage/get_storage.dart'; 4 | 5 | class Application { 6 | /// [Production - Dev] 7 | static String version = '1.0.0'; 8 | static String baseUrl = ''; 9 | static String imageUrl = ''; 10 | static String socketUrl = ''; 11 | static String mode = ''; 12 | static bool isProductionMode = true; 13 | 14 | Future initialAppLication() async { 15 | try { 16 | await GetStorage.init(); 17 | baseUrl = 'https://services.streamos.tk/'; 18 | imageUrl = baseUrl + 'api/up-load-file?id='; 19 | socketUrl = 'https://services.streamos.tk/'; 20 | mode = 'PRODUCTION'; 21 | requestPermission(); 22 | handleReceiveNotification(); 23 | } catch (error) { 24 | debugPrint(error.toString()); 25 | } 26 | } 27 | 28 | ///Singleton factory 29 | static final Application _instance = Application._internal(); 30 | 31 | factory Application() { 32 | return _instance; 33 | } 34 | 35 | Application._internal(); 36 | } 37 | -------------------------------------------------------------------------------- /lib/src/configs/language.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class AppLanguage { 4 | ///Default Language 5 | static Locale defaultLanguage = Locale("vi"); 6 | 7 | ///List Language support in Application 8 | static List supportLanguage = [ 9 | Locale("en"), 10 | Locale("vi"), 11 | Locale("da"), 12 | Locale("de"), 13 | Locale("el"), 14 | Locale("fr"), 15 | Locale("id"), 16 | Locale("ja"), 17 | Locale("ko"), 18 | Locale("nl"), 19 | Locale("zh"), 20 | Locale("ru"), 21 | ]; 22 | 23 | ///Singleton factory 24 | static final AppLanguage _instance = AppLanguage._internal(); 25 | 26 | factory AppLanguage() { 27 | return _instance; 28 | } 29 | 30 | AppLanguage._internal(); 31 | } 32 | -------------------------------------------------------------------------------- /lib/src/helpers/audio_helper.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | import 'package:just_audio/just_audio.dart'; 3 | 4 | class AudioHelper { 5 | static AudioPlayer player = AudioPlayer(); 6 | 7 | static StreamController bufferedController = StreamController.broadcast(); 8 | 9 | Future soundAndRing(String url) async { 10 | player = AudioPlayer(); 11 | 12 | try { 13 | if (player.playing) { 14 | player.stop(); 15 | } 16 | await player.setUrl(url); 17 | player.setVolume(1); 18 | player.play(); 19 | 20 | player.bufferedPositionStream.listen((event) { 21 | print('BUFFERED: $event'); 22 | bufferedController.add(event); 23 | }); 24 | 25 | player.durationStream.listen((event) { 26 | print('DURATION: $event'); 27 | }); 28 | 29 | player.positionStream.listen((event) { 30 | print('POSITION: $event'); 31 | }); 32 | 33 | player.setLoopMode(LoopMode.off); 34 | } catch (error) { 35 | print('audio error: ${error.toString()}'); 36 | } 37 | } 38 | 39 | // Stream get positionDataStream => 40 | // Rx.combineLatest3( 41 | // player.positionStream, 42 | // player.bufferedPositionStream, 43 | // player.durationStream, 44 | // (position, bufferedPosition, duration) => 45 | // PositionData(position, bufferedPosition, duration ?? Duration.zero)); 46 | } 47 | 48 | class PositionData { 49 | Duration position; 50 | Duration duration; 51 | Duration bufferedPosition; 52 | 53 | PositionData(this.position, this.bufferedPosition, this.duration); 54 | 55 | @override 56 | String toString() { 57 | return 'PositionData{position: ${position.toString()}, duration: ${duration.toString()}, bufferedPosition: ${bufferedPosition}}'; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /lib/src/helpers/device_helper.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:cloudmate/src/models/device_model.dart'; 4 | import 'package:cloudmate/src/services/firebase_messaging/handle_messaging.dart'; 5 | import 'package:device_info/device_info.dart'; 6 | import 'package:flutter/services.dart'; 7 | 8 | Future getDeviceDetails() async { 9 | late String deviceName; 10 | // late String deviceVersion; 11 | late String identifier; 12 | late String appVersion; 13 | final String? fcmToken = await getFirebaseMessagingToken(); 14 | print(fcmToken); 15 | final DeviceInfoPlugin deviceInfoPlugin = new DeviceInfoPlugin(); 16 | try { 17 | if (Platform.isAndroid) { 18 | var build = await deviceInfoPlugin.androidInfo; 19 | deviceName = build.model; 20 | // deviceVersion = build.version.toString(); 21 | identifier = build.androidId; //UUID for Android 22 | appVersion = "1.0.0"; 23 | } else if (Platform.isIOS) { 24 | var data = await deviceInfoPlugin.iosInfo; 25 | deviceName = data.name; 26 | // deviceVersion = data.systemVersion; 27 | identifier = data.identifierForVendor; //UUID for iOS 28 | appVersion = "1.0.0"; 29 | } 30 | } on PlatformException { 31 | print('Failed to get platform version'); 32 | } 33 | return DeviceModel( 34 | appVersion: appVersion, 35 | deviceModel: deviceName, 36 | deviceUUid: identifier, 37 | fcmToken: fcmToken!, 38 | ); 39 | } 40 | -------------------------------------------------------------------------------- /lib/src/helpers/int.dart: -------------------------------------------------------------------------------- 1 | import 'package:cloudmate/src/themes/app_colors.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | extension IntHelper on int { 5 | String formatTwoDigits() { 6 | Duration duration = Duration(seconds: this); 7 | String twoDigits(int n) => n.toString().padLeft(2, "0"); 8 | String twoDigitMinutes = twoDigits(duration.inMinutes.remainder(60)); 9 | String twoDigitSeconds = twoDigits(duration.inSeconds.remainder(60)); 10 | return "${twoDigits(duration.inHours)}:$twoDigitMinutes:$twoDigitSeconds"; 11 | } 12 | 13 | Color getColorByPing() { 14 | if (this < 200) { 15 | return colorActive; 16 | } else if (this < 400) { 17 | return colorMedium; 18 | } else { 19 | return colorHigh; 20 | } 21 | } 22 | 23 | String getRoleName() { 24 | switch (this) { 25 | case 0: 26 | return "Thành viên"; 27 | case 1: 28 | return "Admin"; 29 | default: 30 | return "Quản lí"; 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /lib/src/helpers/members_helpers.dart: -------------------------------------------------------------------------------- 1 | import 'package:cloudmate/src/blocs/app_bloc.dart'; 2 | import 'package:cloudmate/src/models/user.dart'; 3 | 4 | class MembersHelper { 5 | List getMembers(List users) { 6 | String userId = AppBloc.authBloc.userModel!.id; 7 | return users.where((user) => user.id != userId && user.role == 0).toList(); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /lib/src/helpers/path_helper.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | import 'package:flutter/services.dart'; 3 | import 'package:path_provider/path_provider.dart' as path_provider; 4 | 5 | class PathHelper { 6 | static Future deleteCacheImageDir(String path) async { 7 | final cacheDir = Directory(path); 8 | if (cacheDir.existsSync()) { 9 | cacheDir.deleteSync(recursive: true); 10 | } 11 | } 12 | 13 | static Future get tempDir async => await path_provider.getTemporaryDirectory(); 14 | 15 | static Future get appDir async => 16 | await path_provider.getApplicationDocumentsDirectory(); 17 | 18 | static Future get downloadsDir async { 19 | Directory downloadsDirectory; 20 | try { 21 | if (Platform.isIOS) { 22 | downloadsDirectory = await path_provider.getApplicationDocumentsDirectory(); 23 | } else { 24 | downloadsDirectory = await path_provider.getApplicationSupportDirectory(); 25 | } 26 | 27 | return downloadsDirectory; 28 | } on PlatformException { 29 | print('Could not get the downloads directory'); 30 | return null; 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /lib/src/helpers/role_helper.dart: -------------------------------------------------------------------------------- 1 | import 'package:cloudmate/src/blocs/app_bloc.dart'; 2 | import 'package:cloudmate/src/models/user.dart'; 3 | 4 | class RoleHelper { 5 | bool canShowOptionReport(List members, String createdBy) { 6 | String userId = AppBloc.authBloc.userModel!.id; 7 | List memberIds = members.map((m) => m.id).toList(); 8 | if (memberIds.contains(userId) && userId != createdBy) { 9 | return true; 10 | } 11 | return false; 12 | } 13 | 14 | bool canShowDrawerClass(List members, String createdBy) { 15 | String userId = AppBloc.authBloc.userModel!.id; 16 | List memberIds = members.map((m) => m.id).toList(); 17 | if (memberIds.contains(userId) || userId == createdBy) { 18 | return true; 19 | } 20 | return false; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /lib/src/helpers/string.dart: -------------------------------------------------------------------------------- 1 | extension StringHelper on String { 2 | String limitLength(int length) { 3 | String input = this; 4 | return input.toString().length <= length 5 | ? input 6 | : input.toString().substring(0, length - 2) + '..'; 7 | } 8 | 9 | formatMoney({String splitBy = ','}) { 10 | String result = ''; 11 | int count = 0; 12 | for (int i = this.length - 1; i >= 0; i--) { 13 | if (count == 3) { 14 | count = 1; 15 | result += splitBy; 16 | } else { 17 | count++; 18 | } 19 | result += this[i]; 20 | } 21 | String formatMoney = ''; 22 | for (int i = result.length - 1; i >= 0; i--) { 23 | formatMoney += result[i]; 24 | } 25 | return formatMoney; 26 | } 27 | 28 | String formatName(int length) { 29 | String name = this; 30 | List names = name.split(' '); 31 | switch (names.length) { 32 | case 1: 33 | return name; 34 | case 2: 35 | return name; 36 | case 3: 37 | if (name.length > length) { 38 | names.removeAt(1); 39 | return names.join(' '); 40 | } else { 41 | return name; 42 | } 43 | case 4: 44 | if (name.length > length) { 45 | names.removeAt(1); 46 | names.removeAt(1); 47 | return names.join(' '); 48 | } else { 49 | return name; 50 | } 51 | default: 52 | if (name.length > length) { 53 | names.removeAt(1); 54 | names.removeAt(1); 55 | names.removeAt(1); 56 | return names.join(' '); 57 | } else { 58 | return name; 59 | } 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /lib/src/helpers/validators/login_validator 2.dart: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /lib/src/helpers/validators/login_validator.dart: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /lib/src/lang/language_service.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:get_storage/get_storage.dart'; 3 | import 'package:i18n_extension/i18n_widget.dart'; 4 | 5 | class LanguageService { 6 | final _getStorage = GetStorage(); 7 | final storageKey = 'locale'; 8 | 9 | String getLocale() { 10 | return _getStorage.read(storageKey) ?? 'vi_vn'; 11 | } 12 | 13 | Future saveLocale(String locale) async { 14 | await _getStorage.write(storageKey, locale); 15 | } 16 | 17 | switchLanguage(context) async { 18 | await saveLocale(((I18n.localeStr == "vi_vn") ? "en_us" : "vi_vn")); 19 | I18n.of(context).locale = 20 | (I18n.localeStr == "vi_vn") ? null : const Locale("vi", "VN"); 21 | } 22 | 23 | initialLanguage(context) { 24 | String localeStr = getLocale(); 25 | if (localeStr == "vi_vn") { 26 | I18n.of(context).locale = Locale("vi", "VN"); 27 | } else { 28 | I18n.of(context).locale = null; 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /lib/src/lang/localization.dart: -------------------------------------------------------------------------------- 1 | import 'package:i18n_extension/i18n_extension.dart'; 2 | 3 | const classTitle = 'class'; 4 | const yourClass = 'yourClass'; 5 | const recommendClass = 'recommendClass'; 6 | 7 | extension Localization on String { 8 | static final _t = Translations.from("en_us", { 9 | classTitle: { 10 | "en_us": "Lớp học", 11 | "vi_vn": "Lớp học", 12 | }, 13 | yourClass: { 14 | "en_us": "Lớp học của bạn", 15 | "vi_vn": "Lớp học của bạn", 16 | }, 17 | recommendClass: { 18 | "en_us": "Lớp học đề xuất", 19 | "vi_vn": "Lớp học đề xuất", 20 | } 21 | }); 22 | 23 | String get i18n => localize(this, _t); 24 | 25 | String fill(List params) => localizeFill(this, params); 26 | 27 | String plural(int value) => localizePlural(value, this, _t); 28 | 29 | String version(Object modifier) => localizeVersion(modifier, this, _t); 30 | } 31 | -------------------------------------------------------------------------------- /lib/src/models/activity.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | class Activity { 4 | final String id; 5 | String title; 6 | DateTime time; 7 | Activity({ 8 | required this.id, 9 | required this.title, 10 | required this.time, 11 | }); 12 | 13 | Activity copyWith({ 14 | String? id, 15 | String? title, 16 | DateTime? time, 17 | }) { 18 | return Activity( 19 | id: id ?? this.id, 20 | title: title ?? this.title, 21 | time: time ?? this.time, 22 | ); 23 | } 24 | 25 | Map toMap() { 26 | return { 27 | 'id': id, 28 | 'title': title, 29 | 'time': time.millisecondsSinceEpoch, 30 | }; 31 | } 32 | 33 | factory Activity.fromMap(Map map) { 34 | return Activity( 35 | id: map['id'], 36 | title: map['title'], 37 | time: DateTime.fromMillisecondsSinceEpoch(map['time']), 38 | ); 39 | } 40 | 41 | String toJson() => json.encode(toMap()); 42 | 43 | factory Activity.fromJson(String source) => 44 | Activity.fromMap(json.decode(source)); 45 | 46 | @override 47 | String toString() => 'Activity(id: $id, title: $title, time: $time)'; 48 | 49 | @override 50 | bool operator ==(Object other) { 51 | if (identical(this, other)) return true; 52 | 53 | return other is Activity && 54 | other.id == id && 55 | other.title == title && 56 | other.time == time; 57 | } 58 | 59 | @override 60 | int get hashCode => id.hashCode ^ title.hashCode ^ time.hashCode; 61 | } 62 | -------------------------------------------------------------------------------- /lib/src/models/device_model.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | class DeviceModel { 4 | final String appVersion; 5 | final String deviceModel; 6 | final String deviceUUid; 7 | final String fcmToken; 8 | DeviceModel({ 9 | required this.appVersion, 10 | required this.deviceModel, 11 | required this.deviceUUid, 12 | required this.fcmToken, 13 | }); 14 | 15 | DeviceModel copyWith({ 16 | String? appVersion, 17 | String? deviceModel, 18 | String? deviceUUid, 19 | String? fcmToken, 20 | }) { 21 | return DeviceModel( 22 | appVersion: appVersion ?? this.appVersion, 23 | deviceModel: deviceModel ?? this.deviceModel, 24 | deviceUUid: deviceUUid ?? this.deviceUUid, 25 | fcmToken: fcmToken ?? this.fcmToken, 26 | ); 27 | } 28 | 29 | Map toMap() { 30 | return { 31 | 'appVersion': appVersion, 32 | 'deviceModel': deviceModel, 33 | 'deviceUUid': deviceUUid, 34 | 'fcmToken': fcmToken, 35 | }; 36 | } 37 | 38 | factory DeviceModel.fromMap(Map map) { 39 | return DeviceModel( 40 | appVersion: map['appVersion'], 41 | deviceModel: map['deviceModel'], 42 | deviceUUid: map['deviceUUid'], 43 | fcmToken: map['fcmToken'], 44 | ); 45 | } 46 | 47 | String toJson() => json.encode(toMap()); 48 | 49 | factory DeviceModel.fromJson(String source) => DeviceModel.fromMap(json.decode(source)); 50 | 51 | @override 52 | String toString() { 53 | return 'DeviceModel(appVersion: $appVersion, deviceModel: $deviceModel, deviceUUid: $deviceUUid, fcmToken: $fcmToken)'; 54 | } 55 | 56 | @override 57 | bool operator ==(Object other) { 58 | if (identical(this, other)) return true; 59 | 60 | return other is DeviceModel && 61 | other.appVersion == appVersion && 62 | other.deviceModel == deviceModel && 63 | other.deviceUUid == deviceUUid && 64 | other.fcmToken == fcmToken; 65 | } 66 | 67 | @override 68 | int get hashCode { 69 | return appVersion.hashCode ^ 70 | deviceModel.hashCode ^ 71 | deviceUUid.hashCode ^ 72 | fcmToken.hashCode; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /lib/src/models/exam.dart: -------------------------------------------------------------------------------- 1 | class Exam { 2 | final String id; 3 | final String name; 4 | final String description; 5 | final String createdBy; 6 | final int usedTimes; 7 | 8 | Exam({ 9 | this.id = '', 10 | required this.name, 11 | required this.description, 12 | required this.createdBy, 13 | required this.usedTimes, 14 | }); 15 | 16 | factory Exam.fromMap(Map data) { 17 | return Exam( 18 | id: data['_id'], 19 | name: data['name'], 20 | description: data['description'], 21 | createdBy: data['createdBy'], 22 | usedTimes: data['usedTimes'], 23 | ); 24 | } 25 | } 26 | 27 | List exams = [ 28 | Exam( 29 | name: 'Bài kiểm tra số 1', 30 | description: 'Kiểm tra 15p, tuần 2', 31 | createdBy: '', 32 | usedTimes: 5, 33 | ), 34 | Exam( 35 | name: 'Bài kiểm tra số 2', 36 | description: 'Kiểm tra 15p, tuần 5', 37 | createdBy: '', 38 | usedTimes: 4, 39 | ), 40 | Exam( 41 | name: 'Bài kiểm tra số 3', 42 | description: 'Kiểm tra 45p, tuần 7', 43 | createdBy: '', 44 | usedTimes: 1, 45 | ), 46 | ]; 47 | -------------------------------------------------------------------------------- /lib/src/models/history_quiz_model.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | class HistoryQuizModel { 4 | final String id; 5 | final String title; 6 | final int score; 7 | final bool isShow; 8 | final DateTime createdAt; 9 | HistoryQuizModel({ 10 | required this.id, 11 | required this.title, 12 | required this.score, 13 | required this.isShow, 14 | required this.createdAt, 15 | }); 16 | 17 | HistoryQuizModel copyWith({ 18 | String? id, 19 | String? title, 20 | int? score, 21 | bool? isShow, 22 | DateTime? createdAt, 23 | }) { 24 | return HistoryQuizModel( 25 | id: id ?? this.id, 26 | title: title ?? this.title, 27 | score: score ?? this.score, 28 | isShow: isShow ?? this.isShow, 29 | createdAt: createdAt ?? this.createdAt, 30 | ); 31 | } 32 | 33 | Map toMap() { 34 | return { 35 | 'id': id, 36 | 'title': title, 37 | 'score': score, 38 | 'isShow': isShow, 39 | 'createdAt': createdAt.millisecondsSinceEpoch, 40 | }; 41 | } 42 | 43 | factory HistoryQuizModel.fromMap(Map map) { 44 | return HistoryQuizModel( 45 | id: map['_id'], 46 | title: map['title'], 47 | score: map['score'], 48 | isShow: map['isShow'], 49 | createdAt: DateTime.parse(map['createdAt']).toLocal(), 50 | ); 51 | } 52 | 53 | String toJson() => json.encode(toMap()); 54 | 55 | factory HistoryQuizModel.fromJson(String source) => HistoryQuizModel.fromMap(json.decode(source)); 56 | 57 | @override 58 | String toString() { 59 | return 'HistoryQuizModel(id: $id, title: $title, score: $score, isShow: $isShow, createdAt: $createdAt)'; 60 | } 61 | 62 | @override 63 | bool operator ==(Object other) { 64 | if (identical(this, other)) return true; 65 | 66 | return other is HistoryQuizModel && 67 | other.id == id && 68 | other.title == title && 69 | other.score == score && 70 | other.isShow == isShow && 71 | other.createdAt == createdAt; 72 | } 73 | 74 | @override 75 | int get hashCode { 76 | return id.hashCode ^ 77 | title.hashCode ^ 78 | score.hashCode ^ 79 | isShow.hashCode ^ 80 | createdAt.hashCode; 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /lib/src/models/notification_model.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | class NotificationModel { 4 | final String id; 5 | final String title; 6 | final String description; 7 | final DateTime createdAt; 8 | NotificationModel({ 9 | required this.id, 10 | required this.title, 11 | required this.description, 12 | required this.createdAt, 13 | }); 14 | 15 | NotificationModel copyWith({ 16 | String? id, 17 | String? title, 18 | String? description, 19 | }) { 20 | return NotificationModel( 21 | id: id ?? this.id, 22 | title: title ?? this.title, 23 | description: description ?? this.description, 24 | createdAt: this.createdAt, 25 | ); 26 | } 27 | 28 | Map toMap() { 29 | return { 30 | 'id': id, 31 | 'title': title, 32 | 'description': description, 33 | }; 34 | } 35 | 36 | factory NotificationModel.fromMap(Map map) { 37 | return NotificationModel( 38 | id: map['_id'], 39 | title: map['title'], 40 | description: map['description'], 41 | createdAt: DateTime.parse(map['createdAt']), 42 | ); 43 | } 44 | 45 | String toJson() => json.encode(toMap()); 46 | 47 | factory NotificationModel.fromJson(String source) => NotificationModel.fromMap(json.decode(source)); 48 | 49 | @override 50 | String toString() => 'NotificationModel(id: $id, title: $title, description: $description)'; 51 | 52 | @override 53 | bool operator ==(Object other) { 54 | if (identical(this, other)) return true; 55 | 56 | return other is NotificationModel && 57 | other.id == id && 58 | other.title == title && 59 | other.description == description; 60 | } 61 | 62 | @override 63 | int get hashCode => id.hashCode ^ title.hashCode ^ description.hashCode; 64 | } 65 | -------------------------------------------------------------------------------- /lib/src/models/question.dart: -------------------------------------------------------------------------------- 1 | class Question { 2 | final String? question; 3 | final int? duration; 4 | 5 | Question({ 6 | this.duration, 7 | this.question, 8 | }); 9 | } 10 | 11 | List questions = [ 12 | Question( 13 | question: 'Flutter là gì?', 14 | duration: 30, 15 | ), 16 | Question( 17 | question: 'Dependency Injection là gì?', 18 | duration: 30, 19 | ), 20 | Question( 21 | question: 'Mô hình bảo mật truyền thống trên server?', 22 | duration: 45, 23 | ), 24 | ]; 25 | -------------------------------------------------------------------------------- /lib/src/models/question_type_enum.dart: -------------------------------------------------------------------------------- 1 | enum QuestionType { 2 | multipleChoise, 3 | singleChoise, 4 | trueFalse, 5 | // audio, 6 | dragAndDrop, 7 | } 8 | 9 | extension ConvertTypeToEnum on QuestionType { 10 | String getTileByEnum() { 11 | switch (this) { 12 | case QuestionType.multipleChoise: 13 | return 'Nhiều lựa chọn'; 14 | case QuestionType.singleChoise: 15 | return 'Một lựa chọn'; 16 | case QuestionType.trueFalse: 17 | return 'Đúng/Sai'; 18 | // case QuestionType.audio: 19 | // return 'Âm thanh'; 20 | case QuestionType.dragAndDrop: 21 | return 'Kéo thả đáp án'; 22 | default: 23 | return 'Một lựa chọn'; 24 | } 25 | } 26 | 27 | int getTypeNumber() { 28 | switch (this) { 29 | case QuestionType.multipleChoise: 30 | return 1; 31 | case QuestionType.singleChoise: 32 | return 2; 33 | case QuestionType.trueFalse: 34 | return 3; 35 | // case QuestionType.audio: 36 | // return 5; 37 | case QuestionType.dragAndDrop: 38 | return 7; 39 | default: 40 | return 2; 41 | } 42 | } 43 | } 44 | 45 | QuestionType fromTypeNumber({required int type}) { 46 | switch (type) { 47 | case 1: 48 | return QuestionType.multipleChoise; 49 | case 2: 50 | return QuestionType.singleChoise; 51 | case 3: 52 | return QuestionType.trueFalse; 53 | // case 5: 54 | // return QuestionType.audio; 55 | case 7: 56 | return QuestionType.dragAndDrop; 57 | default: 58 | return QuestionType.singleChoise; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /lib/src/models/road_map_content_type.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:phosphor_flutter/phosphor_flutter.dart'; 3 | 4 | enum RoadMapContentType { 5 | assignment, 6 | attendance, 7 | } 8 | 9 | extension RoadMapContentTypeExtension on RoadMapContentType { 10 | String get value { 11 | switch (this) { 12 | case RoadMapContentType.assignment: 13 | return 'Bài tập'; 14 | case RoadMapContentType.attendance: 15 | return 'Điểm danh'; 16 | } 17 | } 18 | 19 | IconData get icon { 20 | switch (this) { 21 | case RoadMapContentType.assignment: 22 | return PhosphorIcons.folderOpenFill; 23 | case RoadMapContentType.attendance: 24 | return PhosphorIcons.handsClappingFill; 25 | } 26 | } 27 | 28 | List get getListRoadMap { 29 | return [ 30 | RoadMapContentType.assignment, 31 | RoadMapContentType.attendance, 32 | ]; 33 | } 34 | 35 | int get toIntValue { 36 | switch (this) { 37 | case RoadMapContentType.assignment: 38 | return 1; 39 | case RoadMapContentType.attendance: 40 | return 0; 41 | } 42 | } 43 | } 44 | 45 | fromIntValue(int value) { 46 | switch (value) { 47 | case 1: 48 | return RoadMapContentType.assignment; 49 | case 0: 50 | return RoadMapContentType.attendance; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /lib/src/models/road_map_model.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | class RoadMapModel { 4 | final String id; 5 | final String name; 6 | final String description; 7 | final int status; 8 | final String createBy; 9 | RoadMapModel({ 10 | required this.id, 11 | required this.name, 12 | required this.description, 13 | required this.status, 14 | required this.createBy, 15 | }); 16 | 17 | RoadMapModel copyWith({ 18 | String? id, 19 | String? name, 20 | String? description, 21 | int? status, 22 | String? createBy, 23 | }) { 24 | return RoadMapModel( 25 | id: id ?? this.id, 26 | name: name ?? this.name, 27 | description: description ?? this.description, 28 | status: status ?? this.status, 29 | createBy: createBy ?? this.createBy, 30 | ); 31 | } 32 | 33 | Map toMap() { 34 | return { 35 | 'id': id, 36 | 'name': name, 37 | 'description': description, 38 | 'status': status, 39 | 'createBy': createBy, 40 | }; 41 | } 42 | 43 | factory RoadMapModel.fromMap(Map map) { 44 | return RoadMapModel( 45 | id: map['_id'], 46 | name: map['name'], 47 | description: map['description'], 48 | status: map['status'], 49 | createBy: map['createBy'], 50 | ); 51 | } 52 | 53 | String toJson() => json.encode(toMap()); 54 | 55 | factory RoadMapModel.fromJson(String source) => 56 | RoadMapModel.fromMap(json.decode(source)); 57 | 58 | @override 59 | String toString() { 60 | return 'RoadMapModel(id: $id, name: $name, description: $description, status: $status, createBy: $createBy)'; 61 | } 62 | 63 | @override 64 | bool operator ==(Object other) { 65 | if (identical(this, other)) return true; 66 | 67 | return other is RoadMapModel && 68 | other.id == id && 69 | other.name == name && 70 | other.description == description && 71 | other.status == status && 72 | other.createBy == createBy; 73 | } 74 | 75 | @override 76 | int get hashCode { 77 | return id.hashCode ^ 78 | name.hashCode ^ 79 | description.hashCode ^ 80 | status.hashCode ^ 81 | createBy.hashCode; 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /lib/src/models/slide_mode.dart: -------------------------------------------------------------------------------- 1 | enum SlideMode { 2 | left, 3 | top, 4 | bot, 5 | right, 6 | } 7 | -------------------------------------------------------------------------------- /lib/src/models/upload_response_model.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | class UploadResponseModel { 4 | final String image; 5 | final String blurHash; 6 | UploadResponseModel({ 7 | required this.image, 8 | required this.blurHash, 9 | }); 10 | 11 | UploadResponseModel copyWith({ 12 | String? image, 13 | String? blurHash, 14 | }) { 15 | return UploadResponseModel( 16 | image: image ?? this.image, 17 | blurHash: blurHash ?? this.blurHash, 18 | ); 19 | } 20 | 21 | Map toMap() { 22 | return { 23 | 'image': image, 24 | 'blurHash': blurHash, 25 | }; 26 | } 27 | 28 | factory UploadResponseModel.fromMap(Map map) { 29 | return UploadResponseModel( 30 | image: map['image'], 31 | blurHash: map['blurHash'], 32 | ); 33 | } 34 | 35 | String toJson() => json.encode(toMap()); 36 | 37 | factory UploadResponseModel.fromJson(String source) => 38 | UploadResponseModel.fromMap(json.decode(source)); 39 | 40 | @override 41 | String toString() => 42 | 'UploadResponseModel(image: $image, blurHash: $blurHash)'; 43 | 44 | @override 45 | bool operator ==(Object other) { 46 | if (identical(this, other)) return true; 47 | 48 | return other is UploadResponseModel && 49 | other.image == image && 50 | other.blurHash == blurHash; 51 | } 52 | 53 | @override 54 | int get hashCode => image.hashCode ^ blurHash.hashCode; 55 | } 56 | -------------------------------------------------------------------------------- /lib/src/public/constants.dart: -------------------------------------------------------------------------------- 1 | import 'package:lottie/lottie.dart'; 2 | 3 | class Constants { 4 | static const INCH_TO_DP = 160; 5 | 6 | // Assets 7 | LottieBuilder splashLottie = Lottie.asset('assets/lottie/splash.json'); 8 | LottieBuilder loadingLottie = Lottie.asset('assets/lottie/cat_sleeping.json'); 9 | static const urlImageDefault = 'https://i.postimg.cc/Dfsg6VYJ/Hi-School.png'; 10 | static const className = 'Tên lớp học'; 11 | static const classTopic = 'Chủ đề'; 12 | static const classIntro = 'Giới thiệu về lớp học'; 13 | static const price = 'Giá lớp học'; 14 | static final List> defaultClassImageUrls = [ 15 | { 16 | 'image': 17 | 'https://i.pinimg.com/originals/02/89/09/02890993e3735184e80ecdf9db079e05.png', 18 | 'blurHash': 19 | r'rGQ8#*9Z~D%2aL$+t6NHNG%NtQaKRkM_axo#oejF^Sr@I.S1S#S2o0n$WBROWWSyoexbj]nij]W;%Mg2NZV[i_nhWrt7t6xajFjbbbbvbbWAWAkD', 20 | }, 21 | { 22 | 'image': 23 | 'https://i.pinimg.com/564x/62/de/59/62de59126d9e5b2a72f7ab306ba08dd5.jpg', 24 | 'blurHash': 25 | r'rGP;+eJC{Lv|:j-:xFNIAJ%hR*Z#xurqRPNHsqO?}v,pOAK6OFSes+r;xVL~S5tQV@K5t7ogbDwH|FR*Ki$$bcI;NIohof==slFMNdnPtRwcV@nh', 26 | }, 27 | { 28 | 'image': 29 | 'https://i.pinimg.com/564x/44/e7/9a/44e79a4fc1ae11b021629dcdfc68503d.jpg', 30 | 'blurHash': 31 | r'r9D[S9%J0}#SmmEdAqxH-nyFT0I.s9wJaLslt7t70c$f}HEyKdnUw#brr?eTr=$+Sht2xtJBRiNY-WJ7J~sqVyxoV?VvxZItbGoaoMXAoIw[NHN1', 32 | }, 33 | { 34 | 'image': 35 | 'https://i.pinimg.com/564x/ba/ab/2b/baab2b85777e2754653d028ee0a30194.jpg', 36 | 'blurHash': 37 | r'rUR1I?Io}Z-oadNbj[xuWr-pkWRPs9S}NFWVf,n*$NbFNuWBs:oze.r=jrnhoIozR+V]ozf*V?X7xGs:R+R*R*a}oyWUn+a{oIW;R,sVoMn%s.WB', 38 | }, 39 | ]; 40 | 41 | static getOnlyDefaultClassImage() { 42 | defaultClassImageUrls.shuffle(); 43 | return defaultClassImageUrls.first; 44 | } 45 | 46 | static const filesSupported = [ 47 | 'docx', 48 | 'doc', 49 | 'pdf', 50 | 'pptx', 51 | ]; 52 | } 53 | -------------------------------------------------------------------------------- /lib/src/public/sockets.dart: -------------------------------------------------------------------------------- 1 | class SocketEvent { 2 | static const PING = 'ping'; 3 | static const PONG = 'pong'; 4 | 5 | static const CREATE_QUIZ_CSS = 'CREATE_QUIZ_CSS'; 6 | static const CREATE_QUIZ_SSC = 'CREATE_QUIZ_SSC'; 7 | 8 | static const JOIN_ROOM_CSS = 'JOIN_ROOM_CSS'; 9 | static const JOIN_ROOM_SSC = 'JOIN_ROOM_SSC'; 10 | static const JOIN_ROOM_NEW_SSC = 'JOIN_ROOM_NEW_SSC'; 11 | 12 | static const LEAVE_ROOM_CSS = 'LEAVE_ROOM_CSS'; 13 | static const LEAVE_ROOM_SSC = 'LEAVE_ROOM_SSC'; 14 | 15 | static const STATISTICAL_ROOM_SSC = 'STATISTICAL_ROOM_SSC'; 16 | 17 | static const START_QUIZ_CSS = 'START_QUIZ_CSS'; 18 | static const START_QUIZ_SSC = 'START_QUIZ_SSC'; 19 | 20 | static const ANSWER_THE_QUESTION_CSS = 'ANSWER_THE_QUESTION_CSS'; 21 | static const ANSWER_THE_QUESTION_SSC = 'ANSWER_THE_QUESTION_SSC'; 22 | 23 | static const TAKE_THE_QUESTION_CSS = 'TAKE_THE_QUESTION_CSS'; 24 | static const TAKE_THE_QUESTION_SSC = 'TAKE_THE_QUESTION_SSC'; 25 | 26 | static const SEND_FCM_TOKEN_CSS = 'SEND_FCM_TOKEN_CSS'; 27 | 28 | static const STATISTICAL_ROOM_FINAL_SSC = 'STATISTICAL_ROOM_FINAL_SSC'; 29 | 30 | static const SEEN_MESSAGE_CONVERSATION_SSC = 'SEND_MESSAGE_CONVERSATION_SSC'; 31 | static const SEEN_MESSAGE_CONVERSATION_CSS = 'SEND_MESSAGE_CONVERSATION_CSS'; 32 | static const JOIN_CONVERSATION_SSC = 'JOIN_CONVERSATION_SSC'; 33 | static const JOIN_CONVERSATION_CSS = 'JOIN_CONVERSATION_CSS'; 34 | static const LEAVE_CONVERSATION_SSC = 'LEAVE_CONVERSATION_SSC'; 35 | static const LEAVE_CONVERSATION_CSS = 'LEAVE_CONVERSATION_CSS'; 36 | } 37 | -------------------------------------------------------------------------------- /lib/src/resources/hard/hard_activities.dart: -------------------------------------------------------------------------------- 1 | import 'package:cloudmate/src/models/activity.dart'; 2 | 3 | List activities = [ 4 | Activity( 5 | id: '', 6 | title: 'Javascript', 7 | time: DateTime.now().add( 8 | Duration(hours: 2), 9 | ), 10 | ), 11 | Activity( 12 | id: '', 13 | title: 'Java', 14 | time: DateTime.now().add( 15 | Duration(hours: 5), 16 | ), 17 | ), 18 | Activity( 19 | id: '', 20 | title: 'Flutter', 21 | time: DateTime.now().add( 22 | Duration(hours: 12), 23 | ), 24 | ), 25 | Activity( 26 | id: '', 27 | title: 'Firebase', 28 | time: DateTime.now().add( 29 | Duration(hours: 36), 30 | ), 31 | ), 32 | ]; 33 | -------------------------------------------------------------------------------- /lib/src/resources/hard/hard_exam_post.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | class Exam { 4 | final String id; 5 | String name; 6 | DateTime startTime; 7 | int duration; 8 | Exam({ 9 | required this.id, 10 | required this.name, 11 | required this.startTime, 12 | required this.duration, 13 | }); 14 | 15 | Exam copyWith({ 16 | String? id, 17 | String? name, 18 | DateTime? startTime, 19 | int? duration, 20 | }) { 21 | return Exam( 22 | id: id ?? this.id, 23 | name: name ?? this.name, 24 | startTime: startTime ?? this.startTime, 25 | duration: duration ?? this.duration, 26 | ); 27 | } 28 | 29 | Map toMap() { 30 | return { 31 | 'id': id, 32 | 'name': name, 33 | 'startTime': startTime.millisecondsSinceEpoch, 34 | 'duration': duration, 35 | }; 36 | } 37 | 38 | factory Exam.fromMap(Map map) { 39 | return Exam( 40 | id: map['id'], 41 | name: map['name'], 42 | startTime: DateTime.fromMillisecondsSinceEpoch(map['startTime']), 43 | duration: map['duration'], 44 | ); 45 | } 46 | 47 | String toJson() => json.encode(toMap()); 48 | 49 | factory Exam.fromJson(String source) => Exam.fromMap(json.decode(source)); 50 | 51 | @override 52 | String toString() { 53 | return 'Exam(id: $id, name: $name, startTime: $startTime, duration: $duration)'; 54 | } 55 | 56 | @override 57 | bool operator ==(Object other) { 58 | if (identical(this, other)) return true; 59 | 60 | return other is Exam && 61 | other.id == id && 62 | other.name == name && 63 | other.startTime == startTime && 64 | other.duration == duration; 65 | } 66 | 67 | @override 68 | int get hashCode { 69 | return id.hashCode ^ name.hashCode ^ startTime.hashCode ^ duration.hashCode; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /lib/src/resources/hard/hard_normal_post.dart: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /lib/src/resources/hard/hard_schedule.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | class ScheduleDeadline { 4 | final String id; 5 | String name; 6 | DateTime deadline; 7 | String fileName; 8 | ScheduleDeadline({ 9 | required this.id, 10 | required this.name, 11 | required this.deadline, 12 | required this.fileName, 13 | }); 14 | 15 | ScheduleDeadline copyWith({ 16 | String? id, 17 | String? name, 18 | DateTime? deadline, 19 | String? fileName, 20 | }) { 21 | return ScheduleDeadline( 22 | id: id ?? this.id, 23 | name: name ?? this.name, 24 | deadline: deadline ?? this.deadline, 25 | fileName: fileName ?? this.fileName, 26 | ); 27 | } 28 | 29 | Map toMap() { 30 | return { 31 | 'id': id, 32 | 'name': name, 33 | 'deadline': deadline.millisecondsSinceEpoch, 34 | 'fileName': fileName, 35 | }; 36 | } 37 | 38 | factory ScheduleDeadline.fromMap(Map map) { 39 | return ScheduleDeadline( 40 | id: map['id'], 41 | name: map['name'], 42 | deadline: DateTime.fromMillisecondsSinceEpoch(map['deadline']), 43 | fileName: map['fileName'], 44 | ); 45 | } 46 | 47 | String toJson() => json.encode(toMap()); 48 | 49 | factory ScheduleDeadline.fromJson(String source) => 50 | ScheduleDeadline.fromMap(json.decode(source)); 51 | 52 | @override 53 | String toString() { 54 | return 'ScheduleDeadline(id: $id, name: $name, deadline: $deadline, fileName: $fileName)'; 55 | } 56 | 57 | @override 58 | bool operator ==(Object other) { 59 | if (identical(this, other)) return true; 60 | 61 | return other is ScheduleDeadline && 62 | other.id == id && 63 | other.name == name && 64 | other.deadline == deadline && 65 | other.fileName == fileName; 66 | } 67 | 68 | @override 69 | int get hashCode { 70 | return id.hashCode ^ name.hashCode ^ deadline.hashCode ^ fileName.hashCode; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /lib/src/resources/local/user_local.dart: -------------------------------------------------------------------------------- 1 | import 'package:cloudmate/src/models/user.dart'; 2 | import 'package:get_storage/get_storage.dart'; 3 | 4 | class UserLocal { 5 | final _getStorage = GetStorage(); 6 | final storageKey = 'token'; 7 | final storageKeyUser = 'userLocal'; 8 | 9 | String getAccessToken() { 10 | return _getStorage.read(storageKey) ?? ''; 11 | } 12 | 13 | UserModel? getUser() { 14 | var rawData = _getStorage.read(storageKeyUser); 15 | if (rawData != null) { 16 | return UserModel.fromJson(rawData); 17 | } 18 | return null; 19 | } 20 | 21 | void saveAccessToken(String token) async { 22 | _getStorage.write(storageKey, token); 23 | } 24 | 25 | void saveUser(UserModel user) async { 26 | _getStorage.write(storageKeyUser, user.toJson()); 27 | } 28 | 29 | void clearAccessToken() async { 30 | _getStorage.remove(storageKey); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /lib/src/resources/remote/authentication_repository.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:cloudmate/src/public/api_gateway.dart'; 4 | import 'package:cloudmate/src/resources/base_repository.dart'; 5 | import 'package:cloudmate/src/resources/local/user_local.dart'; 6 | import 'package:dio/dio.dart'; 7 | 8 | class AuthenticationRepository { 9 | Future login(String username, String password, {String? token}) async { 10 | var body = { 11 | 'username': username.toLowerCase(), 12 | 'password': password, 13 | }; 14 | Response response = await BaseRepository().postRoute( 15 | ApiGateway.LOGIN, 16 | body, 17 | token: token, 18 | ); 19 | 20 | if (response.statusCode == 200) { 21 | if (token == null) { 22 | UserLocal().saveAccessToken(response.data['data']['token']); 23 | } 24 | return response.data['data']['token']; 25 | } 26 | return null; 27 | } 28 | 29 | Future register({ 30 | required String fistName, 31 | required String lastName, 32 | required String username, 33 | required String password, 34 | String? token, 35 | }) async { 36 | var body = { 37 | 'firstName': fistName, 38 | 'lastName': lastName, 39 | 'username': username.toLowerCase(), 40 | 'password': password, 41 | }; 42 | Response response = await BaseRepository().postRoute( 43 | ApiGateway.REGISTER, 44 | body, 45 | token: token, 46 | ); 47 | 48 | if (response.statusCode == 200) { 49 | if (token == null) { 50 | UserLocal().saveAccessToken(response.data['data']['token']); 51 | } 52 | return true; 53 | } 54 | return false; 55 | } 56 | 57 | FutureOr logOut() async { 58 | UserLocal().clearAccessToken(); 59 | return false; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /lib/src/resources/remote/conversation_repository.dart: -------------------------------------------------------------------------------- 1 | import 'package:cloudmate/src/models/conversation_model.dart'; 2 | import 'package:cloudmate/src/public/api_gateway.dart'; 3 | import 'package:cloudmate/src/resources/base_repository.dart'; 4 | import 'package:dio/dio.dart'; 5 | 6 | class ConversationRepository { 7 | Future> getListClasses({ 8 | required int skip, 9 | int limit = 10, 10 | }) async { 11 | Response response = await BaseRepository().getRoute( 12 | ApiGateway.CONVERSATION, 13 | query: 'skip=$skip&limit=$limit', 14 | ); 15 | if ([200].contains(response.statusCode)) { 16 | List listResult = response.data['data']; 17 | return listResult.map((e) => ConversationModel.fromMap(e)).toList(); 18 | } 19 | 20 | return []; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /lib/src/resources/remote/history_quiz_repository.dart: -------------------------------------------------------------------------------- 1 | import 'package:cloudmate/src/models/history_quiz_model.dart'; 2 | import 'package:cloudmate/src/models/user.dart'; 3 | import 'package:cloudmate/src/public/api_gateway.dart'; 4 | import 'package:cloudmate/src/resources/base_repository.dart'; 5 | import 'package:dio/dio.dart'; 6 | 7 | class HistoryQuizRepository { 8 | Future> getHistory({required String classId}) async { 9 | Response response = 10 | await BaseRepository().getRoute(ApiGateway.HISTORY, query: 'idClass=$classId'); 11 | if (response.statusCode == 200) { 12 | List data = response.data['data']; 13 | return data.map((e) => HistoryQuizModel.fromMap(e)).toList(); 14 | } 15 | return []; 16 | } 17 | 18 | Future> getDetailsHistory({required String quizId}) async { 19 | Response response = 20 | await BaseRepository().getRoute(ApiGateway.DETAIL_HISTORY, query: 'idQuizClass=$quizId'); 21 | print(response.data.toString()); 22 | if (response.statusCode == 200) { 23 | List data = response.data['data']; 24 | return data.where((e) => e['user'] != null).map((e) => UserModel.fromStatistic(e['user'], score: e['score'])).toList(); 25 | } 26 | return []; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /lib/src/resources/remote/member_repository.dart: -------------------------------------------------------------------------------- 1 | import 'package:cloudmate/src/models/user.dart'; 2 | import 'package:cloudmate/src/public/api_gateway.dart'; 3 | import 'package:cloudmate/src/resources/base_repository.dart'; 4 | import 'package:dio/dio.dart'; 5 | 6 | class MemberRepository { 7 | Future> getListMember({ 8 | required int skip, 9 | required String id, 10 | }) async { 11 | Response response = await BaseRepository().getRoute( 12 | ApiGateway.QUESTION, 13 | query: 'skip=$skip&idSetOfQuestions=$id', 14 | ); 15 | if (response.statusCode == 200) { 16 | List jsonResponse = response.data['data']; 17 | return jsonResponse.map((item) => UserModel.fromMap(item)).toList(); 18 | } 19 | 20 | return []; 21 | } 22 | 23 | Future removeMember({ 24 | required String classId, 25 | required String memberId, 26 | }) async { 27 | return false; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /lib/src/resources/remote/message_repository.dart: -------------------------------------------------------------------------------- 1 | import 'package:cloudmate/src/models/message_model.dart'; 2 | import 'package:cloudmate/src/public/api_gateway.dart'; 3 | import 'package:cloudmate/src/resources/base_repository.dart'; 4 | import 'package:dio/dio.dart'; 5 | 6 | class MessageRepository { 7 | Future> getMessages({ 8 | required String classId, 9 | required int skip, 10 | int limit = 15, 11 | }) async { 12 | Response response = await BaseRepository().getRoute( 13 | ApiGateway.MESSAGE_CONVERSATION + '/$classId', 14 | query: 'skip=$skip&limit=$limit', 15 | ); 16 | if ([200].contains(response.statusCode)) { 17 | List listResult = response.data['data']; 18 | return listResult.map((e) => MessageModel.fromMap(e)).toList(); 19 | } 20 | 21 | return []; 22 | } 23 | 24 | Future createMessage({ 25 | required String idClass, 26 | required String message, 27 | }) async { 28 | var body = { 29 | 'idClass': idClass, 30 | 'message': message, 31 | }; 32 | Response response = await BaseRepository().postRoute( 33 | ApiGateway.MESSAGE, 34 | body, 35 | ); 36 | if ([201].contains(response.statusCode)) { 37 | var item = response.data['data']; 38 | return MessageModel.fromMapCreate(item); 39 | } 40 | 41 | return null; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /lib/src/resources/remote/notification_repository.dart: -------------------------------------------------------------------------------- 1 | import 'package:cloudmate/src/models/notification_model.dart'; 2 | import 'package:cloudmate/src/public/api_gateway.dart'; 3 | import 'package:cloudmate/src/resources/base_repository.dart'; 4 | import 'package:dio/dio.dart'; 5 | 6 | class NotificationRepository { 7 | Future> getNotifications() async { 8 | Response response = await BaseRepository().getRoute( 9 | ApiGateway.NOTIFICATION, 10 | ); 11 | print(response.data.toString()); 12 | if (response.statusCode == 200) { 13 | List resultJson = response.data['data']; 14 | return resultJson.map((item) => NotificationModel.fromMap(item)).toList(); 15 | } 16 | 17 | return []; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /lib/src/resources/remote/post_repository.dart: -------------------------------------------------------------------------------- 1 | import 'package:cloudmate/src/models/post_model.dart'; 2 | import 'package:cloudmate/src/public/api_gateway.dart'; 3 | import 'package:cloudmate/src/resources/base_repository.dart'; 4 | import 'package:dio/dio.dart'; 5 | 6 | class PostRepository { 7 | Future> getListPostHome({ 8 | int skip = 0, 9 | int limit = 15, 10 | }) async { 11 | Response? response = await BaseRepository().getRoute( 12 | ApiGateway.POST_HOME, 13 | query: 'skip=$skip&limit=$limit', 14 | ); 15 | 16 | if ([200, 201].contains(response.statusCode)) { 17 | List rawData = response.data['data']; 18 | return rawData.map((e) => PostModel.fromMap(e)).toList(); 19 | } 20 | 21 | return []; 22 | } 23 | 24 | Future> getListPostClass({ 25 | int skip = 0, 26 | int limit = 15, 27 | required String classId, 28 | }) async { 29 | Response? response = await BaseRepository().getRoute( 30 | ApiGateway.POST_CLASS + '/$classId', 31 | query: 'skip=$skip&limit=$limit', 32 | ); 33 | 34 | if ([200, 201].contains(response.statusCode)) { 35 | List rawData = response.data['data']; 36 | return rawData.map((e) => PostModel.fromMap(e)).toList(); 37 | } 38 | 39 | return []; 40 | } 41 | 42 | Future createPost({ 43 | required String content, 44 | required String classId, 45 | }) async { 46 | var body = { 47 | 'classId': classId, 48 | 'content': content, 49 | }; 50 | 51 | Response? response = 52 | await BaseRepository().postRoute(ApiGateway.POST, body); 53 | 54 | if ([200, 201].contains(response.statusCode)) { 55 | var rawData = response.data['data']; 56 | return PostModel.fromMap(rawData); 57 | } 58 | 59 | return null; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /lib/src/resources/remote/road_map_repository.dart: -------------------------------------------------------------------------------- 1 | import 'package:cloudmate/src/models/road_map_model.dart'; 2 | import 'package:cloudmate/src/public/api_gateway.dart'; 3 | import 'package:cloudmate/src/resources/base_repository.dart'; 4 | import 'package:dio/dio.dart'; 5 | 6 | class RoadMapRepository { 7 | Future createRoadMap({ 8 | required String classId, 9 | required String name, 10 | required String description, 11 | }) async { 12 | var body = { 13 | 'name': name, 14 | 'description': description, 15 | }; 16 | 17 | Response response = await BaseRepository().postRoute( 18 | ApiGateway.ROAD_MAP, 19 | body, 20 | query: 'idClass=$classId', 21 | ); 22 | 23 | if ([200, 201].contains(response.statusCode)) { 24 | var jsonResult = response.data['data']; 25 | return RoadMapModel.fromMap(jsonResult); 26 | } 27 | 28 | return null; 29 | } 30 | 31 | Future> getRoadMaps({required String classId}) async { 32 | Response response = await BaseRepository().getRoute( 33 | ApiGateway.ROAD_MAP, 34 | query: 'idClass=$classId', 35 | ); 36 | 37 | if ([200, 201].contains(response.statusCode)) { 38 | var jsonResult = response.data['data']; 39 | return jsonResult.map((json) => RoadMapModel.fromMap(json)).toList(); 40 | } 41 | 42 | return []; 43 | } 44 | 45 | Future deleteRoadMap({required String roadMapId}) async { 46 | Response response = await BaseRepository().deleteRoute( 47 | ApiGateway.ROAD_MAP, 48 | query: 'id=$roadMapId&status=0', 49 | ); 50 | 51 | return [200, 201].contains(response.statusCode); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /lib/src/resources/remote/share_exam_repository.dart: -------------------------------------------------------------------------------- 1 | import 'package:cloudmate/src/models/exam_model.dart'; 2 | import 'package:cloudmate/src/public/api_gateway.dart'; 3 | import 'package:cloudmate/src/resources/base_repository.dart'; 4 | import 'package:dio/dio.dart'; 5 | 6 | class ShareExamRepository { 7 | Future createExam({ 8 | required String name, 9 | required String description, 10 | }) async { 11 | var body = { 12 | "name": name, 13 | "description": description, 14 | }; 15 | Response response = await BaseRepository().postRoute(ApiGateway.SET_OF_QUESTIONS_SHARE, body); 16 | if ([200, 201].contains(response.statusCode)) { 17 | dynamic jsonResponse = response.data['data']; 18 | return ExamModel.fromMap(jsonResponse); 19 | } 20 | 21 | return null; 22 | } 23 | 24 | Future> getListExam() async { 25 | Response response = await BaseRepository().getRoute( 26 | ApiGateway.SET_OF_QUESTIONS_SHARE, 27 | query: 'status=1', 28 | ); 29 | 30 | if (response.statusCode == 200) { 31 | List jsonResponse = response.data['data']; 32 | return jsonResponse.map((item) => ExamModel.fromMap(item)).toList(); 33 | } 34 | return []; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /lib/src/resources/remote/transaction_repository.dart: -------------------------------------------------------------------------------- 1 | import 'package:cloudmate/src/models/transaction_model.dart'; 2 | import 'package:cloudmate/src/public/api_gateway.dart'; 3 | import 'package:cloudmate/src/resources/base_repository.dart'; 4 | import 'package:dio/dio.dart'; 5 | 6 | class TransactionRepository { 7 | Future> getTransactions() async { 8 | Response response = await BaseRepository().getRoute( 9 | ApiGateway.TRANSACTION, 10 | ); 11 | if (response.statusCode == 200) { 12 | List rawData = response.data['data']; 13 | return rawData.map((e) => TransactionModel.fromMap(e)).toList(); 14 | } 15 | return []; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /lib/src/resources/remote/upload_repository.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | import 'package:cloudmate/src/models/upload_response_model.dart'; 3 | import 'package:cloudmate/src/public/api_gateway.dart'; 4 | import 'package:cloudmate/src/resources/base_repository.dart'; 5 | import 'package:dio/dio.dart'; 6 | 7 | class UploadRepository { 8 | Future uploadSingleFile({ 9 | required File file, 10 | }) async { 11 | FormData formData = FormData.fromMap({ 12 | 'file': await MultipartFile.fromBytes( 13 | file.readAsBytesSync(), 14 | filename: file.path, 15 | ), 16 | }); 17 | 18 | Response response = await BaseRepository().sendFormData( 19 | ApiGateway.UPLOAD_SINGLE_FILE, 20 | formData, 21 | ); 22 | 23 | if ([200, 201].contains(response.statusCode)) { 24 | var jsonResponse = await response.data['data']; 25 | return UploadResponseModel.fromMap(jsonResponse); 26 | } 27 | 28 | return null; 29 | } 30 | 31 | Future?> uploadMultipleFile({ 32 | required List files, 33 | }) async { 34 | List filesBody = []; 35 | files.forEach((item) async { 36 | filesBody.add(await MultipartFile.fromBytes( 37 | item.readAsBytesSync(), 38 | filename: item.path, 39 | )); 40 | }); 41 | FormData formData = FormData.fromMap({ 42 | 'files': files, 43 | }); 44 | 45 | Response response = await BaseRepository().sendFormData( 46 | ApiGateway.UPLOAD_MULTIPLE_FILE, 47 | formData, 48 | ); 49 | 50 | if ([200, 201].contains(response.statusCode)) { 51 | List jsonResponses = await response.data['data']; 52 | return jsonResponses 53 | .map((item) => UploadResponseModel.fromMap(item)) 54 | .toList(); 55 | } 56 | 57 | return null; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /lib/src/resources/remote/user_repository.dart: -------------------------------------------------------------------------------- 1 | import 'package:cloudmate/src/models/user.dart'; 2 | import 'package:cloudmate/src/public/api_gateway.dart'; 3 | import 'package:cloudmate/src/resources/base_repository.dart'; 4 | import 'package:dio/dio.dart'; 5 | 6 | class UserRepository { 7 | Future getInfoUser({String? token}) async { 8 | Response response = await BaseRepository().getRoute( 9 | ApiGateway.GET_INFO, 10 | token: token, 11 | ); 12 | if (response.statusCode == 200) { 13 | return UserModel.fromMap(response.data['data'] as Map); 14 | } 15 | return null; 16 | } 17 | 18 | Future updateUser({ 19 | required String firstName, 20 | required String lastName, 21 | required String phone, 22 | required String intro, 23 | }) async { 24 | var body = { 25 | "firstName": firstName, 26 | "lastName": lastName, 27 | "intro": intro, 28 | "phone": phone, 29 | }; 30 | 31 | Response response = await BaseRepository().patchRoute(ApiGateway.USER, body: body); 32 | 33 | print(response.data); 34 | 35 | if ([200, 201].contains(response.statusCode)) { 36 | return UserModel.fromMap(response.data['data'] as Map); 37 | } 38 | return null; 39 | } 40 | 41 | Future updateAvatar({ 42 | required String avatar, 43 | required String blurHash, 44 | }) async { 45 | var body = { 46 | "blurHash": blurHash, 47 | "image": avatar, 48 | }; 49 | Response response = await BaseRepository().patchRoute(ApiGateway.UPDATE_AVATAR, body: body); 50 | print(response.statusCode); 51 | print(response.data.toString()); 52 | if ([200, 201].contains(response.statusCode)) { 53 | return UserModel.fromMap(response.data['data'] as Map); 54 | } 55 | return null; 56 | } 57 | 58 | Future deleteAccount() async { 59 | Response response = await BaseRepository().deleteRoute(ApiGateway.DELETE_ACCOUNT); 60 | print(response.statusCode); 61 | print(response.data.toString()); 62 | if (response.statusCode == 200) { 63 | return true; 64 | } 65 | return false; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /lib/src/routes/app_routes.dart: -------------------------------------------------------------------------------- 1 | class AppRoutes { 2 | static const ROOT = '/'; 3 | 4 | // Home 5 | static const NOTIFICATION = '/notification'; 6 | 7 | // Classes 8 | static const DETAILS_CLASS = '/detailsCLass'; 9 | static const CREATE_CLASS = '/createClass'; 10 | static const LIST_REQUEST = '/listRequest'; 11 | static const LIST_MEMBERS = '/listMembers'; 12 | 13 | // Exam 14 | static const LIST_EXAM = '/listExam'; 15 | static const CREATE_EXAM = '/createExam'; 16 | static const LIST_QUESTION = '/listQuestion'; 17 | static const CREATE_QUESTION = '/createQuestion'; 18 | static const LOBBY_EXAM = '/lobbyExam'; 19 | static const STATISTIC_QUESTION = '/statisticQuestion'; 20 | static const FINAL_STATISTIC_QUESTION = '/finalStatisticQuestion'; 21 | static const HISTORY_EXAM = '/historyExam'; 22 | static const DETAILS_HISTORY_EXAM = '/detailsHistoryExam'; 23 | static const LIST_SHARE_EXAM = '/listShareExam'; 24 | 25 | // Road Map 26 | static const ROAD_MAP = '/roadMap'; 27 | static const CREATE_ROAD_MAP = '/createRoadMap'; 28 | static const CREATE_DEADLINE = '/createDeadline'; 29 | static const DO_EXAM = '/doExam'; 30 | 31 | // Road Map Content 32 | static const ROAD_MAP_CONTENT = '/roadMapContent'; 33 | static const CREATE_ROAD_MAP_CONTENT = '/createRoadMapContent'; 34 | 35 | // User 36 | static const EDIT_INFO_USER = '/editInfoUser'; 37 | 38 | // Conversation 39 | static const CONVERSATION = '/conversation'; 40 | } 41 | -------------------------------------------------------------------------------- /lib/src/routes/scaffold_wrapper.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class ScaffoldWrapper extends StatefulWidget { 4 | final Widget child; 5 | ScaffoldWrapper({required this.child}); 6 | 7 | @override 8 | _ScaffoldWrapperState createState() => _ScaffoldWrapperState(); 9 | } 10 | 11 | class _ScaffoldWrapperState extends State 12 | with AutomaticKeepAliveClientMixin { 13 | _hideKeyboard() { 14 | if (FocusScope.of(context).hasFocus) { 15 | FocusScope.of(context).unfocus(); 16 | } 17 | } 18 | 19 | @override 20 | bool get wantKeepAlive => true; 21 | 22 | @override 23 | Widget build(BuildContext context) { 24 | super.build(context); 25 | return _getBody; 26 | } 27 | 28 | Widget get _getBody { 29 | return GestureDetector( 30 | onTap: () => _hideKeyboard(), 31 | child: widget.child, 32 | ); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /lib/src/routes/slides/fade_route.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class FadeRoute extends PageRouteBuilder { 4 | final Widget? page; 5 | final Duration duration; 6 | 7 | FadeRoute({this.page, this.duration = const Duration(milliseconds: 150)}) 8 | : super( 9 | transitionDuration: duration, 10 | reverseTransitionDuration: duration, 11 | pageBuilder: (BuildContext context, Animation animation, 12 | Animation secondaryAnimation) => 13 | page!, 14 | transitionsBuilder: ( 15 | BuildContext context, 16 | Animation animation, 17 | Animation secondaryAnimation, 18 | Widget child, 19 | ) => 20 | FadeTransition(opacity: animation, child: page), 21 | ); 22 | } 23 | -------------------------------------------------------------------------------- /lib/src/routes/slides/slide_from_bottom_route.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class SlideFromBottomRoute extends PageRouteBuilder { 4 | final Widget? page; 5 | final Duration duration; 6 | final RouteSettings settings; 7 | SlideFromBottomRoute( 8 | {required this.settings, 9 | this.page, 10 | this.duration = const Duration(milliseconds: 200)}) 11 | : super( 12 | settings: settings, 13 | transitionDuration: duration, 14 | reverseTransitionDuration: duration, 15 | pageBuilder: ( 16 | BuildContext context, 17 | Animation animation, 18 | Animation secondaryAnimation, 19 | ) => 20 | page!, 21 | transitionsBuilder: ( 22 | BuildContext context, 23 | Animation animation, 24 | Animation secondaryAnimation, 25 | Widget child, 26 | ) => 27 | SlideTransition( 28 | position: Tween( 29 | begin: const Offset(0, 1), 30 | end: Offset.zero, 31 | ).animate(animation), 32 | child: child, 33 | ), 34 | ); 35 | } 36 | -------------------------------------------------------------------------------- /lib/src/routes/slides/slide_from_left_route.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class SlideFromLeftRoute extends PageRouteBuilder { 4 | final Widget? page; 5 | final Duration duration; 6 | final RouteSettings settings; 7 | SlideFromLeftRoute( 8 | {required this.settings, 9 | this.page, 10 | this.duration = const Duration(milliseconds: 200)}) 11 | : super( 12 | settings: settings, 13 | transitionDuration: duration, 14 | reverseTransitionDuration: duration, 15 | pageBuilder: ( 16 | BuildContext context, 17 | Animation animation, 18 | Animation secondaryAnimation, 19 | ) => 20 | page!, 21 | transitionsBuilder: ( 22 | BuildContext context, 23 | Animation animation, 24 | Animation secondaryAnimation, 25 | Widget child, 26 | ) => 27 | SlideTransition( 28 | position: Tween( 29 | begin: const Offset(-1, 0), 30 | end: Offset.zero, 31 | ).animate(animation), 32 | child: child, 33 | ), 34 | ); 35 | } 36 | -------------------------------------------------------------------------------- /lib/src/routes/slides/slide_from_right_route.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class SlideFromRightRoute extends PageRouteBuilder { 4 | final Widget? page; 5 | final Duration duration; 6 | final RouteSettings settings; 7 | SlideFromRightRoute( 8 | {required this.settings, 9 | this.page, 10 | this.duration = const Duration(milliseconds: 200)}) 11 | : super( 12 | settings: settings, 13 | pageBuilder: (context, animation, anotherAnimation) => page!, 14 | transitionDuration: duration, 15 | reverseTransitionDuration: Duration(milliseconds: 340), 16 | transitionsBuilder: (context, animation, anotherAnimation, child) { 17 | animation = CurvedAnimation( 18 | curve: Curves.fastLinearToSlowEaseIn, 19 | parent: animation, 20 | reverseCurve: Curves.fastOutSlowIn); 21 | return SlideTransition( 22 | position: Tween(begin: Offset(1.0, 0.0), end: Offset(0.0, 0.0)) 23 | .animate(animation), 24 | child: page, 25 | ); 26 | }); 27 | } 28 | -------------------------------------------------------------------------------- /lib/src/routes/slides/slide_from_top_route.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class SlideFromTopRoute extends PageRouteBuilder { 4 | final Widget? page; 5 | final Duration duration; 6 | final RouteSettings settings; 7 | SlideFromTopRoute( 8 | {required this.settings, 9 | this.page, 10 | this.duration = const Duration(milliseconds: 200)}) 11 | : super( 12 | settings: settings, 13 | transitionDuration: duration, 14 | reverseTransitionDuration: duration, 15 | pageBuilder: ( 16 | BuildContext context, 17 | Animation animation, 18 | Animation secondaryAnimation, 19 | ) => 20 | page!, 21 | transitionsBuilder: ( 22 | BuildContext context, 23 | Animation animation, 24 | Animation secondaryAnimation, 25 | Widget child, 26 | ) => 27 | SlideTransition( 28 | position: Tween( 29 | begin: const Offset(0, -1), 30 | end: Offset.zero, 31 | ).animate(animation), 32 | child: child, 33 | ), 34 | ); 35 | } 36 | -------------------------------------------------------------------------------- /lib/src/services/firebase_firestore/attendance_firestore.dart: -------------------------------------------------------------------------------- 1 | import 'package:cloud_firestore/cloud_firestore.dart'; 2 | import 'package:cloudmate/src/blocs/app_bloc.dart'; 3 | import 'package:cloudmate/src/models/user.dart'; 4 | 5 | class AttendanceFirestore { 6 | Future> getAttendance(String roadmapContentId) async { 7 | QuerySnapshot snapshot = await FirebaseFirestore.instance 8 | .collection('attendances') 9 | .where('roadmapContentId', isEqualTo: roadmapContentId) 10 | .get(); 11 | 12 | List users = []; 13 | 14 | for (int index = 0; index < snapshot.docs.length; index++) { 15 | QuerySnapshot snapshotUser = await FirebaseFirestore.instance 16 | .collection('users') 17 | .where('_id', isEqualTo: snapshot.docs[index]['userId']) 18 | .get(); 19 | 20 | if (snapshotUser.docs.isNotEmpty) { 21 | users.add(UserModel.fromMap(snapshotUser.docs.first)); 22 | } 23 | } 24 | 25 | return users; 26 | } 27 | 28 | Future createAttendance(String roadmapContentId) async { 29 | await FirebaseFirestore.instance.collection('attendances').add({ 30 | 'roadmapContentId': roadmapContentId, 31 | 'userId': AppBloc.authBloc.userModel?.id ?? '', 32 | }); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /lib/src/services/firebase_firestore/post_firestore.dart: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Py-Ec/cloudmate-classroom-flutter/d1d241a3416e19b192dfd9743e4ce12e0d05357f/lib/src/services/firebase_firestore/post_firestore.dart -------------------------------------------------------------------------------- /lib/src/services/firebase_storage/upload_file.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | import 'package:firebase_storage/firebase_storage.dart'; 3 | 4 | class StorageService { 5 | Future uploadFileToStorage(String path) async { 6 | String fileName = DateTime.now().toString(); 7 | Reference ref = FirebaseStorage.instance.ref().child('Files').child(fileName); 8 | UploadTask uploadTask = ref.putFile(File(path)); 9 | TaskSnapshot snapshot = await uploadTask; 10 | var downUrl = await snapshot.ref.getDownloadURL(); 11 | String url = downUrl.toString(); 12 | return url; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /lib/src/services/payment/momo_payment.dart: -------------------------------------------------------------------------------- 1 | import 'package:cloudmate/src/routes/app_pages.dart'; 2 | import 'package:momo_vn/momo_vn.dart'; 3 | 4 | class MomoAppPayment { 5 | MomoVn? _momoPay; 6 | 7 | handlePaymentMomo( 8 | {required int amount, 9 | required Function(PaymentResponse) handleFinished}) { 10 | MomoPaymentInfo options = MomoPaymentInfo( 11 | merchantName: "Cloudmate", 12 | appScheme: "momoiwtv20220329", 13 | merchantCode: 'MOMOIWTV20220329', 14 | partnerCode: 'MOMOIWTV20220329', 15 | amount: amount, 16 | orderId: DateTime.now().microsecondsSinceEpoch.toString(), 17 | orderLabel: 'THANH TOÁN KHOÁ HỌC CLOUDMATE', 18 | merchantNameLabel: "THANH TOÁN KHOÁ HỌC CLOUDMATE", 19 | fee: 0, 20 | description: 'Thanh toán khoá học trên Cloudmate', 21 | partner: 'merchant', 22 | isTestMode: true, 23 | extra: "{\"key1\":\"value1\",\"key2\":\"value2\"}", 24 | ); 25 | try { 26 | _momoPay = MomoVn(); 27 | _momoPay?.on( 28 | MomoVn.EVENT_PAYMENT_SUCCESS, 29 | (res) => _handlePaymentSuccess( 30 | response: res, 31 | handleFinished: handleFinished, 32 | ), 33 | ); 34 | _momoPay?.on(MomoVn.EVENT_PAYMENT_ERROR, _handlePaymentError); 35 | _momoPay?.open(options); 36 | } catch (e) { 37 | print(e.toString()); 38 | } 39 | } 40 | 41 | void _handlePaymentSuccess( 42 | {required PaymentResponse response, 43 | required Function(PaymentResponse) handleFinished}) { 44 | handleFinished(response); 45 | _momoPay?.clear(); 46 | } 47 | 48 | void _handlePaymentError(PaymentResponse response) { 49 | AppNavigator.pop(); 50 | _momoPay?.clear(); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /lib/src/themes/font_family.dart: -------------------------------------------------------------------------------- 1 | class FontFamily { 2 | FontFamily._(); 3 | 4 | static const String lato = 'Lato'; 5 | static const String allison = 'Allison'; 6 | static const String dancing = 'DancingScript'; 7 | } 8 | -------------------------------------------------------------------------------- /lib/src/themes/theme_service.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:flutter/material.dart'; 4 | import 'package:flutter/services.dart'; 5 | import 'package:get_storage/get_storage.dart'; 6 | 7 | enum ThemeOptions { light, dark } 8 | 9 | class ThemeService extends ChangeNotifier { 10 | static ThemeOptions themeOptions = ThemeOptions.light; 11 | static ThemeMode currentTheme = ThemeMode.light; 12 | static final systemBrightness = SystemUiOverlayStyle( 13 | statusBarColor: Colors.transparent, 14 | ); 15 | final _getStorage = GetStorage(); 16 | final storageKey = 'isDarkMode'; 17 | 18 | switchStatusColor() { 19 | SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle( 20 | statusBarColor: Colors.transparent, 21 | statusBarBrightness: Platform.isIOS 22 | ? (isSavedDarkMode() ? Brightness.dark : Brightness.light) 23 | : (isSavedDarkMode() ? Brightness.light : Brightness.dark), 24 | statusBarIconBrightness: Platform.isIOS 25 | ? (isSavedDarkMode() ? Brightness.dark : Brightness.light) 26 | : (isSavedDarkMode() ? Brightness.light : Brightness.dark), 27 | )); 28 | } 29 | 30 | ThemeMode getThemeMode() { 31 | switchStatusColor(); 32 | return isSavedDarkMode() ? ThemeMode.dark : ThemeMode.light; 33 | } 34 | 35 | bool isSavedDarkMode() { 36 | return _getStorage.read(storageKey) ?? false; 37 | } 38 | 39 | void saveThemeMode(bool isDarkMode) async { 40 | _getStorage.write(storageKey, isDarkMode); 41 | } 42 | 43 | void changeThemeMode() { 44 | saveThemeMode(!isSavedDarkMode()); 45 | switchStatusColor(); 46 | notifyListeners(); 47 | } 48 | } 49 | 50 | ThemeService themeService = ThemeService(); 51 | -------------------------------------------------------------------------------- /lib/src/ui/authentication/authentication_screen.dart: -------------------------------------------------------------------------------- 1 | import 'package:cloudmate/src/ui/authentication/screens/login_screen.dart'; 2 | import 'package:cloudmate/src/ui/authentication/screens/register_screen.dart'; 3 | import 'package:flutter/material.dart'; 4 | 5 | class AuthenticateScreen extends StatefulWidget { 6 | @override 7 | State createState() => _AuthenticateScreenState(); 8 | } 9 | 10 | class _AuthenticateScreenState extends State { 11 | bool signIn = true; 12 | @override 13 | void initState() { 14 | super.initState(); 15 | } 16 | 17 | switchScreen() { 18 | setState(() { 19 | signIn = !signIn; 20 | }); 21 | } 22 | 23 | @override 24 | Widget build(BuildContext context) { 25 | return signIn 26 | ? LoginPage( 27 | toggleView: switchScreen, 28 | ) 29 | : RegisterPage( 30 | toggleView: switchScreen, 31 | ); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /lib/src/ui/calendar/widgets/dot_below_date.dart: -------------------------------------------------------------------------------- 1 | import 'package:cloudmate/src/themes/app_colors.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:cloudmate/src/utils/sizer_custom/sizer.dart'; 4 | 5 | class DotBelowDate extends StatelessWidget { 6 | final int quantity; 7 | const DotBelowDate({required this.quantity}); 8 | @override 9 | Widget build(BuildContext context) { 10 | return Row( 11 | mainAxisAlignment: MainAxisAlignment.center, 12 | crossAxisAlignment: CrossAxisAlignment.center, 13 | children: [ 14 | ...List.generate( 15 | quantity, 16 | (index) => Padding( 17 | padding: EdgeInsets.only(right: quantity == 1 || index == quantity - 1 ? 0 : 1.25.sp), 18 | child: Container( 19 | height: 2.sp, 20 | width: 2.sp, 21 | decoration: BoxDecoration( 22 | color: colorPrimary, 23 | shape: BoxShape.circle, 24 | ), 25 | ), 26 | ), 27 | ), 28 | ], 29 | ); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /lib/src/ui/classes/blocs/class/class_event.dart: -------------------------------------------------------------------------------- 1 | part of 'class_bloc.dart'; 2 | 3 | @immutable 4 | abstract class ClassEvent {} 5 | 6 | class TransitionToClassScreen extends ClassEvent {} 7 | 8 | class GetClasses extends ClassEvent {} 9 | 10 | class GetRecommendClasses extends ClassEvent {} 11 | 12 | class CreateClass extends ClassEvent { 13 | final BuildContext context; 14 | final String name; 15 | final String topic; 16 | final String intro; 17 | final double price; 18 | CreateClass({ 19 | required this.context, 20 | required this.name, 21 | required this.intro, 22 | required this.topic, 23 | required this.price, 24 | }); 25 | } 26 | 27 | class EditClass extends ClassEvent { 28 | final BuildContext context; 29 | final String id; 30 | final String name; 31 | final String topic; 32 | final String intro; 33 | final double price; 34 | final List setOfQuestionShare; 35 | 36 | EditClass({ 37 | required this.context, 38 | required this.id, 39 | required this.name, 40 | required this.intro, 41 | required this.topic, 42 | required this.setOfQuestionShare, 43 | required this.price, 44 | }); 45 | } 46 | 47 | class GetMemberClass extends ClassEvent { 48 | final String classId; 49 | GetMemberClass({required this.classId}); 50 | } 51 | 52 | class JoinClass extends ClassEvent { 53 | final BuildContext context; 54 | final String classId; 55 | final double amount; 56 | final String senderPhone; 57 | JoinClass({ 58 | required this.classId, 59 | required this.context, 60 | required this.senderPhone, 61 | required this.amount, 62 | }); 63 | } 64 | 65 | class LeaveClass extends ClassEvent { 66 | final BuildContext context; 67 | final String classId; 68 | LeaveClass({required this.classId, required this.context}); 69 | } 70 | 71 | class UpdateImageClass extends ClassEvent { 72 | final File image; 73 | final String id; 74 | UpdateImageClass({required this.image, required this.id}); 75 | } 76 | 77 | class ClearClass extends ClassEvent {} 78 | -------------------------------------------------------------------------------- /lib/src/ui/classes/blocs/class/class_state.dart: -------------------------------------------------------------------------------- 1 | part of 'class_bloc.dart'; 2 | 3 | @immutable 4 | abstract class ClassState { 5 | List get props => []; 6 | } 7 | 8 | class ClassInitial extends ClassState { 9 | @override 10 | List get props => [[]]; 11 | } 12 | 13 | class GettingClasses extends ClassState { 14 | final List listClasses; 15 | final List listRecommend; 16 | final bool isOver; 17 | GettingClasses({ 18 | required this.listClasses, 19 | required this.listRecommend, 20 | this.isOver = false, 21 | }); 22 | 23 | @override 24 | List get props => [listClasses, listRecommend]; 25 | } 26 | 27 | class GetClassesDone extends ClassState { 28 | final List listClasses; 29 | final List listRecommend; 30 | final bool isOver; 31 | GetClassesDone({ 32 | required this.listClasses, 33 | required this.listRecommend, 34 | this.isOver = false, 35 | }); 36 | 37 | @override 38 | List get props => [listClasses, listRecommend]; 39 | } 40 | -------------------------------------------------------------------------------- /lib/src/ui/classes/blocs/do_exam/do_exam_event.dart: -------------------------------------------------------------------------------- 1 | part of 'do_exam_bloc.dart'; 2 | 3 | @immutable 4 | abstract class DoExamEvent {} 5 | 6 | class CreateQuizEvent extends DoExamEvent { 7 | final String examId; 8 | final String classId; 9 | final String title; 10 | final String description; 11 | CreateQuizEvent({ 12 | required this.examId, 13 | required this.classId, 14 | required this.title, 15 | required this.description, 16 | }); 17 | } 18 | 19 | class CreateQuizSuccessEvent extends DoExamEvent { 20 | final String roomId; 21 | CreateQuizSuccessEvent({required this.roomId}); 22 | } 23 | 24 | class StartQuizEvent extends DoExamEvent {} 25 | 26 | class JoinQuizEvent extends DoExamEvent { 27 | final String roomId; 28 | 29 | JoinQuizEvent({required this.roomId}); 30 | } 31 | 32 | class JoinQuizSuccessEvent extends DoExamEvent { 33 | final List users; 34 | 35 | JoinQuizSuccessEvent({required this.users}); 36 | } 37 | 38 | class NewUserJoined extends DoExamEvent { 39 | final UserModel user; 40 | NewUserJoined({required this.user}); 41 | } 42 | 43 | class LeaveUserJoined extends DoExamEvent { 44 | final String userId; 45 | LeaveUserJoined({required this.userId}); 46 | } 47 | 48 | class UpdateStatisticEvent extends DoExamEvent { 49 | final StatisticModel statistic; 50 | UpdateStatisticEvent({required this.statistic}); 51 | } 52 | 53 | class AnswerQuestionEvent extends DoExamEvent { 54 | final String answer; 55 | AnswerQuestionEvent({required this.answer}); 56 | } 57 | 58 | class SubmitAnswerDaDEvent extends DoExamEvent { 59 | final List answers; 60 | SubmitAnswerDaDEvent({required this.answers}); 61 | } 62 | 63 | class TakeQuestionEvent extends DoExamEvent { 64 | final QuestionModel question; 65 | final String indexQuestion; 66 | TakeQuestionEvent({required this.question, required this.indexQuestion}); 67 | } 68 | 69 | class FinishQuizEvent extends DoExamEvent { 70 | final FinalStatisticModel finalStatistic; 71 | FinishQuizEvent({required this.finalStatistic}); 72 | } 73 | 74 | class QuitQuizEvent extends DoExamEvent {} 75 | 76 | class StartPingEvent extends DoExamEvent {} 77 | 78 | class EndPingEvent extends DoExamEvent {} 79 | -------------------------------------------------------------------------------- /lib/src/ui/classes/blocs/do_exam/do_exam_state.dart: -------------------------------------------------------------------------------- 1 | part of 'do_exam_bloc.dart'; 2 | 3 | @immutable 4 | abstract class DoExamState {} 5 | 6 | class DoExamInitial extends DoExamState {} 7 | 8 | class InLobby extends DoExamState { 9 | final List users; 10 | InLobby({required this.users}); 11 | } 12 | 13 | class DoExamLoading extends DoExamState {} 14 | 15 | class DoingQuestion extends DoExamState { 16 | final QuestionModel? question; 17 | final int ping; 18 | DoingQuestion({this.question, required this.ping}); 19 | } 20 | 21 | class ShowStatistic extends DoExamState { 22 | final StatisticModel statistic; 23 | ShowStatistic({required this.statistic}); 24 | } 25 | 26 | class FinishStatistic extends DoExamState { 27 | final FinalStatisticModel statistic; 28 | FinishStatistic({required this.statistic}); 29 | } 30 | -------------------------------------------------------------------------------- /lib/src/ui/classes/blocs/exam/exam_event.dart: -------------------------------------------------------------------------------- 1 | part of 'exam_bloc.dart'; 2 | 3 | @immutable 4 | abstract class ExamEvent {} 5 | 6 | class GetListExamEvent extends ExamEvent { 7 | final String classId; 8 | GetListExamEvent({required this.classId}); 9 | } 10 | 11 | class CreateExamEvent extends ExamEvent { 12 | final BuildContext context; 13 | final String classId; 14 | final String name; 15 | final String description; 16 | CreateExamEvent({ 17 | required this.context, 18 | required this.classId, 19 | required this.name, 20 | required this.description, 21 | }); 22 | } 23 | 24 | class EditExamEvent extends ExamEvent { 25 | final BuildContext context; 26 | final String examId; 27 | final String name; 28 | final String description; 29 | EditExamEvent({ 30 | required this.context, 31 | required this.examId, 32 | required this.name, 33 | required this.description, 34 | }); 35 | } 36 | 37 | class DeleteExamEvent extends ExamEvent { 38 | final BuildContext context; 39 | final String examId; 40 | DeleteExamEvent({ 41 | required this.context, 42 | required this.examId, 43 | }); 44 | } 45 | -------------------------------------------------------------------------------- /lib/src/ui/classes/blocs/exam/exam_state.dart: -------------------------------------------------------------------------------- 1 | part of 'exam_bloc.dart'; 2 | 3 | @immutable 4 | abstract class ExamState { 5 | List get props => []; 6 | } 7 | 8 | class ExamInitial extends ExamState {} 9 | 10 | class GettingExamState extends ExamState { 11 | final List listExam; 12 | final bool isOver; 13 | GettingExamState({required this.listExam, required this.isOver}); 14 | 15 | @override 16 | List get props => [listExam, isOver]; 17 | } 18 | 19 | class GetExamDoneState extends ExamState { 20 | final List listExam; 21 | final bool isOver; 22 | GetExamDoneState({required this.listExam, required this.isOver}); 23 | 24 | @override 25 | List get props => [listExam, isOver]; 26 | } 27 | -------------------------------------------------------------------------------- /lib/src/ui/classes/blocs/history_quiz/history_quiz_bloc.dart: -------------------------------------------------------------------------------- 1 | import 'package:bloc/bloc.dart'; 2 | import 'package:cloudmate/src/models/history_quiz_model.dart'; 3 | import 'package:cloudmate/src/resources/remote/history_quiz_repository.dart'; 4 | import 'package:meta/meta.dart'; 5 | 6 | part 'history_quiz_event.dart'; 7 | part 'history_quiz_state.dart'; 8 | 9 | class HistoryQuizBloc extends Bloc { 10 | HistoryQuizBloc() : super(HistoryQuizInitial()); 11 | 12 | List _historyQuizList = []; 13 | 14 | @override 15 | Stream mapEventToState(HistoryQuizEvent event) async* { 16 | if (event is GetHistoryQuizEvent) { 17 | yield HistoryQuizInitial(); 18 | await _fetchHistoryQuiz(event.classId); 19 | yield GetDoneHistoryQuiz(_historyQuizList); 20 | } 21 | } 22 | 23 | // MARK: - private methods 24 | Future _fetchHistoryQuiz(String classId) async { 25 | List historyQuizList = 26 | await HistoryQuizRepository().getHistory(classId: classId); 27 | _historyQuizList = historyQuizList; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /lib/src/ui/classes/blocs/history_quiz/history_quiz_event.dart: -------------------------------------------------------------------------------- 1 | part of 'history_quiz_bloc.dart'; 2 | 3 | @immutable 4 | abstract class HistoryQuizEvent {} 5 | 6 | class GetHistoryQuizEvent extends HistoryQuizEvent { 7 | final String classId; 8 | GetHistoryQuizEvent({required this.classId}); 9 | } 10 | -------------------------------------------------------------------------------- /lib/src/ui/classes/blocs/history_quiz/history_quiz_state.dart: -------------------------------------------------------------------------------- 1 | part of 'history_quiz_bloc.dart'; 2 | 3 | @immutable 4 | abstract class HistoryQuizState { 5 | List get props => []; 6 | } 7 | 8 | class HistoryQuizInitial extends HistoryQuizState {} 9 | 10 | class GetDoneHistoryQuiz extends HistoryQuizState { 11 | final List quizs; 12 | GetDoneHistoryQuiz(this.quizs); 13 | 14 | @override 15 | List get props => [quizs]; 16 | } 17 | -------------------------------------------------------------------------------- /lib/src/ui/classes/blocs/member/member_bloc.dart: -------------------------------------------------------------------------------- 1 | import 'package:bloc/bloc.dart'; 2 | import 'package:cloudmate/src/models/user.dart'; 3 | import 'package:meta/meta.dart'; 4 | 5 | part 'member_event.dart'; 6 | part 'member_state.dart'; 7 | 8 | class MemberBloc extends Bloc { 9 | MemberBloc() : super(MemberInitial()); 10 | 11 | List listMember = []; 12 | 13 | @override 14 | Stream mapEventToState(MemberEvent event) async* {} 15 | } 16 | 17 | // Mark: - Event handle function 18 | 19 | // Future _getMembers(String classId) async {} 20 | 21 | // Future _removeMember(String classId, String memberId) async {} 22 | -------------------------------------------------------------------------------- /lib/src/ui/classes/blocs/member/member_event.dart: -------------------------------------------------------------------------------- 1 | part of 'member_bloc.dart'; 2 | 3 | @immutable 4 | abstract class MemberEvent {} 5 | -------------------------------------------------------------------------------- /lib/src/ui/classes/blocs/member/member_state.dart: -------------------------------------------------------------------------------- 1 | part of 'member_bloc.dart'; 2 | 3 | @immutable 4 | abstract class MemberState {} 5 | 6 | class MemberInitial extends MemberState {} 7 | -------------------------------------------------------------------------------- /lib/src/ui/classes/blocs/question/question_event.dart: -------------------------------------------------------------------------------- 1 | part of 'question_bloc.dart'; 2 | 3 | @immutable 4 | abstract class QuestionEvent {} 5 | 6 | class GetListQuestionEvent extends QuestionEvent { 7 | final String examId; 8 | GetListQuestionEvent({required this.examId}); 9 | } 10 | 11 | class CreateQuestionEvent extends QuestionEvent { 12 | final BuildContext context; 13 | final String examId; 14 | final int duration; 15 | final List corrects; 16 | final List answers; 17 | final String question; 18 | final int score; 19 | final File? banner; 20 | final File? audio; 21 | final QuestionType type; 22 | 23 | CreateQuestionEvent({ 24 | required this.answers, 25 | required this.context, 26 | required this.corrects, 27 | required this.duration, 28 | required this.examId, 29 | required this.question, 30 | required this.score, 31 | required this.banner, 32 | required this.audio, 33 | required this.type, 34 | }); 35 | } 36 | 37 | class UpdateQuestionEvent extends QuestionEvent { 38 | final BuildContext context; 39 | final int duration; 40 | final List corrects; 41 | final List answers; 42 | final String question; 43 | final String questionId; 44 | final int score; 45 | final File? banner; 46 | 47 | UpdateQuestionEvent({ 48 | required this.answers, 49 | required this.context, 50 | required this.corrects, 51 | required this.duration, 52 | required this.question, 53 | required this.questionId, 54 | required this.score, 55 | required this.banner, 56 | }); 57 | } 58 | 59 | class DeleteQuestionEvent extends QuestionEvent { 60 | final BuildContext context; 61 | final String questionId; 62 | DeleteQuestionEvent({required this.questionId, required this.context}); 63 | } 64 | 65 | class ImportQuestionsEvent extends QuestionEvent { 66 | final BuildContext context; 67 | final String examId; 68 | final List questions; 69 | ImportQuestionsEvent({required this.context, required this.examId, required this.questions}); 70 | } 71 | -------------------------------------------------------------------------------- /lib/src/ui/classes/blocs/question/question_state.dart: -------------------------------------------------------------------------------- 1 | part of 'question_bloc.dart'; 2 | 3 | @immutable 4 | abstract class QuestionState { 5 | List get props => []; 6 | } 7 | 8 | class QuestionInitial extends QuestionState {} 9 | 10 | class GettingQuestion extends QuestionState { 11 | final List listQuestion; 12 | final bool isOver; 13 | GettingQuestion({required this.listQuestion, required this.isOver}); 14 | 15 | @override 16 | List get props => [listQuestion]; 17 | } 18 | 19 | class GetDoneQuestion extends QuestionState { 20 | final List listQuestion; 21 | final bool isOver; 22 | GetDoneQuestion({required this.listQuestion, required this.isOver}); 23 | 24 | @override 25 | List get props => [listQuestion]; 26 | } 27 | -------------------------------------------------------------------------------- /lib/src/ui/classes/blocs/road_map/road_map_event.dart: -------------------------------------------------------------------------------- 1 | part of 'road_map_bloc.dart'; 2 | 3 | @immutable 4 | abstract class RoadMapEvent {} 5 | 6 | class GetRoadMapEvent extends RoadMapEvent { 7 | final String classId; 8 | GetRoadMapEvent({required this.classId}); 9 | } 10 | 11 | class CreateRoadMapEvent extends RoadMapEvent { 12 | final BuildContext context; 13 | final String classId; 14 | final String name; 15 | final String description; 16 | CreateRoadMapEvent({ 17 | required this.context, 18 | required this.classId, 19 | required this.name, 20 | required this.description, 21 | }); 22 | } 23 | 24 | class UpdateRoadMapEvent extends RoadMapEvent { 25 | final String id; 26 | final String name; 27 | final String description; 28 | final BuildContext context; 29 | UpdateRoadMapEvent({ 30 | required this.id, 31 | required this.name, 32 | required this.description, 33 | required this.context, 34 | }); 35 | } 36 | 37 | class DeleteRoadMapEvent extends RoadMapEvent { 38 | final String id; 39 | DeleteRoadMapEvent({required this.id}); 40 | } 41 | -------------------------------------------------------------------------------- /lib/src/ui/classes/blocs/road_map/road_map_state.dart: -------------------------------------------------------------------------------- 1 | part of 'road_map_bloc.dart'; 2 | 3 | @immutable 4 | abstract class RoadMapState { 5 | List get props => []; 6 | } 7 | 8 | class RoadMapInitial extends RoadMapState {} 9 | 10 | class GettingRoadMap extends RoadMapState { 11 | final List roadMaps; 12 | 13 | GettingRoadMap({required this.roadMaps}); 14 | 15 | @override 16 | List get props => [roadMaps]; 17 | } 18 | 19 | class GetDoneRoadMap extends RoadMapState { 20 | final List roadMaps; 21 | 22 | GetDoneRoadMap({required this.roadMaps}); 23 | 24 | @override 25 | List get props => [roadMaps]; 26 | } 27 | -------------------------------------------------------------------------------- /lib/src/ui/classes/blocs/road_map_content/road_map_content_event.dart: -------------------------------------------------------------------------------- 1 | part of 'road_map_content_bloc.dart'; 2 | 3 | @immutable 4 | abstract class RoadMapContentEvent {} 5 | 6 | class CreateRoadMapContentEvent extends RoadMapContentEvent { 7 | final String classId; 8 | final String roadMapId; 9 | final String name; 10 | final DateTime startTime; 11 | final DateTime endTime; 12 | final BuildContext context; 13 | final RoadMapContentType type; 14 | final List? fileExtensions; 15 | CreateRoadMapContentEvent({ 16 | required this.classId, 17 | required this.roadMapId, 18 | required this.name, 19 | required this.startTime, 20 | required this.endTime, 21 | required this.context, 22 | required this.type, 23 | required this.fileExtensions, 24 | }); 25 | } 26 | 27 | class GetRoadMapContentEvent extends RoadMapContentEvent { 28 | final String classId; 29 | final String roadMapId; 30 | GetRoadMapContentEvent({required this.classId, required this.roadMapId}); 31 | } 32 | -------------------------------------------------------------------------------- /lib/src/ui/classes/blocs/road_map_content/road_map_content_state.dart: -------------------------------------------------------------------------------- 1 | part of 'road_map_content_bloc.dart'; 2 | 3 | @immutable 4 | abstract class RoadMapContentState { 5 | List get props => []; 6 | } 7 | 8 | class RoadMapContentInitial extends RoadMapContentState {} 9 | 10 | class GettingRoadMapContent extends RoadMapContentState { 11 | final List roadMapContentList; 12 | 13 | GettingRoadMapContent({required this.roadMapContentList}); 14 | 15 | @override 16 | List get props => [roadMapContentList]; 17 | } 18 | 19 | class GetDoneRoadMapContent extends RoadMapContentState { 20 | final List roadMapContentList; 21 | 22 | GetDoneRoadMapContent({required this.roadMapContentList}); 23 | 24 | @override 25 | List get props => [roadMapContentList]; 26 | } 27 | -------------------------------------------------------------------------------- /lib/src/ui/classes/screens/list_request_screen.dart: -------------------------------------------------------------------------------- 1 | import 'package:cloudmate/src/routes/app_pages.dart'; 2 | import 'package:cloudmate/src/themes/font_family.dart'; 3 | import 'package:cloudmate/src/themes/theme_service.dart'; 4 | import 'package:flutter/material.dart'; 5 | import 'package:phosphor_flutter/phosphor_flutter.dart'; 6 | import 'package:cloudmate/src/utils/sizer_custom/sizer.dart'; 7 | 8 | class ListRequestClassScreen extends StatefulWidget { 9 | @override 10 | State createState() => _ListRequestClassScreenState(); 11 | } 12 | 13 | class _ListRequestClassScreenState extends State { 14 | @override 15 | Widget build(BuildContext context) { 16 | return Scaffold( 17 | resizeToAvoidBottomInset: false, 18 | appBar: AppBar( 19 | systemOverlayStyle: ThemeService.systemBrightness, 20 | centerTitle: true, 21 | elevation: .0, 22 | leading: IconButton( 23 | onPressed: () { 24 | AppNavigator.pop(); 25 | }, 26 | icon: Icon( 27 | PhosphorIcons.caretLeft, 28 | size: 20.sp, 29 | ), 30 | ), 31 | title: Text( 32 | 'Yêu cầu tham gia', 33 | style: TextStyle( 34 | fontSize: 15.sp, 35 | fontFamily: FontFamily.lato, 36 | fontWeight: FontWeight.bold, 37 | color: Theme.of(context).textTheme.bodyLarge!.color, 38 | ), 39 | ), 40 | ), 41 | body: Container( 42 | height: 100.h, 43 | width: 100.w, 44 | child: Column( 45 | children: [ 46 | SizedBox(height: 2.5.sp), 47 | Divider( 48 | height: .25, 49 | thickness: .25, 50 | ), 51 | SizedBox(height: 6.sp), 52 | ], 53 | ), 54 | ), 55 | ); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /lib/src/ui/classes/screens/new_post_screen.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class NewPostScreen extends StatefulWidget { 4 | @override 5 | State createState() => _NewPostScreenState(); 6 | } 7 | 8 | class _NewPostScreenState extends State { 9 | @override 10 | Widget build(BuildContext context) { 11 | return Scaffold( 12 | appBar: AppBar( 13 | title: Text('New Post'), 14 | ), 15 | body: Center( 16 | child: Text('New Post'), 17 | ), 18 | ); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /lib/src/ui/classes/widgets/character_counter.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:percent_indicator/circular_percent_indicator.dart'; 3 | 4 | class CharacterCounter extends StatefulWidget { 5 | final int min; 6 | final int value; 7 | 8 | const CharacterCounter({ 9 | required this.min, 10 | required this.value, 11 | }); 12 | 13 | @override 14 | _CharacterCounterState createState() => _CharacterCounterState(); 15 | } 16 | 17 | class _CharacterCounterState extends State { 18 | @override 19 | Widget build(BuildContext context) { 20 | final _min = widget.min; 21 | final _value = widget.value; 22 | final _percentage = _value / _min; 23 | 24 | return CircularPercentIndicator( 25 | radius: 25, 26 | lineWidth: 3, 27 | progressColor: _tweetCharsCountExceeded 28 | ? Colors.red 29 | : Theme.of(context).primaryColor, 30 | percent: _percentage > 1 ? 1 : _percentage, 31 | center: Visibility( 32 | visible: _tweetCharsCountExceeded, 33 | child: Text( 34 | ((_min - _value) * -1).toString(), 35 | style: TextStyle(fontSize: 10), 36 | ), 37 | ), 38 | ); 39 | } 40 | 41 | bool get _tweetCharsCountExceeded => widget.value > widget.min; 42 | } 43 | -------------------------------------------------------------------------------- /lib/src/ui/classes/widgets/lobby_user_card.dart: -------------------------------------------------------------------------------- 1 | import 'package:cloudmate/src/helpers/string.dart'; 2 | import 'package:cloudmate/src/models/user.dart'; 3 | import 'package:cloudmate/src/themes/font_family.dart'; 4 | import 'package:flutter/material.dart'; 5 | import 'package:cloudmate/src/utils/sizer_custom/sizer.dart'; 6 | 7 | class LobbyUserCard extends StatelessWidget { 8 | final UserModel userModel; 9 | const LobbyUserCard({required this.userModel}); 10 | 11 | @override 12 | Widget build(BuildContext context) { 13 | return Column( 14 | crossAxisAlignment: CrossAxisAlignment.center, 15 | children: [ 16 | Container( 17 | height: 36.sp, 18 | width: 36.sp, 19 | padding: EdgeInsets.all(1.25.sp), 20 | decoration: BoxDecoration( 21 | shape: BoxShape.circle, 22 | border: Border.all( 23 | color: Theme.of(context).primaryColor, 24 | width: 1.5.sp, 25 | ), 26 | ), 27 | child: Container( 28 | decoration: BoxDecoration( 29 | shape: BoxShape.circle, 30 | image: DecorationImage( 31 | image: NetworkImage(userModel.image!), 32 | fit: BoxFit.cover, 33 | ), 34 | ), 35 | ), 36 | ), 37 | SizedBox(height: 6.sp), 38 | Text( 39 | userModel.lastName!.formatName(12), 40 | style: TextStyle( 41 | fontFamily: FontFamily.lato, 42 | fontSize: 9.sp, 43 | fontWeight: FontWeight.w400, 44 | ), 45 | ), 46 | ], 47 | ); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /lib/src/ui/common/dialogs/dialog_loading.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | Future dialogAnimationWrapper( 4 | {context, 5 | slideFrom = 'left', 6 | child, 7 | duration = 200, 8 | paddingTop = 0.0, 9 | paddingBottom = 0.0, 10 | paddingHorizontal = 15.0, 11 | dismissible = true, 12 | borderRadius = 25.0, 13 | barrierColor, 14 | maxWidth = 320.0}) { 15 | var beginOffset = Offset(-1, 0); 16 | switch (slideFrom) { 17 | case 'left': 18 | beginOffset = Offset(-1, 0); 19 | break; 20 | case 'right': 21 | beginOffset = Offset(1, 0); 22 | break; 23 | case 'top': 24 | beginOffset = Offset(0, -1); 25 | break; 26 | case 'bottom': 27 | beginOffset = Offset(0, 1); 28 | break; 29 | } 30 | return showGeneralDialog( 31 | barrierLabel: "Barrier", 32 | barrierDismissible: dismissible, 33 | barrierColor: barrierColor != null ? barrierColor : Colors.black.withOpacity(0.5), 34 | transitionDuration: Duration(milliseconds: duration), 35 | context: context, 36 | pageBuilder: (_, __, ___) { 37 | return Dialog( 38 | shape: RoundedRectangleBorder( 39 | borderRadius: BorderRadius.circular(borderRadius), 40 | ), 41 | insetPadding: EdgeInsets.only( 42 | left: paddingHorizontal, 43 | right: paddingHorizontal, 44 | top: paddingTop, 45 | bottom: paddingBottom), 46 | child: Container( 47 | constraints: BoxConstraints(maxWidth: 320), 48 | child: child, 49 | ), 50 | backgroundColor: Theme.of(context).scaffoldBackgroundColor, 51 | ); 52 | }, 53 | transitionBuilder: (_, anim, __, child) { 54 | return SlideTransition( 55 | position: Tween(begin: beginOffset, end: Offset(0, 0)).animate(anim), 56 | child: child, 57 | ); 58 | }, 59 | ); 60 | } 61 | 62 | showDialogLoading(context) { 63 | showDialog( 64 | context: context, 65 | builder: (context) { 66 | return Center( 67 | child: CircularProgressIndicator( 68 | valueColor: AlwaysStoppedAnimation(Colors.white), 69 | ), 70 | ); 71 | }, 72 | barrierColor: Color(0x80000000), 73 | barrierDismissible: false, 74 | ); 75 | } 76 | -------------------------------------------------------------------------------- /lib/src/ui/common/dialogs/dialog_notice.dart: -------------------------------------------------------------------------------- 1 | import 'package:cloudmate/src/routes/app_pages.dart'; 2 | import 'package:cloudmate/src/themes/app_colors.dart'; 3 | import 'package:flutter/material.dart'; 4 | import 'package:cloudmate/src/utils/sizer_custom/sizer.dart'; 5 | 6 | class DialogNotice extends StatelessWidget { 7 | final String title; 8 | final String subTitle; 9 | 10 | const DialogNotice({required this.title, required this.subTitle}); 11 | 12 | @override 13 | Widget build(BuildContext context) { 14 | return Container( 15 | width: 300.sp, 16 | height: 155.sp, 17 | padding: EdgeInsets.symmetric(vertical: 16.sp), 18 | child: Column( 19 | mainAxisAlignment: MainAxisAlignment.start, 20 | children: [ 21 | SizedBox(height: 6.sp), 22 | Padding( 23 | padding: EdgeInsets.symmetric(horizontal: 15.sp), 24 | child: Text( 25 | title, 26 | style: TextStyle(fontWeight: FontWeight.w600, fontSize: 13.sp), 27 | ), 28 | ), 29 | SizedBox(height: 10.sp), 30 | Padding( 31 | padding: EdgeInsets.symmetric(horizontal: 15.sp, vertical: 7.5.sp), 32 | child: Text( 33 | subTitle, 34 | textAlign: TextAlign.center, 35 | style: TextStyle(fontWeight: FontWeight.w400, fontSize: 10.5.sp), 36 | ), 37 | ), 38 | SizedBox(height: 8.sp), 39 | Divider(), 40 | GestureDetector( 41 | onTap: () { 42 | AppNavigator.pop(); 43 | }, 44 | child: Container( 45 | color: Colors.transparent, 46 | width: 300.sp, 47 | alignment: Alignment.center, 48 | padding: EdgeInsets.symmetric(vertical: 5.sp), 49 | child: Text( 50 | 'OK', 51 | style: TextStyle( 52 | fontWeight: FontWeight.w600, 53 | fontSize: 12.sp, 54 | color: colorPrimary, 55 | ), 56 | ), 57 | ), 58 | ), 59 | Divider(color: Colors.grey), 60 | ], 61 | ), 62 | ); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /lib/src/ui/common/network_cached.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:cloudmate/src/themes/app_decorations.dart'; 3 | 4 | class ErrorLoadingImage extends StatelessWidget { 5 | @override 6 | Widget build(BuildContext context) { 7 | return Container( 8 | decoration: AppDecoration.buttonActionCircle(context).decoration, 9 | ); 10 | } 11 | } 12 | 13 | class PlaceHolderImage extends StatelessWidget { 14 | @override 15 | Widget build(BuildContext context) { 16 | return Container( 17 | decoration: AppDecoration.inputChatDecoration(context).decoration, 18 | ); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /lib/src/ui/common/screens/loading_screen.dart: -------------------------------------------------------------------------------- 1 | import 'package:cloudmate/src/public/constants.dart'; 2 | import 'package:cloudmate/src/themes/app_colors.dart'; 3 | import 'package:cloudmate/src/themes/font_family.dart'; 4 | import 'package:flutter/material.dart'; 5 | import 'package:cloudmate/src/utils/sizer_custom/sizer.dart'; 6 | 7 | class LoadingScreen extends StatelessWidget { 8 | final bool isShowText; 9 | const LoadingScreen({this.isShowText = true}); 10 | @override 11 | Widget build(BuildContext context) { 12 | return Scaffold( 13 | body: Container( 14 | height: 100.h, 15 | width: 100.w, 16 | child: Column( 17 | crossAxisAlignment: CrossAxisAlignment.center, 18 | mainAxisAlignment: MainAxisAlignment.center, 19 | children: [ 20 | Container( 21 | width: isShowText ? 70.w : 50.w, 22 | height: isShowText ? 70.w : 50.w, 23 | child: Constants().loadingLottie, 24 | ), 25 | isShowText 26 | ? RichText( 27 | text: TextSpan( 28 | children: [ 29 | TextSpan( 30 | text: 'Load', 31 | style: TextStyle( 32 | fontSize: 26.sp, 33 | fontWeight: FontWeight.w600, 34 | fontFamily: FontFamily.dancing, 35 | color: colorPrimary, 36 | ), 37 | ), 38 | TextSpan( 39 | text: 'ing', 40 | style: TextStyle( 41 | fontSize: 26.sp, 42 | fontWeight: FontWeight.w600, 43 | fontFamily: FontFamily.dancing, 44 | color: Theme.of(context).textTheme.bodyLarge!.color, 45 | ), 46 | ), 47 | ], 48 | ), 49 | ) 50 | : Container(), 51 | ], 52 | ), 53 | ), 54 | ); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /lib/src/ui/common/widgets/animated_fade.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class AnimatedFade extends AnimatedWidget { 4 | const AnimatedFade({ 5 | required this.child, 6 | required this.animation, 7 | }) : super(listenable: animation); 8 | 9 | final Animation animation; 10 | final Widget child; 11 | 12 | @override 13 | Widget build(BuildContext context) { 14 | final opacity = animation.value; 15 | 16 | return IgnorePointer( 17 | ignoring: opacity < 1, 18 | child: Opacity( 19 | opacity: opacity, 20 | child: child, 21 | ), 22 | ); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /lib/src/ui/common/widgets/get_snack_bar.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:get/get.dart'; 3 | import 'package:cloudmate/src/utils/sizer_custom/sizer.dart'; 4 | 5 | class GetSnackBar { 6 | final String title; 7 | final String subTitle; 8 | final int duration; 9 | GetSnackBar({ 10 | required this.title, 11 | required this.subTitle, 12 | this.duration = 1500, 13 | }); 14 | 15 | show() { 16 | Get.snackbar( 17 | '', 18 | '', 19 | onTap: (obj) {}, 20 | colorText: Colors.white, 21 | backgroundColor: Colors.black45, 22 | duration: Duration( 23 | milliseconds: duration, 24 | ), 25 | titleText: Text( 26 | title, 27 | style: TextStyle( 28 | fontSize: 12.sp, 29 | color: Colors.white, 30 | fontWeight: FontWeight.bold, 31 | ), 32 | ), 33 | messageText: Text( 34 | subTitle, 35 | style: TextStyle( 36 | fontSize: 10.5.sp, 37 | color: Colors.white.withOpacity(.85), 38 | fontWeight: FontWeight.w400, 39 | ), 40 | ), 41 | padding: EdgeInsets.fromLTRB( 42 | 16.sp, 43 | 16.sp, 44 | 6.sp, 45 | 14.sp, 46 | ), 47 | ); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /lib/src/ui/common/widgets/indicator.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class Indicator extends StatelessWidget { 4 | final Color? color; 5 | final String? text; 6 | final bool? isSquare; 7 | final double? size; 8 | final Color? textColor; 9 | 10 | const Indicator({ 11 | this.color, 12 | this.text, 13 | this.isSquare, 14 | this.size = 16, 15 | this.textColor = const Color(0xff505050), 16 | }); 17 | 18 | @override 19 | Widget build(BuildContext context) { 20 | return Row( 21 | children: [ 22 | Container( 23 | width: size, 24 | height: size, 25 | decoration: BoxDecoration( 26 | shape: isSquare! ? BoxShape.rectangle : BoxShape.circle, 27 | color: color, 28 | ), 29 | ), 30 | const SizedBox( 31 | width: 4, 32 | ), 33 | Text( 34 | text!, 35 | style: TextStyle(fontSize: size, fontWeight: FontWeight.bold, color: textColor), 36 | ) 37 | ], 38 | ); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /lib/src/ui/home/widgets/post_shimmer_list.dart: -------------------------------------------------------------------------------- 1 | import 'package:cloudmate/src/ui/home/widgets/new_post.dart'; 2 | import 'package:cloudmate/src/ui/home/widgets/post_shimmer_card.dart'; 3 | import 'package:flutter/material.dart'; 4 | import 'package:cloudmate/src/utils/sizer_custom/sizer.dart'; 5 | 6 | class PostShimmerList extends StatelessWidget { 7 | final bool isShowNewPost; 8 | const PostShimmerList({this.isShowNewPost = true}); 9 | @override 10 | Widget build(BuildContext context) { 11 | return ListView.builder( 12 | padding: isShowNewPost 13 | ? EdgeInsets.only(top: 12.sp, bottom: 20.sp) 14 | : EdgeInsets.only(bottom: 80.sp), 15 | itemCount: 5, 16 | shrinkWrap: true, 17 | physics: NeverScrollableScrollPhysics(), 18 | itemBuilder: (context, index) { 19 | return index == (isShowNewPost ? 0 : -1) ? NewPost() : PostShimmerCard(isLast: index == 2); 20 | }, 21 | ); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /lib/src/ui/notification/blocs/notification_bloc.dart: -------------------------------------------------------------------------------- 1 | import 'package:bloc/bloc.dart'; 2 | import 'package:cloudmate/src/models/notification_model.dart'; 3 | import 'package:cloudmate/src/resources/remote/notification_repository.dart'; 4 | import 'package:meta/meta.dart'; 5 | 6 | part 'notification_event.dart'; 7 | part 'notification_state.dart'; 8 | 9 | class NotificationBloc extends Bloc { 10 | NotificationBloc() : super(NotificationInitial()); 11 | 12 | List notifications = []; 13 | bool isNotificationOver = false; 14 | 15 | @override 16 | Stream mapEventToState(NotificationEvent event) async* { 17 | if (event is GetNotificationEvent) { 18 | if (notifications.isEmpty) { 19 | yield NotificationInitial(); 20 | } else { 21 | yield GettingNotification(notificationList: notifications); 22 | } 23 | 24 | await _getNotification(); 25 | 26 | yield GetDoneNotification(notificationList: notifications); 27 | } 28 | } 29 | 30 | // MARK: - Private methods 31 | Future _getNotification() async { 32 | List notificationList = await NotificationRepository().getNotifications(); 33 | 34 | if (notificationList.isEmpty) { 35 | isNotificationOver = true; 36 | } else { 37 | notifications.addAll(notificationList); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /lib/src/ui/notification/blocs/notification_event.dart: -------------------------------------------------------------------------------- 1 | part of 'notification_bloc.dart'; 2 | 3 | @immutable 4 | abstract class NotificationEvent {} 5 | 6 | class GetNotificationEvent extends NotificationEvent {} 7 | 8 | class RemoveNotificationEvent extends NotificationEvent { 9 | final int id; 10 | RemoveNotificationEvent({required this.id}); 11 | } 12 | 13 | class ClearNotificationEvent extends NotificationEvent {} 14 | -------------------------------------------------------------------------------- /lib/src/ui/notification/blocs/notification_state.dart: -------------------------------------------------------------------------------- 1 | part of 'notification_bloc.dart'; 2 | 3 | @immutable 4 | abstract class NotificationState { 5 | List get props => []; 6 | } 7 | 8 | class NotificationInitial extends NotificationState {} 9 | 10 | class GettingNotification extends NotificationState { 11 | final List notificationList; 12 | GettingNotification({required this.notificationList}); 13 | 14 | @override 15 | List get props => [notificationList]; 16 | } 17 | 18 | class GetDoneNotification extends NotificationState { 19 | final List notificationList; 20 | GetDoneNotification({required this.notificationList}); 21 | 22 | @override 23 | List get props => [notificationList]; 24 | } 25 | -------------------------------------------------------------------------------- /lib/src/utils/logger.dart: -------------------------------------------------------------------------------- 1 | import 'dart:developer' as developer; 2 | import 'package:cloudmate/src/configs/application.dart'; 3 | 4 | class UtilLogger { 5 | static const String TAG = "SALEBOLT"; 6 | 7 | static log([String tag = TAG, dynamic msg]) { 8 | if (Application.mode == 'DEV') { 9 | developer.log('$msg', name: tag); 10 | } 11 | } 12 | 13 | ///Singleton factory 14 | static final UtilLogger _instance = UtilLogger._internal(); 15 | 16 | factory UtilLogger() { 17 | return _instance; 18 | } 19 | 20 | UtilLogger._internal(); 21 | } 22 | -------------------------------------------------------------------------------- /lib/src/utils/sizer_custom/extension.dart: -------------------------------------------------------------------------------- 1 | part of sizer; 2 | 3 | extension SizerExt on num { 4 | /// Calculates the height depending on the device's screen size 5 | /// 6 | /// Eg: 20.h -> will take 20% of the screen's height 7 | double get h => this * SizerUtil.height / 100; 8 | 9 | /// Calculates the width depending on the device's screen size 10 | /// 11 | /// Eg: 20.w -> will take 20% of the screen's width 12 | double get w => this * SizerUtil.width / 100; 13 | 14 | /// Calculates the sp (Scalable Pixel) depending on the device's screen size 15 | // double get sp => this * (SizerUtil.width / 3) / 100; 16 | 17 | double get width { 18 | // DEVICE INCH 19 | double deviceSize = math.sqrt(100.h * 100.h + 100.w * 100.w) / Constants.INCH_TO_DP; 20 | if (deviceSize > 6.5) { 21 | return 65.w * (6.5 / deviceSize); 22 | } else if (deviceSize > 5.5) { 23 | return 100.w; 24 | } else if (deviceSize > 5.0) { 25 | return 90.w; 26 | } else { 27 | return 85.w; 28 | } 29 | } 30 | 31 | bool get isTablet { 32 | // DEVICE INCH 33 | double deviceSize = math.sqrt(100.h * 100.h + 100.w * 100.w) / Constants.INCH_TO_DP; 34 | if (deviceSize > 6.5) { 35 | return true; 36 | } 37 | 38 | return false; 39 | } 40 | 41 | double get sp => this * (width / 3) / 100; 42 | 43 | int get itemCountGridViewCalendar { 44 | return (100.w / (150.sp)).round(); 45 | } 46 | 47 | int get itemCountGridViewMoney { 48 | return (100.w / (100.sp)).round(); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /lib/src/utils/sizer_custom/sizer.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Created by Urmish patel on 2018/9/29. 3 | * email: urmishpatel9@gmail.com 4 | */ 5 | library sizer; 6 | 7 | import 'package:cloudmate/src/public/constants.dart'; 8 | import 'package:flutter/widgets.dart'; 9 | import 'dart:io'; 10 | import 'package:flutter/foundation.dart' show kIsWeb; 11 | import 'dart:math' as math; 12 | 13 | part 'extension.dart'; 14 | 15 | part 'util.dart'; 16 | 17 | part 'widget.dart'; 18 | -------------------------------------------------------------------------------- /lib/src/utils/sizer_custom/util.dart: -------------------------------------------------------------------------------- 1 | part of sizer; 2 | 3 | class SizerUtil { 4 | /// Device's BoxConstraints 5 | static late BoxConstraints boxConstraints; 6 | 7 | /// Device's Orientation 8 | static late Orientation orientation; 9 | 10 | /// Type of Device 11 | /// 12 | /// This can either be mobile or tablet 13 | static late DeviceType deviceType; 14 | 15 | /// Device's Height 16 | static late double height; 17 | 18 | /// Device's Width 19 | static late double width; 20 | 21 | /// Sets the Screen's size and Device's Orientation, 22 | /// BoxConstraints, Height, and Width 23 | static void setScreenSize(BoxConstraints constraints, Orientation currentOrientation) { 24 | // Sets boxconstraints and orientation 25 | boxConstraints = constraints; 26 | orientation = currentOrientation; 27 | 28 | // Sets screen width and height 29 | if (orientation == Orientation.portrait) { 30 | width = boxConstraints.maxWidth; 31 | height = boxConstraints.maxHeight; 32 | } else { 33 | width = boxConstraints.maxHeight; 34 | height = boxConstraints.maxWidth; 35 | } 36 | 37 | // Sets ScreenType 38 | if (kIsWeb) { 39 | deviceType = DeviceType.web; 40 | } else if (Platform.isAndroid || Platform.isIOS) { 41 | if ((orientation == Orientation.portrait && width < 600) || 42 | (orientation == Orientation.landscape && height < 600)) { 43 | deviceType = DeviceType.mobile; 44 | } else { 45 | deviceType = DeviceType.tablet; 46 | } 47 | } else if (Platform.isMacOS) { 48 | deviceType = DeviceType.mac; 49 | } else if (Platform.isWindows) { 50 | deviceType = DeviceType.windows; 51 | } else if (Platform.isLinux) { 52 | deviceType = DeviceType.linux; 53 | } else { 54 | deviceType = DeviceType.fuchsia; 55 | } 56 | } 57 | 58 | //for responsive web 59 | static getWebResponsiveSize({smallSize, mediumSize, largeSize}) { 60 | return width < 600 61 | ? smallSize //'phone' 62 | : width >= 600 && width <= 1024 63 | ? mediumSize //'tablet' 64 | : largeSize; //'desktop'; 65 | } 66 | } 67 | 68 | /// Type of Device 69 | /// 70 | /// This can be either mobile or tablet 71 | enum DeviceType { mobile, tablet, web, mac, windows, linux, fuchsia } 72 | -------------------------------------------------------------------------------- /lib/src/utils/sizer_custom/widget.dart: -------------------------------------------------------------------------------- 1 | part of sizer; 2 | 3 | /// Provides `Context`, `Orientation`, and `DeviceType` parameters to the builder function 4 | typedef ResponsiveBuild = Widget Function( 5 | BuildContext context, 6 | Orientation orientation, 7 | DeviceType deviceType, 8 | ); 9 | 10 | /// A widget that gets the device's details like orientation and constraints 11 | /// 12 | /// Usage: Wrap MaterialApp with this widget 13 | class Sizer extends StatelessWidget { 14 | const Sizer({Key? key, required this.builder}) : super(key: key); 15 | 16 | /// Builds the widget whenever the orientation changes 17 | final ResponsiveBuild builder; 18 | 19 | @override 20 | Widget build(BuildContext context) { 21 | return LayoutBuilder(builder: (context, constraints) { 22 | return OrientationBuilder(builder: (context, orientation) { 23 | SizerUtil.setScreenSize(constraints, orientation); 24 | return builder(context, orientation, SizerUtil.deviceType); 25 | }); 26 | }); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /lib/src/utils/stack_avatar.dart: -------------------------------------------------------------------------------- 1 | import 'package:cloudmate/src/themes/app_colors.dart'; 2 | import 'package:cloudmate/src/utils/blurhash.dart'; 3 | import 'package:flutter/material.dart'; 4 | import 'package:cloudmate/src/utils/sizer_custom/sizer.dart'; 5 | 6 | class StackAvatar extends StatefulWidget { 7 | final List images; 8 | final List blueHash; 9 | final double size; 10 | StackAvatar({required this.images, required this.blueHash, this.size = 25}); 11 | @override 12 | State createState() => _StackAvatarState(); 13 | } 14 | 15 | class _StackAvatarState extends State { 16 | @override 17 | void initState() { 18 | super.initState(); 19 | } 20 | 21 | @override 22 | Widget build(BuildContext context) { 23 | return Container( 24 | child: Stack( 25 | alignment: Alignment.centerLeft, 26 | children: [ 27 | _buildAvatar(context, 0), 28 | widget.images.length >= 2 ? _buildAvatar(context, 1) : Container(), 29 | widget.images.length >= 3 ? _buildAvatar(context, 2) : Container(), 30 | ], 31 | ), 32 | ); 33 | } 34 | 35 | Widget _buildAvatar(context, index) { 36 | return Container( 37 | height: widget.size, 38 | width: widget.size, 39 | margin: EdgeInsets.only(left: index * 12.sp), 40 | decoration: BoxDecoration( 41 | shape: BoxShape.circle, 42 | border: Border.all( 43 | color: Theme.of(context).scaffoldBackgroundColor, 44 | width: 1.15.sp, 45 | ), 46 | ), 47 | child: ClipRRect( 48 | borderRadius: BorderRadius.circular(1000.sp), 49 | child: BlurHash( 50 | hash: widget.blueHash[index], 51 | image: widget.images[index], 52 | imageFit: BoxFit.cover, 53 | color: colorPrimary, 54 | ), 55 | ), 56 | ); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /screenshots/class.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Py-Ec/cloudmate-classroom-flutter/d1d241a3416e19b192dfd9743e4ce12e0d05357f/screenshots/class.png -------------------------------------------------------------------------------- /screenshots/details_class.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Py-Ec/cloudmate-classroom-flutter/d1d241a3416e19b192dfd9743e4ce12e0d05357f/screenshots/details_class.png -------------------------------------------------------------------------------- /screenshots/home.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Py-Ec/cloudmate-classroom-flutter/d1d241a3416e19b192dfd9743e4ce12e0d05357f/screenshots/home.png -------------------------------------------------------------------------------- /screenshots/profile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Py-Ec/cloudmate-classroom-flutter/d1d241a3416e19b192dfd9743e4ce12e0d05357f/screenshots/profile.png --------------------------------------------------------------------------------