├── app
├── .gitignore
├── src
│ ├── main
│ │ ├── ic_app_icon-playstore.png
│ │ ├── res
│ │ │ ├── font
│ │ │ │ ├── pretendard_bold.otf
│ │ │ │ ├── pretendard_regular.otf
│ │ │ │ ├── pretendard_semibold.otf
│ │ │ │ ├── font_pretendard_bold.xml
│ │ │ │ ├── font_pretendard_regular.xml
│ │ │ │ └── font_pretendard_semibold.xml
│ │ │ ├── mipmap-hdpi
│ │ │ │ ├── ic_app_icon.webp
│ │ │ │ ├── ic_app_icon_round.webp
│ │ │ │ └── ic_app_icon_foreground.webp
│ │ │ ├── mipmap-mdpi
│ │ │ │ ├── ic_app_icon.webp
│ │ │ │ ├── ic_app_icon_round.webp
│ │ │ │ └── ic_app_icon_foreground.webp
│ │ │ ├── mipmap-xhdpi
│ │ │ │ ├── ic_app_icon.webp
│ │ │ │ ├── ic_app_icon_round.webp
│ │ │ │ └── ic_app_icon_foreground.webp
│ │ │ ├── values
│ │ │ │ ├── dimens.xml
│ │ │ │ └── spinner_array.xml
│ │ │ ├── mipmap-xxhdpi
│ │ │ │ ├── ic_app_icon.webp
│ │ │ │ ├── ic_app_icon_round.webp
│ │ │ │ └── ic_app_icon_foreground.webp
│ │ │ ├── mipmap-xxxhdpi
│ │ │ │ ├── ic_app_icon.webp
│ │ │ │ ├── ic_app_icon_round.webp
│ │ │ │ └── ic_app_icon_foreground.webp
│ │ │ ├── drawable
│ │ │ │ ├── shape_regular_fill_30_rect.xml
│ │ │ │ ├── shape_blue50_fill_14_rect.xml
│ │ │ │ ├── shape_gray50_fill_10_rect.xml
│ │ │ │ ├── shape_blue300_fill_30_rect.xml
│ │ │ │ ├── shape_gray200_fill_10_rect.xml
│ │ │ │ ├── shape_mint400_fill_10_rect.xml
│ │ │ │ ├── checkbox_selector.xml
│ │ │ │ ├── shpae_mint50_fill_40_rect.xml
│ │ │ │ ├── shape_gray200_fill_20_rect.xml
│ │ │ │ ├── shape_gray200_fill_40_rect.xml
│ │ │ │ ├── shape_gray200_fill_90_rect.xml
│ │ │ │ ├── shape_mint400_fill_20_rect.xml
│ │ │ │ ├── shape_mint400_fill_24_rect.xml
│ │ │ │ ├── shape_mint400_fill_30_rect.xml
│ │ │ │ ├── shape_mint400_fill_40_rect.xml
│ │ │ │ ├── shape_mint900_fill_50_rect.xml
│ │ │ │ ├── sel_date_day_text.xml
│ │ │ │ ├── shape_gradient_fill_rect.xml
│ │ │ │ ├── shape_regular_line_16_rect.xml
│ │ │ │ ├── bg_spinner.xml
│ │ │ │ ├── shape_regular_line_rect.xml
│ │ │ │ ├── shape_white_fill_top25_rect.xml
│ │ │ │ ├── shape_gray50_line_12_rect.xml
│ │ │ │ ├── sel_home_nav_selected_item.xml
│ │ │ │ ├── sel_quick_scan_tab_indicator.xml
│ │ │ │ ├── shape_gray900_fill_circle.xml
│ │ │ │ ├── sel_date_day_button.xml
│ │ │ │ ├── sel_login_button.xml
│ │ │ │ ├── sel_setting_nav_selected_item.xml
│ │ │ │ ├── sel_signup_button.xml
│ │ │ │ ├── sel_storage_nav_selected_item.xml
│ │ │ │ ├── sel_createaccount_button.xml
│ │ │ │ ├── shape_gray100_fill_8_rect.xml
│ │ │ │ ├── shape_regular_line_4_rect.xml
│ │ │ │ ├── shape_white_line_30_rect.xml
│ │ │ │ ├── shape_white_line_50_rect.xml
│ │ │ │ ├── shape_white_line_40_rect.xml
│ │ │ │ ├── bg_spinner_down.xml
│ │ │ │ ├── bg_spinner_up.xml
│ │ │ │ ├── sel_notice_detail_like.xml
│ │ │ │ ├── sel_notice_detail_bookmark.xml
│ │ │ │ ├── sel_quick_scan_bookmark.xml
│ │ │ │ ├── ic_box.xml
│ │ │ │ ├── ic_cursor.xml
│ │ │ │ ├── ic_check_box_checked.xml
│ │ │ │ ├── bg_student_id_spinner.xml
│ │ │ │ ├── ic_check.xml
│ │ │ │ ├── bg_date_gradient.xml
│ │ │ │ ├── ic_date_arrow.xml
│ │ │ │ ├── ic_setting_arrow.xml
│ │ │ │ ├── ic_date_close.xml
│ │ │ │ ├── ic_notice_detail_bookmark_on.xml
│ │ │ │ ├── ic_signup_right_arrow.xml
│ │ │ │ ├── ic_notice_post_arrow.xml
│ │ │ │ ├── ic_notice_post_delete.xml
│ │ │ │ ├── ic_handle.xml
│ │ │ │ ├── ic_notice_detail_bookmark_off.xml
│ │ │ │ ├── ic_check_box_unchecked.xml
│ │ │ │ ├── ic_quick_scan_bookmark_selected.xml
│ │ │ │ ├── ic_bottomsheet_notice_post_target_delete.xml
│ │ │ │ ├── ic_quick_scan_bookmark_unselected.xml
│ │ │ │ ├── ic_nav_storage_on.xml
│ │ │ │ ├── ic_nav_storage_off.xml
│ │ │ │ ├── ic_back.xml
│ │ │ │ ├── ic_home_floating_action_btn.xml
│ │ │ │ ├── ic_nav_home_on.xml
│ │ │ │ ├── ic_nav_home_off.xml
│ │ │ │ ├── ic_notice_post_image_delete.xml
│ │ │ │ ├── ic_home_views.xml
│ │ │ │ ├── img_quick_scan_placeholder.xml
│ │ │ │ ├── ic_notice_post_date.xml
│ │ │ │ ├── ic_notice_detail_like.xml
│ │ │ │ ├── ic_notice_post_photo.xml
│ │ │ │ ├── ic_home_like.xml
│ │ │ │ └── ic_notice_detail_dislike.xml
│ │ │ ├── color
│ │ │ │ └── sel_color_bnv_menu.xml
│ │ │ ├── mipmap-anydpi-v26
│ │ │ │ ├── ic_app_icon.xml
│ │ │ │ └── ic_app_icon_round.xml
│ │ │ ├── values-v31
│ │ │ │ └── themes.xml
│ │ │ ├── values-night
│ │ │ │ └── themes.xml
│ │ │ ├── values-v23
│ │ │ │ └── themes.xml
│ │ │ ├── xml
│ │ │ │ ├── backup_rules.xml
│ │ │ │ └── data_extraction_rules.xml
│ │ │ ├── layout
│ │ │ │ ├── item_signup_list.xml
│ │ │ │ ├── activity_splash.xml
│ │ │ │ ├── item_date_number.xml
│ │ │ │ ├── item_bottom_button.xml
│ │ │ │ ├── item_bottom_button_create.xml
│ │ │ │ ├── item_home_notice_category.xml
│ │ │ │ ├── item_notice_detail_image.xml
│ │ │ │ ├── item_toolbar.xml
│ │ │ │ ├── item_notice_post_image.xml
│ │ │ │ └── fragment_storage.xml
│ │ │ └── menu
│ │ │ │ └── menu_main_nav.xml
│ │ └── java
│ │ │ └── com
│ │ │ └── univoice
│ │ │ ├── domain
│ │ │ ├── repository
│ │ │ │ ├── LoginRepository.kt
│ │ │ │ ├── SettingRepository.kt
│ │ │ │ ├── StorageRepository.kt
│ │ │ │ ├── QuickScanRepository.kt
│ │ │ │ ├── PostRepository.kt
│ │ │ │ ├── UserInfoRepository.kt
│ │ │ │ ├── HomeRepository.kt
│ │ │ │ ├── NoticeDetailRepository.kt
│ │ │ │ └── SignUpRepository.kt
│ │ │ └── entity
│ │ │ │ ├── HomeQuickScanListEntity.kt
│ │ │ │ ├── NoticeListEntity.kt
│ │ │ │ ├── StorageListEntity.kt
│ │ │ │ ├── SettingUserEntity.kt
│ │ │ │ ├── QuickScanListEntity.kt
│ │ │ │ └── NoticeDetailEntity.kt
│ │ │ ├── app
│ │ │ ├── di
│ │ │ │ ├── Extension.kt
│ │ │ │ ├── Qualifier.kt
│ │ │ │ ├── UserPreferencesModule.kt
│ │ │ │ ├── HomeModule.kt
│ │ │ │ ├── PostModule.kt
│ │ │ │ ├── SettingModule.kt
│ │ │ │ ├── SignUpModule.kt
│ │ │ │ ├── StorageModule.kt
│ │ │ │ ├── QuickScanModule.kt
│ │ │ │ ├── NoticeDetailModule.kt
│ │ │ │ └── LoginModule.kt
│ │ │ └── interceptor
│ │ │ │ └── TokenInterceptor.kt
│ │ │ ├── feature
│ │ │ ├── util
│ │ │ │ ├── ToolbarUtil.kt
│ │ │ │ ├── Debouncer.kt
│ │ │ │ ├── ThrottleFirst.kt
│ │ │ │ ├── BindingAdapter.kt
│ │ │ │ ├── BiggerDotPasswordTransformationMethod.kt
│ │ │ │ └── CalculateTime.kt
│ │ │ ├── noticePost
│ │ │ │ ├── timePicker
│ │ │ │ │ └── adapter
│ │ │ │ │ │ ├── DateViewHolder.kt
│ │ │ │ │ │ ├── DateDayAdapter.kt
│ │ │ │ │ │ ├── TimeDateAdapter.kt
│ │ │ │ │ │ ├── DateMonthAdapter.kt
│ │ │ │ │ │ ├── DateYearAdapter.kt
│ │ │ │ │ │ ├── TimeMinuteAdapter.kt
│ │ │ │ │ │ ├── TimeHourAdapter.kt
│ │ │ │ │ │ └── TimeMeridiemAdapter.kt
│ │ │ │ ├── NoticePostImageItemDecorator.kt
│ │ │ │ ├── NoticePostImageAdapter.kt
│ │ │ │ └── NoticePostViewModel.kt
│ │ │ ├── noticeDetail
│ │ │ │ ├── NoticeDetailModel.kt
│ │ │ │ ├── NoticeDetailAdapter.kt
│ │ │ │ └── NoticeDetailViewHolder.kt
│ │ │ ├── signup
│ │ │ │ ├── SchoolDepartmentListViewHolder.kt
│ │ │ │ ├── SignUpActivity.kt
│ │ │ │ ├── CreateAccountViewModel.kt
│ │ │ │ ├── SchoolInputViewModel.kt
│ │ │ │ ├── DepartmentInputViewModel.kt
│ │ │ │ ├── CheckInfoActivity.kt
│ │ │ │ └── SignupBottomSheetFragmentViewModel.kt
│ │ │ ├── quickscan
│ │ │ │ ├── QuickScanCompleteActivity.kt
│ │ │ │ └── QuickScanAdapter.kt
│ │ │ ├── entry
│ │ │ │ └── EntryActivity.kt
│ │ │ ├── home
│ │ │ │ ├── HomeQuickscanItemDecorator.kt
│ │ │ │ ├── HomeNoticeCategoryItemDecorator.kt
│ │ │ │ ├── HomeNoticeContentItemDecorator.kt
│ │ │ │ ├── HomeQuickscanViewHolder.kt
│ │ │ │ ├── HomeNoticeContentAdapter.kt
│ │ │ │ ├── HomeQuickscanAdapter.kt
│ │ │ │ └── HomeNoticeContentViewHolder.kt
│ │ │ ├── storage
│ │ │ │ ├── StorageViewHolder.kt
│ │ │ │ ├── StorageAdapter.kt
│ │ │ │ └── StorageViewModel.kt
│ │ │ ├── login
│ │ │ │ ├── LoginBottomSheetFragment.kt
│ │ │ │ ├── WelcomeActivity.kt
│ │ │ │ └── LoginViewModel.kt
│ │ │ ├── setting
│ │ │ │ └── SettingViewModel.kt
│ │ │ ├── MainActivity.kt
│ │ │ └── SplashActivity.kt
│ │ │ ├── data
│ │ │ ├── datasource
│ │ │ │ ├── SettingDataSource.kt
│ │ │ │ ├── StorageDataSource.kt
│ │ │ │ ├── LoginDataSource.kt
│ │ │ │ ├── UserPreferencesDataSource.kt
│ │ │ │ ├── QuickScanDataSource.kt
│ │ │ │ ├── PostDataSource.kt
│ │ │ │ ├── HomeDataSource.kt
│ │ │ │ ├── NoticeDetailDataSource.kt
│ │ │ │ └── SignUpDataSource.kt
│ │ │ ├── dto
│ │ │ │ ├── request
│ │ │ │ │ ├── RequestCheckEmailDto.kt
│ │ │ │ │ ├── RequestDepartmentDto.kt
│ │ │ │ │ ├── RequestQuickScanDto.kt
│ │ │ │ │ └── RequestLoginDto.kt
│ │ │ │ ├── response
│ │ │ │ │ ├── ResponseLoginDto.kt
│ │ │ │ │ ├── ResponseSettingDto.kt
│ │ │ │ │ ├── ResponseNoticeAllDto.kt
│ │ │ │ │ ├── ResponseStorageDto.kt
│ │ │ │ │ ├── ResponseQuickScanDto.kt
│ │ │ │ │ ├── ResponseNoticeQuickScanDto.kt
│ │ │ │ │ └── ResponseNoticeDetailDto.kt
│ │ │ │ └── BaseResponse.kt
│ │ │ ├── mapper
│ │ │ │ ├── ResponseSettingDtoMapper.kt
│ │ │ │ ├── ResponseNoticeAllDtoMapper.kt
│ │ │ │ ├── ResponseStorageDtoMapper.kt
│ │ │ │ ├── ResponseQuickScanDtoMapper.kt
│ │ │ │ └── NoticeDetailResponseDtoMapper.kt
│ │ │ └── repositoryimpl
│ │ │ │ ├── StorageRepositoryImpl.kt
│ │ │ │ ├── LoginRepositoryImpl.kt
│ │ │ │ ├── util
│ │ │ │ └── extractErrorMessage.kt
│ │ │ │ ├── SettingRepositoryImpl.kt
│ │ │ │ ├── UserInfoRepositoryImpl.kt
│ │ │ │ └── QuickScanRepositoryImpl.kt
│ │ │ ├── UniVoiceApp.kt
│ │ │ ├── core_ui
│ │ │ ├── component
│ │ │ │ └── SetStatusBarColor.kt
│ │ │ ├── view
│ │ │ │ ├── ViewExt.kt
│ │ │ │ └── UiState.kt
│ │ │ ├── base
│ │ │ │ ├── BindingActivity.kt
│ │ │ │ ├── BindingFragment.kt
│ │ │ │ ├── BindingBottomSheetFragment.kt
│ │ │ │ └── BindingDialogFragment.kt
│ │ │ ├── theme
│ │ │ │ └── Color.kt
│ │ │ └── CustomSpinner.kt
│ │ │ ├── data_remote
│ │ │ ├── api
│ │ │ │ ├── SettingApiService.kt
│ │ │ │ ├── StorageApiService.kt
│ │ │ │ ├── LoginApiService.kt
│ │ │ │ ├── ApiKeyStorage.kt
│ │ │ │ ├── PostApiService.kt
│ │ │ │ ├── QuickScanApiService.kt
│ │ │ │ ├── HomeApiService.kt
│ │ │ │ └── NoticeDetailApiService.kt
│ │ │ └── datasourceimpl
│ │ │ │ ├── SettingDataSourceImpl.kt
│ │ │ │ ├── StorageDataSourceImpl.kt
│ │ │ │ ├── LoginDataSourceImpl.kt
│ │ │ │ ├── PostDataSourceImpl.kt
│ │ │ │ ├── QuickScanDataSourceImpl.kt
│ │ │ │ ├── HomeDataSourceImpl.kt
│ │ │ │ ├── NoticeDetailDataSourceImpl.kt
│ │ │ │ └── SignUpDataSourceImpl.kt
│ │ │ └── data_local
│ │ │ ├── di
│ │ │ └── ContentResolverModule.kt
│ │ │ └── UserPreferencesDataSourceImpl.kt
│ ├── test
│ │ └── java
│ │ │ └── com
│ │ │ └── univoice
│ │ │ └── ExampleUnitTest.kt
│ └── androidTest
│ │ └── java
│ │ └── com
│ │ └── univoice
│ │ └── ExampleInstrumentedTest.kt
└── proguard-rules.pro
├── .github
├── CODEOWNERS
├── ISSUE_TEMPLATE
│ └── univoice-android-issue-template.md
└── pull_request_template.md
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── icon
├── ic_date_arrow.svg
└── ic_date_close.svg
├── settings.gradle.kts
└── gradle.properties
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/.github/CODEOWNERS:
--------------------------------------------------------------------------------
1 | * @Team-UniVoice/AndroidUniVoice
2 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Team-UniVoice/UniVoice_Android/HEAD/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/app/src/main/ic_app_icon-playstore.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Team-UniVoice/UniVoice_Android/HEAD/app/src/main/ic_app_icon-playstore.png
--------------------------------------------------------------------------------
/app/src/main/res/font/pretendard_bold.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Team-UniVoice/UniVoice_Android/HEAD/app/src/main/res/font/pretendard_bold.otf
--------------------------------------------------------------------------------
/app/src/main/res/font/pretendard_regular.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Team-UniVoice/UniVoice_Android/HEAD/app/src/main/res/font/pretendard_regular.otf
--------------------------------------------------------------------------------
/app/src/main/res/font/pretendard_semibold.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Team-UniVoice/UniVoice_Android/HEAD/app/src/main/res/font/pretendard_semibold.otf
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_app_icon.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Team-UniVoice/UniVoice_Android/HEAD/app/src/main/res/mipmap-hdpi/ic_app_icon.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_app_icon.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Team-UniVoice/UniVoice_Android/HEAD/app/src/main/res/mipmap-mdpi/ic_app_icon.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_app_icon.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Team-UniVoice/UniVoice_Android/HEAD/app/src/main/res/mipmap-xhdpi/ic_app_icon.webp
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 160dp
4 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_app_icon.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Team-UniVoice/UniVoice_Android/HEAD/app/src/main/res/mipmap-xxhdpi/ic_app_icon.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_app_icon.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Team-UniVoice/UniVoice_Android/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_app_icon.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_app_icon_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Team-UniVoice/UniVoice_Android/HEAD/app/src/main/res/mipmap-hdpi/ic_app_icon_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_app_icon_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Team-UniVoice/UniVoice_Android/HEAD/app/src/main/res/mipmap-mdpi/ic_app_icon_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_app_icon_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Team-UniVoice/UniVoice_Android/HEAD/app/src/main/res/mipmap-xhdpi/ic_app_icon_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_app_icon_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Team-UniVoice/UniVoice_Android/HEAD/app/src/main/res/mipmap-xxhdpi/ic_app_icon_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_app_icon_foreground.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Team-UniVoice/UniVoice_Android/HEAD/app/src/main/res/mipmap-hdpi/ic_app_icon_foreground.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_app_icon_foreground.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Team-UniVoice/UniVoice_Android/HEAD/app/src/main/res/mipmap-mdpi/ic_app_icon_foreground.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_app_icon_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Team-UniVoice/UniVoice_Android/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_app_icon_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_app_icon_foreground.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Team-UniVoice/UniVoice_Android/HEAD/app/src/main/res/mipmap-xhdpi/ic_app_icon_foreground.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_app_icon_foreground.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Team-UniVoice/UniVoice_Android/HEAD/app/src/main/res/mipmap-xxhdpi/ic_app_icon_foreground.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_app_icon_foreground.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Team-UniVoice/UniVoice_Android/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_app_icon_foreground.webp
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/domain/repository/LoginRepository.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.domain.repository
2 |
3 | interface LoginRepository {
4 | suspend fun postLogin(email: String, password: String): Result
5 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/domain/entity/HomeQuickScanListEntity.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.domain.entity
2 |
3 | data class HomeQuickScanListEntity(
4 | val name: String,
5 | val count: Int,
6 | val image: String,
7 | )
--------------------------------------------------------------------------------
/icon/ic_date_arrow.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/icon/ic_date_close.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/shape_regular_fill_30_rect.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/domain/repository/SettingRepository.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.domain.repository
2 |
3 | import com.univoice.domain.entity.SettingUserEntity
4 |
5 | interface SettingRepository {
6 | suspend fun getMyPage(): Result
7 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable/shape_blue50_fill_14_rect.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/shape_gray50_fill_10_rect.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/app/di/Extension.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.app.di
2 |
3 | fun String?.isJsonObject(): Boolean = this?.startsWith("{") == true && this.endsWith("}")
4 | fun String?.isJsonArray(): Boolean = this?.startsWith("[") == true && this.endsWith("]")
5 |
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/domain/repository/StorageRepository.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.domain.repository
2 |
3 | import com.univoice.domain.entity.StorageListEntity
4 |
5 | interface StorageRepository {
6 | suspend fun getSaves(): Result?>
7 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable/shape_blue300_fill_30_rect.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/shape_gray200_fill_10_rect.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/shape_mint400_fill_10_rect.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/checkbox_selector.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Thu Jun 27 14:50:18 KST 2024
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip
5 | zipStoreBase=GRADLE_USER_HOME
6 | zipStorePath=wrapper/dists
7 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/shpae_mint50_fill_40_rect.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/shape_gray200_fill_20_rect.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/shape_gray200_fill_40_rect.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/shape_gray200_fill_90_rect.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/shape_mint400_fill_20_rect.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/shape_mint400_fill_24_rect.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/shape_mint400_fill_30_rect.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/shape_mint400_fill_40_rect.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/shape_mint900_fill_50_rect.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/feature/util/ToolbarUtil.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.feature.util
2 |
3 | import android.app.Activity
4 | import android.widget.ImageButton
5 |
6 | fun Activity.setupToolbarClickListener(button: ImageButton) {
7 | button.setOnClickListener {
8 | finish()
9 | }
10 | }
--------------------------------------------------------------------------------
/app/src/main/res/font/font_pretendard_bold.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/univoice-android-issue-template.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: UniVoice android issue template
3 | about: Describe this issue template's purpose here.
4 | title: "[FEAT] : "
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | ## 📌𝗧𝗮𝘀𝗸
11 | - [ ]
12 | - [ ]
13 |
14 | ## 💡𝗥𝗲𝗳𝗲𝗿𝗲𝗻𝗰𝗲
15 |
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/data/datasource/SettingDataSource.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.data.datasource
2 |
3 | import com.univoice.data.dto.BaseResponse
4 | import com.univoice.data.dto.response.ResponseSettingDto
5 |
6 | interface SettingDataSource {
7 | suspend fun getMyPage(): BaseResponse
8 | }
--------------------------------------------------------------------------------
/app/src/main/res/font/font_pretendard_regular.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/app/di/Qualifier.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.app.di
2 |
3 | import javax.inject.Qualifier
4 |
5 | @Qualifier
6 | @Retention(AnnotationRetention.BINARY)
7 | annotation class UniVoiceRetrofit
8 |
9 | @Qualifier
10 | @Retention(AnnotationRetention.BINARY)
11 | annotation class AccessToken
12 |
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/data/datasource/StorageDataSource.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.data.datasource
2 |
3 | import com.univoice.data.dto.BaseResponse
4 | import com.univoice.data.dto.response.ResponseStorageDto
5 |
6 | interface StorageDataSource {
7 | suspend fun getSaves(): BaseResponse>
8 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable/sel_date_day_text.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/font/font_pretendard_semibold.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/color/sel_color_bnv_menu.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_app_icon.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/data/dto/request/RequestCheckEmailDto.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.data.dto.request
2 |
3 | import kotlinx.serialization.SerialName
4 | import kotlinx.serialization.Serializable
5 |
6 | @Serializable
7 | data class RequestCheckEmailDto(
8 | @SerialName("email")
9 | val email: String
10 | )
11 |
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/domain/entity/NoticeListEntity.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.domain.entity
2 |
3 | data class NoticeListEntity(
4 | val id: Int,
5 | val title: String,
6 | val likeCount: Int,
7 | val viewCount: Int,
8 | val category: String,
9 | val date: String,
10 | val image: String,
11 | )
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_app_icon_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/data/dto/response/ResponseLoginDto.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.data.dto.response
2 |
3 | import kotlinx.serialization.SerialName
4 | import kotlinx.serialization.Serializable
5 |
6 | @Serializable
7 | data class ResponseLoginDto(
8 | @SerialName("accessToken")
9 | val accessToken: String = "",
10 | )
--------------------------------------------------------------------------------
/app/src/main/res/drawable/shape_gradient_fill_rect.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/shape_regular_line_16_rect.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
7 |
8 |
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/domain/entity/StorageListEntity.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.domain.entity
2 |
3 | data class StorageListEntity (
4 | val id: Int,
5 | val title: String,
6 | val viewCount: Int,
7 | val noticeLike: Int,
8 | val category: String,
9 | val createdAt: String,
10 | val image: String?
11 | )
--------------------------------------------------------------------------------
/app/src/main/res/drawable/bg_spinner.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/shape_regular_line_rect.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
7 |
8 |
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/data/dto/request/RequestDepartmentDto.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.data.dto.request
2 |
3 | import kotlinx.serialization.SerialName
4 | import kotlinx.serialization.Serializable
5 |
6 | @Serializable
7 | data class RequestDepartmentDto(
8 | @SerialName("universityName")
9 | val universityName: String = ""
10 | )
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/shape_white_fill_top25_rect.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
8 |
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/data/dto/request/RequestQuickScanDto.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.data.dto.request
2 |
3 | import kotlinx.serialization.SerialName
4 | import kotlinx.serialization.Serializable
5 | import java.io.Serial
6 |
7 | @Serializable
8 | data class RequestQuickScanDto(
9 | @SerialName("affiliation") val affiliation: String = ""
10 | )
--------------------------------------------------------------------------------
/app/src/main/res/drawable/shape_gray50_line_12_rect.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/sel_home_nav_selected_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/sel_quick_scan_tab_indicator.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/shape_gray900_fill_circle.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
9 |
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/domain/entity/SettingUserEntity.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.domain.entity
2 |
3 | data class SettingUserEntity(
4 | val id: Int,
5 | val name: String,
6 | val collegeDepartment: String,
7 | val department: String,
8 | val admissionNumber: String,
9 | val university: String,
10 | val universityLogoImage: String,
11 | )
--------------------------------------------------------------------------------
/app/src/main/res/drawable/sel_date_day_button.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/sel_login_button.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/sel_setting_nav_selected_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/sel_signup_button.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/sel_storage_nav_selected_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/domain/repository/QuickScanRepository.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.domain.repository
2 |
3 | import com.univoice.domain.entity.QuickScanListEntity
4 |
5 | interface QuickScanRepository {
6 | suspend fun postQuickScan(writeAffiliation: String): Result?>
7 | suspend fun postQuickScanViewCheck(noticeId: Int): Result
8 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable/sel_createaccount_button.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/shape_gray100_fill_8_rect.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/shape_regular_line_4_rect.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/shape_white_line_30_rect.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/shape_white_line_50_rect.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/shape_white_line_40_rect.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/data/dto/request/RequestLoginDto.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.data.dto.request
2 |
3 | import kotlinx.serialization.SerialName
4 | import kotlinx.serialization.Serializable
5 |
6 | @Serializable
7 | data class RequestLoginDto(
8 | @SerialName("email")
9 | val email: String = "",
10 | @SerialName("password")
11 | val password: String = "",
12 | )
--------------------------------------------------------------------------------
/app/src/main/res/drawable/bg_spinner_down.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/bg_spinner_up.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/data/datasource/LoginDataSource.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.data.datasource
2 |
3 | import com.univoice.data.dto.BaseResponse
4 | import com.univoice.data.dto.request.RequestLoginDto
5 | import com.univoice.data.dto.response.ResponseLoginDto
6 |
7 | interface LoginDataSource {
8 | suspend fun postLogin(requestLoginDto: RequestLoginDto): BaseResponse
9 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/data/mapper/ResponseSettingDtoMapper.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.data.mapper
2 |
3 | import com.univoice.data.dto.response.ResponseSettingDto
4 | import com.univoice.domain.entity.SettingUserEntity
5 |
6 | fun ResponseSettingDto.toSettingUserEntity() = SettingUserEntity(
7 | id, name, collegeDepartment, department, admissionNumber, university, universityLogoImage,
8 | )
--------------------------------------------------------------------------------
/app/src/main/res/drawable/sel_notice_detail_like.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
7 |
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/feature/noticePost/timePicker/adapter/DateViewHolder.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.feature.noticePost.timePicker.adapter
2 |
3 | import androidx.annotation.Keep
4 | import androidx.recyclerview.widget.RecyclerView
5 | import com.univoice.databinding.ItemDateNumberBinding
6 |
7 | @Keep
8 | class DateViewHolder(val binding: ItemDateNumberBinding) :
9 | RecyclerView.ViewHolder(binding.root)
--------------------------------------------------------------------------------
/app/src/main/res/drawable/sel_notice_detail_bookmark.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/sel_quick_scan_bookmark.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
7 |
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/data/dto/BaseResponse.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.data.dto
2 |
3 | import kotlinx.serialization.SerialName
4 | import kotlinx.serialization.Serializable
5 |
6 | @Serializable
7 | data class BaseResponse(
8 | @SerialName("status")
9 | val status: Int,
10 | @SerialName("message")
11 | val message: String,
12 | @SerialName("data")
13 | val data: T? = null,
14 | )
15 |
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/domain/repository/PostRepository.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.domain.repository
2 |
3 | import java.io.File
4 |
5 | interface PostRepository {
6 | suspend fun postSignUp(
7 | title: String,
8 | content: String,
9 | target: String?,
10 | startTime: String?,
11 | endTime: String?,
12 | noticeImages: List?,
13 | ): Result
14 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_box.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_cursor.xml:
--------------------------------------------------------------------------------
1 |
6 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/values/spinner_array.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | - 학번 선택하기
5 | - 24학번
6 | - 23학번
7 | - 22학번
8 | - 21학번
9 | - 20학번
10 | - 19학번
11 | - 18학번
12 |
13 |
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/data/mapper/ResponseNoticeAllDtoMapper.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.data.mapper
2 |
3 | import com.univoice.data.dto.response.ResponseNoticeAllDto
4 | import com.univoice.domain.entity.NoticeListEntity
5 |
6 | fun ResponseNoticeAllDto.toNoticeListEntity() = NoticeListEntity(
7 | id,
8 | title,
9 | likeCount,
10 | viewCount,
11 | category,
12 | createdAt,
13 | image ?: ""
14 | )
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/data/mapper/ResponseStorageDtoMapper.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.data.mapper
2 |
3 | import com.univoice.data.dto.response.ResponseStorageDto
4 | import com.univoice.domain.entity.StorageListEntity
5 |
6 | fun ResponseStorageDto.toStorageListEntity() = StorageListEntity(
7 | id,
8 | title,
9 | viewCount,
10 | noticeLike,
11 | category,
12 | createdAt,
13 | image ?: ""
14 | )
15 |
16 |
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/UniVoiceApp.kt:
--------------------------------------------------------------------------------
1 | package com.univoice
2 |
3 | import android.app.Application
4 | import dagger.hilt.android.HiltAndroidApp
5 | import timber.log.Timber
6 |
7 | @HiltAndroidApp
8 | class UniVoiceApp : Application() {
9 | override fun onCreate() {
10 | super.onCreate()
11 | setTimber()
12 | }
13 |
14 | private fun setTimber() {
15 | Timber.plant(Timber.DebugTree())
16 | }
17 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_check_box_checked.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/data/datasource/UserPreferencesDataSource.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.data.datasource
2 |
3 | import kotlinx.coroutines.flow.Flow
4 |
5 | interface UserPreferencesDataSource {
6 | suspend fun saveUserAccessToken(accessToken: String)
7 | fun getUserAccessToken(): Flow
8 |
9 | suspend fun saveCheckLogin(checkLogin: Boolean)
10 | fun getCheckLogin(): Flow
11 |
12 | suspend fun clear()
13 | }
--------------------------------------------------------------------------------
/app/src/main/res/values-v31/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
--------------------------------------------------------------------------------
/app/src/test/java/com/univoice/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package com.univoice
2 |
3 | import org.junit.Test
4 |
5 | import org.junit.Assert.*
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * See [testing documentation](http://d.android.com/tools/testing).
11 | */
12 | class ExampleUnitTest {
13 | @Test
14 | fun addition_isCorrect() {
15 | assertEquals(4, 2 + 2)
16 | }
17 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/domain/repository/UserInfoRepository.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.domain.repository
2 |
3 | import kotlinx.coroutines.flow.Flow
4 |
5 | interface UserInfoRepository {
6 | suspend fun saveUserAccessToken(accessToken: String)
7 |
8 | fun getUserAccessToken(): Flow
9 |
10 | suspend fun saveCheckLogin(checkLogin: Boolean)
11 |
12 | fun getCheckLogin(): Flow
13 |
14 | suspend fun clear()
15 | }
--------------------------------------------------------------------------------
/.github/pull_request_template.md:
--------------------------------------------------------------------------------
1 | ## ✅ 𝗖𝗵𝗲𝗰𝗸-𝗟𝗶𝘀𝘁
2 | - merge할 브랜치의 위치를 확인해 주세요.(main❌/develop⭕)
3 | - 리뷰가 필요한 경우 리뷰어를 지정해 주세요.
4 | - 리뷰는 PR이 올라오면 최대한 빠르게 진행합니다.
5 | - P1 단계의 리뷰는 빠르게 확인 후 반영합니다.
6 | - Approve된 PR은 assigner가 머지하고, 수정 요청이 온 경우 수정 후 다시 push를 합니다.
7 |
8 | ## 📌 𝗜𝘀𝘀𝘂𝗲𝘀
9 | - closed #
10 |
11 | ## 📎 𝗪𝗼𝗿𝗸 𝗗𝗲𝘀𝗰𝗿𝗶𝗽𝘁𝗶𝗼𝗻
12 | -
13 | -
14 |
15 | ## 📷 𝗦𝗰𝗿𝗲𝗲𝗻𝘀𝗵𝗼𝘁
16 |
17 |
18 | ## 💬 𝗧𝗼 𝗥𝗲𝘃𝗶𝗲𝘄𝗲𝗿𝘀
19 |
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/feature/noticeDetail/NoticeDetailModel.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.feature.noticeDetail
2 |
3 | data class NoticeDetailModel(
4 | val noticeId: Int,
5 | val writeAffiliation: String,
6 | val title: String,
7 | val target: String,
8 | val startTime: String,
9 | val endTime: String,
10 | val imageList: List,
11 | val content: String,
12 | val createdAt: String,
13 | val viewCount: Int
14 | )
--------------------------------------------------------------------------------
/app/src/main/res/drawable/bg_student_id_spinner.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_check.xml:
--------------------------------------------------------------------------------
1 |
6 |
12 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/bg_date_gradient.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
5 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/data/datasource/QuickScanDataSource.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.data.datasource
2 |
3 | import com.univoice.data.dto.BaseResponse
4 | import com.univoice.data.dto.request.RequestQuickScanDto
5 | import com.univoice.data.dto.response.ResponseQuickScanDto
6 |
7 | interface QuickScanDataSource {
8 | suspend fun postQuickScan(requestQuickScanDto: RequestQuickScanDto): BaseResponse>
9 | suspend fun postQuickScanViewCheck(noticeId: Int): BaseResponse
10 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_date_arrow.xml:
--------------------------------------------------------------------------------
1 |
6 |
13 |
14 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_setting_arrow.xml:
--------------------------------------------------------------------------------
1 |
6 |
13 |
14 |
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/data/mapper/ResponseQuickScanDtoMapper.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.data.mapper
2 |
3 | import com.univoice.data.dto.response.ResponseQuickScanDto
4 | import com.univoice.domain.entity.QuickScanListEntity
5 |
6 | fun ResponseQuickScanDto.toQuickScanListEntity() = QuickScanListEntity(
7 | id,
8 | startTime,
9 | endTime,
10 | title,
11 | target,
12 | writeAffiliation,
13 | contentSummary,
14 | likeCount,
15 | viewCount,
16 | category,
17 | createdAt
18 | )
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_date_close.xml:
--------------------------------------------------------------------------------
1 |
6 |
13 |
14 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_notice_detail_bookmark_on.xml:
--------------------------------------------------------------------------------
1 |
6 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_signup_right_arrow.xml:
--------------------------------------------------------------------------------
1 |
6 |
13 |
14 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_notice_post_arrow.xml:
--------------------------------------------------------------------------------
1 |
6 |
13 |
14 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_notice_post_delete.xml:
--------------------------------------------------------------------------------
1 |
6 |
13 |
14 |
--------------------------------------------------------------------------------
/app/src/main/res/values-night/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_handle.xml:
--------------------------------------------------------------------------------
1 |
6 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_notice_detail_bookmark_off.xml:
--------------------------------------------------------------------------------
1 |
6 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/values-v23/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_check_box_unchecked.xml:
--------------------------------------------------------------------------------
1 |
6 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_quick_scan_bookmark_selected.xml:
--------------------------------------------------------------------------------
1 |
6 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/data/datasource/PostDataSource.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.data.datasource
2 |
3 | import com.univoice.data.dto.BaseResponse
4 | import okhttp3.MultipartBody
5 | import okhttp3.RequestBody
6 |
7 | interface PostDataSource {
8 | suspend fun postNotice(
9 | title: RequestBody,
10 | content: RequestBody,
11 | target: RequestBody?,
12 | startTime: RequestBody?,
13 | endTime: RequestBody?,
14 | noticeImages: List?,
15 | ): BaseResponse
16 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_bottomsheet_notice_post_target_delete.xml:
--------------------------------------------------------------------------------
1 |
6 |
13 |
14 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_quick_scan_bookmark_unselected.xml:
--------------------------------------------------------------------------------
1 |
6 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/core_ui/component/SetStatusBarColor.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.core_ui.component
2 |
3 | import androidx.compose.runtime.Composable
4 | import androidx.compose.runtime.SideEffect
5 | import androidx.compose.ui.graphics.Color
6 | import com.google.accompanist.systemuicontroller.rememberSystemUiController
7 |
8 | @Composable
9 | fun SetStatusBarColor(color: Color) {
10 | val systemUiController = rememberSystemUiController()
11 | SideEffect {
12 | systemUiController.setSystemBarsColor(color)
13 | }
14 | }
--------------------------------------------------------------------------------
/app/src/main/res/xml/backup_rules.xml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
13 |
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/data_remote/api/SettingApiService.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.data_remote.api
2 |
3 | import com.univoice.data.dto.BaseResponse
4 | import com.univoice.data.dto.response.ResponseSettingDto
5 | import com.univoice.data_remote.api.ApiKeyStorage.API
6 | import com.univoice.data_remote.api.ApiKeyStorage.MYPAGE
7 | import com.univoice.data_remote.api.ApiKeyStorage.V1
8 | import retrofit2.http.GET
9 |
10 | interface SettingApiService {
11 | @GET("/$API/$V1/$MYPAGE")
12 | suspend fun getMyPage(): BaseResponse
13 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/core_ui/view/ViewExt.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.core_ui.view
2 |
3 | import androidx.recyclerview.widget.DiffUtil
4 |
5 | class ItemDiffCallback(
6 | val onItemsTheSame: (T, T) -> Boolean,
7 | val onContentsTheSame: (T, T) -> Boolean
8 | ) : DiffUtil.ItemCallback() {
9 | override fun areItemsTheSame(
10 | oldItem: T, newItem: T
11 | ): Boolean = onItemsTheSame(oldItem, newItem)
12 |
13 | override fun areContentsTheSame(
14 | oldItem: T, newItem: T
15 | ): Boolean = onContentsTheSame(oldItem, newItem)
16 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/domain/entity/QuickScanListEntity.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.domain.entity
2 |
3 | data class QuickScanListEntity(
4 | val id: Int,
5 | val startTime: String? = null,
6 | val endTime: String? = null,
7 | val title: String = "",
8 | val target: String? = null,
9 | val writeAffiliation: String = "",
10 | val contentSummary: String = "",
11 | val likeCount: Int = 0,
12 | var viewCount: Int = 0,
13 | val category: String = "",
14 | val createdAt: String = "",
15 | val logoImage: String? = null,
16 | var saveCheck: Boolean = false
17 | )
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/feature/util/Debouncer.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.feature.util
2 |
3 | import kotlinx.coroutines.Dispatchers
4 | import kotlinx.coroutines.GlobalScope
5 | import kotlinx.coroutines.Job
6 | import kotlinx.coroutines.delay
7 | import kotlinx.coroutines.launch
8 |
9 | class Debouncer {
10 | private var debounceJob: Job? = null
11 | fun setDelay(value: T, delay: Long, action: (T) -> Unit) {
12 | debounceJob?.cancel()
13 | debounceJob = GlobalScope.launch(Dispatchers.Main) {
14 | delay(delay)
15 | action(value)
16 | }
17 | }
18 | }
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_signup_list.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
14 |
15 |
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/feature/util/ThrottleFirst.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.feature.util
2 |
3 | import kotlinx.coroutines.flow.Flow
4 | import kotlinx.coroutines.flow.flow
5 |
6 | fun Flow.throttleFirst(periodMillis: Long): Flow {
7 | require(periodMillis > 0) { "period should be positive" }
8 | return flow {
9 | var lastTime = 0L
10 | collect { value ->
11 | val currentTime = System.currentTimeMillis()
12 | if (currentTime - lastTime >= periodMillis) {
13 | lastTime = currentTime
14 | emit(value)
15 | }
16 | }
17 | }
18 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_nav_storage_on.xml:
--------------------------------------------------------------------------------
1 |
6 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_splash.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/data/mapper/NoticeDetailResponseDtoMapper.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.data.mapper
2 |
3 | import com.univoice.data.dto.response.ResponseNoticeDetailDto
4 | import com.univoice.domain.entity.NoticeDetailEntity
5 |
6 | fun ResponseNoticeDetailDto.toNoticeDetailEntity() = NoticeDetailEntity(
7 | id,
8 | title,
9 | content,
10 | noticeLike,
11 | viewCount,
12 | target,
13 | startTime,
14 | endTime,
15 | category,
16 | contentSummary,
17 | memberId,
18 | writeAffiliation,
19 | noticeImages,
20 | createdAt,
21 | likeCheck,
22 | saveCheck,
23 | dayOfWeek
24 | )
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_nav_storage_off.xml:
--------------------------------------------------------------------------------
1 |
6 |
11 |
12 |
--------------------------------------------------------------------------------
/settings.gradle.kts:
--------------------------------------------------------------------------------
1 | pluginManagement {
2 | repositories {
3 | google {
4 | content {
5 | includeGroupByRegex("com\\.android.*")
6 | includeGroupByRegex("com\\.google.*")
7 | includeGroupByRegex("androidx.*")
8 | }
9 | }
10 | mavenCentral()
11 | gradlePluginPortal()
12 | }
13 | }
14 | dependencyResolutionManagement {
15 | repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
16 | repositories {
17 | google()
18 | mavenCentral()
19 | }
20 | }
21 |
22 | rootProject.name = "UniVoice"
23 | include(":app")
24 |
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/data_remote/datasourceimpl/SettingDataSourceImpl.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.data_remote.datasourceimpl
2 |
3 | import com.univoice.data.datasource.SettingDataSource
4 | import com.univoice.data.dto.BaseResponse
5 | import com.univoice.data.dto.response.ResponseSettingDto
6 | import com.univoice.data_remote.api.SettingApiService
7 | import javax.inject.Inject
8 |
9 | class SettingDataSourceImpl @Inject constructor(
10 | private val settingApiService: SettingApiService
11 | ) : SettingDataSource {
12 | override suspend fun getMyPage(): BaseResponse =
13 | settingApiService.getMyPage()
14 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/feature/signup/SchoolDepartmentListViewHolder.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.feature.signup
2 |
3 | import android.view.View
4 | import android.widget.TextView
5 | import androidx.recyclerview.widget.RecyclerView
6 | import com.univoice.R
7 |
8 | class SchoolDepartmentListViewHolder(itemView: View, private val itemClickListener: ((Int) -> Unit)?) :
9 | RecyclerView.ViewHolder(itemView) {
10 | val textView: TextView = itemView.findViewById(R.id.tv_listview_item)
11 |
12 | init {
13 | itemView.setOnClickListener {
14 | itemClickListener?.invoke(adapterPosition)
15 | }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/data_remote/datasourceimpl/StorageDataSourceImpl.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.data_remote.datasourceimpl
2 |
3 | import com.univoice.data.datasource.StorageDataSource
4 | import com.univoice.data.dto.BaseResponse
5 | import com.univoice.data.dto.response.ResponseStorageDto
6 | import com.univoice.data_remote.api.StorageApiService
7 | import javax.inject.Inject
8 |
9 | class StorageDataSourceImpl @Inject constructor(
10 | private val storageApiService: StorageApiService
11 | ) : StorageDataSource {
12 | override suspend fun getSaves(): BaseResponse> =
13 | storageApiService.getSaves()
14 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/domain/repository/HomeRepository.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.domain.repository
2 |
3 | import com.univoice.domain.entity.NoticeListEntity
4 | import com.univoice.domain.entity.HomeQuickScanListEntity
5 |
6 | interface HomeRepository {
7 | suspend fun getNoticeQuickScan(): Result?>
8 |
9 | suspend fun getNoticeAll(): Result?>
10 |
11 | suspend fun getNoticeUniversity(): Result?>
12 |
13 | suspend fun getNoticeCollege(): Result?>
14 |
15 | suspend fun getNoticeDepartment(): Result?>
16 | }
--------------------------------------------------------------------------------
/app/src/main/res/xml/data_extraction_rules.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
12 |
13 |
19 |
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/domain/entity/NoticeDetailEntity.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.domain.entity
2 |
3 |
4 | data class NoticeDetailEntity(
5 | val id: Int,
6 | val title: String,
7 | val content: String,
8 | val noticeLike: Int,
9 | val viewCount: Int,
10 | val target: String?,
11 | val startTime: String?,
12 | val endTime: String?,
13 | val category: String,
14 | val contentSummary: String,
15 | val memberId: Int,
16 | val writeAffiliation: String,
17 | val noticeImages: List,
18 | val createdAt: String,
19 | val likeCheck: Boolean,
20 | val saveCheck: Boolean,
21 | val dayOfWeek: String
22 | )
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/domain/repository/NoticeDetailRepository.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.domain.repository
2 |
3 | import com.univoice.domain.entity.NoticeDetailEntity
4 |
5 | interface NoticeDetailRepository {
6 | suspend fun getNoticeDetail(noticeId: Int): Result
7 |
8 | suspend fun postNoticeLike(noticeId: Int): Result
9 |
10 | suspend fun postNoticeCancelLike(noticeId: Int): Result
11 |
12 | suspend fun postNoticeDetailViewCount(noticeId: Int): Result
13 |
14 | suspend fun postNoticeDetailSave(noticeId: Int): Result
15 |
16 | suspend fun postNoticeDetailCancel(noticeId: Int): Result
17 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/data_remote/api/StorageApiService.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.data_remote.api
2 |
3 | import com.univoice.data.dto.BaseResponse
4 | import com.univoice.data.dto.response.ResponseStorageDto
5 | import com.univoice.data_remote.api.ApiKeyStorage.ALL
6 | import com.univoice.data_remote.api.ApiKeyStorage.API
7 | import com.univoice.data_remote.api.ApiKeyStorage.NOTICE
8 | import com.univoice.data_remote.api.ApiKeyStorage.SAVE
9 | import com.univoice.data_remote.api.ApiKeyStorage.V1
10 | import retrofit2.http.GET
11 |
12 | interface StorageApiService {
13 | @GET("$API/$V1/$NOTICE/$SAVE/$ALL")
14 | suspend fun getSaves(): BaseResponse>
15 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/data_local/di/ContentResolverModule.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.data_local.di
2 |
3 | import android.content.ContentResolver
4 | import android.content.Context
5 | import dagger.Module
6 | import dagger.Provides
7 | import dagger.hilt.InstallIn
8 | import dagger.hilt.android.qualifiers.ApplicationContext
9 | import dagger.hilt.components.SingletonComponent
10 | import javax.inject.Singleton
11 |
12 | @Module
13 | @InstallIn(SingletonComponent::class)
14 | object ContentResolverModule {
15 | @Provides
16 | @Singleton
17 | fun providesContentResolver(
18 | @ApplicationContext context: Context,
19 | ): ContentResolver = context.contentResolver
20 | }
--------------------------------------------------------------------------------
/app/src/main/res/menu/menu_main_nav.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/data/dto/response/ResponseSettingDto.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.data.dto.response
2 |
3 | import kotlinx.serialization.SerialName
4 | import kotlinx.serialization.Serializable
5 |
6 | @Serializable
7 | data class ResponseSettingDto(
8 | @SerialName("id") val id: Int = -1,
9 | @SerialName("name") val name: String = "",
10 | @SerialName("collegeDepartment") val collegeDepartment: String = "",
11 | @SerialName("department") val department: String = "",
12 | @SerialName("admissionNumber") val admissionNumber: String = "",
13 | @SerialName("university") val university: String = "",
14 | @SerialName("universityLogoImage") val universityLogoImage: String = "",
15 | )
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_back.xml:
--------------------------------------------------------------------------------
1 |
6 |
12 |
15 |
16 |
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/data_remote/datasourceimpl/LoginDataSourceImpl.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.data_remote.datasourceimpl
2 |
3 | import com.univoice.data.datasource.LoginDataSource
4 | import com.univoice.data.dto.BaseResponse
5 | import com.univoice.data.dto.request.RequestLoginDto
6 | import com.univoice.data.dto.response.ResponseLoginDto
7 | import com.univoice.data_remote.api.LoginApiService
8 | import javax.inject.Inject
9 |
10 | class LoginDataSourceImpl @Inject constructor(
11 | private val loginApiService: LoginApiService
12 | ) : LoginDataSource {
13 | override suspend fun postLogin(requestLoginDto: RequestLoginDto): BaseResponse =
14 | loginApiService.postLogin(requestLoginDto)
15 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/feature/util/BindingAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.feature.util
2 |
3 | import android.widget.ImageView
4 | import androidx.databinding.BindingAdapter
5 | import coil.load
6 | import coil.transform.RoundedCornersTransformation
7 | import com.univoice.R
8 |
9 | @BindingAdapter("imageUrl")
10 | fun loadImage(view: ImageView, url: String?) {
11 | view.load(url) {
12 | placeholder(R.drawable.img_quick_scan_placeholder)
13 | error(R.drawable.img_quick_scan_placeholder)
14 | }
15 | }
16 |
17 | @BindingAdapter("setCircleImage")
18 | fun ImageView.setCircleImage(img: String?) {
19 | load(img) {
20 | transformations(RoundedCornersTransformation(1000f))
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/data/repositoryimpl/StorageRepositoryImpl.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.data.repositoryimpl
2 |
3 | import com.univoice.data.datasource.StorageDataSource
4 | import com.univoice.data.mapper.toStorageListEntity
5 | import com.univoice.domain.entity.StorageListEntity
6 | import com.univoice.domain.repository.StorageRepository
7 | import javax.inject.Inject
8 |
9 | class StorageRepositoryImpl @Inject constructor(
10 | private val storageDataSource: StorageDataSource
11 | ) : StorageRepository {
12 | override suspend fun getSaves(): Result?> {
13 | return runCatching {
14 | storageDataSource.getSaves().data?.map { it.toStorageListEntity() }
15 | }
16 | }
17 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/data/datasource/HomeDataSource.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.data.datasource
2 |
3 | import com.univoice.data.dto.BaseResponse
4 | import com.univoice.data.dto.response.ResponseNoticeAllDto
5 | import com.univoice.data.dto.response.ResponseNoticeQuickScanDto
6 |
7 | interface HomeDataSource {
8 | suspend fun getNoticeQuickScan(): BaseResponse
9 |
10 | suspend fun getNoticeAll(): BaseResponse>
11 |
12 | suspend fun getNoticeUniversity(): BaseResponse>
13 |
14 | suspend fun getNoticeCollege(): BaseResponse>
15 |
16 | suspend fun getNoticeDepartment(): BaseResponse>
17 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/data/datasource/NoticeDetailDataSource.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.data.datasource
2 |
3 | import com.univoice.data.dto.BaseResponse
4 | import com.univoice.data.dto.response.ResponseNoticeDetailDto
5 |
6 | interface NoticeDetailDataSource {
7 | suspend fun getNoticeDetail(noticeId: Int): BaseResponse
8 |
9 | suspend fun postNoticeLike(noticeId: Int): BaseResponse
10 |
11 | suspend fun postNoticeCancelLike(noticeId: Int): BaseResponse
12 |
13 | suspend fun postNoticeDetailViewCount(noticeId: Int): BaseResponse
14 |
15 | suspend fun postNoticeDetailSave(noticeId: Int): BaseResponse
16 |
17 | suspend fun postNoticeDetailCancel(noticeId: Int): BaseResponse
18 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/data_remote/api/LoginApiService.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.data_remote.api
2 |
3 | import com.univoice.data.dto.BaseResponse
4 | import com.univoice.data.dto.request.RequestLoginDto
5 | import com.univoice.data.dto.response.ResponseLoginDto
6 | import com.univoice.data_remote.api.ApiKeyStorage.API
7 | import com.univoice.data_remote.api.ApiKeyStorage.AUTH
8 | import com.univoice.data_remote.api.ApiKeyStorage.SIGNIN
9 | import com.univoice.data_remote.api.ApiKeyStorage.V1
10 | import retrofit2.http.Body
11 | import retrofit2.http.POST
12 |
13 | interface LoginApiService {
14 | @POST("/$API/$V1/$AUTH/$SIGNIN")
15 | suspend fun postLogin(
16 | @Body requestLoginDto: RequestLoginDto,
17 | ): BaseResponse
18 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_home_floating_action_btn.xml:
--------------------------------------------------------------------------------
1 |
6 |
13 |
20 |
21 |
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/data/repositoryimpl/LoginRepositoryImpl.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.data.repositoryimpl
2 |
3 | import com.univoice.data.datasource.LoginDataSource
4 | import com.univoice.data.dto.request.RequestLoginDto
5 | import com.univoice.domain.repository.LoginRepository
6 | import timber.log.Timber
7 | import javax.inject.Inject
8 |
9 | class LoginRepositoryImpl @Inject constructor(
10 | private val loginDataSource: LoginDataSource
11 | ) : LoginRepository {
12 | override suspend fun postLogin(email: String, password: String): Result {
13 | return runCatching {
14 | val result = loginDataSource.postLogin(RequestLoginDto(email, password))
15 | Timber.d(result.message)
16 | result.data?.accessToken
17 | }
18 | }
19 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/data/repositoryimpl/util/extractErrorMessage.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.data.repositoryimpl.util
2 |
3 | import okhttp3.ResponseBody
4 | import org.json.JSONException
5 | import org.json.JSONObject
6 | import retrofit2.HttpException
7 |
8 | fun HttpException.extractErrorMessage(): String {
9 | if (response()?.code() == 413) return "이미지는 3mb를 넘을 수 없습니다"
10 |
11 | val errorBody: ResponseBody? = response()?.errorBody()
12 | if (errorBody != null) {
13 | val error = errorBody.string()
14 | return try {
15 | val jsonObject = JSONObject(error)
16 | jsonObject.getString("message")
17 | } catch (e: JSONException) {
18 | "알수 없는 오류가 발생 했습니다"
19 | }
20 | }
21 | return "알수 없는 오류가 발생 했습니다"
22 | }
23 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/univoice/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package com.univoice
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("com.univoice", appContext.packageName)
23 | }
24 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/core_ui/base/BindingActivity.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.core_ui.base
2 |
3 | import android.os.Bundle
4 | import androidx.annotation.LayoutRes
5 | import androidx.appcompat.app.AppCompatActivity
6 | import androidx.databinding.DataBindingUtil
7 | import androidx.databinding.ViewDataBinding
8 |
9 | abstract class BindingActivity(
10 | @LayoutRes private val layoutRes: Int,
11 | ) : AppCompatActivity() {
12 | protected lateinit var binding: T
13 |
14 | override fun onCreate(savedInstanceState: Bundle?) {
15 | super.onCreate(savedInstanceState)
16 | binding = DataBindingUtil.setContentView(this, layoutRes)
17 | binding.lifecycleOwner = this
18 | initView()
19 | }
20 |
21 | protected abstract fun initView()
22 |
23 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/data/dto/response/ResponseNoticeAllDto.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.data.dto.response
2 |
3 | import kotlinx.serialization.SerialName
4 | import kotlinx.serialization.Serializable
5 |
6 | @Serializable
7 | data class ResponseNoticeAllDto(
8 | @SerialName("id")
9 | val id: Int,
10 | @SerialName("startTime")
11 | val startTime: String? = "",
12 | @SerialName("endTime")
13 | val endTime: String? = "",
14 | @SerialName("title")
15 | val title: String,
16 | @SerialName("likeCount")
17 | val likeCount: Int,
18 | @SerialName("viewCount")
19 | val viewCount: Int,
20 | @SerialName("category")
21 | val category: String,
22 | @SerialName("createdAt")
23 | val createdAt: String,
24 | @SerialName("image")
25 | val image: String? = "",
26 | )
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/data/dto/response/ResponseStorageDto.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.data.dto.response
2 |
3 | import kotlinx.serialization.SerialName
4 | import kotlinx.serialization.Serializable
5 |
6 | @Serializable
7 | data class ResponseStorageDto(
8 | @SerialName("id") val id: Int = -1,
9 | @SerialName("title") val title: String = "",
10 | @SerialName("viewCount") val viewCount: Int = 0,
11 | @SerialName("noticeLike") val noticeLike: Int = 0,
12 | @SerialName("category") val category: String = "",
13 | @SerialName("startTime") val startTime: String? = null,
14 | @SerialName("endTime") val endTime: String? = null,
15 | @SerialName("createdAt") val createdAt: String = "",
16 | @SerialName("updatedAt") val updatedAt: String = "",
17 | @SerialName("image") val image: String? = null
18 | )
--------------------------------------------------------------------------------
/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/main/java/com/univoice/core_ui/view/UiState.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.core_ui.view
2 |
3 | sealed interface UiState {
4 | data object Empty : UiState
5 |
6 | data object Loading : UiState
7 |
8 | data class Success(
9 | val data: T,
10 | ) : UiState
11 |
12 | data class Failure(
13 | val msg: String,
14 | ) : UiState
15 |
16 | fun getUiStateModel(): UiStateModel {
17 | return UiStateModel(
18 | this is Empty,
19 | this is Loading,
20 | this is Success,
21 | this is Failure
22 | )
23 | }
24 | }
25 |
26 | data class UiStateModel(
27 | val isEmpty: Boolean = false,
28 | val isLoading: Boolean = true,
29 | val isSuccess: Boolean = false,
30 | val isFailure: Boolean = false
31 | )
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_date_number.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
12 |
13 |
22 |
23 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_nav_home_on.xml:
--------------------------------------------------------------------------------
1 |
6 |
11 |
17 |
18 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_nav_home_off.xml:
--------------------------------------------------------------------------------
1 |
6 |
11 |
17 |
18 |
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/data_remote/datasourceimpl/PostDataSourceImpl.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.data_remote.datasourceimpl
2 |
3 | import com.univoice.data.datasource.PostDataSource
4 | import com.univoice.data.dto.BaseResponse
5 | import com.univoice.data_remote.api.PostApiService
6 | import okhttp3.MultipartBody
7 | import okhttp3.RequestBody
8 | import javax.inject.Inject
9 |
10 | class PostDataSourceImpl @Inject constructor(
11 | private val postApiService: PostApiService
12 | ) : PostDataSource {
13 | override suspend fun postNotice(
14 | title: RequestBody,
15 | content: RequestBody,
16 | target: RequestBody?,
17 | startTime: RequestBody?,
18 | endTime: RequestBody?,
19 | noticeImages: List?
20 | ): BaseResponse {
21 | return postApiService.postNotice(title, content, target, startTime, endTime, noticeImages)
22 | }
23 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/feature/quickscan/QuickScanCompleteActivity.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.feature.quickscan
2 |
3 | import android.content.Intent
4 | import com.univoice.R
5 | import com.univoice.core_ui.base.BindingActivity
6 | import com.univoice.databinding.ActivityQuickScanCompleteBinding
7 | import com.univoice.feature.MainActivity
8 |
9 | class QuickScanCompleteActivity :
10 | BindingActivity(R.layout.activity_quick_scan_complete) {
11 | override fun initView() {
12 | initConfirmBtnClickListener()
13 | }
14 |
15 | private fun initConfirmBtnClickListener() {
16 | binding.btnQuickScanCompleteConfirm.setOnClickListener {
17 | val intent = Intent(this, MainActivity::class.java)
18 | intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK
19 | startActivity(intent)
20 | }
21 | }
22 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/data/repositoryimpl/SettingRepositoryImpl.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.data.repositoryimpl
2 |
3 | import com.univoice.data.datasource.SettingDataSource
4 | import com.univoice.data.mapper.toSettingUserEntity
5 | import com.univoice.domain.entity.SettingUserEntity
6 | import com.univoice.domain.repository.SettingRepository
7 | import javax.inject.Inject
8 |
9 | class SettingRepositoryImpl @Inject constructor(
10 | private val settingDataSource: SettingDataSource
11 | ) : SettingRepository {
12 | override suspend fun getMyPage(): Result {
13 | return runCatching {
14 | settingDataSource.getMyPage().data?.toSettingUserEntity() ?: SettingUserEntity(
15 | -1,
16 | "",
17 | "",
18 | "",
19 | "",
20 | "",
21 | "",
22 | )
23 | }
24 | }
25 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_notice_post_image_delete.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
12 |
18 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/app/di/UserPreferencesModule.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.app.di
2 |
3 | import android.content.Context
4 | import androidx.datastore.core.DataStore
5 | import androidx.datastore.preferences.core.Preferences
6 | import androidx.datastore.preferences.preferencesDataStore
7 | import dagger.Module
8 | import dagger.Provides
9 | import dagger.hilt.InstallIn
10 | import dagger.hilt.android.qualifiers.ApplicationContext
11 | import dagger.hilt.components.SingletonComponent
12 | import javax.inject.Singleton
13 |
14 | @Module
15 | @InstallIn(SingletonComponent::class)
16 | object UserPreferencesModule {
17 | private const val PREFERENCE_NAME = "user_preferences"
18 | private val Context.dataStore by preferencesDataStore(name = PREFERENCE_NAME)
19 |
20 | @Provides
21 | @Singleton
22 | fun provideDataStore(
23 | @ApplicationContext context: Context
24 | ): DataStore = context.dataStore
25 | }
26 |
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/data_remote/datasourceimpl/QuickScanDataSourceImpl.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.data_remote.datasourceimpl
2 |
3 | import com.univoice.data.datasource.QuickScanDataSource
4 | import com.univoice.data.dto.BaseResponse
5 | import com.univoice.data.dto.request.RequestQuickScanDto
6 | import com.univoice.data.dto.response.ResponseQuickScanDto
7 | import com.univoice.data_remote.api.QuickScanApiService
8 | import javax.inject.Inject
9 |
10 | class QuickScanDataSourceImpl @Inject constructor(
11 | private val quickScanApiService: QuickScanApiService
12 | ) : QuickScanDataSource {
13 | override suspend fun postQuickScan(requestQuickScanDto: RequestQuickScanDto): BaseResponse> =
14 | quickScanApiService.postQuickScan(requestQuickScanDto)
15 |
16 | override suspend fun postQuickScanViewCheck(noticeId: Int): BaseResponse =
17 | quickScanApiService.postQuickScanViewCheck(noticeId)
18 |
19 | }
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_bottom_button.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
22 |
23 |
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/data_remote/api/ApiKeyStorage.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.data_remote.api
2 |
3 | object ApiKeyStorage {
4 | const val API = "api"
5 | const val V1 = "v1"
6 | const val AUTH = "auth"
7 | const val SIGNIN = "signin"
8 | const val NOTICE = "notice"
9 | const val ALL = "all"
10 | const val QUICKHEAD = "quickhead"
11 | const val UNIVERSITY_DATA = "universityData"
12 | const val UNIVERSITY = "university"
13 | const val SAVE = "save"
14 | const val QUICK = "quick"
15 | const val COLLEGE_DEPARTMENT = "college-department"
16 | const val DEPARTMENT = "department"
17 | const val VIEW_CHECK = "view-check"
18 | const val NOTICE_ID = "noticeId"
19 | const val MYPAGE = "mypage"
20 | const val VIEW_COUNT = "view-count"
21 | const val CANCEL = "cancel"
22 | const val CHECK_EMAIL = "check-email"
23 | const val SIGNUP = "signup"
24 | const val LIKE = "like"
25 | const val CREATE = "create"
26 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/data/repositoryimpl/UserInfoRepositoryImpl.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.data.repositoryimpl
2 |
3 | import com.univoice.data.datasource.UserPreferencesDataSource
4 | import com.univoice.domain.repository.UserInfoRepository
5 | import kotlinx.coroutines.flow.Flow
6 | import javax.inject.Inject
7 |
8 | class UserInfoRepositoryImpl @Inject constructor(
9 | private val dataSource: UserPreferencesDataSource
10 | ) : UserInfoRepository {
11 |
12 | override suspend fun saveUserAccessToken(accessToken: String) {
13 | dataSource.saveUserAccessToken(accessToken)
14 | }
15 |
16 | override fun getUserAccessToken(): Flow = dataSource.getUserAccessToken()
17 |
18 | override suspend fun saveCheckLogin(checkLogin: Boolean) {
19 | dataSource.saveCheckLogin(checkLogin)
20 | }
21 |
22 | override fun getCheckLogin(): Flow = dataSource.getCheckLogin()
23 |
24 | override suspend fun clear() = dataSource.clear()
25 |
26 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/app/interceptor/TokenInterceptor.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.app.interceptor
2 |
3 | import com.univoice.data.datasource.UserPreferencesDataSource
4 | import kotlinx.coroutines.flow.first
5 | import kotlinx.coroutines.runBlocking
6 | import okhttp3.Interceptor
7 | import okhttp3.Response
8 | import timber.log.Timber
9 | import javax.inject.Inject
10 |
11 | class TokenInterceptor @Inject
12 | constructor(
13 | private val userPreferencesDataSource: UserPreferencesDataSource,
14 | ) : Interceptor {
15 | override fun intercept(chain: Interceptor.Chain): Response = runBlocking {
16 | var accessToken = userPreferencesDataSource.getUserAccessToken().first()
17 |
18 | val request = chain.request().newBuilder()
19 | .addHeader("Authorization", "Bearer $accessToken")
20 | .build()
21 |
22 | val response = chain.proceed(request)
23 | Timber.tag("interceptor").d("accessToken $accessToken")
24 |
25 | response
26 | }
27 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/domain/repository/SignUpRepository.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.domain.repository
2 |
3 | import com.univoice.data.dto.BaseResponse
4 | import com.univoice.data.dto.request.RequestCheckEmailDto
5 | import com.univoice.data.dto.request.RequestDepartmentDto
6 | import okhttp3.MultipartBody
7 | import okhttp3.RequestBody
8 | import java.io.File
9 |
10 | interface SignUpRepository {
11 | suspend fun postUniversityNames(): Result>
12 | suspend fun postDepartments(requestDepartmentDto: RequestDepartmentDto): Result>>
13 | suspend fun postEmail(requestCheckEmailDto: RequestCheckEmailDto): Result>
14 | suspend fun postSignUp(
15 | admissionNumber: String,
16 | name: String,
17 | studentNumber: String,
18 | email: String,
19 | password: String,
20 | universityName: String,
21 | departmentName: String,
22 | studentCardImage: File
23 | ): Result
24 | }
25 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_home_views.xml:
--------------------------------------------------------------------------------
1 |
6 |
13 |
20 |
21 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/img_quick_scan_placeholder.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
15 |
20 |
21 |
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/feature/entry/EntryActivity.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.feature.entry
2 |
3 | import android.content.Intent
4 | import com.univoice.R
5 | import com.univoice.core_ui.base.BindingActivity
6 | import com.univoice.databinding.ActivityEntryBinding
7 | import com.univoice.feature.login.LoginActivity
8 | import com.univoice.feature.signup.SignUpActivity
9 |
10 | class EntryActivity : BindingActivity(R.layout.activity_entry) {
11 | override fun initView() {
12 | initLoginBtnClickListener()
13 | initSignupBtnClickListener()
14 | }
15 |
16 | private fun initSignupBtnClickListener() {
17 | binding.btnEntrySignup.setOnClickListener {
18 | startActivity(Intent(this, SignUpActivity::class.java))
19 | }
20 | }
21 |
22 | private fun initLoginBtnClickListener() {
23 | binding.btnEntryLogin.setOnClickListener {
24 | startActivity(Intent(this, LoginActivity::class.java))
25 | }
26 | }
27 |
28 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/data_remote/api/PostApiService.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.data_remote.api
2 |
3 | import com.univoice.data.dto.BaseResponse
4 | import com.univoice.data_remote.api.ApiKeyStorage.API
5 | import com.univoice.data_remote.api.ApiKeyStorage.CREATE
6 | import com.univoice.data_remote.api.ApiKeyStorage.NOTICE
7 | import com.univoice.data_remote.api.ApiKeyStorage.V1
8 | import okhttp3.MultipartBody
9 | import okhttp3.RequestBody
10 | import retrofit2.http.Multipart
11 | import retrofit2.http.POST
12 | import retrofit2.http.Part
13 |
14 | interface PostApiService {
15 | @Multipart
16 | @POST("/$API/$V1/$NOTICE/$CREATE")
17 | suspend fun postNotice(
18 | @Part("title") title: RequestBody,
19 | @Part("content") content: RequestBody,
20 | @Part("target") target: RequestBody?,
21 | @Part("startTime") startTime: RequestBody?,
22 | @Part("endTime") endTime: RequestBody?,
23 | @Part noticeImages: List?,
24 | ): BaseResponse
25 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/feature/signup/SignUpActivity.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.feature.signup
2 |
3 | import android.content.Intent
4 | import com.univoice.R
5 | import com.univoice.core_ui.base.BindingActivity
6 | import com.univoice.databinding.ActivitySignupBinding
7 | import com.univoice.feature.util.setupToolbarClickListener
8 |
9 | class SignUpActivity : BindingActivity(R.layout.activity_signup) {
10 | override fun initView() {
11 | initStartBtnClickListener()
12 | initToolbar()
13 | }
14 |
15 | private fun initToolbar() {
16 | with(binding.toolbarSignup) {
17 | tvToolbarTitle.text = applicationContext.getString(R.string.tv_toolbar_signup_title)
18 | setupToolbarClickListener(ibToolbarIcon)
19 | }
20 | }
21 |
22 | private fun initStartBtnClickListener() {
23 | binding.btnSignupStart.setOnClickListener {
24 | startActivity(Intent(this, SchoolInputActivity::class.java))
25 | }
26 | }
27 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/data/datasource/SignUpDataSource.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.data.datasource
2 |
3 | import com.univoice.data.dto.BaseResponse
4 | import com.univoice.data.dto.request.RequestCheckEmailDto
5 | import com.univoice.data.dto.request.RequestDepartmentDto
6 | import okhttp3.MultipartBody
7 | import okhttp3.RequestBody
8 |
9 | interface SignUpDataSource {
10 | suspend fun postUniversityNames(): BaseResponse>
11 | suspend fun postDepartments(requestDepartmentDto: RequestDepartmentDto): BaseResponse>
12 | suspend fun postEmail(requestCheckEmailDto: RequestCheckEmailDto): BaseResponse
13 | suspend fun postSignUp(
14 | admissionNumber: RequestBody,
15 | name: RequestBody,
16 | studentNumber: RequestBody,
17 | email: RequestBody,
18 | password: RequestBody,
19 | universityName: RequestBody,
20 | departmentName: RequestBody,
21 | studentCardImage: MultipartBody.Part,
22 | ): BaseResponse
23 | }
24 |
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/data/dto/response/ResponseQuickScanDto.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.data.dto.response
2 |
3 | import kotlinx.serialization.SerialName
4 | import kotlinx.serialization.Serializable
5 |
6 | @Serializable
7 | data class ResponseQuickScanDto(
8 | @SerialName("id") val id: Int = -1,
9 | @SerialName("startTime") val startTime: String? = null,
10 | @SerialName("endTime") val endTime: String? = null,
11 | @SerialName("title") val title: String = "",
12 | @SerialName("target") val target: String? = null,
13 | @SerialName("writeAffiliation") val writeAffiliation: String = "",
14 | @SerialName("contentSummary") val contentSummary: String = "",
15 | @SerialName("likeCount") val likeCount: Int = 0,
16 | @SerialName("viewCount") val viewCount: Int = 0,
17 | @SerialName("category") val category: String = "",
18 | @SerialName("createdAt") val createdAt: String = "",
19 | @SerialName("logoImage") val logoImage: String? = null,
20 | @SerialName("saveCheck") val saveCheck: Boolean = false
21 | )
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/data/dto/response/ResponseNoticeQuickScanDto.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.data.dto.response
2 |
3 | import kotlinx.serialization.SerialName
4 | import kotlinx.serialization.Serializable
5 |
6 | @Serializable
7 | data class ResponseNoticeQuickScanDto(
8 | @SerialName("universityName")
9 | val universityName: String = "",
10 | @SerialName("universityNameCount")
11 | val universityNameCount: Int = 0,
12 | @SerialName("universityLogoImage")
13 | val universityLogoImage: String = "",
14 | @SerialName("collegeDepartmentName")
15 | val collegeDepartmentName: String = "",
16 | @SerialName("collegeDepartmentCount")
17 | val collegeDepartmentCount: Int = 0,
18 | @SerialName("collegeDepartmentLogoImage")
19 | val collegeDepartmentLogoImage: String = "",
20 | @SerialName("departmentName")
21 | val departmentName: String = "",
22 | @SerialName("departmentCount")
23 | val departmentCount: Int = 0,
24 | @SerialName("departmentLogoImage")
25 | val departmentLogoImage: String = "",
26 | )
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/feature/noticeDetail/NoticeDetailAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.feature.noticeDetail
2 |
3 | import android.view.ViewGroup
4 | import androidx.recyclerview.widget.ListAdapter
5 | import com.univoice.core_ui.view.ItemDiffCallback
6 |
7 | class NoticeDetailAdapter :
8 | ListAdapter(
9 | NoticeDetailItemDiffCallback
10 | ) {
11 |
12 | override fun onCreateViewHolder(
13 | parent: ViewGroup,
14 | viewType: Int
15 | ): NoticeDetailViewHolder {
16 | return NoticeDetailViewHolder.from(parent)
17 | }
18 |
19 | override fun onBindViewHolder(
20 | holder: NoticeDetailViewHolder,
21 | position: Int
22 | ) {
23 | val item = getItem(position)
24 | holder.bind(item)
25 | }
26 |
27 | companion object {
28 | private val NoticeDetailItemDiffCallback =
29 | ItemDiffCallback(onItemsTheSame = { old, new -> old == new },
30 | onContentsTheSame = { old, new -> old == new })
31 | }
32 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_notice_post_date.xml:
--------------------------------------------------------------------------------
1 |
6 |
13 |
20 |
21 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_bottom_button_create.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
24 |
25 |
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/data/repositoryimpl/QuickScanRepositoryImpl.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.data.repositoryimpl
2 |
3 | import com.univoice.data.datasource.QuickScanDataSource
4 | import com.univoice.data.dto.request.RequestQuickScanDto
5 | import com.univoice.data.mapper.toQuickScanListEntity
6 | import com.univoice.domain.entity.QuickScanListEntity
7 | import com.univoice.domain.repository.QuickScanRepository
8 | import javax.inject.Inject
9 |
10 | class QuickScanRepositoryImpl @Inject constructor(
11 | private val quickScanDataSource: QuickScanDataSource
12 | ) : QuickScanRepository {
13 | override suspend fun postQuickScan(writeAffiliation: String): Result?> {
14 | return runCatching {
15 | quickScanDataSource.postQuickScan(RequestQuickScanDto(writeAffiliation)).data?.map { it.toQuickScanListEntity() }
16 | }
17 | }
18 |
19 | override suspend fun postQuickScanViewCheck(noticeId: Int): Result {
20 | return runCatching {
21 | quickScanDataSource.postQuickScanViewCheck(noticeId)
22 | }
23 | }
24 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/feature/home/HomeQuickscanItemDecorator.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.feature.home
2 |
3 | import android.content.Context
4 | import android.graphics.Rect
5 | import android.view.View
6 | import androidx.recyclerview.widget.RecyclerView
7 | import com.univoice.core_ui.util.context.pxToDp
8 |
9 | class HomeQuickscanItemDecorator(val context: Context) : RecyclerView.ItemDecoration() {
10 | override fun getItemOffsets(
11 | outRect: Rect,
12 | view: View,
13 | parent: RecyclerView,
14 | state: RecyclerView.State,
15 | ) {
16 | super.getItemOffsets(outRect, view, parent, state)
17 | val position = parent.getChildAdapterPosition(view)
18 | val itemCount = parent.adapter?.itemCount ?: 0
19 |
20 | when (position) {
21 | 0 -> {
22 | outRect.left = context.pxToDp(16)
23 | outRect.right = context.pxToDp(10)
24 | }
25 |
26 | itemCount - 1 -> outRect.right = context.pxToDp(16)
27 |
28 | else -> outRect.right = context.pxToDp(10)
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/feature/home/HomeNoticeCategoryItemDecorator.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.feature.home
2 |
3 | import android.content.Context
4 | import android.graphics.Rect
5 | import android.view.View
6 | import androidx.recyclerview.widget.RecyclerView
7 | import com.univoice.core_ui.util.context.pxToDp
8 |
9 | class HomeNoticeCategoryItemDecorator(val context: Context) : RecyclerView.ItemDecoration() {
10 | override fun getItemOffsets(
11 | outRect: Rect,
12 | view: View,
13 | parent: RecyclerView,
14 | state: RecyclerView.State,
15 | ) {
16 | super.getItemOffsets(outRect, view, parent, state)
17 | val position = parent.getChildAdapterPosition(view)
18 | val itemCount = parent.adapter?.itemCount ?: 0
19 |
20 | when (position) {
21 | 0 -> {
22 | outRect.left = context.pxToDp(16)
23 | outRect.right = context.pxToDp(8)
24 | }
25 |
26 | itemCount - 1 -> outRect.right = context.pxToDp(16)
27 |
28 | else -> outRect.right = context.pxToDp(8)
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/feature/home/HomeNoticeContentItemDecorator.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.feature.home
2 |
3 | import android.content.Context
4 | import android.graphics.Rect
5 | import android.view.View
6 | import androidx.recyclerview.widget.RecyclerView
7 | import com.univoice.core_ui.util.context.pxToDp
8 |
9 | class HomeNoticeContentItemDecorator(val context: Context) : RecyclerView.ItemDecoration() {
10 | override fun getItemOffsets(
11 | outRect: Rect,
12 | view: View,
13 | parent: RecyclerView,
14 | state: RecyclerView.State,
15 | ) {
16 | super.getItemOffsets(outRect, view, parent, state)
17 | val position = parent.getChildAdapterPosition(view)
18 | val itemCount = parent.adapter?.itemCount ?: 0
19 |
20 | when (position) {
21 | 0 -> {
22 | outRect.top = context.pxToDp(16)
23 | outRect.bottom = context.pxToDp(12)
24 | }
25 |
26 | itemCount - 1 -> outRect.bottom = context.pxToDp(16)
27 |
28 | else -> outRect.bottom = context.pxToDp(12)
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/feature/noticePost/NoticePostImageItemDecorator.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.feature.noticePost
2 |
3 | import android.content.Context
4 | import android.graphics.Rect
5 | import android.view.View
6 | import androidx.recyclerview.widget.RecyclerView
7 | import com.univoice.core_ui.util.context.pxToDp
8 |
9 | class NoticePostImageItemDecorator(val context: Context) : RecyclerView.ItemDecoration() {
10 | override fun getItemOffsets(
11 | outRect: Rect,
12 | view: View,
13 | parent: RecyclerView,
14 | state: RecyclerView.State,
15 | ) {
16 | super.getItemOffsets(outRect, view, parent, state)
17 | val position = parent.getChildAdapterPosition(view)
18 | val itemCount = parent.adapter?.itemCount ?: 0
19 |
20 | when (position) {
21 | 0 -> {
22 | outRect.left = context.pxToDp(16)
23 | outRect.right = context.pxToDp(12)
24 | }
25 |
26 | itemCount - 1 -> outRect.right = context.pxToDp(16)
27 |
28 | else -> outRect.right = context.pxToDp(12)
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_home_notice_category.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
22 |
23 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_notice_detail_like.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/feature/util/BiggerDotPasswordTransformationMethod.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.feature.util
2 |
3 | import android.content.Context
4 | import android.text.method.PasswordTransformationMethod
5 | import android.view.View
6 | import com.univoice.R
7 |
8 | class BiggerDotPasswordTransformationMethod(private val context: Context) :
9 | PasswordTransformationMethod() {
10 | override fun getTransformation(source: CharSequence?, view: View?): CharSequence {
11 | return BiggerDotCharSequence(super.getTransformation(source, view), context)
12 | }
13 |
14 | private class BiggerDotCharSequence(
15 | private val original: CharSequence,
16 | private val context: Context
17 | ) : CharSequence {
18 | override val length: Int
19 | get() = original.length
20 |
21 | override fun get(index: Int): Char {
22 | return context.getString(R.string.login_pwd_mask).single()
23 | }
24 |
25 | override fun subSequence(startIndex: Int, endIndex: Int): CharSequence {
26 | return BiggerDotCharSequence(original.subSequence(startIndex, endIndex), context)
27 | }
28 | }
29 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/data_remote/api/QuickScanApiService.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.data_remote.api
2 |
3 | import com.univoice.data.dto.BaseResponse
4 | import com.univoice.data.dto.request.RequestQuickScanDto
5 | import com.univoice.data.dto.response.ResponseQuickScanDto
6 | import com.univoice.data.dto.response.ResponseStorageDto
7 | import com.univoice.data_remote.api.ApiKeyStorage.API
8 | import com.univoice.data_remote.api.ApiKeyStorage.NOTICE
9 | import com.univoice.data_remote.api.ApiKeyStorage.NOTICE_ID
10 | import com.univoice.data_remote.api.ApiKeyStorage.QUICK
11 | import com.univoice.data_remote.api.ApiKeyStorage.V1
12 | import com.univoice.data_remote.api.ApiKeyStorage.VIEW_CHECK
13 | import retrofit2.http.Body
14 | import retrofit2.http.POST
15 | import retrofit2.http.Path
16 |
17 | interface QuickScanApiService {
18 | @POST("$API/$V1/$NOTICE/$QUICK")
19 | suspend fun postQuickScan(
20 | @Body requestQuickScanDto: RequestQuickScanDto
21 | ): BaseResponse>
22 |
23 | @POST("$API/$V1/$NOTICE/$VIEW_CHECK/{$NOTICE_ID}")
24 | suspend fun postQuickScanViewCheck(
25 | @Path(NOTICE_ID) noticeId: Int
26 | ): BaseResponse
27 | }
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_notice_detail_image.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
9 |
10 |
13 |
14 |
26 |
27 |
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/feature/noticeDetail/NoticeDetailViewHolder.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.feature.noticeDetail
2 |
3 | import android.view.LayoutInflater
4 | import android.view.View
5 | import android.view.ViewGroup
6 | import androidx.recyclerview.widget.RecyclerView
7 | import coil.load
8 | import com.univoice.databinding.ItemNoticeDetailImageBinding
9 |
10 | class NoticeDetailViewHolder(private val binding: ItemNoticeDetailImageBinding) :
11 | RecyclerView.ViewHolder(binding.root) {
12 |
13 | fun bind(image: String) {
14 | with(binding) {
15 | if (image.isEmpty()) {
16 | ivNoticeDetailContent.visibility = View.GONE
17 | } else {
18 | ivNoticeDetailContent.visibility = View.VISIBLE
19 | ivNoticeDetailContent.load(image)
20 | }
21 | }
22 | }
23 |
24 | companion object {
25 | fun from(parent: ViewGroup): NoticeDetailViewHolder {
26 | val binding = ItemNoticeDetailImageBinding.inflate(
27 | LayoutInflater.from(parent.context),
28 | parent,
29 | false
30 | )
31 | return NoticeDetailViewHolder(binding)
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_notice_post_photo.xml:
--------------------------------------------------------------------------------
1 |
6 |
13 |
20 |
21 |
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/data_remote/datasourceimpl/HomeDataSourceImpl.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.data_remote.datasourceimpl
2 |
3 | import com.univoice.data.datasource.HomeDataSource
4 | import com.univoice.data.dto.BaseResponse
5 | import com.univoice.data.dto.response.ResponseNoticeAllDto
6 | import com.univoice.data.dto.response.ResponseNoticeQuickScanDto
7 | import com.univoice.data_remote.api.HomeApiService
8 | import javax.inject.Inject
9 |
10 | class HomeDataSourceImpl @Inject constructor(
11 | private val homeApiService: HomeApiService
12 | ) : HomeDataSource {
13 | override suspend fun getNoticeQuickScan(): BaseResponse =
14 | homeApiService.getNoticeQuickScan()
15 |
16 | override suspend fun getNoticeAll(): BaseResponse> =
17 | homeApiService.getNoticeAll()
18 |
19 | override suspend fun getNoticeUniversity(): BaseResponse> =
20 | homeApiService.getNoticeUniversity()
21 |
22 | override suspend fun getNoticeCollege(): BaseResponse> =
23 | homeApiService.getNoticeCollege()
24 |
25 | override suspend fun getNoticeDepartment(): BaseResponse> =
26 | homeApiService.getNoticeDepartment()
27 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/feature/storage/StorageViewHolder.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.feature.storage
2 |
3 | import androidx.recyclerview.widget.RecyclerView
4 | import coil.load
5 | import coil.transform.RoundedCornersTransformation
6 | import com.univoice.databinding.ItemNoticeBinding
7 | import com.univoice.domain.entity.NoticeListEntity
8 | import com.univoice.domain.entity.StorageListEntity
9 | import com.univoice.feature.util.CalculateDate
10 |
11 | class StorageViewHolder(
12 | private val binding: ItemNoticeBinding,
13 | private val onClick: (StorageListEntity) -> Unit = { _ -> },
14 | ) : RecyclerView.ViewHolder(binding.root) {
15 | fun bind(data: StorageListEntity) {
16 | with(binding) {
17 | btnItemNoticeHeader.text = data.category
18 | tvItemNoticeTitle.text = data.title
19 | tvItemNoticeDate.text = CalculateDate().getCalculateDate(data.createdAt)
20 | tvItemNoticeLike.text = data.noticeLike.toString()
21 | tvItemNoticeViews.text = data.viewCount.toString()
22 | ivItemNoticeThumbnail.load(data.image) {
23 | transformations(RoundedCornersTransformation(5f))
24 | }
25 | root.setOnClickListener {
26 | onClick(data)
27 | }
28 | }
29 | }
30 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/data/dto/response/ResponseNoticeDetailDto.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.data.dto.response
2 |
3 | import kotlinx.serialization.SerialName
4 | import kotlinx.serialization.Serializable
5 |
6 | @Serializable
7 | data class ResponseNoticeDetailDto(
8 | @SerialName("id") val id: Int,
9 | @SerialName("title") val title: String,
10 | @SerialName("content") val content: String,
11 | @SerialName("noticeLike") val noticeLike: Int,
12 | @SerialName("viewCount") val viewCount: Int,
13 | @SerialName("target") val target: String? = "",
14 | @SerialName("startTime")
15 | val startTime: String? = null,
16 | @SerialName("endTime")
17 | val endTime: String? = null,
18 | @SerialName("category")
19 | val category: String,
20 | @SerialName("contentSummary")
21 | val contentSummary: String,
22 | @SerialName("memberId")
23 | val memberId: Int,
24 | @SerialName("writeAffiliation")
25 | val writeAffiliation: String,
26 | @SerialName("noticeImages")
27 | val noticeImages: List,
28 | @SerialName("createdAt")
29 | val createdAt: String,
30 | @SerialName("likeCheck")
31 | val likeCheck: Boolean,
32 | @SerialName("saveCheck")
33 | val saveCheck: Boolean,
34 | @SerialName("dayOfWeek")
35 | val dayOfWeek: String
36 | )
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/feature/home/HomeQuickscanViewHolder.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.feature.home
2 |
3 | import android.view.View
4 | import androidx.recyclerview.widget.RecyclerView
5 | import coil.load
6 | import com.univoice.databinding.ItemHomeNoticeQuickscanBinding
7 | import com.univoice.domain.entity.HomeQuickScanListEntity
8 |
9 | class HomeQuickscanViewHolder(
10 | private val binding: ItemHomeNoticeQuickscanBinding,
11 | private val click: (HomeQuickScanListEntity, Int) -> Unit = { _, _ -> },
12 | ) : RecyclerView.ViewHolder(binding.root) {
13 | fun bind(data: HomeQuickScanListEntity) {
14 | with(binding) {
15 | if (data.count < 1) {
16 | layoutHomeNoticeQuickscanCount.visibility = View.INVISIBLE
17 | tvHomeNoticeQuickscanCount.visibility = View.INVISIBLE
18 | } else {
19 | tvHomeNoticeQuickscanCount.visibility = View.VISIBLE
20 | tvHomeNoticeQuickscanCount.text = data.count.toString()
21 | }
22 |
23 | tvHomeNoticeQuickscanName.text = data.name.replace(" ", "\n")
24 | ivHomeNoticeQuickscanProfile.load(data.image)
25 |
26 | root.setOnClickListener {
27 | click(data, bindingAdapterPosition)
28 | }
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_home_like.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/feature/signup/CreateAccountViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.feature.signup
2 |
3 | import androidx.lifecycle.ViewModel
4 | import androidx.lifecycle.viewModelScope
5 | import com.univoice.core_ui.view.UiState
6 | import com.univoice.data.dto.request.RequestCheckEmailDto
7 | import com.univoice.domain.repository.SignUpRepository
8 | import dagger.hilt.android.lifecycle.HiltViewModel
9 | import kotlinx.coroutines.flow.MutableSharedFlow
10 | import kotlinx.coroutines.flow.SharedFlow
11 | import kotlinx.coroutines.launch
12 | import javax.inject.Inject
13 |
14 | @HiltViewModel
15 | class CreateAccountViewModel @Inject constructor(
16 | private val signUpRepository: SignUpRepository
17 | ) : ViewModel() {
18 |
19 | private val _emailCheckState = MutableSharedFlow>(replay = 0)
20 | val emailCheckState: SharedFlow> = _emailCheckState
21 |
22 | fun checkEmail(email: String) {
23 | viewModelScope.launch {
24 | _emailCheckState.emit(UiState.Loading)
25 | signUpRepository.postEmail(RequestCheckEmailDto(email)).onSuccess {
26 | _emailCheckState.emit(UiState.Success(it))
27 | }.onFailure {
28 | _emailCheckState.emit(UiState.Failure(it.message ?: ""))
29 | }
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/feature/storage/StorageAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.feature.storage
2 |
3 | import android.view.LayoutInflater
4 | import android.view.ViewGroup
5 | import androidx.recyclerview.widget.ListAdapter
6 | import com.univoice.core_ui.view.ItemDiffCallback
7 | import com.univoice.databinding.ItemNoticeBinding
8 | import com.univoice.domain.entity.NoticeListEntity
9 | import com.univoice.domain.entity.StorageListEntity
10 |
11 | class StorageAdapter(
12 | private val onClick: (StorageListEntity) -> Unit = { _ -> },
13 | ) : ListAdapter(
14 | StorageAdapterDiffCallback
15 | ) {
16 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): StorageViewHolder {
17 | val binding = ItemNoticeBinding.inflate(LayoutInflater.from(parent.context), parent, false)
18 | return StorageViewHolder(binding, onClick)
19 | }
20 |
21 | override fun onBindViewHolder(holder: StorageViewHolder, position: Int) {
22 | holder.bind(getItem(position))
23 | }
24 |
25 | companion object {
26 | private val StorageAdapterDiffCallback =
27 | ItemDiffCallback(
28 | onItemsTheSame = { old, new -> old.id == new.id },
29 | onContentsTheSame = { old, new -> old == new })
30 | }
31 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/feature/quickscan/QuickScanAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.feature.quickscan
2 |
3 | import android.view.LayoutInflater
4 | import android.view.ViewGroup
5 | import androidx.recyclerview.widget.ListAdapter
6 | import com.univoice.core_ui.view.ItemDiffCallback
7 | import com.univoice.databinding.ItemQuickScanBinding
8 | import com.univoice.domain.entity.QuickScanListEntity
9 |
10 | class QuickScanAdapter(
11 | private val image: String,
12 | private val onClick: (Int, Boolean) -> Unit = { _, _ -> },
13 | ) : ListAdapter(
14 | QuickScanDiffCallback
15 | ) {
16 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): QuickScanViewHolder {
17 | val binding =
18 | ItemQuickScanBinding.inflate(LayoutInflater.from(parent.context), parent, false)
19 | return QuickScanViewHolder(image, binding, onClick)
20 | }
21 |
22 | override fun onBindViewHolder(holder: QuickScanViewHolder, position: Int) {
23 | holder.bind(getItem(position))
24 | }
25 |
26 | companion object {
27 | private val QuickScanDiffCallback =
28 | ItemDiffCallback(
29 | onItemsTheSame = { old, new -> old.id == new.id },
30 | onContentsTheSame = { old, new -> old == new })
31 | }
32 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/feature/signup/SchoolInputViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.feature.signup
2 |
3 | import androidx.lifecycle.ViewModel
4 | import androidx.lifecycle.viewModelScope
5 | import com.univoice.core_ui.view.UiState
6 | import com.univoice.domain.repository.SignUpRepository
7 | import dagger.hilt.android.lifecycle.HiltViewModel
8 | import kotlinx.coroutines.flow.MutableStateFlow
9 | import kotlinx.coroutines.flow.StateFlow
10 | import kotlinx.coroutines.launch
11 | import javax.inject.Inject
12 |
13 | @HiltViewModel
14 | class SchoolInputViewModel @Inject constructor(
15 | private val signupRepository: SignUpRepository
16 | ) : ViewModel() {
17 |
18 | private val _schoolListState = MutableStateFlow>>(UiState.Empty)
19 | val schoolListState: StateFlow>> = _schoolListState
20 |
21 | init {
22 | postUniversityNames()
23 | }
24 |
25 | private fun postUniversityNames() {
26 | _schoolListState.value = UiState.Loading
27 | viewModelScope.launch {
28 | signupRepository.postUniversityNames().onSuccess { response ->
29 | _schoolListState.value = UiState.Success(response)
30 | }.onFailure {
31 | _schoolListState.value = UiState.Failure(it.message ?: "")
32 | }
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/core_ui/base/BindingFragment.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.core_ui.base
2 |
3 | import android.os.Bundle
4 | import android.view.LayoutInflater
5 | import android.view.View
6 | import android.view.ViewGroup
7 | import androidx.annotation.LayoutRes
8 | import androidx.databinding.DataBindingUtil
9 | import androidx.databinding.ViewDataBinding
10 | import androidx.fragment.app.Fragment
11 |
12 | abstract class BindingFragment(
13 | @LayoutRes private val layoutRes: Int
14 | ) : Fragment() {
15 | private var _binding: T? = null
16 | protected val binding
17 | get() = requireNotNull(_binding) {
18 | }
19 |
20 | override fun onCreateView(
21 | inflater: LayoutInflater,
22 | container: ViewGroup?,
23 | savedInstanceState: Bundle?
24 | ): View? {
25 | _binding = DataBindingUtil.inflate(inflater, layoutRes, container, false)
26 | binding.lifecycleOwner = viewLifecycleOwner
27 | return binding.root
28 | }
29 |
30 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
31 | super.onViewCreated(view, savedInstanceState)
32 | initView()
33 | }
34 |
35 | protected abstract fun initView()
36 |
37 | override fun onDestroyView() {
38 | _binding = null
39 | super.onDestroyView()
40 | }
41 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/app/di/HomeModule.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.app.di
2 |
3 | import com.univoice.data.datasource.HomeDataSource
4 | import com.univoice.data.repositoryimpl.HomeRepositoryImpl
5 | import com.univoice.data_remote.api.HomeApiService
6 | import com.univoice.data_remote.datasourceimpl.HomeDataSourceImpl
7 | import com.univoice.domain.repository.HomeRepository
8 | import dagger.Binds
9 | import dagger.Module
10 | import dagger.Provides
11 | import dagger.hilt.InstallIn
12 | import dagger.hilt.components.SingletonComponent
13 | import retrofit2.Retrofit
14 | import javax.inject.Singleton
15 |
16 | @Module
17 | @InstallIn(SingletonComponent::class)
18 | object HomeModule {
19 | @Provides
20 | @Singleton
21 | fun provideHomeService(
22 | @UniVoiceRetrofit retrofit: Retrofit,
23 | ): HomeApiService = retrofit.create(HomeApiService::class.java)
24 |
25 | @Module
26 | @InstallIn(SingletonComponent::class)
27 | interface RepositoryModule {
28 | @Binds
29 | @Singleton
30 | fun bindsHomeRepository(RepositoryImpl: HomeRepositoryImpl): HomeRepository
31 | }
32 |
33 | @Module
34 | @InstallIn(SingletonComponent::class)
35 | interface DataSourceModule {
36 | @Singleton
37 | @Binds
38 | fun providesHomeDataSource(DataSourceImpl: HomeDataSourceImpl): HomeDataSource
39 | }
40 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/app/di/PostModule.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.app.di
2 |
3 | import com.univoice.data.datasource.PostDataSource
4 | import com.univoice.data.repositoryimpl.PostRepositoryImpl
5 | import com.univoice.data_remote.api.PostApiService
6 | import com.univoice.data_remote.datasourceimpl.PostDataSourceImpl
7 | import com.univoice.domain.repository.PostRepository
8 | import dagger.Binds
9 | import dagger.Module
10 | import dagger.Provides
11 | import dagger.hilt.InstallIn
12 | import dagger.hilt.components.SingletonComponent
13 | import retrofit2.Retrofit
14 | import javax.inject.Singleton
15 |
16 | @Module
17 | @InstallIn(SingletonComponent::class)
18 | object PostModule {
19 | @Provides
20 | @Singleton
21 | fun providePostService(
22 | @UniVoiceRetrofit retrofit: Retrofit,
23 | ): PostApiService = retrofit.create(PostApiService::class.java)
24 |
25 | @Module
26 | @InstallIn(SingletonComponent::class)
27 | interface RepositoryModule {
28 | @Binds
29 | @Singleton
30 | fun bindsPostRepository(repositoryImpl: PostRepositoryImpl): PostRepository
31 | }
32 |
33 | @Module
34 | @InstallIn(SingletonComponent::class)
35 | interface DataSourceModule {
36 | @Binds
37 | @Singleton
38 | fun providesPostDataSource(dataSourceImpl: PostDataSourceImpl): PostDataSource
39 | }
40 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/core_ui/base/BindingBottomSheetFragment.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.core_ui.base
2 |
3 | import android.os.Bundle
4 | import android.view.LayoutInflater
5 | import android.view.View
6 | import android.view.ViewGroup
7 | import androidx.annotation.LayoutRes
8 | import androidx.databinding.DataBindingUtil
9 | import androidx.databinding.ViewDataBinding
10 | import com.google.android.material.bottomsheet.BottomSheetDialogFragment
11 |
12 | abstract class BindingBottomSheetFragment(
13 | @LayoutRes private val layoutRes: Int,
14 | ) : BottomSheetDialogFragment() {
15 | private var _binding: T? = null
16 | protected val binding get() = requireNotNull(_binding)
17 |
18 | override fun onCreateView(
19 | inflater: LayoutInflater,
20 | container: ViewGroup?,
21 | savedInstanceState: Bundle?,
22 | ): View? {
23 | _binding = DataBindingUtil.inflate(inflater, layoutRes, container, false)
24 | binding.lifecycleOwner = viewLifecycleOwner
25 | return binding.root
26 | }
27 |
28 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
29 | super.onViewCreated(view, savedInstanceState)
30 | initView()
31 | }
32 |
33 | protected abstract fun initView()
34 |
35 | override fun onDestroyView() {
36 | _binding = null
37 | super.onDestroyView()
38 | }
39 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_notice_detail_dislike.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/app/di/SettingModule.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.app.di
2 |
3 | import com.univoice.data.datasource.SettingDataSource
4 | import com.univoice.data.repositoryimpl.SettingRepositoryImpl
5 | import com.univoice.data_remote.api.SettingApiService
6 | import com.univoice.data_remote.datasourceimpl.SettingDataSourceImpl
7 | import com.univoice.domain.repository.SettingRepository
8 | import dagger.Binds
9 | import dagger.Module
10 | import dagger.Provides
11 | import dagger.hilt.InstallIn
12 | import dagger.hilt.components.SingletonComponent
13 | import retrofit2.Retrofit
14 | import javax.inject.Singleton
15 |
16 | @Module
17 | @InstallIn(SingletonComponent::class)
18 | object SettingModule {
19 | @Provides
20 | @Singleton
21 | fun provideSettingService(
22 | @UniVoiceRetrofit retrofit: Retrofit,
23 | ): SettingApiService = retrofit.create(SettingApiService::class.java)
24 |
25 | @Module
26 | @InstallIn(SingletonComponent::class)
27 | interface RepositoryModule {
28 | @Binds
29 | @Singleton
30 | fun bindsSettingRepository(RepositoryImpl: SettingRepositoryImpl): SettingRepository
31 | }
32 |
33 | @Module
34 | @InstallIn(SingletonComponent::class)
35 | interface DataSourceModule {
36 | @Singleton
37 | @Binds
38 | fun providesSettingDataSource(DataSourceImpl: SettingDataSourceImpl): SettingDataSource
39 | }
40 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/app/di/SignUpModule.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.app.di
2 |
3 | import com.univoice.data.datasource.SignUpDataSource
4 | import com.univoice.data.repositoryimpl.SignUpRepositoryImpl
5 | import com.univoice.domain.repository.SignUpRepository
6 | import com.univoice.data_remote.api.SignUpApiService
7 | import com.univoice.data_remote.datasourceimpl.SignUpDataSourceImpl
8 | import dagger.Binds
9 | import dagger.Module
10 | import dagger.Provides
11 | import dagger.hilt.InstallIn
12 | import dagger.hilt.components.SingletonComponent
13 | import retrofit2.Retrofit
14 | import javax.inject.Singleton
15 |
16 | @Module
17 | @InstallIn(SingletonComponent::class)
18 | object SignUpModule {
19 |
20 | @Provides
21 | @Singleton
22 | fun provideSignUpService(
23 | @UniVoiceRetrofit retrofit: Retrofit,
24 | ): SignUpApiService = retrofit.create(SignUpApiService::class.java)
25 |
26 | @Module
27 | @InstallIn(SingletonComponent::class)
28 | interface RepositoryModule {
29 | @Binds
30 | @Singleton
31 | fun bindsSignUpRepository(repositoryImpl: SignUpRepositoryImpl): SignUpRepository
32 | }
33 |
34 | @Module
35 | @InstallIn(SingletonComponent::class)
36 | interface DataSourceModule {
37 | @Binds
38 | @Singleton
39 | fun providesSignUpDataSource(dataSourceImpl: SignUpDataSourceImpl): SignUpDataSource
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/app/di/StorageModule.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.app.di
2 |
3 | import com.univoice.data.datasource.StorageDataSource
4 | import com.univoice.data.repositoryimpl.StorageRepositoryImpl
5 | import com.univoice.data_remote.api.StorageApiService
6 | import com.univoice.data_remote.datasourceimpl.StorageDataSourceImpl
7 | import com.univoice.domain.repository.StorageRepository
8 | import dagger.Binds
9 | import dagger.Module
10 | import dagger.Provides
11 | import dagger.hilt.InstallIn
12 | import dagger.hilt.components.SingletonComponent
13 | import retrofit2.Retrofit
14 | import javax.inject.Singleton
15 |
16 | @Module
17 | @InstallIn(SingletonComponent::class)
18 | object StorageModule {
19 | @Provides
20 | @Singleton
21 | fun provideStorageService(
22 | @UniVoiceRetrofit retrofit: Retrofit,
23 | ): StorageApiService = retrofit.create(StorageApiService::class.java)
24 |
25 | @Module
26 | @InstallIn(SingletonComponent::class)
27 | interface RepositoryModule {
28 | @Binds
29 | @Singleton
30 | fun bindsStorageRepository(RepositoryImpl: StorageRepositoryImpl): StorageRepository
31 | }
32 |
33 | @Module
34 | @InstallIn(SingletonComponent::class)
35 | interface DataSourceModule {
36 | @Singleton
37 | @Binds
38 | fun providesStorageDataSource(DataSourceImpl: StorageDataSourceImpl): StorageDataSource
39 | }
40 | }
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. For more details, visit
12 | # https://developer.android.com/r/tools/gradle-multi-project-decoupled-projects
13 | # org.gradle.parallel=true
14 | # AndroidX package structure to make it clearer which packages are bundled with the
15 | # Android operating system, and which are packaged with your app's APK
16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn
17 | android.useAndroidX=true
18 | # Kotlin code style for this project: "official" or "obsolete":
19 | kotlin.code.style=official
20 | # Enables namespacing of each library's R class so that its R class includes only the
21 | # resources declared in the library itself and none from the library's dependencies,
22 | # thereby reducing the size of the R class for that library
23 | android.nonTransitiveRClass=true
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/data_remote/api/HomeApiService.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.data_remote.api
2 |
3 | import com.univoice.data.dto.BaseResponse
4 | import com.univoice.data.dto.response.ResponseNoticeAllDto
5 | import com.univoice.data.dto.response.ResponseNoticeQuickScanDto
6 | import com.univoice.data_remote.api.ApiKeyStorage.ALL
7 | import com.univoice.data_remote.api.ApiKeyStorage.API
8 | import com.univoice.data_remote.api.ApiKeyStorage.COLLEGE_DEPARTMENT
9 | import com.univoice.data_remote.api.ApiKeyStorage.DEPARTMENT
10 | import com.univoice.data_remote.api.ApiKeyStorage.NOTICE
11 | import com.univoice.data_remote.api.ApiKeyStorage.UNIVERSITY
12 | import com.univoice.data_remote.api.ApiKeyStorage.V1
13 | import retrofit2.http.GET
14 |
15 | interface HomeApiService {
16 | @GET("/$API/$V1/$NOTICE/${ApiKeyStorage.QUICKHEAD}")
17 | suspend fun getNoticeQuickScan(): BaseResponse
18 |
19 | @GET("/$API/$V1/$NOTICE/$ALL")
20 | suspend fun getNoticeAll(): BaseResponse>
21 |
22 | @GET("/$API/$V1/$NOTICE/$UNIVERSITY")
23 | suspend fun getNoticeUniversity(): BaseResponse>
24 |
25 | @GET("/$API/$V1/$NOTICE/$COLLEGE_DEPARTMENT")
26 | suspend fun getNoticeCollege(): BaseResponse>
27 |
28 | @GET("/$API/$V1/$NOTICE/$DEPARTMENT")
29 | suspend fun getNoticeDepartment(): BaseResponse>
30 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/app/di/QuickScanModule.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.app.di
2 |
3 | import com.univoice.data.datasource.QuickScanDataSource
4 | import com.univoice.data.repositoryimpl.QuickScanRepositoryImpl
5 | import com.univoice.data_remote.api.QuickScanApiService
6 | import com.univoice.data_remote.datasourceimpl.QuickScanDataSourceImpl
7 | import com.univoice.domain.repository.QuickScanRepository
8 | import dagger.Binds
9 | import dagger.Module
10 | import dagger.Provides
11 | import dagger.hilt.InstallIn
12 | import dagger.hilt.components.SingletonComponent
13 | import retrofit2.Retrofit
14 | import javax.inject.Singleton
15 |
16 | @Module
17 | @InstallIn(SingletonComponent::class)
18 | object QuickScanModule {
19 | @Provides
20 | @Singleton
21 | fun provideQuickScanService(
22 | @UniVoiceRetrofit retrofit: Retrofit,
23 | ): QuickScanApiService = retrofit.create(QuickScanApiService::class.java)
24 |
25 | @Module
26 | @InstallIn(SingletonComponent::class)
27 | interface RepositoryModule {
28 | @Binds
29 | @Singleton
30 | fun bindsQuickScanRepository(RepositoryImpl: QuickScanRepositoryImpl): QuickScanRepository
31 | }
32 |
33 | @Module
34 | @InstallIn(SingletonComponent::class)
35 | interface DataSourceModule {
36 | @Singleton
37 | @Binds
38 | fun providesQuickScanDataSource(DataSourceImpl: QuickScanDataSourceImpl): QuickScanDataSource
39 | }
40 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/feature/storage/StorageViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.feature.storage
2 |
3 | import androidx.lifecycle.ViewModel
4 | import androidx.lifecycle.viewModelScope
5 | import com.univoice.core_ui.view.UiState
6 | import com.univoice.domain.entity.StorageListEntity
7 | import com.univoice.domain.repository.StorageRepository
8 | import dagger.hilt.android.lifecycle.HiltViewModel
9 | import kotlinx.coroutines.flow.MutableStateFlow
10 | import kotlinx.coroutines.flow.StateFlow
11 | import kotlinx.coroutines.launch
12 | import javax.inject.Inject
13 |
14 | @HiltViewModel
15 | class StorageViewModel @Inject constructor(
16 | private val storageRepository: StorageRepository
17 | ) : ViewModel() {
18 | private val _getStorageState = MutableStateFlow>>(UiState.Empty)
19 | val getStorageState: StateFlow>> = _getStorageState
20 |
21 | init {
22 | getStorageList()
23 | }
24 |
25 | fun getStorageList() = viewModelScope.launch {
26 | _getStorageState.emit(UiState.Loading)
27 | storageRepository.getSaves().fold(
28 | {
29 | if (it != null) _getStorageState.emit(UiState.Success(it)) else _getStorageState.emit(
30 | UiState.Failure("400")
31 | )
32 | },
33 | { _getStorageState.emit(UiState.Failure(it.message.toString())) }
34 | )
35 |
36 | }
37 | }
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_toolbar.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
18 |
19 |
26 |
27 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/app/di/NoticeDetailModule.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.app.di
2 |
3 | import com.univoice.data.datasource.NoticeDetailDataSource
4 | import com.univoice.data.repositoryimpl.NoticeDetailRepositoryImpl
5 | import com.univoice.data_remote.api.NoticeDetailApiService
6 | import com.univoice.data_remote.datasourceimpl.NoticeDetailDataSourceImpl
7 | import com.univoice.domain.repository.NoticeDetailRepository
8 | import dagger.Binds
9 | import dagger.Module
10 | import dagger.Provides
11 | import dagger.hilt.InstallIn
12 | import dagger.hilt.components.SingletonComponent
13 | import retrofit2.Retrofit
14 | import javax.inject.Singleton
15 |
16 | @Module
17 | @InstallIn(SingletonComponent::class)
18 | object NoticeDetailModule {
19 | @Provides
20 | @Singleton
21 | fun noticeDetailService(
22 | @UniVoiceRetrofit retrofit: Retrofit,
23 | ): NoticeDetailApiService = retrofit.create(NoticeDetailApiService::class.java)
24 |
25 | @Module
26 | @InstallIn(SingletonComponent::class)
27 | interface RepositoryModule {
28 | @Binds
29 | @Singleton
30 | fun bindsNoticeDetailRepository(RepositoryImpl: NoticeDetailRepositoryImpl): NoticeDetailRepository
31 | }
32 |
33 | @Module
34 | @InstallIn(SingletonComponent::class)
35 | interface DataSourceModule {
36 | @Singleton
37 | @Binds
38 | fun providesNoticeDetailDataSource(DataSourceImpl: NoticeDetailDataSourceImpl): NoticeDetailDataSource
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/feature/noticePost/NoticePostImageAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.feature.noticePost
2 |
3 | import android.net.Uri
4 | import android.view.LayoutInflater
5 | import android.view.ViewGroup
6 | import android.widget.ImageView
7 | import androidx.recyclerview.widget.RecyclerView
8 | import com.univoice.databinding.ItemNoticePostImageBinding
9 |
10 | class NoticePostImageAdapter(private val imageUris: MutableList) :
11 | RecyclerView.Adapter() {
12 |
13 | inner class ViewHolder(binding: ItemNoticePostImageBinding) :
14 | RecyclerView.ViewHolder(binding.root) {
15 | val imageView: ImageView = binding.ivNoticePostImageItem
16 | val cancelImageView: ImageView = binding.ivPostingCancelImage
17 | }
18 |
19 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
20 | val binding =
21 | ItemNoticePostImageBinding.inflate(LayoutInflater.from(parent.context), parent, false)
22 | return ViewHolder(binding)
23 | }
24 |
25 | override fun onBindViewHolder(holder: ViewHolder, position: Int) {
26 | holder.imageView.setImageURI(imageUris[position])
27 | holder.cancelImageView.setOnClickListener {
28 | imageUris.removeAt(position)
29 | notifyItemRemoved(position)
30 | notifyItemRangeChanged(position, imageUris.size)
31 | }
32 | }
33 |
34 | override fun getItemCount() = imageUris.size
35 | }
36 |
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/feature/signup/DepartmentInputViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.feature.signup
2 |
3 | import androidx.lifecycle.ViewModel
4 | import androidx.lifecycle.viewModelScope
5 | import com.univoice.core_ui.view.UiState
6 | import com.univoice.data.dto.request.RequestDepartmentDto
7 | import com.univoice.domain.repository.SignUpRepository
8 | import dagger.hilt.android.lifecycle.HiltViewModel
9 | import kotlinx.coroutines.flow.MutableStateFlow
10 | import kotlinx.coroutines.flow.StateFlow
11 | import kotlinx.coroutines.launch
12 | import timber.log.Timber
13 | import javax.inject.Inject
14 |
15 | @HiltViewModel
16 | class DepartmentInputViewModel @Inject constructor(
17 | private val signupRepository: SignUpRepository
18 | ) : ViewModel() {
19 |
20 | private val _departmentListState = MutableStateFlow>>(UiState.Empty)
21 | val departmentListState: StateFlow>> = _departmentListState
22 |
23 | fun postDepartments(universityName: String) {
24 | _departmentListState.value = UiState.Loading
25 | viewModelScope.launch {
26 | val request = RequestDepartmentDto(universityName)
27 | signupRepository.postDepartments(request).onSuccess { response ->
28 | _departmentListState.value = UiState.Success(response.data ?: emptyList())
29 | }.onFailure {
30 | _departmentListState.value = UiState.Failure(it.message ?: "")
31 | }
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/feature/util/CalculateTime.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.feature.util
2 |
3 | import android.content.Context
4 | import com.univoice.R
5 | import java.time.LocalDateTime
6 | import java.time.format.DateTimeFormatter
7 | import java.time.temporal.ChronoUnit
8 |
9 | class CalculateTime(private val context: Context) {
10 | fun getCalculateTime(dateTimeString: String): String {
11 | val dateFormat = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss")
12 | val targetDate = LocalDateTime.parse(dateTimeString, dateFormat)
13 | val currentDate = LocalDateTime.now()
14 |
15 | val minutesDifference = ChronoUnit.MINUTES.between(targetDate, currentDate)
16 | val hoursDifference = ChronoUnit.HOURS.between(targetDate, currentDate)
17 | val daysDifference = ChronoUnit.DAYS.between(targetDate, currentDate)
18 |
19 | return when {
20 | minutesDifference < TIME_THRESHOLD -> context.getString(R.string.feed_time_now)
21 | hoursDifference < TIME_THRESHOLD -> "$minutesDifference${context.getString(R.string.feed_time_minute)}"
22 | daysDifference < TIME_THRESHOLD -> "$hoursDifference${context.getString(R.string.feed_time_hour)}"
23 | else -> {
24 | val desiredFormat = DateTimeFormatter.ofPattern("yyyy/MM/dd")
25 | return targetDate.format(desiredFormat)
26 | }
27 | }
28 | }
29 |
30 | companion object {
31 | private const val TIME_THRESHOLD = 1
32 | }
33 |
34 |
35 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/feature/signup/CheckInfoActivity.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.feature.signup
2 |
3 | import android.content.Intent
4 | import android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK
5 | import android.content.Intent.FLAG_ACTIVITY_NEW_TASK
6 | import androidx.activity.OnBackPressedCallback
7 | import com.univoice.R
8 | import com.univoice.core_ui.base.BindingActivity
9 | import com.univoice.databinding.ActivityCheckInfoBinding
10 | import com.univoice.feature.entry.EntryActivity
11 |
12 | class CheckInfoActivity :
13 | BindingActivity(R.layout.activity_check_info) {
14 |
15 | override fun initView() {
16 | backPressedListener()
17 | initButtonClickListener()
18 | }
19 |
20 | private fun backPressedListener() {
21 | onBackPressedDispatcher.addCallback(this, object : OnBackPressedCallback(true) {
22 | override fun handleOnBackPressed() {
23 | Intent(this@CheckInfoActivity, EntryActivity::class.java).apply {
24 | flags = FLAG_ACTIVITY_CLEAR_TASK or FLAG_ACTIVITY_NEW_TASK
25 | startActivity(this)
26 | }
27 | }
28 | })
29 | }
30 |
31 | private fun initButtonClickListener() {
32 | binding.btnCheckInfoStart.setOnClickListener {
33 | Intent(this, EntryActivity::class.java).apply {
34 | flags = FLAG_ACTIVITY_CLEAR_TASK or FLAG_ACTIVITY_NEW_TASK
35 | startActivity(this)
36 | }
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/feature/home/HomeNoticeContentAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.feature.home
2 |
3 | import android.view.LayoutInflater
4 | import android.view.ViewGroup
5 | import androidx.recyclerview.widget.ListAdapter
6 | import com.univoice.core_ui.view.ItemDiffCallback
7 | import com.univoice.databinding.ItemHomeNoticeContentBinding
8 | import com.univoice.domain.entity.NoticeListEntity
9 |
10 | class HomeNoticeContentAdapter(
11 | private val click: (NoticeListEntity, Int) -> Unit = { _, _ -> },
12 | ) : ListAdapter(
13 | HomeNoticeContentDiffCallback,
14 | ) {
15 | override fun onCreateViewHolder(
16 | parent: ViewGroup,
17 | viewType: Int,
18 | ): HomeNoticeContentViewHolder {
19 | val binding =
20 | ItemHomeNoticeContentBinding.inflate(
21 | LayoutInflater.from(parent.context),
22 | parent,
23 | false
24 | )
25 | return HomeNoticeContentViewHolder(binding, click)
26 | }
27 |
28 | override fun onBindViewHolder(
29 | holder: HomeNoticeContentViewHolder,
30 | position: Int,
31 | ) {
32 | holder.bind(currentList[position])
33 | }
34 |
35 | companion object {
36 | private val HomeNoticeContentDiffCallback =
37 | ItemDiffCallback(
38 | onItemsTheSame = { old, new -> old.id == new.id },
39 | onContentsTheSame = { old, new -> old == new },
40 | )
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/feature/login/LoginBottomSheetFragment.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.feature.login
2 |
3 | import android.app.Dialog
4 | import android.content.Intent
5 | import android.os.Bundle
6 | import android.view.View
7 | import com.google.android.material.bottomsheet.BottomSheetBehavior
8 | import com.google.android.material.bottomsheet.BottomSheetDialog
9 | import com.univoice.R
10 | import com.univoice.core_ui.base.BindingBottomSheetFragment
11 | import com.univoice.databinding.FragmentLoginBottomSheetBinding
12 | import com.univoice.feature.signup.SignUpActivity
13 |
14 | class LoginBottomSheetFragment :
15 | BindingBottomSheetFragment(R.layout.fragment_login_bottom_sheet) {
16 |
17 | override fun onCreate(savedInstanceState: Bundle?) {
18 | super.onCreate(savedInstanceState)
19 | setStyle(STYLE_NORMAL, R.style.TransparentBottomSheetDialogFragment)
20 | }
21 |
22 | override fun initView() {
23 | initCloseBtnClickListener()
24 | initSignUpBtnClickListener()
25 | }
26 |
27 | private fun initSignUpBtnClickListener() {
28 | binding.btnLoginBottomSheetSignup.setOnClickListener {
29 | navigateToSignUp()
30 | }
31 | }
32 |
33 | private fun initCloseBtnClickListener() {
34 | binding.btnLoginBottomSheetClose.setOnClickListener {
35 | dismiss()
36 | }
37 | }
38 |
39 | private fun navigateToSignUp() {
40 | startActivity(Intent(requireContext(), SignUpActivity::class.java))
41 | }
42 |
43 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/feature/login/WelcomeActivity.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.feature.login
2 |
3 | import android.content.Intent
4 | import android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK
5 | import android.content.Intent.FLAG_ACTIVITY_NEW_TASK
6 | import androidx.activity.OnBackPressedCallback
7 | import com.univoice.R
8 | import com.univoice.core_ui.base.BindingActivity
9 | import com.univoice.databinding.ActivityWelcomeBinding
10 | import com.univoice.feature.MainActivity
11 | import com.univoice.feature.entry.EntryActivity
12 |
13 | class WelcomeActivity : BindingActivity(R.layout.activity_welcome) {
14 | override fun initView() {
15 | backPressedListener()
16 | initConfirmBtnClickListener()
17 | }
18 |
19 | private fun backPressedListener() {
20 | onBackPressedDispatcher.addCallback(this, object : OnBackPressedCallback(true) {
21 | override fun handleOnBackPressed() {
22 | Intent(this@WelcomeActivity, EntryActivity::class.java).apply {
23 | flags = FLAG_ACTIVITY_CLEAR_TASK or FLAG_ACTIVITY_NEW_TASK
24 | startActivity(this)
25 | }
26 | }
27 | })
28 | }
29 |
30 | private fun initConfirmBtnClickListener() {
31 | binding.btnWelcomeConfirm.setOnClickListener {
32 | Intent(this, MainActivity::class.java).apply {
33 | flags = FLAG_ACTIVITY_NEW_TASK or FLAG_ACTIVITY_CLEAR_TASK
34 | startActivity(this)
35 | }
36 | }
37 | }
38 | }
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_notice_post_image.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
21 |
22 |
31 |
32 |
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/feature/setting/SettingViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.feature.setting
2 |
3 | import androidx.lifecycle.ViewModel
4 | import androidx.lifecycle.viewModelScope
5 | import com.univoice.core_ui.view.UiState
6 | import com.univoice.domain.entity.SettingUserEntity
7 | import com.univoice.domain.repository.SettingRepository
8 | import com.univoice.domain.repository.UserInfoRepository
9 | import dagger.hilt.android.lifecycle.HiltViewModel
10 | import kotlinx.coroutines.flow.MutableStateFlow
11 | import kotlinx.coroutines.flow.StateFlow
12 | import kotlinx.coroutines.launch
13 | import javax.inject.Inject
14 |
15 | @HiltViewModel
16 | class SettingViewModel @Inject constructor(
17 | private val settingRepository: SettingRepository,
18 | private val userInfoRepository: UserInfoRepository
19 | ) : ViewModel() {
20 | private val _getMyPageState = MutableStateFlow>(UiState.Empty)
21 | val getMyPageState: StateFlow> = _getMyPageState
22 |
23 | init {
24 | getMyPage()
25 | }
26 |
27 | private fun getMyPage() = viewModelScope.launch {
28 | _getMyPageState.emit(UiState.Loading)
29 | settingRepository.getMyPage().fold(
30 | {
31 | _getMyPageState.emit(UiState.Success(it))
32 | },
33 | { _getMyPageState.emit(UiState.Failure(it.message.toString())) }
34 | )
35 | }
36 |
37 | fun saveCheckLogin(checkLogin: Boolean) =
38 | viewModelScope.launch { userInfoRepository.saveCheckLogin(checkLogin) }
39 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/feature/home/HomeQuickscanAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.feature.home
2 |
3 | import android.view.LayoutInflater
4 | import android.view.ViewGroup
5 | import androidx.recyclerview.widget.ListAdapter
6 | import com.univoice.core_ui.view.ItemDiffCallback
7 | import com.univoice.databinding.ItemHomeNoticeQuickscanBinding
8 | import com.univoice.domain.entity.HomeQuickScanListEntity
9 |
10 | class HomeQuickscanAdapter(
11 | private val click: (HomeQuickScanListEntity, Int) -> Unit = { _, _ -> },
12 | ) :
13 | ListAdapter(
14 | HomeQuickscanAdapterDiffCallback,
15 | ) {
16 | override fun onCreateViewHolder(
17 | parent: ViewGroup,
18 | viewType: Int,
19 | ): HomeQuickscanViewHolder {
20 | val binding =
21 | ItemHomeNoticeQuickscanBinding.inflate(
22 | LayoutInflater.from(parent.context),
23 | parent,
24 | false
25 | )
26 | return HomeQuickscanViewHolder(binding, click)
27 | }
28 |
29 | override fun onBindViewHolder(
30 | holder: HomeQuickscanViewHolder,
31 | position: Int,
32 | ) {
33 | holder.bind(currentList[position])
34 | }
35 |
36 | companion object {
37 | private val HomeQuickscanAdapterDiffCallback =
38 | ItemDiffCallback(
39 | onItemsTheSame = { old, new -> old.name == new.name },
40 | onContentsTheSame = { old, new -> old == new },
41 | )
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/data_remote/datasourceimpl/NoticeDetailDataSourceImpl.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.data_remote.datasourceimpl
2 |
3 | import com.univoice.data.datasource.NoticeDetailDataSource
4 | import com.univoice.data.dto.BaseResponse
5 | import com.univoice.data.dto.response.ResponseNoticeDetailDto
6 | import com.univoice.data_remote.api.NoticeDetailApiService
7 | import javax.inject.Inject
8 |
9 | class NoticeDetailDataSourceImpl @Inject constructor(
10 | private val noticeDetailApiService: NoticeDetailApiService
11 | ) : NoticeDetailDataSource {
12 | override suspend fun getNoticeDetail(noticeId: Int): BaseResponse {
13 | return noticeDetailApiService.getNoticeDetail(noticeId)
14 | }
15 |
16 | override suspend fun postNoticeLike(noticeId: Int): BaseResponse {
17 | return noticeDetailApiService.postNoticeLike(noticeId)
18 | }
19 |
20 | override suspend fun postNoticeCancelLike(noticeId: Int): BaseResponse {
21 | return noticeDetailApiService.postNoticeCancelLike(noticeId)
22 | }
23 |
24 | override suspend fun postNoticeDetailViewCount(noticeId: Int): BaseResponse {
25 | return noticeDetailApiService.postNoticeDetailViewCount(noticeId)
26 | }
27 |
28 | override suspend fun postNoticeDetailSave(noticeId: Int): BaseResponse {
29 | return noticeDetailApiService.postNoticeDetailSave(noticeId)
30 | }
31 |
32 | override suspend fun postNoticeDetailCancel(noticeId: Int): BaseResponse {
33 | return noticeDetailApiService.postNoticeDetailCancel(noticeId)
34 | }
35 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/feature/home/HomeNoticeContentViewHolder.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.feature.home
2 |
3 | import android.view.View
4 | import androidx.recyclerview.widget.RecyclerView
5 | import coil.load
6 | import coil.transform.RoundedCornersTransformation
7 | import com.univoice.databinding.ItemHomeNoticeContentBinding
8 | import com.univoice.domain.entity.NoticeListEntity
9 | import com.univoice.feature.util.CalculateDate
10 |
11 | class HomeNoticeContentViewHolder(
12 | private val binding: ItemHomeNoticeContentBinding,
13 | private val click: (NoticeListEntity, Int) -> Unit = { _, _ -> },
14 | ) : RecyclerView.ViewHolder(binding.root) {
15 | fun bind(data: NoticeListEntity) {
16 | with(binding) {
17 | btnHomeNoticeContentCategory.text = data.category
18 | tvHomeNoticeContentTitle.text = data.title
19 | tvHomeNoticeContentLike.text = data.likeCount.toString()
20 | tvHomeNoticeContentView.text = data.viewCount.toString()
21 | tvHomeNoticeContentDate.text = CalculateDate().getCalculateDate(data.date)
22 |
23 | if (data.image.isEmpty()) {
24 | ivHomeNoticeContent.visibility = View.INVISIBLE
25 | } else {
26 | ivHomeNoticeContent.load(data.image) {
27 | ivHomeNoticeContent.visibility = View.VISIBLE
28 | transformations(RoundedCornersTransformation(5f))
29 | }
30 | }
31 |
32 | root.setOnClickListener {
33 | click(data, bindingAdapterPosition)
34 | }
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/core_ui/theme/Color.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.core_ui.theme
2 |
3 | import androidx.compose.ui.graphics.Color
4 |
5 | // Gray
6 | val Gray900 = Color(0xFF111111)
7 | val Gray800 = Color(0xFF333333)
8 | val Gray700 = Color(0xFF505050)
9 | val Gray600 = Color(0xFF666666)
10 | val Gray500 = Color(0xFF767676)
11 | val Gray400 = Color(0xFF888888)
12 | val Gray300 = Color(0xFF999999)
13 | val Gray200 = Color(0xFFBBBBBB)
14 | val Gray100 = Color(0xFFE1E1E1)
15 | val Gray50 = Color(0xFFF1F1F5)
16 |
17 | // Mint_main
18 | val Mint900 = Color(0xFF004F45)
19 | val Mint800 = Color(0xFF006559)
20 | val Mint700 = Color(0xFF008777)
21 | val Mint600 = Color(0xFF00A995)
22 | val Mint500 = Color(0xFF00B49E)
23 | val Mint400 = Color(0xFF00CBB2)
24 | val Mint300 = Color(0xFF00E1C6)
25 | val Mint200 = Color(0xFFB0F6ED)
26 | val Mint100 = Color(0xFFD9FBF6)
27 | val Mint50 = Color(0xFFE6FCF9)
28 |
29 | // Blue_sub
30 | val Blue900 = Color(0xFF102457)
31 | val Blue800 = Color(0xFF152F70)
32 | val Blue700 = Color(0xFF1C3E95)
33 | val Blue600 = Color(0xFF234EBB)
34 | val Blue500 = Color(0xFF2653C7)
35 | val Blue400 = Color(0xFF2A5EE0)
36 | val Blue300 = Color(0xFF2F68F9)
37 | val Blue200 = Color(0xFFBFD0FD)
38 | val Blue100 = Color(0xFFE0E8FE)
39 | val Blue50 = Color(0xFFEAF0FE)
40 |
41 | val White = Color(0xFFFFFFFF)
42 |
43 | // Font
44 | val Font_B01 = Color(0xFF111111)
45 | val Font_B02 = Color(0xFF555555)
46 | val Font_B03 = Color(0xFF767676)
47 | val Font_B04 = Color(0xFF999999)
48 | val Font_W01 = Color(0xFFFFFFFF)
49 |
50 | // Line
51 | val Light = Color(0xFFF1F1F5)
52 | val Regular = Color(0xFFE5E5EC)
53 | val Black = Color(0xFF111111)
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/feature/noticePost/timePicker/adapter/DateDayAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.feature.noticePost.timePicker.adapter
2 |
3 | import android.view.LayoutInflater
4 | import android.view.ViewGroup
5 | import androidx.databinding.DataBindingUtil
6 | import androidx.recyclerview.widget.RecyclerView
7 | import com.univoice.R
8 | import com.univoice.feature.noticePost.timePicker.dpToPx
9 | import com.univoice.feature.noticePost.timePicker.getDayFromCalendar
10 | import java.util.Calendar
11 |
12 | class DateDayAdapter(
13 | val days: ArrayList,
14 | private val dividerHeight: Int
15 | ) :
16 | RecyclerView.Adapter() {
17 |
18 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
19 | val view = DateViewHolder(
20 | DataBindingUtil.inflate(
21 | LayoutInflater.from(parent.context),
22 | R.layout.item_date_number,
23 | parent,
24 | false
25 | )
26 | )
27 | view.binding.layoutDateNumber.layoutParams.height =
28 | dividerHeight.dpToPx(view.binding.tvDateNumber.context).toInt()
29 | return view
30 | }
31 |
32 | override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
33 | val viewHolder = holder as DateViewHolder
34 | viewHolder.binding.tvDateNumber.text = getDayFromCalendar(days[position])
35 | }
36 |
37 | override fun getItemCount() = days.size
38 |
39 | override fun getItemId(position: Int): Long {
40 | return position.toLong()
41 | }
42 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/feature/noticePost/timePicker/adapter/TimeDateAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.feature.noticePost.timePicker.adapter
2 |
3 | import android.view.LayoutInflater
4 | import android.view.ViewGroup
5 | import androidx.databinding.DataBindingUtil
6 | import androidx.recyclerview.widget.RecyclerView
7 | import com.univoice.R
8 | import com.univoice.feature.noticePost.timePicker.dpToPx
9 | import com.univoice.feature.noticePost.timePicker.getDateFromCalendar
10 | import java.util.Calendar
11 |
12 | class TimeDateAdapter(
13 | val dates: ArrayList,
14 | private val dividerHeight: Int
15 | ) :
16 | RecyclerView.Adapter() {
17 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
18 | val view = DateViewHolder(
19 | DataBindingUtil.inflate(
20 | LayoutInflater.from(parent.context),
21 | R.layout.item_date_number,
22 | parent,
23 | false
24 | )
25 | )
26 | view.binding.layoutDateNumber.layoutParams.height =
27 | dividerHeight.dpToPx(view.binding.tvDateNumber.context).toInt()
28 | return view
29 | }
30 |
31 | override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
32 | val viewHolder = holder as DateViewHolder
33 |
34 | viewHolder.binding.tvDateNumber.text = getDateFromCalendar(dates[position])
35 | }
36 |
37 | override fun getItemCount() = dates.size
38 |
39 | override fun getItemId(position: Int): Long {
40 | return position.toLong()
41 | }
42 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/feature/noticePost/timePicker/adapter/DateMonthAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.feature.noticePost.timePicker.adapter
2 |
3 | import android.view.LayoutInflater
4 | import android.view.ViewGroup
5 | import androidx.databinding.DataBindingUtil
6 | import androidx.recyclerview.widget.RecyclerView
7 | import com.univoice.R
8 | import com.univoice.feature.noticePost.timePicker.dpToPx
9 | import com.univoice.feature.noticePost.timePicker.getMonthFromCalendar
10 | import java.util.Calendar
11 |
12 | class DateMonthAdapter(
13 | val months: ArrayList,
14 | private val dividerHeight: Int
15 | ) :
16 | RecyclerView.Adapter() {
17 |
18 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
19 | val view = DateViewHolder(
20 | DataBindingUtil.inflate(
21 | LayoutInflater.from(parent.context),
22 | R.layout.item_date_number,
23 | parent,
24 | false
25 | )
26 | )
27 | view.binding.layoutDateNumber.layoutParams.height =
28 | dividerHeight.dpToPx(view.binding.tvDateNumber.context).toInt()
29 | return view
30 | }
31 |
32 | override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
33 | val viewHolder = holder as DateViewHolder
34 |
35 | viewHolder.binding.tvDateNumber.text = getMonthFromCalendar(months[position])
36 | }
37 |
38 | override fun getItemCount() = months.size
39 |
40 | override fun getItemId(position: Int): Long {
41 | return position.toLong()
42 | }
43 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/feature/noticePost/timePicker/adapter/DateYearAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.feature.noticePost.timePicker.adapter
2 |
3 | import android.view.LayoutInflater
4 | import android.view.ViewGroup
5 | import androidx.databinding.DataBindingUtil
6 | import androidx.recyclerview.widget.RecyclerView
7 | import com.univoice.R
8 | import com.univoice.feature.noticePost.timePicker.dpToPx
9 | import com.univoice.feature.noticePost.timePicker.getYearFromCalendar
10 | import java.util.Calendar
11 |
12 | class DateYearAdapter(
13 | val years: ArrayList,
14 | private val dividerHeight: Int
15 | ) :
16 | RecyclerView.Adapter() {
17 |
18 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
19 | val view = DateViewHolder(
20 | DataBindingUtil.inflate(
21 | LayoutInflater.from(parent.context),
22 | R.layout.item_date_number,
23 | parent,
24 | false
25 | )
26 | )
27 | view.binding.layoutDateNumber.layoutParams.height =
28 | dividerHeight.dpToPx(view.binding.tvDateNumber.context).toInt()
29 | return view
30 | }
31 |
32 | override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
33 | val viewHolder = holder as DateViewHolder
34 |
35 | viewHolder.binding.tvDateNumber.text = getYearFromCalendar(years[position])
36 | }
37 |
38 |
39 | override fun getItemCount() = years.size
40 |
41 | override fun getItemId(position: Int): Long {
42 | return position.toLong()
43 | }
44 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/feature/noticePost/timePicker/adapter/TimeMinuteAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.feature.noticePost.timePicker.adapter
2 |
3 | import android.view.LayoutInflater
4 | import android.view.ViewGroup
5 | import androidx.databinding.DataBindingUtil
6 | import androidx.recyclerview.widget.RecyclerView
7 | import com.univoice.R
8 | import com.univoice.feature.noticePost.timePicker.dpToPx
9 | import com.univoice.feature.noticePost.timePicker.getMinuteFromCalendar
10 | import java.util.Calendar
11 |
12 | class TimeMinuteAdapter(
13 | val minute: ArrayList,
14 | private val dividerHeight: Int
15 | ) :
16 | RecyclerView.Adapter() {
17 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
18 | val view = DateViewHolder(
19 | DataBindingUtil.inflate(
20 | LayoutInflater.from(parent.context),
21 | R.layout.item_date_number,
22 | parent,
23 | false
24 | )
25 | )
26 | view.binding.layoutDateNumber.layoutParams.height =
27 | dividerHeight.dpToPx(view.binding.tvDateNumber.context).toInt()
28 | return view
29 | }
30 |
31 | override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
32 | val viewHolder = holder as DateViewHolder
33 |
34 | viewHolder.binding.tvDateNumber.text = getMinuteFromCalendar(minute[position])
35 | }
36 |
37 | override fun getItemCount() = minute.size
38 |
39 | override fun getItemId(position: Int): Long {
40 | return position.toLong()
41 | }
42 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/feature/noticePost/timePicker/adapter/TimeHourAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.feature.noticePost.timePicker.adapter
2 |
3 | import android.view.LayoutInflater
4 | import android.view.ViewGroup
5 | import androidx.databinding.DataBindingUtil
6 | import androidx.recyclerview.widget.RecyclerView
7 | import com.univoice.R
8 | import com.univoice.feature.noticePost.timePicker.dpToPx
9 | import com.univoice.feature.noticePost.timePicker.getHourFromCalendar
10 | import java.util.Calendar
11 |
12 |
13 | class TimeHourAdapter(
14 | val hour: ArrayList,
15 | private val dividerHeight: Int
16 | ) :
17 | RecyclerView.Adapter() {
18 |
19 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
20 | val view = DateViewHolder(
21 | DataBindingUtil.inflate(
22 | LayoutInflater.from(parent.context),
23 | R.layout.item_date_number,
24 | parent,
25 | false
26 | )
27 | )
28 | view.binding.layoutDateNumber.layoutParams.height =
29 | dividerHeight.dpToPx(view.binding.tvDateNumber.context).toInt()
30 | return view
31 | }
32 |
33 | override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
34 | val viewHolder = holder as DateViewHolder
35 |
36 | viewHolder.binding.tvDateNumber.text = getHourFromCalendar(hour[position])
37 | }
38 |
39 |
40 | override fun getItemCount() = hour.size
41 |
42 | override fun getItemId(position: Int): Long {
43 | return position.toLong()
44 | }
45 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/feature/noticePost/timePicker/adapter/TimeMeridiemAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.feature.noticePost.timePicker.adapter
2 |
3 | import android.view.LayoutInflater
4 | import android.view.ViewGroup
5 | import androidx.databinding.DataBindingUtil
6 | import androidx.recyclerview.widget.RecyclerView
7 | import com.univoice.R
8 | import com.univoice.feature.noticePost.timePicker.dpToPx
9 |
10 | class TimeMeridiemAdapter(
11 | val meridiem: ArrayList,
12 | private val dividerHeight: Int
13 | ) :
14 | RecyclerView.Adapter() {
15 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
16 | val view = DateViewHolder(
17 | DataBindingUtil.inflate(
18 | LayoutInflater.from(parent.context),
19 | R.layout.item_date_number,
20 | parent,
21 | false
22 | )
23 | )
24 | view.binding.layoutDateNumber.layoutParams.height =
25 | dividerHeight.dpToPx(view.binding.tvDateNumber.context).toInt()
26 | return view
27 | }
28 |
29 | override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
30 | val viewHolder = holder as DateViewHolder
31 |
32 | if (meridiem[position].isNotEmpty())
33 | viewHolder.binding.tvDateNumber.text = meridiem[position]
34 | else
35 | viewHolder.binding.tvDateNumber.text = ""
36 | }
37 |
38 | override fun getItemCount() = meridiem.size
39 |
40 | override fun getItemId(position: Int): Long {
41 | return position.toLong()
42 | }
43 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/app/di/LoginModule.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.app.di
2 |
3 | import com.univoice.data.datasource.LoginDataSource
4 | import com.univoice.data.repositoryimpl.LoginRepositoryImpl
5 | import com.univoice.data.repositoryimpl.UserInfoRepositoryImpl
6 | import com.univoice.data_remote.api.LoginApiService
7 | import com.univoice.data_remote.datasourceimpl.LoginDataSourceImpl
8 | import com.univoice.domain.repository.LoginRepository
9 | import com.univoice.domain.repository.UserInfoRepository
10 | import dagger.Binds
11 | import dagger.Module
12 | import dagger.Provides
13 | import dagger.hilt.InstallIn
14 | import dagger.hilt.components.SingletonComponent
15 | import retrofit2.Retrofit
16 | import javax.inject.Singleton
17 |
18 | @Module
19 | @InstallIn(SingletonComponent::class)
20 | object LoginModule {
21 | @Provides
22 | @Singleton
23 | fun provideLoginService(
24 | @UniVoiceRetrofit retrofit: Retrofit,
25 | ): LoginApiService = retrofit.create(LoginApiService::class.java)
26 |
27 | @Module
28 | @InstallIn(SingletonComponent::class)
29 | interface RepositoryModule {
30 | @Binds
31 | @Singleton
32 | fun bindsLoginRepository(RepositoryImpl: LoginRepositoryImpl): LoginRepository
33 |
34 | @Binds
35 | @Singleton
36 | fun bindsUserInfoRepository(RepositoryImpl: UserInfoRepositoryImpl): UserInfoRepository
37 | }
38 |
39 | @Module
40 | @InstallIn(SingletonComponent::class)
41 | interface DataSourceModule {
42 | @Singleton
43 | @Binds
44 | fun providesLoginDataSource(DataSourceImpl: LoginDataSourceImpl): LoginDataSource
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/feature/noticePost/NoticePostViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.feature.noticePost
2 |
3 | import androidx.lifecycle.ViewModel
4 | import androidx.lifecycle.viewModelScope
5 | import com.univoice.core_ui.view.UiState
6 | import com.univoice.domain.repository.PostRepository
7 | import dagger.hilt.android.lifecycle.HiltViewModel
8 | import kotlinx.coroutines.flow.MutableSharedFlow
9 | import kotlinx.coroutines.flow.MutableStateFlow
10 | import kotlinx.coroutines.flow.SharedFlow
11 | import kotlinx.coroutines.flow.StateFlow
12 | import kotlinx.coroutines.flow.asSharedFlow
13 | import kotlinx.coroutines.launch
14 | import java.io.File
15 | import javax.inject.Inject
16 |
17 | @HiltViewModel
18 | class NoticePostViewModel @Inject constructor(
19 | private val postRepository: PostRepository
20 | ) : ViewModel() {
21 | private val _postNoticeState = MutableSharedFlow>()
22 | val postNoticeState: SharedFlow> get() = _postNoticeState.asSharedFlow()
23 |
24 | fun postNotice(
25 | title: String,
26 | content: String,
27 | target: String?,
28 | startTime: String?,
29 | endTime: String?,
30 | noticeImages: List?
31 | ) = viewModelScope.launch {
32 | _postNoticeState.emit(UiState.Loading)
33 | postRepository.postSignUp(
34 | title,
35 | content,
36 | target,
37 | startTime,
38 | endTime,
39 | noticeImages,
40 | ).onSuccess { _postNoticeState.emit(UiState.Success(it)) }
41 | .onFailure { _postNoticeState.emit(UiState.Failure(it.message.toString())) }
42 | }
43 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/data_remote/datasourceimpl/SignUpDataSourceImpl.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.data_remote.datasourceimpl
2 |
3 | import com.univoice.data.datasource.SignUpDataSource
4 | import com.univoice.data.dto.BaseResponse
5 | import com.univoice.data.dto.request.RequestCheckEmailDto
6 | import com.univoice.data.dto.request.RequestDepartmentDto
7 | import com.univoice.data_remote.api.SignUpApiService
8 | import okhttp3.MultipartBody
9 | import okhttp3.RequestBody
10 | import javax.inject.Inject
11 |
12 | class SignUpDataSourceImpl @Inject constructor(
13 | private val signUpApiService: SignUpApiService
14 | ) : SignUpDataSource {
15 | override suspend fun postUniversityNames(): BaseResponse> =
16 | signUpApiService.postUniversityNames()
17 |
18 | override suspend fun postDepartments(requestDepartmentDto: RequestDepartmentDto): BaseResponse> =
19 | signUpApiService.postDepartments(requestDepartmentDto)
20 |
21 | override suspend fun postEmail(requestCheckEmailDto: RequestCheckEmailDto): BaseResponse =
22 | signUpApiService.postEmail(requestCheckEmailDto)
23 |
24 | override suspend fun postSignUp(
25 | admissionNumber: RequestBody,
26 | name: RequestBody,
27 | studentNumber: RequestBody,
28 | email: RequestBody,
29 | password: RequestBody,
30 | universityName: RequestBody,
31 | departmentName: RequestBody,
32 | studentCardImage: MultipartBody.Part
33 | ): BaseResponse {
34 | return signUpApiService.postSignUp(admissionNumber, name, studentNumber, email, password, universityName, departmentName, studentCardImage)
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/core_ui/base/BindingDialogFragment.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.core_ui.base
2 |
3 | import android.os.Bundle
4 | import android.view.LayoutInflater
5 | import android.view.View
6 | import android.view.ViewGroup
7 | import android.view.WindowManager
8 | import androidx.annotation.LayoutRes
9 | import androidx.databinding.DataBindingUtil
10 | import androidx.databinding.ViewDataBinding
11 | import androidx.fragment.app.DialogFragment
12 |
13 | abstract class BindingDialogFragment(
14 | @LayoutRes val layoutRes: Int
15 | ) : DialogFragment() {
16 | private var _binding: T? = null
17 | protected val binding get() = requireNotNull(_binding) { { "binding object is not initialized" } }
18 |
19 | override fun onStart() {
20 | super.onStart()
21 | dialog?.window?.apply {
22 | setLayout(
23 | WindowManager.LayoutParams.WRAP_CONTENT,
24 | WindowManager.LayoutParams.WRAP_CONTENT
25 | )
26 | }
27 | }
28 |
29 | override fun onCreateView(
30 | inflater: LayoutInflater,
31 | container: ViewGroup?,
32 | savedInstanceState: Bundle?
33 | ): View {
34 | _binding = DataBindingUtil.inflate(inflater, layoutRes, container, false)
35 | return binding.root
36 | }
37 |
38 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
39 | super.onViewCreated(view, savedInstanceState)
40 | binding.lifecycleOwner = viewLifecycleOwner
41 | initView()
42 | }
43 |
44 | protected abstract fun initView()
45 |
46 | override fun onDestroyView() {
47 | _binding = null
48 | super.onDestroyView()
49 | }
50 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/feature/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.feature
2 |
3 | import android.view.View
4 | import androidx.navigation.NavController
5 | import androidx.navigation.fragment.NavHostFragment
6 | import androidx.navigation.fragment.findNavController
7 | import androidx.navigation.ui.setupWithNavController
8 | import com.univoice.R
9 | import com.univoice.core_ui.base.BindingActivity
10 | import com.univoice.databinding.ActivityMainBinding
11 | import dagger.hilt.android.AndroidEntryPoint
12 |
13 | @AndroidEntryPoint
14 | class MainActivity : BindingActivity(R.layout.activity_main) {
15 | override fun initView() {
16 | initMainBottomNavigation()
17 | }
18 |
19 | private fun initMainBottomNavigation() {
20 | val navController = (supportFragmentManager.findFragmentById(R.id.fcv_main_nav) as NavHostFragment).findNavController()
21 | binding.bnvMainNav.apply {
22 | setupWithNavController(navController)
23 | itemIconTintList = null
24 | }
25 |
26 | setBottomNavigationVisible(navController)
27 | }
28 |
29 | private fun setBottomNavigationVisible(navController: NavController) {
30 | navController.addOnDestinationChangedListener { _, destination, _ ->
31 | binding.bnvMainNav.visibility =
32 | if (destination.id in
33 | listOf(
34 | R.id.fragment_home,
35 | R.id.fragment_storage,
36 | R.id.fragment_setting
37 | )
38 | ) {
39 | View.VISIBLE
40 | } else {
41 | View.GONE
42 | }
43 | }
44 | }
45 | }
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_storage.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
9 |
10 |
14 |
15 |
26 |
27 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/data_local/UserPreferencesDataSourceImpl.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.data_local
2 |
3 | import androidx.datastore.core.DataStore
4 | import androidx.datastore.preferences.core.Preferences
5 | import androidx.datastore.preferences.core.booleanPreferencesKey
6 | import androidx.datastore.preferences.core.edit
7 | import androidx.datastore.preferences.core.stringPreferencesKey
8 | import com.univoice.data.datasource.UserPreferencesDataSource
9 | import kotlinx.coroutines.flow.Flow
10 | import kotlinx.coroutines.flow.map
11 | import javax.inject.Inject
12 |
13 | class UserPreferencesDataSourceImpl @Inject constructor
14 | (
15 | private val dataStore: DataStore
16 | ) : UserPreferencesDataSource {
17 | private val USER_ACCESSTOKEN = stringPreferencesKey("user_accesstoken")
18 | private val CHECK_LOGIN = booleanPreferencesKey("check_login")
19 |
20 | override suspend fun saveUserAccessToken(accessToken: String) {
21 | dataStore.edit { preferences ->
22 | preferences[USER_ACCESSTOKEN] = accessToken
23 | }
24 | }
25 |
26 | override fun getUserAccessToken(): Flow = dataStore.data.map { preferences ->
27 | preferences[USER_ACCESSTOKEN]
28 | }
29 |
30 | override suspend fun saveCheckLogin(checkLogin: Boolean) {
31 | dataStore.edit { preferences ->
32 | preferences[CHECK_LOGIN] = checkLogin
33 | }
34 | }
35 |
36 | override fun getCheckLogin(): Flow = dataStore.data.map { preferences ->
37 | preferences[CHECK_LOGIN] ?: false
38 | }
39 |
40 | override suspend fun clear() {
41 | dataStore.edit { preferences ->
42 | preferences.remove(USER_ACCESSTOKEN)
43 | preferences.remove(CHECK_LOGIN)
44 | }
45 | }
46 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/core_ui/CustomSpinner.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.core_ui
2 |
3 | import android.content.Context
4 | import android.util.AttributeSet
5 | import android.widget.Spinner
6 | import androidx.appcompat.widget.AppCompatSpinner
7 |
8 | class CustomSpinner @JvmOverloads constructor(
9 | context: Context,
10 | attrs: AttributeSet? = null,
11 | defStyleAttr: Int = 0
12 | ) : AppCompatSpinner(context, attrs, defStyleAttr) {
13 |
14 | interface OnSpinnerEventsListener {
15 | fun onSpinnerOpened(spinner: Spinner?)
16 |
17 | fun onSpinnerClosed(spinner: Spinner?)
18 | }
19 |
20 | private var mListener: OnSpinnerEventsListener? = null
21 | private var mOpenInitiated = false
22 |
23 | override fun performClick(): Boolean {
24 | mOpenInitiated = true
25 | mListener?.onSpinnerOpened(this)
26 | return super.performClick()
27 | }
28 |
29 | override fun onWindowFocusChanged(hasFocus: Boolean) {
30 | if (hasBeenOpened() && hasFocus) {
31 | performClosedEvent()
32 | }
33 | }
34 |
35 | /**
36 | * Register the listener which will listen for events.
37 | */
38 | fun setSpinnerEventsListener(
39 | onSpinnerEventsListener: OnSpinnerEventsListener?
40 | ) {
41 | mListener = onSpinnerEventsListener
42 | }
43 |
44 | /**
45 | * Propagate the closed Spinner event to the listener from outside if needed.
46 | */
47 | fun performClosedEvent() {
48 | mOpenInitiated = false
49 | mListener?.onSpinnerClosed(this)
50 | }
51 |
52 | /**
53 | * A boolean flag indicating that the Spinner triggered an open event.
54 | *
55 | * @return true for opened Spinner
56 | */
57 | fun hasBeenOpened(): Boolean {
58 | return mOpenInitiated
59 | }
60 | }
61 |
62 |
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/feature/SplashActivity.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.feature
2 |
3 | import android.app.Activity
4 | import android.content.Intent
5 | import android.os.Handler
6 | import androidx.activity.viewModels
7 | import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
8 | import com.univoice.R
9 | import com.univoice.core_ui.base.BindingActivity
10 | import com.univoice.databinding.ActivitySplashBinding
11 | import com.univoice.feature.entry.EntryActivity
12 | import com.univoice.feature.login.LoginViewModel
13 | import dagger.hilt.android.AndroidEntryPoint
14 | import kotlinx.coroutines.flow.first
15 | import kotlinx.coroutines.runBlocking
16 |
17 | @AndroidEntryPoint
18 | class SplashActivity : BindingActivity(R.layout.activity_splash) {
19 | private val loginViewModel by viewModels()
20 |
21 | override fun initView() {
22 | installSplashScreen()
23 | initSplash()
24 | }
25 |
26 | private fun initSplash() {
27 | Handler().postDelayed({
28 | runBlocking {
29 | when {
30 | (loginViewModel.getUserAccessToken().toString().isNotBlank() &&
31 | loginViewModel.getCheckLogin().first()) -> {
32 | navigateTo()
33 | }
34 |
35 | else -> {
36 | navigateTo()
37 | }
38 | }
39 | finish()
40 | }
41 | }, 3000)
42 | }
43 |
44 | private inline fun navigateTo() {
45 | Intent(this@SplashActivity, T::class.java).apply {
46 | addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK)
47 | startActivity(this)
48 | }
49 | }
50 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/feature/signup/SignupBottomSheetFragmentViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.feature.signup
2 |
3 | import androidx.lifecycle.ViewModel
4 | import androidx.lifecycle.viewModelScope
5 | import com.univoice.core_ui.view.UiState
6 | import com.univoice.domain.repository.SignUpRepository
7 | import dagger.hilt.android.lifecycle.HiltViewModel
8 | import kotlinx.coroutines.flow.MutableSharedFlow
9 | import kotlinx.coroutines.flow.MutableStateFlow
10 | import kotlinx.coroutines.flow.SharedFlow
11 | import kotlinx.coroutines.flow.StateFlow
12 | import kotlinx.coroutines.flow.asSharedFlow
13 | import kotlinx.coroutines.launch
14 | import java.io.File
15 | import javax.inject.Inject
16 |
17 | @HiltViewModel
18 | class SignupBottomSheetFragmentViewModel @Inject constructor(
19 | private val signUpRepository: SignUpRepository
20 | ) : ViewModel() {
21 |
22 | private val _postSignupState = MutableSharedFlow>()
23 | val postSignupState: SharedFlow> get() = _postSignupState.asSharedFlow()
24 |
25 | fun postSignUp(
26 | admissionNumber: String,
27 | name: String,
28 | studentNumber: String,
29 | email: String,
30 | password: String,
31 | universityName: String,
32 | departmentName: String,
33 | studentCardImage: File
34 | ) = viewModelScope.launch {
35 | _postSignupState.emit(UiState.Loading)
36 | signUpRepository.postSignUp(
37 | admissionNumber,
38 | name,
39 | studentNumber,
40 | email,
41 | password,
42 | universityName,
43 | departmentName,
44 | studentCardImage
45 | ).onSuccess { _postSignupState.emit(UiState.Success(it)) }
46 | .onFailure { _postSignupState.emit(UiState.Failure(it.message.toString())) }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/data_remote/api/NoticeDetailApiService.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.data_remote.api
2 |
3 | import com.univoice.data.dto.BaseResponse
4 | import com.univoice.data.dto.response.ResponseNoticeDetailDto
5 | import com.univoice.data_remote.api.ApiKeyStorage.API
6 | import com.univoice.data_remote.api.ApiKeyStorage.CANCEL
7 | import com.univoice.data_remote.api.ApiKeyStorage.LIKE
8 | import com.univoice.data_remote.api.ApiKeyStorage.NOTICE
9 | import com.univoice.data_remote.api.ApiKeyStorage.NOTICE_ID
10 | import com.univoice.data_remote.api.ApiKeyStorage.SAVE
11 | import com.univoice.data_remote.api.ApiKeyStorage.V1
12 | import com.univoice.data_remote.api.ApiKeyStorage.VIEW_COUNT
13 | import retrofit2.http.GET
14 | import retrofit2.http.POST
15 | import retrofit2.http.Path
16 |
17 | interface NoticeDetailApiService {
18 | @GET("/$API/$V1/$NOTICE/{$NOTICE_ID}")
19 | suspend fun getNoticeDetail(
20 | @Path(NOTICE_ID) noticeId: Int
21 | ): BaseResponse
22 |
23 | @POST("/$API/$V1/$NOTICE/$LIKE/{$NOTICE_ID}")
24 | suspend fun postNoticeLike(
25 | @Path(NOTICE_ID) noticeId: Int
26 | ): BaseResponse
27 |
28 | @POST("/$API/$V1/$NOTICE/$LIKE/$CANCEL/{$NOTICE_ID}")
29 | suspend fun postNoticeCancelLike(
30 | @Path(NOTICE_ID) noticeId: Int
31 | ): BaseResponse
32 |
33 | @POST("$API/$V1/$NOTICE/$VIEW_COUNT/{$NOTICE_ID}")
34 | suspend fun postNoticeDetailViewCount(
35 | @Path(NOTICE_ID) noticeId: Int
36 | ): BaseResponse
37 |
38 | @POST("$API/$V1/$NOTICE/$SAVE/{$NOTICE_ID}")
39 | suspend fun postNoticeDetailSave(
40 | @Path(NOTICE_ID) noticeId: Int
41 | ): BaseResponse
42 |
43 | @POST("$API/$V1/$NOTICE/$SAVE/$CANCEL/{$NOTICE_ID}")
44 | suspend fun postNoticeDetailCancel(
45 | @Path(NOTICE_ID) noticeId: Int
46 | ): BaseResponse
47 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/univoice/feature/login/LoginViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.univoice.feature.login
2 |
3 | import androidx.lifecycle.ViewModel
4 | import androidx.lifecycle.viewModelScope
5 | import com.univoice.core_ui.view.UiState
6 | import com.univoice.domain.repository.LoginRepository
7 | import com.univoice.domain.repository.UserInfoRepository
8 | import dagger.hilt.android.lifecycle.HiltViewModel
9 | import kotlinx.coroutines.flow.MutableStateFlow
10 | import kotlinx.coroutines.flow.StateFlow
11 | import kotlinx.coroutines.launch
12 | import javax.inject.Inject
13 |
14 | @HiltViewModel
15 | class LoginViewModel @Inject constructor(
16 | private val loginRepository: LoginRepository,
17 | private val userInfoRepository: UserInfoRepository
18 | ) : ViewModel() {
19 | private val _postLoginState = MutableStateFlow>(UiState.Empty)
20 | val postLoginState: StateFlow> = _postLoginState
21 |
22 | fun postLogin(email: String, password: String) = viewModelScope.launch {
23 | _postLoginState.emit(UiState.Loading)
24 | loginRepository.postLogin(email, password).fold(
25 | {
26 | if (it != null) _postLoginState.emit(UiState.Success(it)) else _postLoginState.emit(
27 | UiState.Failure("400")
28 | )
29 | },
30 | { _postLoginState.emit(UiState.Failure(it.message.toString())) }
31 | )
32 | }
33 |
34 | fun getUserAccessToken() = userInfoRepository.getUserAccessToken()
35 |
36 | fun saveUserAccessToken(accessToken: String) {
37 | viewModelScope.launch {
38 | userInfoRepository.saveUserAccessToken(accessToken)
39 | }
40 | }
41 |
42 | fun getCheckLogin() = userInfoRepository.getCheckLogin()
43 |
44 | fun saveCheckLogin(checkLogin: Boolean) {
45 | viewModelScope.launch {
46 | userInfoRepository.saveCheckLogin(checkLogin)
47 | }
48 | }
49 | }
--------------------------------------------------------------------------------