├── .editorconfig ├── .github ├── ISSUE_TEMPLATE │ └── 이슈-생성-템플릿.md ├── PULL_REQUEST_TEMPLATE.md ├── actions │ └── setup │ │ └── action.yml └── workflows │ └── ktlint and build.yml ├── .gitignore ├── README.md ├── app ├── .gitignore ├── build.gradle.kts ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── kr │ │ └── boostcamp_2024 │ │ └── course │ │ └── wequiz │ │ └── ExampleInstrumentedTest.kt │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── kr │ │ │ └── boostcamp_2024 │ │ │ └── course │ │ │ └── wequiz │ │ │ ├── WeQuizApplication.kt │ │ │ └── ui │ │ │ ├── MainActivity.kt │ │ │ ├── WeQuizApp.kt │ │ │ └── WeQuizNavHost.kt │ └── res │ │ ├── drawable │ │ └── ic_launcher_foreground.xml │ │ ├── mipmap-anydpi-v26 │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.webp │ │ └── ic_launcher_round.webp │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.webp │ │ └── ic_launcher_round.webp │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.webp │ │ └── ic_launcher_round.webp │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.webp │ │ └── ic_launcher_round.webp │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.webp │ │ └── ic_launcher_round.webp │ │ ├── values-ko │ │ └── strings.xml │ │ ├── values-zh │ │ └── strings.xml │ │ ├── values │ │ ├── colors.xml │ │ ├── ic_launcher_background.xml │ │ ├── strings.xml │ │ └── themes.xml │ │ └── xml │ │ ├── backup_rules.xml │ │ └── data_extraction_rules.xml │ └── test │ └── java │ └── kr │ └── boostcamp_2024 │ └── course │ └── wequiz │ └── ExampleUnitTest.kt ├── build-logic ├── .gitignore ├── build.gradle.kts ├── gradle.properties ├── settings.gradle.kts └── src │ └── main │ └── java │ ├── convention.android.application.gradle.kts │ ├── convention.android.compose.gradle.kts │ ├── convention.android.feature.gradle.kts │ ├── convention.android.hilt.gradle.kts │ ├── convention.android.library.gradle.kts │ ├── convention.firebase.gradle.kts │ └── kr │ └── boostcamp_2024 │ └── course │ └── build_logic │ ├── ComposeAndroid.kt │ ├── Extension.kt │ ├── Firebase.kt │ ├── HiltAndroid.kt │ └── KotlinAndroid.kt ├── build.gradle.kts ├── core ├── data │ ├── .gitignore │ ├── build.gradle.kts │ ├── consumer-rules.pro │ ├── proguard-rules.pro │ └── src │ │ ├── androidTest │ │ └── java │ │ │ └── kr │ │ │ └── boostcamp_2024 │ │ │ └── course │ │ │ └── data │ │ │ └── ExampleInstrumentedTest.kt │ │ ├── main │ │ ├── AndroidManifest.xml │ │ └── java │ │ │ └── kr │ │ │ └── boostcamp_2024 │ │ │ └── course │ │ │ └── data │ │ │ ├── di │ │ │ ├── AddHeadInterceptor.kt │ │ │ ├── AppModule.kt │ │ │ └── RepositoryModule.kt │ │ │ ├── model │ │ │ ├── AiQuestionRequest.kt │ │ │ ├── AiQuestionResponse.kt │ │ │ ├── BlankQuestionDTO.kt │ │ │ ├── CategoryDTO.kt │ │ │ ├── ChoiceQuestionDTO.kt │ │ │ ├── NotificationDTO.kt │ │ │ ├── QuizDTO.kt │ │ │ ├── RealTimeQuizDTO.kt │ │ │ ├── StudyGroupDTO.kt │ │ │ ├── UserDTO.kt │ │ │ └── UserOmrDTO.kt │ │ │ ├── network │ │ │ └── AiService.kt │ │ │ └── repository │ │ │ ├── AiRepositoryImpl.kt │ │ │ ├── AuthRepositoryImpl.kt │ │ │ ├── CategoryRepositoryImpl.kt │ │ │ ├── GuideRepositoryImpl.kt │ │ │ ├── NotificationRepositoryImpl.kt │ │ │ ├── QuestionRepositoryImpl.kt │ │ │ ├── QuizRepositoryImpl.kt │ │ │ ├── StorageRepositoryImpl.kt │ │ │ ├── StudyGroupRepositoryImpl.kt │ │ │ ├── UserOmrRepositoryImpl.kt │ │ │ └── UserRepositoryImpl.kt │ │ └── test │ │ └── java │ │ └── kr │ │ └── boostcamp_2024 │ │ └── course │ │ └── data │ │ └── ExampleUnitTest.kt ├── designsystem │ ├── .gitignore │ ├── build.gradle.kts │ ├── consumer-rules.pro │ ├── proguard-rules.pro │ └── src │ │ ├── androidTest │ │ └── java │ │ │ └── kr │ │ │ └── boostcamp_2024 │ │ │ └── course │ │ │ └── designsystem │ │ │ └── ExampleInstrumentedTest.kt │ │ ├── main │ │ ├── AndroidManifest.xml │ │ ├── java │ │ │ └── kr │ │ │ │ └── boostcamp_2024 │ │ │ │ └── course │ │ │ │ └── designsystem │ │ │ │ └── ui │ │ │ │ ├── annotation │ │ │ │ └── PreviewAnnotations.kt │ │ │ │ └── theme │ │ │ │ ├── Colors.kt │ │ │ │ ├── Theme.kt │ │ │ │ └── component │ │ │ │ ├── WeQuizBaseDialog.kt │ │ │ │ ├── WeQuizChatBubble.kt │ │ │ │ ├── WeQuizImageLargeTopAppBar.kt │ │ │ │ ├── WeQuizLoadingIndicator.kt │ │ │ │ ├── WeQuizPhotoPicker.kt │ │ │ │ ├── WeQuizRoundedImage.kt │ │ │ │ ├── WeQuizTextField.kt │ │ │ │ └── WeQuizValidateTextField.kt │ │ └── res │ │ │ ├── drawable │ │ │ ├── img_error.xml │ │ │ ├── img_photo_picker.xml │ │ │ └── outline_cancel_24.xml │ │ │ ├── values-ko │ │ │ └── strings.xml │ │ │ ├── values-zh │ │ │ └── strings.xml │ │ │ └── values │ │ │ └── strings.xml │ │ └── test │ │ └── java │ │ └── kr │ │ └── boostcamp_2024 │ │ └── course │ │ └── designsystem │ │ └── ExampleUnitTest.kt └── domain │ ├── .gitignore │ ├── build.gradle.kts │ └── src │ ├── main │ └── java │ │ └── kr │ │ └── boostcamp_2024 │ │ └── course │ │ └── domain │ │ ├── enum │ │ ├── BlankContentType.kt │ │ ├── QuestionType.kt │ │ └── QuizType.kt │ │ ├── model │ │ ├── AiQuestion.kt │ │ ├── BlankQuestion.kt │ │ ├── BlankQuestionCreationInfo.kt │ │ ├── BlankQuestionManager.kt │ │ ├── Category.kt │ │ ├── ChoiceQuestion.kt │ │ ├── ChoiceQuestionCreationInfo.kt │ │ ├── Notification.kt │ │ ├── NotificationWithGroupInfo.kt │ │ ├── Quiz.kt │ │ ├── QuizCreationInfo.kt │ │ ├── QuizNotFoundException.kt │ │ ├── QuizResult.kt │ │ ├── RealtimeQuiz.kt │ │ ├── StudyGroup.kt │ │ ├── StudyGroupCreationInfo.kt │ │ ├── StudyGroupUpdatedInfo.kt │ │ ├── User.kt │ │ ├── UserOmr.kt │ │ ├── UserOmrCreationInfo.kt │ │ └── UserSubmitInfo.kt │ │ └── repository │ │ ├── AiRepository.kt │ │ ├── AuthRepository.kt │ │ ├── CategoryRepository.kt │ │ ├── GuideRepository.kt │ │ ├── NotificationRepository.kt │ │ ├── QuestionRepository.kt │ │ ├── QuizRepository.kt │ │ ├── StorageRepository.kt │ │ ├── StudyGroupRepository.kt │ │ ├── UserOmrRepository.kt │ │ └── UserRepository.kt │ └── test │ └── java │ └── BlankQuestionQuizWithAnswerTest.kt ├── feature ├── category │ ├── .gitignore │ ├── build.gradle.kts │ ├── consumer-rules.pro │ ├── proguard-rules.pro │ └── src │ │ ├── androidTest │ │ └── java │ │ │ └── kr │ │ │ └── boostcamp_2024 │ │ │ └── course │ │ │ └── category │ │ │ └── ExampleInstrumentedTest.kt │ │ ├── main │ │ ├── AndroidManifest.xml │ │ ├── java │ │ │ └── kr │ │ │ │ └── boostcamp_2024 │ │ │ │ └── course │ │ │ │ └── category │ │ │ │ ├── component │ │ │ │ └── CategorySettingMenu.kt │ │ │ │ ├── navigation │ │ │ │ └── CategoryNavigation.kt │ │ │ │ ├── presentation │ │ │ │ ├── CategoryScreen.kt │ │ │ │ └── CreateCategoryScreen.kt │ │ │ │ ├── viewModel │ │ │ │ └── CategoryViewModel.kt │ │ │ │ └── viewmodel │ │ │ │ └── CreateCategoryViewModel.kt │ │ └── res │ │ │ ├── drawable │ │ │ ├── default_profile_image.xml │ │ │ ├── sample_profile.png │ │ │ └── sample_profile1.png │ │ │ ├── values-ko │ │ │ └── strings.xml │ │ │ ├── values-zh │ │ │ └── strings.xml │ │ │ └── values │ │ │ └── strings.xml │ │ └── test │ │ └── java │ │ └── kr │ │ └── boostcamp_2024 │ │ └── course │ │ └── category │ │ └── ExampleUnitTest.kt ├── login │ ├── .gitignore │ ├── build.gradle.kts │ ├── consumer-rules.pro │ ├── proguard-rules.pro │ └── src │ │ ├── androidTest │ │ └── java │ │ │ └── kr │ │ │ └── boostcamp_2024 │ │ │ └── course │ │ │ └── login │ │ │ └── ExampleInstrumentedTest.kt │ │ ├── main │ │ ├── AndroidManifest.xml │ │ ├── java │ │ │ └── kr │ │ │ │ └── boostcamp_2024 │ │ │ │ └── course │ │ │ │ └── login │ │ │ │ ├── model │ │ │ │ └── UserUiModel.kt │ │ │ │ ├── navigation │ │ │ │ ├── CustomNavType.kt │ │ │ │ └── LoginNavigation.kt │ │ │ │ ├── presentation │ │ │ │ ├── LoginScreen.kt │ │ │ │ └── SignUpScreen.kt │ │ │ │ └── viewmodel │ │ │ │ ├── LoginViewModel.kt │ │ │ │ └── SignUpViewModel.kt │ │ └── res │ │ │ ├── drawable │ │ │ ├── baseline_visibility_24.xml │ │ │ ├── baseline_visibility_off_24.xml │ │ │ ├── img_app_logo.png │ │ │ ├── img_google_light_btn_login.xml │ │ │ └── outline_cancel_on_surface_variant.xml │ │ │ ├── values-ko │ │ │ └── strings.xml │ │ │ ├── values-zh │ │ │ └── strings.xml │ │ │ └── values │ │ │ └── strings.xml │ │ └── test │ │ └── java │ │ └── kr │ │ └── boostcamp_2024 │ │ └── course │ │ └── login │ │ └── ExampleUnitTest.kt ├── main │ ├── .gitignore │ ├── build.gradle.kts │ ├── consumer-rules.pro │ ├── proguard-rules.pro │ └── src │ │ ├── androidTest │ │ └── java │ │ │ └── kr │ │ │ └── boostcamp_2024 │ │ │ └── course │ │ │ └── main │ │ │ └── ExampleInstrumentedTest.kt │ │ ├── main │ │ ├── AndroidManifest.xml │ │ ├── java │ │ │ └── kr │ │ │ │ └── boostcamp_2024 │ │ │ │ └── course │ │ │ │ └── main │ │ │ │ ├── component │ │ │ │ ├── BaseGuideScreen.kt │ │ │ │ ├── GuideDialog.kt │ │ │ │ ├── MainDropDownMenu.kt │ │ │ │ ├── NotificationItem.kt │ │ │ │ ├── NotificationTopAppBar.kt │ │ │ │ └── StudyGroupItem.kt │ │ │ │ ├── navigation │ │ │ │ └── MainNavigation.kt │ │ │ │ ├── presentation │ │ │ │ ├── MainScreen.kt │ │ │ │ └── NotificationScreen.kt │ │ │ │ └── viewmodel │ │ │ │ ├── MainViewModel.kt │ │ │ │ └── NotificationViewModel.kt │ │ └── res │ │ │ ├── drawable │ │ │ └── sample_profile1.png │ │ │ ├── raw │ │ │ └── anim_arrow.json │ │ │ ├── values-ko │ │ │ └── strings.xml │ │ │ ├── values-zh │ │ │ └── strings.xml │ │ │ └── values │ │ │ └── strings.xml │ │ └── test │ │ └── java │ │ └── kr │ │ └── boostcamp_2024 │ │ └── course │ │ └── main │ │ └── ExampleUnitTest.kt ├── quiz │ ├── .gitignore │ ├── build.gradle.kts │ ├── consumer-rules.pro │ ├── proguard-rules.pro │ └── src │ │ ├── androidTest │ │ └── java │ │ │ └── kr │ │ │ └── boostcamp_2024 │ │ │ └── course │ │ │ └── quiz │ │ │ ├── CreateQuestionScreenTest.kt │ │ │ ├── QuestionDetailScreenTest.kt │ │ │ └── QuizDataButtonTest.kt │ │ ├── main │ │ ├── AndroidManifest.xml │ │ ├── java │ │ │ └── kr │ │ │ │ └── boostcamp_2024 │ │ │ │ └── course │ │ │ │ └── quiz │ │ │ │ ├── component │ │ │ │ ├── BlankQuestionContent.kt │ │ │ │ ├── BlankQuestionContentUi.kt │ │ │ │ ├── BlankQuestionDescription.kt │ │ │ │ ├── ChoiceQuestionContent.kt │ │ │ │ ├── CreateBlankQuestionContent.kt │ │ │ │ ├── CreateChoiceItems.kt │ │ │ │ ├── CreateQuestionContent.kt │ │ │ │ ├── Question.kt │ │ │ │ ├── QuestionConent.kt │ │ │ │ ├── QuestionDescription.kt │ │ │ │ ├── QuestionDetailTopAppBar.kt │ │ │ │ ├── QuestionItems.kt │ │ │ │ ├── QuestionSolution.kt │ │ │ │ ├── QuestionTextBox.kt │ │ │ │ ├── QuestionTitle.kt │ │ │ │ ├── QuestionTitleAndDetail.kt │ │ │ │ ├── QuestionTopBar.kt │ │ │ │ ├── QuizAiDialog.kt │ │ │ │ ├── QuizDataButton.kt │ │ │ │ ├── QuizDataChip.kt │ │ │ │ ├── QuizDatePickerTextField.kt │ │ │ │ ├── QuizOwnerDialog.kt │ │ │ │ ├── QuizSolveTimeSlider.kt │ │ │ │ ├── QuizTopAppBar.kt │ │ │ │ ├── RadioTextButton.kt │ │ │ │ ├── RealTimeQuestion.kt │ │ │ │ └── RealTimeQuizGuideContent.kt │ │ │ │ ├── navigation │ │ │ │ └── QuizNavigation.kt │ │ │ │ ├── presentation │ │ │ │ ├── question │ │ │ │ │ ├── AiLoadingIndicator.kt │ │ │ │ │ ├── CreateQuestionScreen.kt │ │ │ │ │ ├── GeneralQuestionScreen.kt │ │ │ │ │ ├── OwnerQuestionScreen.kt │ │ │ │ │ ├── PieChartScreen.kt │ │ │ │ │ ├── QuestionDetailScreen.kt │ │ │ │ │ ├── QuestionScreen.kt │ │ │ │ │ └── UserQuestionScreen.kt │ │ │ │ └── quiz │ │ │ │ │ ├── CreateQuizScreen.kt │ │ │ │ │ ├── GeneralQuizResultScreen.kt │ │ │ │ │ ├── OwnerQuizResultScreen.kt │ │ │ │ │ ├── QuizResultScreen.kt │ │ │ │ │ ├── QuizScreen.kt │ │ │ │ │ └── QuizStatisticsDialog.kt │ │ │ │ ├── utils │ │ │ │ ├── QuestionParameterProvider.kt │ │ │ │ ├── QuizContentPreviewParameterProvider.kt │ │ │ │ ├── QuizParameterProvider.kt │ │ │ │ └── TimerFormat.kt │ │ │ │ └── viewmodel │ │ │ │ ├── CreateQuestionViewModel.kt │ │ │ │ ├── CreateQuizViewModel.kt │ │ │ │ ├── OwnerQuestionViewModel.kt │ │ │ │ ├── QuestionDetailViewModel.kt │ │ │ │ ├── QuestionViewModel.kt │ │ │ │ ├── QuizResultViewModel.kt │ │ │ │ ├── QuizViewModel.kt │ │ │ │ └── UserQuestionViewModel.kt │ │ └── res │ │ │ ├── drawable │ │ │ ├── baseline_dehaze_24.xml │ │ │ ├── create_study_character.png │ │ │ ├── edit_24.xml │ │ │ ├── image_ai.xml │ │ │ ├── image_guide.xml │ │ │ ├── img_clock_character.png │ │ │ ├── outline_cancel_on_surface_variant.xml │ │ │ ├── quiz_create_ai_profile.png │ │ │ ├── quiz_system_profile.png │ │ │ ├── rounded_directions_walk_24.xml │ │ │ ├── sample_profile.png │ │ │ ├── sample_profile1.png │ │ │ └── search_24.xml │ │ │ ├── raw │ │ │ └── anim_ai.json │ │ │ ├── values-ko │ │ │ └── strings.xml │ │ │ ├── values-zh │ │ │ └── strings.xml │ │ │ └── values │ │ │ └── strings.xml │ │ └── test │ │ └── java │ │ └── kr │ │ └── boostcamp_2024 │ │ └── course │ │ └── quiz │ │ └── ExampleUnitTest.kt └── study │ ├── .gitignore │ ├── build.gradle.kts │ ├── consumer-rules.pro │ ├── proguard-rules.pro │ └── src │ ├── androidTest │ └── java │ │ └── kr │ │ └── boostcamp_2024 │ │ └── course │ │ └── study │ │ └── ExampleInstrumentedTest.kt │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── kr │ │ │ └── boostcamp_2024 │ │ │ └── course │ │ │ └── study │ │ │ ├── component │ │ │ ├── CategoryItem.kt │ │ │ ├── CreateStudyTopAppBar.kt │ │ │ ├── CustomPropertyTab.kt │ │ │ ├── StudyGroupMemberItem.kt │ │ │ └── StudySubmitButton.kt │ │ │ ├── navigation │ │ │ ├── DetailScreenRouter.kt │ │ │ └── StudyNavigation.kt │ │ │ ├── presentation │ │ │ ├── CategoryListScreen.kt │ │ │ ├── CreateGroupDialog.kt │ │ │ ├── CreateStudyScreen.kt │ │ │ ├── DetailStudyScreen.kt │ │ │ ├── GroupListScreen.kt │ │ │ └── StudyScreen.kt │ │ │ └── viewmodel │ │ │ ├── CreateStudyViewModel.kt │ │ │ └── DetailStudyViewModel.kt │ └── res │ │ ├── drawable │ │ ├── baseline_account_circle_24.xml │ │ ├── baseline_add_circle_outline_24.xml │ │ ├── baseline_arrow_back_24.xml │ │ ├── baseline_dehaze_24.xml │ │ ├── baseline_remove_24.xml │ │ ├── baseline_settings_24.xml │ │ ├── create_study_character.png │ │ ├── img_photo_picker.xml │ │ ├── member_invite_character.png │ │ └── rounded_directions_walk_24.xml │ │ ├── values-ko │ │ └── strings.xml │ │ ├── values-zh │ │ └── strings.xml │ │ └── values │ │ └── strings.xml │ └── test │ └── java │ └── kr │ └── boostcamp_2024 │ └── course │ └── study │ └── ExampleUnitTest.kt ├── gradle.properties ├── gradle ├── libs.versions.toml └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle.kts /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | end_of_line = lf 6 | insert_final_newline = true 7 | max_line_length = 300 8 | trim_trailing_whitespace = true 9 | ktlint_function_naming_ignore_when_annotated_with = Composable, Test 10 | ktlint_standard_package-name = disabled 11 | 12 | [*.{kt,kts}] 13 | ij_kotlin_code_style_defaults = KOTLIN_OFFICIAL 14 | ij_kotlin_name_count_to_use_star_import = 2147483647 15 | ij_kotlin_name_count_to_use_star_import_for_members = 2147483647 16 | ij_kotlin_packages_to_use_import_on_demand = unset 17 | 18 | ktlint_code_style = ktlint_official 19 | ktlint_standard_string-template-indent = disabled 20 | ktlint_standard_multiline-expression-wrapping = disabled 21 | ktlint_standard_max-line-length = disabled 22 | ktlint_standard_no-wildcard-imports = disabled 23 | ktlint_standard_annotation = disabled 24 | ktlint_standard_function-signature = disabled 25 | ktlint_standard_import-ordering = disabled 26 | ktlint_standard_value-argument-comment = disabled 27 | ktlint_standard_comment-spacing = disabled 28 | ktlint_standard_no-empty-first-line-in-method-block = disabled 29 | ktlint_standard_no-blank-line-before-rbrace = disabled 30 | ktlint_no-multi-spaces = disabled 31 | ij_kotlin_allow_trailing_comma = true 32 | ij_kotlin_allow_trailing_comma_on_call_site = true 33 | ktlint_standard_multiline_expression_wrapping = disabled 34 | ktlint_standard_value-parameter-comment = disabled 35 | ktlint_standard_chain-method-continuation = disabled 36 | 37 | [*.{yml,yaml}] 38 | indent_size = 2 -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/이슈-생성-템플릿.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: 이슈 생성 템플릿 3 | about: 작업 전 이슈 생성 템플릿입니다! 4 | title: 'Issue: 이슈 생성 템플릿' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | ### 🪴 기능 설명 11 | (진행할 작업을 설명해주세요.) 12 | 13 | ### 📷 참고 이미지 14 | (작업 참고 디자인을 첨부해주세요.) 15 | 16 | 17 | 18 | ### 🗣️ 필요 태스크 19 | (해당 작업에 대한 상세 체크 리스트를 작성해주세요.) 20 | - [ ] 이거 해야 해요!! 21 | - [ ] 22 | - [ ] 23 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: PR 생성 템플릿 3 | about: PR 작성 템플릿입니다! 4 | title: 'feat: 작업 제목' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | ### 👩‍🌾 진행한 작업 11 | ✅ 로그인 기능 구현 12 | (필요에 따라 구체적인 과정을 추가해주세요!) 13 | 14 | ### 📷 작업 결과(사진) 15 | 16 | 17 | ### 🗣️ 공유할 내용 18 | (해당 작업에 대해 전달할 내용을 적어주세요!) 19 | 20 | closed #이슈 번호 21 | -------------------------------------------------------------------------------- /.github/actions/setup/action.yml: -------------------------------------------------------------------------------- 1 | name: setup 2 | 3 | inputs: 4 | base-url: 5 | description: 'Base URL for the AI API' 6 | required: true 7 | post-url: 8 | description: 'Post URL for the AI API' 9 | required: true 10 | google-services-json: 11 | description: 'Google Services JSON' 12 | required: true 13 | x-ncp-clovastudio-api-key: 14 | description: 'X-NCP-CLOVASTUDIO-API-KEY' 15 | required: true 16 | x-ncp-apigw-api-key: 17 | description: 'X-NCP-APIGW-API-KEY' 18 | required: true 19 | x-ncp-clovastudio-request-id: 20 | description: 'X-NCP-CLOVASTUDIO-REQUEST-ID' 21 | required: true 22 | 23 | runs: 24 | using: "composite" 25 | steps: 26 | - name: Set up JDK 17 27 | uses: actions/setup-java@v4 28 | with: 29 | java-version: '17' 30 | distribution: 'temurin' 31 | cache: gradle 32 | 33 | - name: Gradle Caching 34 | uses: actions/cache@v4 35 | with: 36 | path: | 37 | ~/.gradle/caches 38 | ~/.gradle/wrapper 39 | key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }} 40 | restore-keys: | 41 | ${{ runner.os }}-gradle- 42 | 43 | - name: Decode Google Services JSON 44 | env: 45 | GOOGLE_SERVICES_JSON: ${{ inputs.google-services-json }} 46 | run: echo $GOOGLE_SERVICES_JSON > ./app/google-services.json 47 | shell: bash 48 | 49 | - name: Configure local.properties 50 | env: 51 | BASE_URL: ${{ inputs.base-url }} 52 | POST_URL: ${{ inputs.post-url }} 53 | X_NCP_CLOVASTUDIO_API_KEY: ${{ inputs.x-ncp-clovastudio-api-key }} 54 | X_NCP_APIGW_API_KEY: ${{ inputs.x-ncp-apigw-api-key }} 55 | X_NCP_CLOVASTUDIO_REQUEST_ID: ${{ inputs.x-ncp-clovastudio-request-id }} 56 | run: | 57 | echo "base_url=${BASE_URL}" >> local.properties 58 | echo "post_url=${POST_URL}" >> local.properties 59 | echo "X-NCP-CLOVASTUDIO-API-KEY=${X_NCP_CLOVASTUDIO_API_KEY}" >> local.properties 60 | echo "X-NCP-APIGW-API-KEY=${X_NCP_APIGW_API_KEY}" >> local.properties 61 | echo "X-NCP-CLOVASTUDIO-REQUEST-ID=${X_NCP_CLOVASTUDIO_REQUEST_ID}" >> local.properties 62 | shell: bash 63 | -------------------------------------------------------------------------------- /.github/workflows/ktlint and build.yml: -------------------------------------------------------------------------------- 1 | name: ktlint and build 2 | 3 | on: 4 | pull_request: 5 | branches: [ "main", "dev" ] 6 | 7 | jobs: 8 | build: 9 | name: Check Code Quality and Build 10 | runs-on: ubuntu-latest 11 | 12 | steps: 13 | - uses: actions/checkout@v4 14 | 15 | - uses: ./.github/actions/setup 16 | with: 17 | base-url: ${{ secrets.BASE_URL }} 18 | post-url: ${{ secrets.POST_URL }} 19 | google-services-json: ${{ secrets.GOOGLE_SERVICES_JSON }} 20 | x-ncp-clovastudio-api-key: ${{ secrets.X_NCP_CLOVASTUDIO_API_KEY }} 21 | x-ncp-apigw-api-key: ${{ secrets.X_NCP_APIGW_API_KEY }} 22 | x-ncp-clovastudio-request-id: ${{ secrets.X_NCP_CLOVASTUDIO_REQUEST_ID }} 23 | 24 | - name: Ktlint Check 25 | uses: ScaCap/action-ktlint@master 26 | with: 27 | github_token: ${{ secrets.GITHUB_TOKEN }} 28 | reporter: github-pr-review 29 | android: true 30 | fail_on_error: true 31 | level: warning 32 | 33 | - name: Build and run unit tests 34 | run: | 35 | ./gradlew build --daemon 36 | ./gradlew test 37 | 38 | androidTest: 39 | name: Run Instrumentation Test 40 | runs-on: ubuntu-latest 41 | strategy: 42 | matrix: 43 | api-level: [ 26, 35 ] 44 | 45 | steps: 46 | - uses: actions/checkout@v4 47 | 48 | - uses: ./.github/actions/setup 49 | with: 50 | base-url: ${{ secrets.BASE_URL }} 51 | post-url: ${{ secrets.POST_URL }} 52 | google-services-json: ${{ secrets.GOOGLE_SERVICES_JSON }} 53 | x-ncp-clovastudio-api-key: ${{ secrets.X_NCP_CLOVASTUDIO_API_KEY }} 54 | x-ncp-apigw-api-key: ${{ secrets.X_NCP_APIGW_API_KEY }} 55 | x-ncp-clovastudio-request-id: ${{ secrets.X_NCP_CLOVASTUDIO_REQUEST_ID }} 56 | 57 | - name: Enable KVM 58 | run: | 59 | echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules 60 | sudo udevadm control --reload-rules 61 | sudo udevadm trigger --name-match=kvm 62 | 63 | - name: Run instrumentation tests 64 | uses: reactivecircus/android-emulator-runner@v2 65 | with: 66 | api-level: ${{ matrix.api-level }} 67 | arch: x86_64 68 | script: ./gradlew connectedDebugAndroidTest 69 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | /google-services.json -------------------------------------------------------------------------------- /app/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | id("convention.android.application") 3 | } 4 | 5 | android { 6 | namespace = "kr.boostcamp_2024.course.wequiz" 7 | 8 | defaultConfig { 9 | applicationId = "kr.boostcamp_2024.course.wequiz" 10 | targetSdk = 35 11 | versionCode = 6 12 | versionName = "1.2.1" 13 | } 14 | } 15 | 16 | dependencies { 17 | implementation(project(":feature:login")) 18 | implementation(project(":feature:main")) 19 | implementation(project(":feature:study")) 20 | implementation(project(":feature:category")) 21 | implementation(project(":feature:quiz")) 22 | 23 | implementation(project(":core:data")) 24 | implementation(project(":core:domain")) 25 | implementation(project(":core:designsystem")) 26 | 27 | implementation(libs.androidx.core.ktx) 28 | implementation(libs.androidx.lifecycle.runtime.ktx) 29 | 30 | testImplementation(libs.junit) 31 | androidTestImplementation(libs.androidx.junit) 32 | androidTestImplementation(libs.androidx.ui.test.junit4) 33 | } 34 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile -------------------------------------------------------------------------------- /app/src/androidTest/java/kr/boostcamp_2024/course/wequiz/ExampleInstrumentedTest.kt: -------------------------------------------------------------------------------- 1 | package kr.boostcamp_2024.course.wequiz 2 | 3 | import androidx.test.platform.app.InstrumentationRegistry 4 | import androidx.test.ext.junit.runners.AndroidJUnit4 5 | 6 | import org.junit.Test 7 | import org.junit.runner.RunWith 8 | 9 | import org.junit.Assert.* 10 | 11 | /** 12 | * Instrumented test, which will execute on an Android device. 13 | * 14 | * See [testing documentation](http://d.android.com/tools/testing). 15 | */ 16 | @RunWith(AndroidJUnit4::class) 17 | class ExampleInstrumentedTest { 18 | @Test 19 | fun useAppContext() { 20 | // Context of the app under test. 21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext 22 | assertEquals("kr.boostcamp_2024.course.wequiz", appContext.packageName) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 16 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /app/src/main/java/kr/boostcamp_2024/course/wequiz/WeQuizApplication.kt: -------------------------------------------------------------------------------- 1 | package kr.boostcamp_2024.course.wequiz 2 | 3 | import android.app.Application 4 | import com.google.firebase.FirebaseApp 5 | import dagger.hilt.android.HiltAndroidApp 6 | 7 | @HiltAndroidApp 8 | class WeQuizApplication : Application() { 9 | override fun onCreate() { 10 | super.onCreate() 11 | FirebaseApp.initializeApp(this) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /app/src/main/java/kr/boostcamp_2024/course/wequiz/ui/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package kr.boostcamp_2024.course.wequiz.ui 2 | 3 | import android.os.Bundle 4 | import androidx.activity.ComponentActivity 5 | import androidx.activity.compose.setContent 6 | import androidx.activity.enableEdgeToEdge 7 | import dagger.hilt.android.AndroidEntryPoint 8 | 9 | @AndroidEntryPoint 10 | class MainActivity : ComponentActivity() { 11 | override fun onCreate(savedInstanceState: Bundle?) { 12 | super.onCreate(savedInstanceState) 13 | enableEdgeToEdge() 14 | setContent { 15 | WeQuizApp() 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /app/src/main/java/kr/boostcamp_2024/course/wequiz/ui/WeQuizApp.kt: -------------------------------------------------------------------------------- 1 | package kr.boostcamp_2024.course.wequiz.ui 2 | 3 | import androidx.compose.foundation.layout.fillMaxSize 4 | import androidx.compose.material3.SnackbarHostState 5 | import androidx.compose.runtime.Composable 6 | import androidx.compose.runtime.remember 7 | import androidx.compose.runtime.rememberCoroutineScope 8 | import androidx.compose.ui.Modifier 9 | import androidx.compose.ui.platform.LocalContext 10 | import com.google.firebase.firestore.FirebaseFirestoreException 11 | import kotlinx.coroutines.launch 12 | import kr.boostcamp_2024.course.designsystem.ui.theme.WeQuizTheme 13 | import kr.boostcamp_2024.course.wequiz.R 14 | 15 | @Composable 16 | fun WeQuizApp() { 17 | val snackbarHostState = remember { SnackbarHostState() } 18 | val coroutineScope = rememberCoroutineScope() 19 | val localContextResource = LocalContext.current.resources 20 | val onShowErrorSnackbar: (throwable: Throwable) -> Unit = { throwable -> 21 | coroutineScope.launch { 22 | snackbarHostState.showSnackbar( 23 | when (throwable) { 24 | is FirebaseFirestoreException -> 25 | when (throwable.code) { 26 | FirebaseFirestoreException.Code.PERMISSION_DENIED -> localContextResource.getString(R.string.permission_denied_error_message) 27 | else -> throwable.message ?: localContextResource.getString(R.string.default_error_message) 28 | } 29 | 30 | else -> throwable.message ?: localContextResource.getString(R.string.default_error_message) 31 | }, 32 | ) 33 | } 34 | } 35 | 36 | WeQuizTheme { 37 | WeQuizNavHost( 38 | snackbarHostState = snackbarHostState, 39 | modifier = Modifier 40 | .fillMaxSize(), 41 | onShowErrorSnackbar = onShowErrorSnackbar, 42 | ) 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostcampwm-2024/and02_weQuiz/b300f5ebc15fc5700e9b3850ef4bd2b5021705e0/app/src/main/res/mipmap-hdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostcampwm-2024/and02_weQuiz/b300f5ebc15fc5700e9b3850ef4bd2b5021705e0/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostcampwm-2024/and02_weQuiz/b300f5ebc15fc5700e9b3850ef4bd2b5021705e0/app/src/main/res/mipmap-mdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostcampwm-2024/and02_weQuiz/b300f5ebc15fc5700e9b3850ef4bd2b5021705e0/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostcampwm-2024/and02_weQuiz/b300f5ebc15fc5700e9b3850ef4bd2b5021705e0/app/src/main/res/mipmap-xhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostcampwm-2024/and02_weQuiz/b300f5ebc15fc5700e9b3850ef4bd2b5021705e0/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostcampwm-2024/and02_weQuiz/b300f5ebc15fc5700e9b3850ef4bd2b5021705e0/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostcampwm-2024/and02_weQuiz/b300f5ebc15fc5700e9b3850ef4bd2b5021705e0/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostcampwm-2024/and02_weQuiz/b300f5ebc15fc5700e9b3850ef4bd2b5021705e0/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostcampwm-2024/and02_weQuiz/b300f5ebc15fc5700e9b3850ef4bd2b5021705e0/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/main/res/values-ko/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 오류가 발생했습니다.\n다시 시도해 주세요. 4 | 해당 기능은 회원가입 후 사용해주세요. 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/values-zh/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 发生错误\n请重试。 4 | 请注册后使用此功能。 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #FFBB86FC 4 | #FF6200EE 5 | #FF3700B3 6 | #FF03DAC5 7 | #FF018786 8 | #FF000000 9 | #FFFFFFFF 10 | -------------------------------------------------------------------------------- /app/src/main/res/values/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #F5FBF6 4 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | wequiz 3 | An Error occured.\nPlease try again. 4 | Please sign up to use this feature. 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/values/themes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |