├── app
├── .gitignore
├── src
│ ├── main
│ │ ├── ic_logo-playstore.png
│ │ ├── ic_main-playstore.png
│ │ ├── ic_launcher-playstore.png
│ │ ├── res
│ │ │ ├── font
│ │ │ │ ├── pretendard_bold.otf
│ │ │ │ ├── pretendard_medium.otf
│ │ │ │ ├── pretendard_regular.otf
│ │ │ │ ├── pretendard_semibold.otf
│ │ │ │ └── pretendard.xml
│ │ │ ├── mipmap-hdpi
│ │ │ │ ├── ic_logo.webp
│ │ │ │ └── ic_logo_round.webp
│ │ │ ├── mipmap-mdpi
│ │ │ │ ├── ic_logo.webp
│ │ │ │ └── ic_logo_round.webp
│ │ │ ├── mipmap-xhdpi
│ │ │ │ ├── ic_logo.webp
│ │ │ │ └── ic_logo_round.webp
│ │ │ ├── mipmap-xxhdpi
│ │ │ │ ├── ic_logo.webp
│ │ │ │ └── ic_logo_round.webp
│ │ │ ├── mipmap-xxxhdpi
│ │ │ │ ├── ic_logo.webp
│ │ │ │ └── ic_logo_round.webp
│ │ │ ├── drawable
│ │ │ │ ├── img_cafeteria_ramen.png
│ │ │ │ ├── img_cafeteria_korean.png
│ │ │ │ ├── img_cafeteria_cheese_ramen.png
│ │ │ │ ├── img_cafeteria_pork_cutlet.png
│ │ │ │ ├── img_cafeteria_seafood_ramen.png
│ │ │ │ ├── img_cafeteria_spicy_mayo_rice.png
│ │ │ │ ├── img_cafeteria_chicken_mayo_rice.png
│ │ │ │ ├── img_cafeteria_cheese_pork_cutlet.png
│ │ │ │ ├── ic_circle.xml
│ │ │ │ ├── img_cafeteria_spam_kimchi_fried_rice.png
│ │ │ │ ├── img_cafeteria_sweet_potato_cheese_pork_cutlet.png
│ │ │ │ ├── bg_blue100_radius_6dp.xml
│ │ │ │ ├── bg_gray100_rounded_corner.xml
│ │ │ │ ├── btn_gray100_radius_10dp.xml
│ │ │ │ ├── btn_gray300_radius_10dp.xml
│ │ │ │ ├── bg_stroke_blue300_radius_2dp.xml
│ │ │ │ ├── bg_stroke_gray300_radius_2dp.xml
│ │ │ │ ├── ic_done.xml
│ │ │ │ ├── ic_close_black.xml
│ │ │ │ ├── ic_popup.xml
│ │ │ │ ├── ic_alarm_fill.xml
│ │ │ │ ├── btn_gray_to_blue_10dp_enabled.xml
│ │ │ │ ├── ic_arrow_right.xml
│ │ │ │ ├── ic_refresh.xml
│ │ │ │ ├── btn_main_stroke_main_radius_8dp.xml
│ │ │ │ ├── ic_menu_home.xml
│ │ │ │ ├── ic_back.xml
│ │ │ │ ├── ic_arrow_left.xml
│ │ │ │ ├── ic_timer.xml
│ │ │ │ ├── ic_location.xml
│ │ │ │ ├── ic_search.xml
│ │ │ │ ├── ic_search_empty.xml
│ │ │ │ ├── ic_search_button.xml
│ │ │ │ ├── ic_alarm.xml
│ │ │ │ ├── ic_close.xml
│ │ │ │ ├── ic_menu_cafeteria.xml
│ │ │ │ ├── ic_setting_right.xml
│ │ │ │ ├── ic_logo_foreground.xml
│ │ │ │ ├── ic_search_clear.xml
│ │ │ │ ├── ic_menu_setting.xml
│ │ │ │ ├── ic_menu_calendar.xml
│ │ │ │ ├── ic_launcher_foreground.xml
│ │ │ │ └── ic_logo_text.xml
│ │ │ ├── values
│ │ │ │ ├── ic_logo_background.xml
│ │ │ │ ├── ic_launcher_background.xml
│ │ │ │ ├── dimens.xml
│ │ │ │ ├── arrays.xml
│ │ │ │ ├── colors.xml
│ │ │ │ ├── themes.xml
│ │ │ │ └── styles.xml
│ │ │ ├── drawable-v24
│ │ │ │ └── bg_main_navi.xml
│ │ │ ├── mipmap-anydpi-v26
│ │ │ │ ├── ic_logo.xml
│ │ │ │ └── ic_logo_round.xml
│ │ │ ├── color
│ │ │ │ ├── bg_chip_select.xml
│ │ │ │ ├── bg_chip_text_select.xml
│ │ │ │ └── bg_chip_stroke_select.xml
│ │ │ ├── font-v26
│ │ │ │ └── pretendard.xml
│ │ │ ├── values-v31
│ │ │ │ └── themes.xml
│ │ │ ├── layout
│ │ │ │ ├── item_cafeteria_korean.xml
│ │ │ │ ├── standard_no_data.xml
│ │ │ │ ├── dialog_loading.xml
│ │ │ │ ├── activity_splash.xml
│ │ │ │ ├── item_image.xml
│ │ │ │ ├── item_depart.xml
│ │ │ │ ├── item_onboarding_depart.xml
│ │ │ │ ├── activity_web.xml
│ │ │ │ ├── activity_license.xml
│ │ │ │ ├── standard_error.xml
│ │ │ │ ├── activity_main.xml
│ │ │ │ ├── item_schedule.xml
│ │ │ │ ├── item_license.xml
│ │ │ │ ├── activity_alarm.xml
│ │ │ │ ├── activity_depart.xml
│ │ │ │ ├── item_cafeteria_another.xml
│ │ │ │ ├── item_notice.xml
│ │ │ │ ├── item_calendar_day.xml
│ │ │ │ ├── dialog_permission.xml
│ │ │ │ ├── standard_toolbar.xml
│ │ │ │ ├── fragment_schedule.xml
│ │ │ │ └── activity_detail.xml
│ │ │ ├── menu
│ │ │ │ └── menu_main.xml
│ │ │ └── values-night
│ │ │ │ └── themes.xml
│ │ ├── java
│ │ │ └── com
│ │ │ │ └── dongyang
│ │ │ │ └── android
│ │ │ │ └── youdongknowme
│ │ │ │ ├── ui
│ │ │ │ ├── view
│ │ │ │ │ ├── notice
│ │ │ │ │ │ └── NoticeTabType.kt
│ │ │ │ │ ├── depart
│ │ │ │ │ │ ├── DepartClickListener.kt
│ │ │ │ │ │ ├── DepartViewModel.kt
│ │ │ │ │ │ └── DepartActivity.kt
│ │ │ │ │ ├── web
│ │ │ │ │ │ ├── WebViewModel.kt
│ │ │ │ │ │ └── WebActivity.kt
│ │ │ │ │ ├── license
│ │ │ │ │ │ ├── LicenseViewModel.kt
│ │ │ │ │ │ ├── LicenseClickListener.kt
│ │ │ │ │ │ └── LicenseActivity.kt
│ │ │ │ │ ├── alarm
│ │ │ │ │ │ ├── AlarmClickListener.kt
│ │ │ │ │ │ ├── AlarmViewModel.kt
│ │ │ │ │ │ └── AlarmActivity.kt
│ │ │ │ │ ├── util
│ │ │ │ │ │ ├── ResourceProvider.kt
│ │ │ │ │ │ ├── KeyboardUtil.kt
│ │ │ │ │ │ ├── Event.kt
│ │ │ │ │ │ └── ToastUtil.kt
│ │ │ │ │ ├── LoadingDialog.kt
│ │ │ │ │ ├── cafeteria
│ │ │ │ │ │ ├── CalendarInterface.kt
│ │ │ │ │ │ └── CafeteriaContainer.kt
│ │ │ │ │ ├── splash
│ │ │ │ │ │ └── SplashViewModel.kt
│ │ │ │ │ ├── detail
│ │ │ │ │ │ └── DetailViewModel.kt
│ │ │ │ │ ├── setting
│ │ │ │ │ │ ├── PermissionDialog.kt
│ │ │ │ │ │ └── OnboardingPermissionActivity.kt
│ │ │ │ │ ├── keyword
│ │ │ │ │ │ └── KeywordViewModel.kt
│ │ │ │ │ ├── schedule
│ │ │ │ │ │ └── ScheduleViewModel.kt
│ │ │ │ │ └── main
│ │ │ │ │ │ └── MainViewModel.kt
│ │ │ │ ├── adapter
│ │ │ │ │ ├── BindingAdapter.kt
│ │ │ │ │ ├── NoticeAdapter.kt
│ │ │ │ │ ├── CafeteriaAnotherAdapter.kt
│ │ │ │ │ ├── CafeteriaKoreanAdapter.kt
│ │ │ │ │ ├── LicenseAdapter.kt
│ │ │ │ │ ├── ScheduleAdapter.kt
│ │ │ │ │ └── OnboardingDepartAdapter.kt
│ │ │ │ └── viewholder
│ │ │ │ │ ├── NoticeViewHodler.kt
│ │ │ │ │ └── CafeteriaAnotherViewHolder.kt
│ │ │ │ ├── data
│ │ │ │ ├── model
│ │ │ │ │ └── AnotherMenuItem.kt
│ │ │ │ ├── repository
│ │ │ │ │ ├── SplashRepository.kt
│ │ │ │ │ ├── DepartRepository.kt
│ │ │ │ │ ├── KeywordRepository.kt
│ │ │ │ │ ├── AlarmRepository.kt
│ │ │ │ │ ├── ScheduleRepository.kt
│ │ │ │ │ ├── MainRepository.kt
│ │ │ │ │ ├── NoticeRepository.kt
│ │ │ │ │ └── CafeteriaRepository.kt
│ │ │ │ ├── remote
│ │ │ │ │ ├── entity
│ │ │ │ │ │ ├── Cafeteria.kt
│ │ │ │ │ │ ├── Setting.kt
│ │ │ │ │ │ ├── Token.kt
│ │ │ │ │ │ ├── Notice.kt
│ │ │ │ │ │ └── Schedule.kt
│ │ │ │ │ └── service
│ │ │ │ │ │ ├── CafeteriaService.kt
│ │ │ │ │ │ ├── ScheduleService.kt
│ │ │ │ │ │ ├── TokenService.kt
│ │ │ │ │ │ ├── SettingService.kt
│ │ │ │ │ │ └── NoticeService.kt
│ │ │ │ └── local
│ │ │ │ │ ├── entity
│ │ │ │ │ ├── KeywordEntity.kt
│ │ │ │ │ ├── AlarmEntity.kt
│ │ │ │ │ └── OpenSourceEntity.kt
│ │ │ │ │ ├── UserDatabase.kt
│ │ │ │ │ ├── dao
│ │ │ │ │ ├── AlarmDao.kt
│ │ │ │ │ └── KeywordDao.kt
│ │ │ │ │ └── SharedPreference.kt
│ │ │ │ └── standard
│ │ │ │ ├── network
│ │ │ │ ├── NetworkResult.kt
│ │ │ │ ├── NetworkError.kt
│ │ │ │ ├── ErrorResponseHandler.kt
│ │ │ │ └── RetrofitObject.kt
│ │ │ │ ├── util
│ │ │ │ ├── Weekdays.kt
│ │ │ │ ├── UtilExt.kt
│ │ │ │ ├── Constants.kt
│ │ │ │ └── Mapping.kt
│ │ │ │ ├── base
│ │ │ │ ├── BaseViewModel.kt
│ │ │ │ ├── BaseFragment.kt
│ │ │ │ └── BaseActivity.kt
│ │ │ │ └── MyApplication.kt
│ │ └── AndroidManifest.xml
│ ├── test
│ │ └── java
│ │ │ └── com
│ │ │ └── dongyang
│ │ │ └── android
│ │ │ └── youdongknowme
│ │ │ └── ExampleUnitTest.kt
│ └── androidTest
│ │ └── java
│ │ └── com
│ │ └── dongyang
│ │ └── android
│ │ └── youdongknowme
│ │ └── ExampleInstrumentedTest.kt
├── proguard-rules.pro
└── google-services.json
├── .idea
├── .name
└── .gitignore
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── .github
├── ISSUE_TEMPLATE.md
├── PULL_REQUEST_TEMPLATE.md
└── workflows
│ └── android.yml
├── settings.gradle
├── gradle.properties
├── README.md
└── gradlew.bat
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/.idea/.name:
--------------------------------------------------------------------------------
1 | YouDongKnowMe
--------------------------------------------------------------------------------
/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 |
--------------------------------------------------------------------------------
/app/src/main/ic_logo-playstore.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TeamDMU/DMU-Android/HEAD/app/src/main/ic_logo-playstore.png
--------------------------------------------------------------------------------
/app/src/main/ic_main-playstore.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TeamDMU/DMU-Android/HEAD/app/src/main/ic_main-playstore.png
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TeamDMU/DMU-Android/HEAD/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | ## 🤔 목적
2 |
3 | > 이슈 등록 목적을 상세하게 적어주세요.
4 |
5 | ## 📝 TO-DO
6 |
7 | - [ ] 구현할 기능을 상세하게 적어주세요.
8 |
--------------------------------------------------------------------------------
/app/src/main/ic_launcher-playstore.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TeamDMU/DMU-Android/HEAD/app/src/main/ic_launcher-playstore.png
--------------------------------------------------------------------------------
/app/src/main/res/font/pretendard_bold.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TeamDMU/DMU-Android/HEAD/app/src/main/res/font/pretendard_bold.otf
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_logo.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TeamDMU/DMU-Android/HEAD/app/src/main/res/mipmap-hdpi/ic_logo.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_logo.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TeamDMU/DMU-Android/HEAD/app/src/main/res/mipmap-mdpi/ic_logo.webp
--------------------------------------------------------------------------------
/app/src/main/res/font/pretendard_medium.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TeamDMU/DMU-Android/HEAD/app/src/main/res/font/pretendard_medium.otf
--------------------------------------------------------------------------------
/app/src/main/res/font/pretendard_regular.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TeamDMU/DMU-Android/HEAD/app/src/main/res/font/pretendard_regular.otf
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_logo.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TeamDMU/DMU-Android/HEAD/app/src/main/res/mipmap-xhdpi/ic_logo.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_logo.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TeamDMU/DMU-Android/HEAD/app/src/main/res/mipmap-xxhdpi/ic_logo.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_logo.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TeamDMU/DMU-Android/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_logo.webp
--------------------------------------------------------------------------------
/app/src/main/res/font/pretendard_semibold.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TeamDMU/DMU-Android/HEAD/app/src/main/res/font/pretendard_semibold.otf
--------------------------------------------------------------------------------
/app/src/main/res/drawable/img_cafeteria_ramen.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TeamDMU/DMU-Android/HEAD/app/src/main/res/drawable/img_cafeteria_ramen.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_logo_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TeamDMU/DMU-Android/HEAD/app/src/main/res/mipmap-hdpi/ic_logo_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_logo_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TeamDMU/DMU-Android/HEAD/app/src/main/res/mipmap-mdpi/ic_logo_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_logo_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TeamDMU/DMU-Android/HEAD/app/src/main/res/mipmap-xhdpi/ic_logo_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_logo_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TeamDMU/DMU-Android/HEAD/app/src/main/res/mipmap-xxhdpi/ic_logo_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/drawable/img_cafeteria_korean.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TeamDMU/DMU-Android/HEAD/app/src/main/res/drawable/img_cafeteria_korean.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_logo_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TeamDMU/DMU-Android/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_logo_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/drawable/img_cafeteria_cheese_ramen.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TeamDMU/DMU-Android/HEAD/app/src/main/res/drawable/img_cafeteria_cheese_ramen.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/img_cafeteria_pork_cutlet.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TeamDMU/DMU-Android/HEAD/app/src/main/res/drawable/img_cafeteria_pork_cutlet.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/img_cafeteria_seafood_ramen.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TeamDMU/DMU-Android/HEAD/app/src/main/res/drawable/img_cafeteria_seafood_ramen.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/img_cafeteria_spicy_mayo_rice.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TeamDMU/DMU-Android/HEAD/app/src/main/res/drawable/img_cafeteria_spicy_mayo_rice.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/img_cafeteria_chicken_mayo_rice.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TeamDMU/DMU-Android/HEAD/app/src/main/res/drawable/img_cafeteria_chicken_mayo_rice.png
--------------------------------------------------------------------------------
/app/src/main/res/values/ic_logo_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FFFFFF
4 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/img_cafeteria_cheese_pork_cutlet.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TeamDMU/DMU-Android/HEAD/app/src/main/res/drawable/img_cafeteria_cheese_pork_cutlet.png
--------------------------------------------------------------------------------
/app/src/main/res/values/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FFFFFF
4 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_circle.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/img_cafeteria_spam_kimchi_fried_rice.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TeamDMU/DMU-Android/HEAD/app/src/main/res/drawable/img_cafeteria_spam_kimchi_fried_rice.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/img_cafeteria_sweet_potato_cheese_pork_cutlet.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TeamDMU/DMU-Android/HEAD/app/src/main/res/drawable/img_cafeteria_sweet_potato_cheese_pork_cutlet.png
--------------------------------------------------------------------------------
/app/src/main/java/com/dongyang/android/youdongknowme/ui/view/notice/NoticeTabType.kt:
--------------------------------------------------------------------------------
1 | package com.dongyang.android.youdongknowme.ui.view.notice
2 |
3 | enum class NoticeTabType {
4 | SCHOOL,
5 | FACULTY
6 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/dongyang/android/youdongknowme/ui/view/depart/DepartClickListener.kt:
--------------------------------------------------------------------------------
1 | package com.dongyang.android.youdongknowme.ui.view.depart
2 |
3 | interface DepartClickListener {
4 | fun containerClick(position: Int)
5 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/dongyang/android/youdongknowme/data/model/AnotherMenuItem.kt:
--------------------------------------------------------------------------------
1 | package com.dongyang.android.youdongknowme.data.model
2 |
3 | data class AnotherMenu(
4 | val menuNameKr: String,
5 | val name: String,
6 | val price: String
7 | )
8 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/bg_blue100_radius_6dp.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/java/com/dongyang/android/youdongknowme/ui/view/web/WebViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.dongyang.android.youdongknowme.ui.view.web
2 |
3 | import com.dongyang.android.youdongknowme.standard.base.BaseViewModel
4 |
5 | class WebViewModel : BaseViewModel() {
6 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable/bg_gray100_rounded_corner.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Sun Jul 27 10:33:58 KST 2025
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip
5 | zipStoreBase=GRADLE_USER_HOME
6 | zipStorePath=wrapper/dists
7 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/btn_gray100_radius_10dp.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/btn_gray300_radius_10dp.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | ## 📮 관련 이슈
2 | - resolved #{issue_number}
3 |
4 | ## ✍️ 구현 내용
5 | - 구현 내용을 상세하게 적어주세요.
6 |
7 | ## 📷 구현 영상
8 | - 구현 영상을 업로드 해주세요.
9 |
10 | ## ✔️ 확인 사항
11 | - [ ] 컨벤션에 맞는 PR 타이틀
12 | - [ ] 관련 이슈 연결
13 | - [ ] PR 관련 정보 연결 (작업자, 라벨, 마일스톤 등)
14 | - [ ] Github Action 통과
15 |
--------------------------------------------------------------------------------
/app/src/main/java/com/dongyang/android/youdongknowme/ui/view/license/LicenseViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.dongyang.android.youdongknowme.ui.view.license
2 |
3 | import com.dongyang.android.youdongknowme.standard.base.BaseViewModel
4 |
5 | class LicenseViewModel : BaseViewModel() {
6 | // NOT IMPLEMENTS
7 | }
8 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/bg_stroke_blue300_radius_2dp.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/bg_stroke_gray300_radius_2dp.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
--------------------------------------------------------------------------------
/app/src/main/java/com/dongyang/android/youdongknowme/ui/view/alarm/AlarmClickListener.kt:
--------------------------------------------------------------------------------
1 | package com.dongyang.android.youdongknowme.ui.view.alarm
2 |
3 | import com.dongyang.android.youdongknowme.data.local.entity.AlarmEntity
4 |
5 | interface AlarmClickListener {
6 | fun itemClick(alarmEntity: AlarmEntity)
7 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/bg_main_navi.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_logo.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_logo_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/color/bg_chip_select.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/java/com/dongyang/android/youdongknowme/standard/network/NetworkResult.kt:
--------------------------------------------------------------------------------
1 | package com.dongyang.android.youdongknowme.standard.network
2 |
3 | sealed class NetworkResult() {
4 | class Success(val data: T) : NetworkResult()
5 | class Error(val errorType: NetworkError) : NetworkResult()
6 | }
7 |
--------------------------------------------------------------------------------
/app/src/main/java/com/dongyang/android/youdongknowme/data/repository/SplashRepository.kt:
--------------------------------------------------------------------------------
1 | package com.dongyang.android.youdongknowme.data.repository
2 |
3 | import com.dongyang.android.youdongknowme.data.local.SharedPreference
4 |
5 | class SplashRepository {
6 | fun getIsFirstLaunch(): Boolean = SharedPreference.getIsFirstLaunch()
7 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/dongyang/android/youdongknowme/ui/view/license/LicenseClickListener.kt:
--------------------------------------------------------------------------------
1 | package com.dongyang.android.youdongknowme.ui.view.license
2 |
3 | import com.dongyang.android.youdongknowme.data.local.entity.OpenSourceEntity
4 |
5 | interface LicenseClickListener {
6 | fun itemClick(openSourceEntity: OpenSourceEntity)
7 | }
--------------------------------------------------------------------------------
/app/src/main/res/color/bg_chip_text_select.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/color/bg_chip_stroke_select.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
7 |
--------------------------------------------------------------------------------
/app/src/main/java/com/dongyang/android/youdongknowme/data/remote/entity/Cafeteria.kt:
--------------------------------------------------------------------------------
1 | package com.dongyang.android.youdongknowme.data.remote.entity
2 |
3 | import com.google.gson.annotations.SerializedName
4 |
5 | data class Cafeteria(
6 | @SerializedName("date")
7 | val date: String,
8 | @SerializedName("menus")
9 | val menus: List
10 | )
11 |
--------------------------------------------------------------------------------
/app/src/main/java/com/dongyang/android/youdongknowme/data/remote/service/CafeteriaService.kt:
--------------------------------------------------------------------------------
1 | package com.dongyang.android.youdongknowme.data.remote.service
2 |
3 | import com.dongyang.android.youdongknowme.data.remote.entity.Cafeteria
4 | import retrofit2.http.GET
5 |
6 | interface CafeteriaService {
7 | @GET("api/v1/dmu/cafeteria")
8 | suspend fun getMenuList(): List
9 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/dongyang/android/youdongknowme/standard/network/NetworkError.kt:
--------------------------------------------------------------------------------
1 | package com.dongyang.android.youdongknowme.standard.network
2 |
3 | sealed class NetworkError {
4 | object Unknown : NetworkError()
5 | object Timeout : NetworkError()
6 | object InternalServer : NetworkError()
7 | class BadRequest(val code: Int, val message: String) : NetworkError()
8 | }
9 |
--------------------------------------------------------------------------------
/app/src/main/res/font/pretendard.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
10 |
--------------------------------------------------------------------------------
/app/src/main/java/com/dongyang/android/youdongknowme/data/remote/service/ScheduleService.kt:
--------------------------------------------------------------------------------
1 | package com.dongyang.android.youdongknowme.data.remote.service
2 |
3 | import com.dongyang.android.youdongknowme.data.remote.entity.Schedule
4 | import retrofit2.http.GET
5 |
6 | interface ScheduleService {
7 | @GET("api/v1/dmu/schedule")
8 | suspend fun getScheduleList(): ArrayList
9 | }
--------------------------------------------------------------------------------
/app/src/main/res/font-v26/pretendard.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
10 |
--------------------------------------------------------------------------------
/app/src/main/java/com/dongyang/android/youdongknowme/data/remote/entity/Setting.kt:
--------------------------------------------------------------------------------
1 | package com.dongyang.android.youdongknowme.data.remote.entity
2 |
3 | data class UpdateDepartment(
4 | val token: String,
5 | val department: String,
6 | )
7 |
8 | data class RemoveToken(
9 | val token: String,
10 | )
11 |
12 | data class UpdateTopic(
13 | val token: String,
14 | val topics: List,
15 | )
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_done.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/java/com/dongyang/android/youdongknowme/ui/adapter/BindingAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.dongyang.android.youdongknowme.ui.adapter
2 |
3 | import android.view.View
4 | import androidx.databinding.BindingAdapter
5 |
6 | @BindingAdapter("bind_is_loading", "bind_is_error")
7 | fun bindShowScreen(view: View, isLoading: Boolean, isError: Boolean) {
8 | view.visibility = if (isLoading || isError) View.GONE else View.VISIBLE
9 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/dongyang/android/youdongknowme/ui/view/util/ResourceProvider.kt:
--------------------------------------------------------------------------------
1 | package com.dongyang.android.youdongknowme.ui.view.util
2 |
3 | import android.content.Context
4 | import androidx.annotation.StringRes
5 |
6 | class ResourceProvider (
7 | private val context: Context
8 | ) {
9 | fun getString(@StringRes stringResId: Int): String {
10 | return context.getString(stringResId)
11 | }
12 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/dongyang/android/youdongknowme/data/remote/entity/Token.kt:
--------------------------------------------------------------------------------
1 | package com.dongyang.android.youdongknowme.data.remote.entity
2 |
3 | import com.google.gson.annotations.SerializedName
4 |
5 | data class Token (
6 | @SerializedName("token")
7 | val token: String,
8 | @SerializedName("department")
9 | val department: String,
10 | @SerializedName("topics")
11 | val topics: List,
12 | )
--------------------------------------------------------------------------------
/app/src/main/java/com/dongyang/android/youdongknowme/data/remote/service/TokenService.kt:
--------------------------------------------------------------------------------
1 | package com.dongyang.android.youdongknowme.data.remote.service
2 |
3 | import com.dongyang.android.youdongknowme.data.remote.entity.Token
4 | import retrofit2.http.Body
5 | import retrofit2.http.POST
6 |
7 | interface TokenService {
8 | @POST("token/v1/dmu/initToken")
9 | suspend fun setInitToken(
10 | @Body data: Token,
11 | )
12 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_close_black.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/values-v31/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/java/com/dongyang/android/youdongknowme/data/remote/entity/Notice.kt:
--------------------------------------------------------------------------------
1 | package com.dongyang.android.youdongknowme.data.remote.entity
2 |
3 | import com.google.gson.annotations.SerializedName
4 |
5 | data class Notice(
6 | @SerializedName("title")
7 | val title: String,
8 | @SerializedName("author")
9 | val author: String,
10 | @SerializedName("date")
11 | val date: String,
12 | @SerializedName("url")
13 | val url: String,
14 | )
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | pluginManagement {
2 | repositories {
3 | gradlePluginPortal()
4 | google()
5 | mavenCentral()
6 | }
7 | }
8 | dependencyResolutionManagement {
9 | repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
10 | repositories {
11 | google()
12 | mavenCentral()
13 | maven { url 'https://jitpack.io'} // calendar
14 | }
15 | }
16 | rootProject.name = "YouDongKnowMe"
17 | include ':app'
18 |
--------------------------------------------------------------------------------
/app/src/test/java/com/dongyang/android/youdongknowme/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package com.dongyang.android.youdongknowme
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/dongyang/android/youdongknowme/data/local/entity/KeywordEntity.kt:
--------------------------------------------------------------------------------
1 | package com.dongyang.android.youdongknowme.data.local.entity
2 |
3 | import androidx.room.ColumnInfo
4 | import androidx.room.Entity
5 | import androidx.room.PrimaryKey
6 |
7 | @Entity(tableName = "keyword")
8 | data class KeywordEntity(
9 | @PrimaryKey @ColumnInfo(name = "name") var name: String = "",
10 | @ColumnInfo(name = "englishName") var englishName: String = "",
11 | @ColumnInfo(name = "isSubscribe") var isSubscribe: Boolean = false,
12 | )
--------------------------------------------------------------------------------
/app/src/main/java/com/dongyang/android/youdongknowme/ui/view/LoadingDialog.kt:
--------------------------------------------------------------------------------
1 | package com.dongyang.android.youdongknowme.ui.view
2 |
3 | import android.app.Dialog
4 | import android.content.Context
5 | import android.graphics.Color
6 | import android.graphics.drawable.ColorDrawable
7 | import com.dongyang.android.youdongknowme.R
8 |
9 | class LoadingDialog(context: Context) : Dialog(context) {
10 |
11 | init {
12 | setCanceledOnTouchOutside(false)
13 | setCancelable(false)
14 | window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
15 | setContentView(R.layout.dialog_loading)
16 | }
17 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/dongyang/android/youdongknowme/data/repository/DepartRepository.kt:
--------------------------------------------------------------------------------
1 | package com.dongyang.android.youdongknowme.data.repository
2 |
3 | import com.dongyang.android.youdongknowme.data.local.SharedPreference
4 | import com.dongyang.android.youdongknowme.standard.util.Department
5 |
6 | class DepartRepository {
7 | fun setDepartment(departName: String) {
8 | val department = Department.getDepartment(departName)
9 | SharedPreference.setDepartment(department.name)
10 | SharedPreference.setCode(department.code)
11 | }
12 |
13 | fun getUserDepartment(): String {
14 | return SharedPreference.getDepartment()
15 | }
16 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/dongyang/android/youdongknowme/ui/view/cafeteria/CalendarInterface.kt:
--------------------------------------------------------------------------------
1 | package com.dongyang.android.youdongknowme.ui.view.cafeteria
2 |
3 | import com.kizitonwose.calendarview.CalendarView
4 | import java.time.LocalDate
5 |
6 | interface CalendarInterface {
7 | fun notifyDateChanged(
8 | viewModel: CafeteriaViewModel,
9 | calendarView: CalendarView,
10 | oldDate: LocalDate?,
11 | selectedDate: LocalDate,
12 | ) {
13 | viewModel.updateMenuList(selectedDate)
14 | viewModel.updateDaysMenu(selectedDate)
15 | calendarView.notifyDateChanged(selectedDate)
16 | oldDate?.let { calendarView.notifyDateChanged(it) }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 36dp
4 |
5 | 280dp
6 |
7 | 10dp
8 | 11dp
9 | 12dp
10 | 14dp
11 | 16dp
12 | 18dp
13 | 20dp
14 | 24dp
15 | 32dp
16 |
--------------------------------------------------------------------------------
/app/src/main/java/com/dongyang/android/youdongknowme/data/remote/entity/Schedule.kt:
--------------------------------------------------------------------------------
1 | package com.dongyang.android.youdongknowme.data.remote.entity
2 |
3 | import com.google.gson.annotations.SerializedName
4 |
5 | data class Schedule(
6 | @SerializedName("year")
7 | val year: Int,
8 | @SerializedName("yearSchedule")
9 | val yearSchedules: List,
10 | )
11 |
12 | data class YearSchedule(
13 | @SerializedName("month")
14 | val month: Int,
15 | @SerializedName("scheduleEntries")
16 | val scheduleEntries: List
17 | )
18 |
19 | data class ScheduleEntry(
20 | @SerializedName("content")
21 | val contents: String,
22 | @SerializedName("date")
23 | val dates: List
24 | )
--------------------------------------------------------------------------------
/app/src/main/java/com/dongyang/android/youdongknowme/ui/view/util/KeyboardUtil.kt:
--------------------------------------------------------------------------------
1 | package com.dongyang.android.youdongknowme.ui.view.util
2 |
3 | import android.content.Context
4 | import android.view.View
5 | import android.view.inputmethod.InputMethodManager
6 |
7 | fun Context.showKeyboard(view: View) {
8 | val inputMethodManager =
9 | getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
10 | inputMethodManager.showSoftInput(view, InputMethodManager.SHOW_IMPLICIT)
11 | }
12 |
13 | fun Context.hideKeyboard(view: View) {
14 | val inputMethodManager =
15 | getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
16 | inputMethodManager.hideSoftInputFromWindow(view.windowToken, 0)
17 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/dongyang/android/youdongknowme/data/local/UserDatabase.kt:
--------------------------------------------------------------------------------
1 | package com.dongyang.android.youdongknowme.data.local
2 |
3 |
4 | import androidx.room.Database
5 | import androidx.room.RoomDatabase
6 | import com.dongyang.android.youdongknowme.data.local.dao.AlarmDao
7 | import com.dongyang.android.youdongknowme.data.local.dao.KeywordDao
8 | import com.dongyang.android.youdongknowme.data.local.entity.AlarmEntity
9 | import com.dongyang.android.youdongknowme.data.local.entity.KeywordEntity
10 |
11 | @Database(entities = [KeywordEntity::class, AlarmEntity::class], version = 1, exportSchema = false)
12 | abstract class UserDatabase : RoomDatabase() {
13 | abstract fun keywordDao(): KeywordDao
14 | abstract fun alarmDao(): AlarmDao
15 | }
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_cafeteria_korean.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
14 |
15 |
16 |
17 |
20 |
21 |
--------------------------------------------------------------------------------
/app/src/main/java/com/dongyang/android/youdongknowme/data/repository/KeywordRepository.kt:
--------------------------------------------------------------------------------
1 | package com.dongyang.android.youdongknowme.data.repository
2 |
3 | import com.dongyang.android.youdongknowme.data.local.SharedPreference
4 | import com.dongyang.android.youdongknowme.data.local.dao.KeywordDao
5 | import com.dongyang.android.youdongknowme.data.local.entity.KeywordEntity
6 | import kotlinx.coroutines.flow.Flow
7 |
8 | class KeywordRepository(
9 | private val keywordDao: KeywordDao
10 | ) {
11 | fun getUserKeywords(): Flow> {
12 | return keywordDao.getAllKeyword()
13 | }
14 |
15 | suspend fun updateUserKeywords(isSubscribe: Boolean, name: String) {
16 | keywordDao.updateKeyword(isSubscribe, name)
17 | }
18 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/dongyang/android/youdongknowme/data/local/entity/AlarmEntity.kt:
--------------------------------------------------------------------------------
1 | package com.dongyang.android.youdongknowme.data.local.entity
2 |
3 | import androidx.room.ColumnInfo
4 | import androidx.room.Entity
5 | import androidx.room.PrimaryKey
6 |
7 | @Entity(tableName = "alarm")
8 | data class AlarmEntity(
9 | @PrimaryKey(autoGenerate = true) @ColumnInfo(name = "id")
10 | var id: Int?,
11 | @ColumnInfo(name = "title")
12 | var title: String = "",
13 | @ColumnInfo(name = "department")
14 | var department: String = "",
15 | @ColumnInfo(name = "keyword")
16 | var keyword: String = "",
17 | @ColumnInfo(name = "num")
18 | var num: Int,
19 | @ColumnInfo(name = "isVisited")
20 | var isVisited: Boolean = false,
21 | )
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_popup.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_alarm_fill.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/java/com/dongyang/android/youdongknowme/data/repository/AlarmRepository.kt:
--------------------------------------------------------------------------------
1 | package com.dongyang.android.youdongknowme.data.repository
2 |
3 | import com.dongyang.android.youdongknowme.data.local.dao.AlarmDao
4 | import com.dongyang.android.youdongknowme.data.local.entity.AlarmEntity
5 | import kotlinx.coroutines.flow.Flow
6 |
7 | class AlarmRepository(
8 | private val alarmDao: AlarmDao
9 | ) {
10 | fun getUserAlarms(): Flow> {
11 | return alarmDao.getAllAlarm()
12 | }
13 |
14 | suspend fun insertAlarm(alarmEntity: AlarmEntity) {
15 | alarmDao.insertAlarm(alarmEntity)
16 | }
17 |
18 | suspend fun updateIsVisitedAlarm(isVisited: Boolean, id: Int) {
19 | alarmDao.updateIsVisitedAlarm(isVisited, id)
20 | }
21 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable/btn_gray_to_blue_10dp_enabled.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | -
7 |
8 |
9 |
10 |
11 |
12 |
13 | -
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_arrow_right.xml:
--------------------------------------------------------------------------------
1 |
6 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/java/com/dongyang/android/youdongknowme/ui/view/splash/SplashViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.dongyang.android.youdongknowme.ui.view.splash
2 |
3 | import androidx.lifecycle.LiveData
4 | import androidx.lifecycle.MutableLiveData
5 | import com.dongyang.android.youdongknowme.data.repository.SplashRepository
6 | import com.dongyang.android.youdongknowme.standard.base.BaseViewModel
7 |
8 | class SplashViewModel(private val splashRepository: SplashRepository) : BaseViewModel() {
9 |
10 | private val _isFirstLaunch: MutableLiveData = MutableLiveData(false)
11 | val isFirstLaunch: LiveData get() = _isFirstLaunch
12 |
13 | fun checkFirstLaunch() {
14 | if (splashRepository.getIsFirstLaunch()) {
15 | _isFirstLaunch.value = true
16 | }
17 | }
18 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/dongyang/android/youdongknowme/data/local/dao/AlarmDao.kt:
--------------------------------------------------------------------------------
1 | package com.dongyang.android.youdongknowme.data.local.dao
2 |
3 | import androidx.room.*
4 | import com.dongyang.android.youdongknowme.data.local.entity.AlarmEntity
5 | import kotlinx.coroutines.flow.Flow
6 |
7 | @Dao
8 | interface AlarmDao {
9 | @Query("SELECT * FROM alarm ORDER BY id DESC")
10 | fun getAllAlarm(): Flow>
11 |
12 | @Insert(onConflict = OnConflictStrategy.REPLACE)
13 | suspend fun insertAlarm(alarm: AlarmEntity)
14 |
15 | @Query("SELECT count(*) FROM alarm WHERE isVisited = 0")
16 | fun getUnVisitedAlarmCount(): Flow
17 |
18 | @Query("UPDATE alarm SET isVisited = :isVisited WHERE id = :id")
19 | suspend fun updateIsVisitedAlarm(isVisited: Boolean, id: Int)
20 | }
--------------------------------------------------------------------------------
/app/src/main/res/layout/standard_no_data.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
12 |
13 |
20 |
--------------------------------------------------------------------------------
/.github/workflows/android.yml:
--------------------------------------------------------------------------------
1 | name: Android CI
2 |
3 | on:
4 | pull_request:
5 | branches: [ develop ]
6 |
7 | jobs:
8 | build:
9 |
10 | runs-on: ubuntu-latest
11 |
12 | steps:
13 | - uses: actions/checkout@v3
14 | - name: set up JDK 11
15 | uses: actions/setup-java@v3
16 | with:
17 | java-version: '11'
18 | distribution: 'temurin'
19 | cache: gradle
20 |
21 | - name: Grant execute permission for gradlew
22 | run: chmod +x gradlew
23 | - name: Access API key
24 | env:
25 | API_KEY: ${{ secrets.API_KEY }}
26 | run:
27 | echo API_KEY=\"$API_KEY\" > ./local.properties
28 | - name: Build with Gradle
29 | env:
30 | BASE_URL: ${{ secrets.BASE_URL }}
31 | run:
32 | echo API_KEY=\"$API_KEY\" > ./local.properties
33 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_refresh.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/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/res/menu/menu_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/dongyang/android/youdongknowme/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package com.dongyang.android.youdongknowme
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.dongyang.android.youdongknowme", appContext.packageName)
23 | }
24 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable/btn_main_stroke_main_radius_8dp.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | -
6 |
7 |
8 |
9 |
10 |
11 | -
12 |
13 |
14 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/app/src/main/java/com/dongyang/android/youdongknowme/ui/view/util/Event.kt:
--------------------------------------------------------------------------------
1 | package com.dongyang.android.youdongknowme.ui.view.util
2 |
3 | import androidx.lifecycle.Observer
4 |
5 | open class Event(private val content: T) {
6 |
7 | @Suppress("MemberVisibilityCanBePrivate")
8 | var hasBeenHandled = false
9 | private set
10 |
11 | fun getContentIfNotHandled(): T? {
12 | return if (hasBeenHandled) {
13 | null
14 | } else {
15 | hasBeenHandled = true
16 | content
17 | }
18 | }
19 |
20 | fun peekContent(): T = content
21 | }
22 |
23 | class EventObserver(private val onEventUnhandledContent: (T) -> Unit) : Observer> {
24 | override fun onChanged(value: Event) {
25 | value.getContentIfNotHandled()?.let {
26 | onEventUnhandledContent(it)
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/dialog_loading.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/app/src/main/res/values-night/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
16 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_menu_home.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/java/com/dongyang/android/youdongknowme/standard/util/Weekdays.kt:
--------------------------------------------------------------------------------
1 | package com.dongyang.android.youdongknowme.standard.util
2 |
3 | import java.time.DayOfWeek
4 |
5 | enum class Weekdays {
6 | MONDAY,
7 | TUESDAY,
8 | WEDNESDAY,
9 | THURSDAY,
10 | FRIDAY,
11 | SATURDAY,
12 | SUNDAY;
13 |
14 | companion object {
15 |
16 | fun from(dayOfWeek: DayOfWeek): Weekdays {
17 | return when (dayOfWeek) {
18 | DayOfWeek.MONDAY -> MONDAY
19 | DayOfWeek.TUESDAY -> TUESDAY
20 | DayOfWeek.WEDNESDAY -> WEDNESDAY
21 | DayOfWeek.THURSDAY -> THURSDAY
22 | DayOfWeek.FRIDAY -> FRIDAY
23 | DayOfWeek.SATURDAY -> SATURDAY
24 | DayOfWeek.SUNDAY -> SUNDAY
25 | else -> throw IllegalArgumentException("일주일 범위에 해당되지 않습니다.")
26 | }
27 | }
28 | }
29 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/dongyang/android/youdongknowme/ui/view/detail/DetailViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.dongyang.android.youdongknowme.ui.view.detail
2 |
3 | import androidx.lifecycle.LiveData
4 | import androidx.lifecycle.MutableLiveData
5 | import com.dongyang.android.youdongknowme.standard.base.BaseViewModel
6 | import com.dongyang.android.youdongknowme.ui.view.util.Event
7 |
8 | class DetailViewModel: BaseViewModel() {
9 |
10 | private val _errorState: MutableLiveData> = MutableLiveData()
11 | val errorState: LiveData> = _errorState
12 |
13 | private val _isError: MutableLiveData = MutableLiveData()
14 | val isError: LiveData = _isError
15 |
16 | private val _isLoading: MutableLiveData = MutableLiveData()
17 | val isLoading: LiveData get() = _isLoading
18 |
19 | companion object {
20 | private const val DEFAULT_VALUE = 0
21 | }
22 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/dongyang/android/youdongknowme/data/remote/service/SettingService.kt:
--------------------------------------------------------------------------------
1 | package com.dongyang.android.youdongknowme.data.remote.service
2 |
3 | import com.dongyang.android.youdongknowme.data.remote.entity.RemoveToken
4 | import com.dongyang.android.youdongknowme.data.remote.entity.UpdateDepartment
5 | import com.dongyang.android.youdongknowme.data.remote.entity.UpdateTopic
6 | import retrofit2.http.Body
7 | import retrofit2.http.POST
8 |
9 | interface SettingService {
10 |
11 | @POST("department/v1/dmu/updateDepartment")
12 | suspend fun updateDepartment(@Body data: UpdateDepartment)
13 |
14 | @POST("department/v1/dmu/deleteDepartment")
15 | suspend fun deleteDepartment(@Body token: RemoveToken)
16 |
17 | @POST("token/v1/dmu/updateTopic")
18 | suspend fun updateTopic(@Body data: UpdateTopic)
19 |
20 | @POST("token/v1/dmu/deleteTopic")
21 | suspend fun deleteTopic(@Body token: RemoveToken)
22 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_back.xml:
--------------------------------------------------------------------------------
1 |
6 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_arrow_left.xml:
--------------------------------------------------------------------------------
1 |
6 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/java/com/dongyang/android/youdongknowme/ui/view/util/ToastUtil.kt:
--------------------------------------------------------------------------------
1 | package com.dongyang.android.youdongknowme.ui.view.util
2 |
3 | import android.content.Context
4 | import android.widget.Toast
5 | import androidx.annotation.StringRes
6 |
7 | private var toast: Toast? = null
8 |
9 | fun Context.toast(message: CharSequence?) {
10 | toast?.cancel()
11 | toast = message?.let { Toast.makeText(this, it, Toast.LENGTH_SHORT) }?.apply { show() }
12 | }
13 |
14 | fun Context.longToast(message: CharSequence?) {
15 | toast?.cancel()
16 | toast = message?.let { Toast.makeText(this, it, Toast.LENGTH_LONG) }?.apply { show() }
17 | }
18 |
19 | fun Context.toast(@StringRes message: Int) {
20 | toast?.cancel()
21 | toast = Toast.makeText(this, message, Toast.LENGTH_SHORT).apply { show() }
22 | }
23 |
24 | fun Context.longToast(@StringRes message: Int) {
25 | toast?.cancel()
26 | toast = Toast.makeText(this, message, Toast.LENGTH_LONG).apply { show() }
27 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/dongyang/android/youdongknowme/ui/viewholder/NoticeViewHodler.kt:
--------------------------------------------------------------------------------
1 | package com.dongyang.android.youdongknowme.ui.viewholder
2 |
3 | import androidx.recyclerview.widget.RecyclerView
4 | import com.dongyang.android.youdongknowme.data.remote.entity.Notice
5 | import com.dongyang.android.youdongknowme.databinding.ItemNoticeBinding
6 |
7 | class NoticeViewHolder(
8 | private val binding: ItemNoticeBinding,
9 | clickListener: (url: String) -> Unit
10 | ) :
11 | RecyclerView.ViewHolder(binding.root) {
12 |
13 | private var noticeUrl: String? = null
14 |
15 | init {
16 | binding.root.setOnClickListener {
17 | clickListener(noticeUrl ?: "0")
18 | }
19 | }
20 |
21 | fun bind(item: Notice) {
22 | noticeUrl = item.url
23 |
24 | binding.tvNoticeTitle.text = item.title
25 | binding.tvNoticeDate.text = item.date.replace("-", ".")
26 | binding.tvNoticeAuthor.text = item.author
27 | }
28 | }
--------------------------------------------------------------------------------
/app/src/main/res/values/arrays.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | - 기계공학과
5 | - 기계설계공학과
6 | - 로봇소프트웨어과
7 | - 자동화공학과
8 | - 전기공학과
9 | - 정보전자공학과
10 | - 반도체전자공학과
11 | - 정보통신공학과
12 | - 소방안전관리과
13 | - 컴퓨터소프트웨어공학과
14 | - 웹응용소프트웨어공학과
15 | - 인공지능소프트웨어학과
16 | - 생명화학공학과
17 | - 바이오융합공학과
18 | - 건축과
19 | - 실내건축디자인과
20 | - 시각디자인과
21 | - AR-VR콘텐츠디자인과
22 | - 경영학과
23 | - 세무회계학과
24 | - 유통마케팅학과
25 | - 호텔관광학과
26 | - 경영정보학과
27 | - 빅데이터경영과
28 | - 자유전공학과
29 |
30 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_splash.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
10 |
11 |
20 |
21 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_timer.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_location.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/java/com/dongyang/android/youdongknowme/data/remote/service/NoticeService.kt:
--------------------------------------------------------------------------------
1 | package com.dongyang.android.youdongknowme.data.remote.service
2 |
3 | import com.dongyang.android.youdongknowme.data.remote.entity.Notice
4 | import retrofit2.http.GET
5 | import retrofit2.http.Path
6 | import retrofit2.http.Query
7 |
8 | interface NoticeService {
9 |
10 | @GET("api/v1/dmu/universityNotice")
11 | suspend fun getUniversityNotice(
12 | @Query("page") page: Int,
13 | @Query("size") size: Int
14 | ): List
15 |
16 | @GET("api/v1/dmu/departmentNotice/{department}")
17 | suspend fun getDepartmentNotice(
18 | @Path("department") department: String,
19 | @Query("page") page: Int,
20 | @Query("size") size: Int
21 | ): List
22 |
23 | @GET("api/v1/dmu/notice/{searchWord}")
24 | suspend fun getSearchNotice(
25 | @Path("searchWord") searchWord: String,
26 | @Query("department") department: String,
27 | @Query("page") page: Int,
28 | @Query("size") size: Int
29 | ): List
30 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_search.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_search_empty.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_search_button.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_alarm.xml:
--------------------------------------------------------------------------------
1 |
6 |
13 |
14 |
--------------------------------------------------------------------------------
/app/src/main/java/com/dongyang/android/youdongknowme/standard/util/UtilExt.kt:
--------------------------------------------------------------------------------
1 | package com.dongyang.android.youdongknowme.standard.util
2 |
3 | import android.app.Activity
4 | import android.content.Context
5 | import android.view.View
6 | import android.view.inputmethod.InputMethodManager
7 |
8 | fun View.showKeyboard(isForced: Boolean = false) {
9 | val inputMethodManager =
10 | context.getSystemService(Activity.INPUT_METHOD_SERVICE) as InputMethodManager
11 | inputMethodManager.showSoftInput(
12 | this,
13 | if (isForced) InputMethodManager.SHOW_FORCED else InputMethodManager.SHOW_IMPLICIT
14 | )
15 | }
16 |
17 | fun View.hideKeyboard() {
18 | val inputMethodManager =
19 | context.getSystemService(Activity.INPUT_METHOD_SERVICE) as InputMethodManager
20 | inputMethodManager.hideSoftInputFromWindow(windowToken, 0)
21 | }
22 |
23 | fun Int.dpToPx(context: Context): Int {
24 | val density = context.resources.displayMetrics.density
25 | return (this * density).toInt()
26 | }
27 |
28 |
29 | object ACTION {
30 | const val FCM_ACTION_NAME = "com.google.firebase.MESSAGING_EVENT"
31 | }
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_image.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
8 |
9 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/app/src/main/java/com/dongyang/android/youdongknowme/standard/network/ErrorResponseHandler.kt:
--------------------------------------------------------------------------------
1 | package com.dongyang.android.youdongknowme.standard.network
2 |
3 | import retrofit2.HttpException
4 | import retrofit2.Response
5 | import java.net.SocketTimeoutException
6 |
7 | class ErrorResponseHandler {
8 |
9 | fun getError(exception: Throwable): NetworkError {
10 | return when (exception) {
11 | is SocketTimeoutException -> NetworkError.Timeout
12 | is HttpException -> {
13 | when (exception.code()) {
14 | in 500..599 -> NetworkError.InternalServer
15 | in 400..499 -> {
16 | val code = exception.code()
17 | val message = extractErrorMessage(exception.response())
18 | NetworkError.BadRequest(code, message)
19 | }
20 | else -> NetworkError.Unknown
21 | }
22 | }
23 | else -> NetworkError.Unknown
24 | }
25 | }
26 |
27 | private fun extractErrorMessage(response: Response<*>?): String {
28 | return response?.message().orEmpty()
29 | }
30 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/dongyang/android/youdongknowme/data/local/dao/KeywordDao.kt:
--------------------------------------------------------------------------------
1 | package com.dongyang.android.youdongknowme.data.local.dao
2 |
3 | import androidx.room.Dao
4 | import androidx.room.Insert
5 | import androidx.room.OnConflictStrategy
6 | import androidx.room.Query
7 | import com.dongyang.android.youdongknowme.data.local.entity.KeywordEntity
8 | import kotlinx.coroutines.flow.Flow
9 |
10 | @Dao
11 | interface KeywordDao {
12 | @Query("SELECT * FROM keyword ORDER BY name DESC")
13 | fun getAllKeyword(): Flow>
14 |
15 | @Insert(onConflict = OnConflictStrategy.REPLACE)
16 | suspend fun insertKeywordList(keyword: List)
17 |
18 | @Insert(onConflict = OnConflictStrategy.REPLACE)
19 | suspend fun insertKeyword(keyword: KeywordEntity)
20 |
21 | @Query("UPDATE keyword SET isSubscribe = :isSubscribe WHERE name = :name")
22 | suspend fun updateKeyword(isSubscribe: Boolean, name: String)
23 |
24 | @Query("DELETE FROM keyword WHERE name = :name")
25 | suspend fun deleteKeyword(name: String)
26 |
27 | @Query("SELECT * FROM keyword WHERE isSubscribe = 1")
28 | suspend fun getSubscribedKeywords(): List
29 | }
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #5265FF
4 | #D75265FF
5 | #665265FF
6 | #0F498C
7 | #FF3700B3
8 | #FF0F498C
9 | #FF018786
10 | #FF000000
11 | #CC000000
12 | #FFFFFFFF
13 | #00FFFFFF
14 |
15 | #D9D9D9
16 |
17 | #FF35373F
18 | #FF4F525F
19 | #FF7E8295
20 | #AEB1C5
21 | #FFEBEBF0
22 | #FFF5F6F8
23 | #FF354DAE
24 | #FF4967E1
25 | #FFD0D8F9
26 | #FFEFF2FF
27 | #FFD92727
28 |
--------------------------------------------------------------------------------
/app/src/main/java/com/dongyang/android/youdongknowme/ui/view/depart/DepartViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.dongyang.android.youdongknowme.ui.view.depart
2 |
3 | import androidx.lifecycle.LiveData
4 | import androidx.lifecycle.MutableLiveData
5 | import com.dongyang.android.youdongknowme.data.repository.DepartRepository
6 | import com.dongyang.android.youdongknowme.standard.base.BaseViewModel
7 |
8 | class DepartViewModel(private val departRepository: DepartRepository) : BaseViewModel() {
9 | private val _myDepartment: MutableLiveData = MutableLiveData()
10 | val myDepartment: LiveData get() = _myDepartment
11 |
12 | private val _selectDepartPosition = MutableLiveData(-1)
13 | val selectDepartPosition: LiveData get() = _selectDepartPosition
14 |
15 | init {
16 | getUserDepartment()
17 | }
18 |
19 | private fun getUserDepartment() {
20 | val myDepartment = departRepository.getUserDepartment()
21 | _myDepartment.postValue(myDepartment)
22 | }
23 |
24 | fun setDepartment(department: String) {
25 | departRepository.setDepartment(department)
26 | }
27 |
28 | fun setSelectPosition(position: Int) {
29 | _selectDepartPosition.postValue(position)
30 | }
31 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_close.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
13 |
14 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_depart.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
17 |
18 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_onboarding_depart.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
16 |
17 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/app/google-services.json:
--------------------------------------------------------------------------------
1 | {
2 | "project_info": {
3 | "project_number": "216931333525",
4 | "project_id": "dm-for-u",
5 | "storage_bucket": "dm-for-u.appspot.com"
6 | },
7 | "client": [
8 | {
9 | "client_info": {
10 | "mobilesdk_app_id": "1:216931333525:android:76b43009912139a0fef29c",
11 | "android_client_info": {
12 | "package_name": "com.dmu.android"
13 | }
14 | },
15 | "oauth_client": [],
16 | "api_key": [
17 | {
18 | "current_key": "AIzaSyCAnvMxwnN_XBoZJPv8Ob3oB4qTz_ILtnA"
19 | }
20 | ],
21 | "services": {
22 | "appinvite_service": {
23 | "other_platform_oauth_client": []
24 | }
25 | }
26 | },
27 | {
28 | "client_info": {
29 | "mobilesdk_app_id": "1:216931333525:android:be451c8a539f9428fef29c",
30 | "android_client_info": {
31 | "package_name": "com.dongyang.android.youdongknowme"
32 | }
33 | },
34 | "oauth_client": [],
35 | "api_key": [
36 | {
37 | "current_key": "AIzaSyCAnvMxwnN_XBoZJPv8Ob3oB4qTz_ILtnA"
38 | }
39 | ],
40 | "services": {
41 | "appinvite_service": {
42 | "other_platform_oauth_client": []
43 | }
44 | }
45 | }
46 | ],
47 | "configuration_version": "1"
48 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/dongyang/android/youdongknowme/standard/util/Constants.kt:
--------------------------------------------------------------------------------
1 | object CODE {
2 | const val SCHOOL_CODE = 1
3 |
4 | const val MECHANICAL_ENGINE_CODE = 101
5 | const val MECHANICAL_DESIGN_CODE = 102
6 |
7 | const val AUTOMATION_ENGINE_CODE = 201
8 | const val ROBOT_SOFTWARE_CODE = 202
9 |
10 | const val COMPUTER_SOFTWARE_ENGINE_CODE = 301
11 | const val WEB_APP_SOFTWARE_ENGINE_CODE = 302
12 | const val ARTIFICIAL_ENGINE_CODE = 303
13 |
14 | const val ELECTRICAL_ENGINE_CODE = 401
15 | const val INFO_ELECTRONIC_ENGINE_CODE = 402
16 | const val SEMICONDUCTOR_ENGINE_CODE = 403
17 | const val INFO_COMMUNICATION_ENGINE_CODE = 404
18 | const val FIRE_MANAGEMENT_CODE = 405
19 |
20 | const val BIOCHEMICAL_ENGINE_CODE = 501
21 | const val BIO_CONVERGENCE_ENGINE_CODE = 502
22 | const val ARCHITECTURE_CODE = 503
23 | const val INTERIOR_DESIGN_CODE = 504
24 | const val VISUAL_DESIGN_CODE = 505
25 | const val AR_VR_CONTENT_CODE = 506
26 |
27 | const val BUSINESS_ADMINISTRATION_CODE = 601
28 | const val TAX_ACCOUNTING_CODE = 602
29 | const val DISTRIBUTION_MARKETING_CODE = 603
30 | const val HOTEL_TOURISM_CODE = 604
31 | const val MANAGEMENT_INFORMATION_CODE = 605
32 | const val BIG_DATA_MANAGEMENT_CODE = 606
33 |
34 | const val LIBERAL_MAJOR_CODE = 701
35 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_menu_cafeteria.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_setting_right.xml:
--------------------------------------------------------------------------------
1 |
6 |
10 |
15 |
16 |
--------------------------------------------------------------------------------
/app/src/main/java/com/dongyang/android/youdongknowme/data/repository/ScheduleRepository.kt:
--------------------------------------------------------------------------------
1 | package com.dongyang.android.youdongknowme.data.repository
2 |
3 | import com.dongyang.android.youdongknowme.data.local.SharedPreference
4 | import com.dongyang.android.youdongknowme.data.remote.entity.Schedule
5 | import com.dongyang.android.youdongknowme.data.remote.service.ScheduleService
6 | import com.dongyang.android.youdongknowme.standard.network.ErrorResponseHandler
7 | import com.dongyang.android.youdongknowme.standard.network.NetworkResult
8 | import com.dongyang.android.youdongknowme.standard.network.RetrofitObject
9 |
10 | class ScheduleRepository(
11 | private val errorResponseHandler: ErrorResponseHandler
12 | ) {
13 | suspend fun fetchSchedules(): NetworkResult> {
14 | return try {
15 | val response = RetrofitObject.getNetwork().create(ScheduleService::class.java).getScheduleList()
16 | NetworkResult.Success(response)
17 | } catch (exception: Exception) {
18 | val error = errorResponseHandler.getError(exception)
19 | NetworkResult.Error(error)
20 | }
21 | }
22 |
23 | fun setLocalSchedules(schedule: String) {
24 | SharedPreference.setSchedule(schedule)
25 | }
26 |
27 | fun getLocalSchedules(): String {
28 | return SharedPreference.getSchedule()
29 | }
30 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/dongyang/android/youdongknowme/ui/adapter/NoticeAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.dongyang.android.youdongknowme.ui.adapter
2 |
3 | import android.annotation.SuppressLint
4 | import android.view.LayoutInflater
5 | import android.view.ViewGroup
6 | import androidx.recyclerview.widget.RecyclerView
7 | import com.dongyang.android.youdongknowme.data.remote.entity.Notice
8 | import com.dongyang.android.youdongknowme.databinding.ItemNoticeBinding
9 | import com.dongyang.android.youdongknowme.ui.viewholder.NoticeViewHolder
10 |
11 | class NoticeAdapter(private val onItemClick: (url: String) -> Unit) :
12 | RecyclerView.Adapter() {
13 |
14 | private val noticeList = arrayListOf()
15 |
16 | @SuppressLint("NotifyDataSetChanged")
17 | fun submitList(item: List) {
18 | noticeList.clear()
19 | noticeList.addAll(item)
20 | notifyDataSetChanged()
21 | }
22 |
23 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): NoticeViewHolder {
24 | return NoticeViewHolder(
25 | ItemNoticeBinding.inflate(
26 | LayoutInflater.from(parent.context), parent, false
27 | ), onItemClick
28 | )
29 | }
30 |
31 | override fun onBindViewHolder(holder: NoticeViewHolder, position: Int) {
32 | holder.bind(noticeList[position])
33 | }
34 |
35 | override fun getItemCount(): Int = noticeList.size
36 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/dongyang/android/youdongknowme/ui/view/web/WebActivity.kt:
--------------------------------------------------------------------------------
1 | package com.dongyang.android.youdongknowme.ui.view.web
2 |
3 | import android.content.Context
4 | import android.content.Intent
5 | import android.content.Intent.FLAG_ACTIVITY_SINGLE_TOP
6 | import com.dongyang.android.youdongknowme.R
7 | import com.dongyang.android.youdongknowme.databinding.ActivityWebBinding
8 | import com.dongyang.android.youdongknowme.standard.base.BaseActivity
9 | import org.koin.androidx.viewmodel.ext.android.viewModel
10 |
11 | class WebActivity : BaseActivity() {
12 |
13 | override val layoutResourceId: Int = R.layout.activity_web
14 | override val viewModel: WebViewModel by viewModel()
15 |
16 | override fun initStartView() {
17 | val url = intent.getStringExtra(KEY_URL)
18 | binding.wvWeb.loadUrl(url.toString())
19 | binding.btnWebClose.setOnClickListener {
20 | finish()
21 | }
22 | }
23 |
24 | override fun initDataBinding() = Unit
25 |
26 | override fun initAfterBinding() = Unit
27 |
28 | companion object {
29 | private const val KEY_URL = "url"
30 |
31 | fun newIntent(context: Context, url: String): Intent {
32 | return Intent(context, WebActivity::class.java).apply {
33 | putExtra(KEY_URL, url)
34 | flags = FLAG_ACTIVITY_SINGLE_TOP
35 | }
36 | }
37 | }
38 | }
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_web.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
21 |
22 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_logo_foreground.xml:
--------------------------------------------------------------------------------
1 |
6 |
10 |
13 |
17 |
21 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/app/src/main/java/com/dongyang/android/youdongknowme/ui/viewholder/CafeteriaAnotherViewHolder.kt:
--------------------------------------------------------------------------------
1 | package com.dongyang.android.youdongknowme.ui.viewholder
2 |
3 | import androidx.core.view.setPadding
4 | import androidx.recyclerview.widget.RecyclerView
5 | import com.dongyang.android.youdongknowme.R
6 | import com.dongyang.android.youdongknowme.data.model.AnotherMenu
7 | import com.dongyang.android.youdongknowme.databinding.ItemCafeteriaAnotherBinding
8 |
9 | class CafeteriaAnotherViewHolder(
10 | private val binding: ItemCafeteriaAnotherBinding
11 | ) : RecyclerView.ViewHolder(binding.root) {
12 |
13 | fun bind(item: AnotherMenu) {
14 | binding.menuKr = item.menuNameKr
15 | binding.menuEn = item.name.split('_')
16 | .joinToString(" ") { word ->
17 | word.lowercase().replaceFirstChar { firstChar -> firstChar.uppercase() }
18 | }
19 | binding.menuPrice = item.price
20 |
21 | val context = binding.root.context
22 | val resourceName = "img_cafeteria_" + item.name.lowercase()
23 | val drawableResId =
24 | context.resources.getIdentifier(resourceName, "drawable", context.packageName)
25 |
26 | if (drawableResId != 0) {
27 | binding.imgAnother.setImageResource(drawableResId)
28 | binding.imgAnother.setPadding(0)
29 | } else {
30 | binding.imgAnother.setImageResource(R.drawable.img_cafeteria_korean)
31 | binding.imgAnother.setPadding(15)
32 | }
33 | }
34 | }
--------------------------------------------------------------------------------
/app/src/main/res/values/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
20 |
21 |
22 |
23 |
24 |
29 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_license.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
20 |
21 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/app/src/main/java/com/dongyang/android/youdongknowme/standard/network/RetrofitObject.kt:
--------------------------------------------------------------------------------
1 | package com.dongyang.android.youdongknowme.standard.network
2 |
3 | import com.dongyang.android.youdongknowme.BuildConfig
4 | import okhttp3.Interceptor
5 | import okhttp3.OkHttpClient
6 | import okhttp3.logging.HttpLoggingInterceptor
7 | import retrofit2.Retrofit
8 | import retrofit2.converter.gson.GsonConverterFactory
9 | import java.util.concurrent.TimeUnit
10 |
11 | object RetrofitObject {
12 | private const val TIME_OUT_COUNT: Long = 40
13 |
14 | fun getNetwork(): Retrofit {
15 | val baseInterceptor = Interceptor { chain ->
16 | val request = chain.request().newBuilder()
17 | val originalHttpUrl = chain.request().url
18 |
19 | val url = originalHttpUrl.newBuilder()
20 | .build()
21 | request.url(url)
22 | chain.proceed(request.build())
23 | }
24 |
25 | val client = OkHttpClient.Builder()
26 | .connectTimeout(TIME_OUT_COUNT, TimeUnit.SECONDS)
27 | .readTimeout(TIME_OUT_COUNT, TimeUnit.SECONDS)
28 | .addInterceptor(baseInterceptor)
29 | .addNetworkInterceptor(HttpLoggingInterceptor().apply {
30 | level = HttpLoggingInterceptor.Level.BASIC
31 | }).build()
32 |
33 | return Retrofit.Builder()
34 | .baseUrl(BuildConfig.BASE_URL)
35 | .addConverterFactory(GsonConverterFactory.create())
36 | .client(client)
37 | .build()
38 | }
39 | }
--------------------------------------------------------------------------------
/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. More details, visit
12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec: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
24 |
25 | android.enableJetifier=true
26 | android.defaults.buildfeatures.buildconfig=true
27 | android.nonFinalResIds=false
--------------------------------------------------------------------------------
/app/src/main/java/com/dongyang/android/youdongknowme/standard/base/BaseViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.dongyang.android.youdongknowme.standard.base
2 |
3 | import androidx.lifecycle.MutableLiveData
4 | import androidx.lifecycle.ViewModel
5 | import com.dongyang.android.youdongknowme.R
6 | import com.dongyang.android.youdongknowme.standard.network.NetworkError
7 | import com.dongyang.android.youdongknowme.standard.network.NetworkResult
8 | import com.dongyang.android.youdongknowme.ui.view.util.Event
9 |
10 | abstract class BaseViewModel : ViewModel() {
11 |
12 | protected fun handleError(
13 | result: NetworkResult.Error,
14 | errorState: MutableLiveData>
15 | ) {
16 | when (result.errorType) {
17 | is NetworkError.Unknown -> {
18 | errorState.postValue(Event(ERROR_UNKNOWN))
19 | }
20 | is NetworkError.Timeout -> {
21 | errorState.postValue(Event(ERROR_TIMEOUT))
22 | }
23 | is NetworkError.InternalServer -> {
24 | errorState.postValue(Event(ERROR_INTERNAL_SERVER))
25 | }
26 | is NetworkError.BadRequest -> {
27 | errorState.postValue(Event(ERROR_BAD_REQUEST))
28 | }
29 | }
30 | }
31 |
32 | companion object {
33 | const val ERROR_UNKNOWN = R.string.error_unknown
34 | const val ERROR_TIMEOUT = R.string.error_timeout
35 | const val ERROR_INTERNAL_SERVER = R.string.error_internal_server
36 | const val ERROR_BAD_REQUEST = R.string.error_bad_request
37 | }
38 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/dongyang/android/youdongknowme/ui/adapter/CafeteriaAnotherAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.dongyang.android.youdongknowme.ui.adapter
2 |
3 | import android.annotation.SuppressLint
4 | import android.view.LayoutInflater
5 | import android.view.ViewGroup
6 | import androidx.recyclerview.widget.RecyclerView
7 | import com.dongyang.android.youdongknowme.data.model.AnotherMenu
8 | import com.dongyang.android.youdongknowme.databinding.ItemCafeteriaAnotherBinding
9 | import com.dongyang.android.youdongknowme.ui.viewholder.CafeteriaAnotherViewHolder
10 |
11 | class CafeteriaAnotherAdapter : RecyclerView.Adapter() {
12 |
13 | init {
14 | setHasStableIds(true)
15 | }
16 |
17 | private var menu = arrayListOf()
18 |
19 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CafeteriaAnotherViewHolder {
20 | return CafeteriaAnotherViewHolder(
21 | ItemCafeteriaAnotherBinding.inflate(
22 | LayoutInflater.from(parent.context), parent, false
23 | )
24 | )
25 | }
26 |
27 | override fun getItemId(position: Int): Long {
28 | return position.toLong()
29 | }
30 |
31 | override fun onBindViewHolder(holder: CafeteriaAnotherViewHolder, position: Int) {
32 | holder.bind(menu[position])
33 | }
34 |
35 | @SuppressLint("NotifyDataSetChanged")
36 | fun submitList(item: List) {
37 | menu.clear()
38 | menu.addAll(item)
39 | notifyDataSetChanged()
40 | }
41 |
42 | override fun getItemCount(): Int = menu.size
43 | }
--------------------------------------------------------------------------------
/app/src/main/res/layout/standard_error.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
10 |
15 |
16 |
24 |
25 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/app/src/main/java/com/dongyang/android/youdongknowme/ui/adapter/CafeteriaKoreanAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.dongyang.android.youdongknowme.ui.adapter
2 |
3 | import android.annotation.SuppressLint
4 | import android.view.LayoutInflater
5 | import android.view.ViewGroup
6 | import androidx.recyclerview.widget.RecyclerView
7 | import com.dongyang.android.youdongknowme.databinding.ItemCafeteriaKoreanBinding
8 |
9 | class CafeteriaKoreanAdapter : RecyclerView.Adapter() {
10 |
11 | init {
12 | setHasStableIds(true)
13 | }
14 |
15 | private var menu = arrayListOf()
16 |
17 | inner class ViewHolder(private val binding: ItemCafeteriaKoreanBinding) :
18 | RecyclerView.ViewHolder(binding.root) {
19 | fun bind(item: String) {
20 | binding.koreanMenu = item
21 | }
22 | }
23 |
24 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
25 | return ViewHolder(
26 | ItemCafeteriaKoreanBinding.inflate(
27 | LayoutInflater.from(parent.context), parent, false
28 | )
29 | )
30 | }
31 |
32 | override fun getItemId(position: Int): Long {
33 | return position.toLong()
34 | }
35 |
36 | override fun onBindViewHolder(holder: ViewHolder, position: Int) {
37 | holder.bind(menu[position])
38 | }
39 |
40 | @SuppressLint("NotifyDataSetChanged")
41 | fun submitList(item: List) {
42 | menu.clear()
43 | menu.addAll(item)
44 | notifyDataSetChanged()
45 | }
46 |
47 | override fun getItemCount(): Int = menu.size
48 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/dongyang/android/youdongknowme/ui/view/alarm/AlarmViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.dongyang.android.youdongknowme.ui.view.alarm
2 |
3 | import androidx.lifecycle.LiveData
4 | import androidx.lifecycle.MutableLiveData
5 | import androidx.lifecycle.viewModelScope
6 | import com.dongyang.android.youdongknowme.data.local.entity.AlarmEntity
7 | import com.dongyang.android.youdongknowme.data.repository.AlarmRepository
8 | import com.dongyang.android.youdongknowme.standard.base.BaseViewModel
9 | import kotlinx.coroutines.flow.collect
10 | import kotlinx.coroutines.launch
11 |
12 | class AlarmViewModel(private val alarmRepository: AlarmRepository) : BaseViewModel() {
13 |
14 | private val _alarmList: MutableLiveData> = MutableLiveData()
15 | val alarmList: LiveData> get() = _alarmList
16 |
17 | private val _title: MutableLiveData = MutableLiveData()
18 | val title: LiveData get() = _title
19 |
20 | private val _department: MutableLiveData = MutableLiveData()
21 | val department: LiveData get() = _department
22 |
23 | private val _keyword: MutableLiveData = MutableLiveData()
24 | val keyword: LiveData get() = _keyword
25 |
26 | fun getAlarms() {
27 | viewModelScope.launch {
28 | alarmRepository.getUserAlarms().collect { alarmList ->
29 | _alarmList.postValue(alarmList)
30 | }
31 | }
32 | }
33 |
34 | fun updateIsVisitedAlarm(isVisited: Boolean, id: Int) {
35 | viewModelScope.launch {
36 | alarmRepository.updateIsVisitedAlarm(isVisited, id)
37 | }
38 | }
39 | }
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
21 |
22 |
27 |
28 |
32 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
19 |
20 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_schedule.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
11 |
12 |
23 |
24 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_search_clear.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/java/com/dongyang/android/youdongknowme/ui/adapter/LicenseAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.dongyang.android.youdongknowme.ui.adapter
2 |
3 | import android.annotation.SuppressLint
4 | import android.view.LayoutInflater
5 | import android.view.ViewGroup
6 | import androidx.recyclerview.widget.RecyclerView
7 | import com.dongyang.android.youdongknowme.data.local.entity.OpenSourceEntity
8 | import com.dongyang.android.youdongknowme.databinding.ItemLicenseBinding
9 | import com.dongyang.android.youdongknowme.ui.view.license.LicenseClickListener
10 |
11 | class LicenseAdapter : RecyclerView.Adapter() {
12 |
13 | private val item = ArrayList()
14 | private var itemClickListener: LicenseClickListener? = null
15 |
16 | inner class ViewHolder(private val binding: ItemLicenseBinding) :
17 | RecyclerView.ViewHolder(binding.root) {
18 | fun bind(item: OpenSourceEntity) {
19 | binding.openSource = item
20 | binding.itemClickListener = itemClickListener
21 | }
22 | }
23 |
24 | @SuppressLint("NotifyDataSetChanged")
25 | fun submitList(item: List) {
26 | this.item.clear()
27 | this.item.addAll(item)
28 | notifyDataSetChanged()
29 | }
30 |
31 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
32 | return ViewHolder(
33 | ItemLicenseBinding.inflate(
34 | LayoutInflater.from(parent.context), parent, false
35 | )
36 | )
37 | }
38 |
39 | override fun onBindViewHolder(holder: ViewHolder, position: Int) = holder.bind(item[position])
40 |
41 | override fun getItemCount(): Int = item.size
42 |
43 | fun setItemClickListener(listener: LicenseClickListener) {
44 | itemClickListener = listener
45 | }
46 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/dongyang/android/youdongknowme/ui/adapter/ScheduleAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.dongyang.android.youdongknowme.ui.adapter
2 |
3 | import android.annotation.SuppressLint
4 | import android.view.LayoutInflater
5 | import android.view.ViewGroup
6 | import androidx.recyclerview.widget.RecyclerView
7 | import com.dongyang.android.youdongknowme.data.remote.entity.Schedule
8 | import com.dongyang.android.youdongknowme.data.remote.entity.ScheduleEntry
9 | import com.dongyang.android.youdongknowme.databinding.ItemScheduleBinding
10 |
11 | class ScheduleAdapter : RecyclerView.Adapter() {
12 |
13 | init {
14 | setHasStableIds(true)
15 | }
16 |
17 | private var item = arrayListOf()
18 |
19 | inner class ViewHolder(private val binding: ItemScheduleBinding)
20 | : RecyclerView.ViewHolder(binding.root) {
21 |
22 | fun bind(item: ScheduleEntry) {
23 | binding.tvItemScheduleDate.text = if(item.dates[0] == item.dates[1]) item.dates[0] else "${item.dates[0]}\n~ ${item.dates[1]}"
24 | binding.tvItemScheduleContents.text = item.contents
25 | }
26 | }
27 |
28 | @SuppressLint("NotifyDataSetChanged")
29 | fun submitList(item: List) {
30 | this.item.clear()
31 | this.item.addAll(item)
32 | notifyDataSetChanged()
33 | }
34 |
35 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
36 | return ViewHolder(
37 | ItemScheduleBinding.inflate(
38 | LayoutInflater.from(parent.context), parent, false
39 | )
40 | )
41 | }
42 |
43 | override fun getItemId(position: Int): Long {
44 | return position.toLong()
45 | }
46 |
47 | override fun onBindViewHolder(holder: ViewHolder, position: Int) {
48 | holder.bind(item[position])
49 | }
50 |
51 | override fun getItemCount(): Int = item.size
52 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/dongyang/android/youdongknowme/ui/view/license/LicenseActivity.kt:
--------------------------------------------------------------------------------
1 | package com.dongyang.android.youdongknowme.ui.view.license
2 |
3 | import android.content.Intent
4 | import android.net.Uri
5 | import androidx.recyclerview.widget.DividerItemDecoration
6 | import androidx.recyclerview.widget.LinearLayoutManager
7 | import com.dongyang.android.youdongknowme.R
8 | import com.dongyang.android.youdongknowme.data.local.entity.OpenSourceEntity
9 | import com.dongyang.android.youdongknowme.databinding.ActivityLicenseBinding
10 | import com.dongyang.android.youdongknowme.standard.base.BaseActivity
11 | import com.dongyang.android.youdongknowme.ui.adapter.LicenseAdapter
12 | import org.koin.androidx.viewmodel.ext.android.viewModel
13 |
14 | class LicenseActivity : BaseActivity(),
15 | LicenseClickListener {
16 | override val layoutResourceId: Int = R.layout.activity_license
17 | override val viewModel: LicenseViewModel by viewModel()
18 |
19 | lateinit var adapter: LicenseAdapter
20 |
21 | override fun initStartView() {
22 | adapter = LicenseAdapter().apply { setItemClickListener(this@LicenseActivity) }
23 | binding.licenseRcv.apply {
24 | this.adapter = this@LicenseActivity.adapter
25 | this.layoutManager = LinearLayoutManager(this@LicenseActivity)
26 | this.addItemDecoration(DividerItemDecoration(this@LicenseActivity, 1))
27 | this.setHasFixedSize(true)
28 | }
29 | }
30 |
31 | override fun initDataBinding() {}
32 |
33 | override fun initAfterBinding() {
34 | adapter.submitList(OpenSourceEntity.openSourceList)
35 |
36 | binding.licenseToolbar.btnToolbarExit.setOnClickListener { finish() }
37 | }
38 |
39 | override fun itemClick(openSourceEntity: OpenSourceEntity) {
40 | val intent = Intent(Intent.ACTION_VIEW, Uri.parse(openSourceEntity.url))
41 | startActivity(intent)
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/app/src/main/java/com/dongyang/android/youdongknowme/data/repository/MainRepository.kt:
--------------------------------------------------------------------------------
1 | package com.dongyang.android.youdongknowme.data.repository
2 |
3 | import com.dongyang.android.youdongknowme.data.local.SharedPreference
4 | import com.dongyang.android.youdongknowme.data.local.dao.KeywordDao
5 | import com.dongyang.android.youdongknowme.data.remote.service.TokenService
6 | import com.dongyang.android.youdongknowme.standard.network.ErrorResponseHandler
7 | import com.dongyang.android.youdongknowme.standard.network.NetworkResult
8 | import com.dongyang.android.youdongknowme.standard.network.RetrofitObject
9 |
10 | class MainRepository(
11 | private val keywordDao: KeywordDao,
12 | private val errorResponseHandler: ErrorResponseHandler
13 | ) {
14 | fun getIsFirstLaunch(): Boolean = SharedPreference.getIsFirstLaunch()
15 |
16 | fun setIsFirstLaunch(isFirstLaunch: Boolean) {
17 | SharedPreference.setIsFirstLaunch(isFirstLaunch)
18 | }
19 |
20 | fun getUserDepartment(): String {
21 | return SharedPreference.getDepartment()
22 | }
23 |
24 | suspend fun getUserTopic(): List {
25 | val subscribedTopic = keywordDao.getSubscribedKeywords()
26 | return subscribedTopic.map { it.englishName }
27 | }
28 |
29 | fun getFCMToken(): String {
30 | return SharedPreference.getFCMToken()
31 | }
32 |
33 | fun setFCMToken(token: String) {
34 | SharedPreference.setFcmToken(token)
35 | }
36 |
37 | suspend fun setUserToken(
38 | data: com.dongyang.android.youdongknowme.data.remote.entity.Token
39 | ): NetworkResult {
40 | return try {
41 | val response = RetrofitObject.getNetwork().create(TokenService::class.java)
42 | .setInitToken(data)
43 | NetworkResult.Success(response)
44 | } catch (exception: Exception) {
45 | val error = errorResponseHandler.getError(exception)
46 | NetworkResult.Error(error)
47 | }
48 | }
49 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_menu_setting.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
--------------------------------------------------------------------------------
/app/src/main/java/com/dongyang/android/youdongknowme/ui/view/setting/PermissionDialog.kt:
--------------------------------------------------------------------------------
1 | package com.dongyang.android.youdongknowme.ui.view.setting
2 |
3 | import android.content.Intent
4 | import android.graphics.Color
5 | import android.graphics.drawable.ColorDrawable
6 | import android.net.Uri
7 | import android.os.Bundle
8 | import android.provider.Settings
9 | import android.view.LayoutInflater
10 | import android.view.View
11 | import android.view.ViewGroup
12 | import androidx.fragment.app.DialogFragment
13 | import com.dongyang.android.youdongknowme.databinding.DialogPermissionBinding
14 |
15 | class PermissionDialog(
16 | val title: String,
17 | val content: String,
18 | val pacakageName: String,
19 | val cancelListener: (() -> Unit)? = null,
20 | ) : DialogFragment() {
21 | private var _binding: DialogPermissionBinding? = null
22 | private val binding get() = _binding!!
23 |
24 | override fun onCreateView(
25 | inflater: LayoutInflater,
26 | container: ViewGroup?,
27 | savedInstanceState: Bundle?,
28 | ): View {
29 | _binding = DialogPermissionBinding.inflate(inflater, container, false)
30 | val view = binding.root
31 |
32 | // 레이아웃 배경을 투명하게
33 | dialog?.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
34 |
35 | // 제목, 내용 설정
36 | binding.tvDialogPermissionTitle.text = title
37 | binding.tvDialogPermissionContent.text = content
38 |
39 | // 취소 버튼
40 | binding.tvDialogPermissionCancel.setOnClickListener {
41 | cancelListener?.invoke()
42 | dismiss()
43 | }
44 |
45 | // 확인 버튼
46 | binding.tvDialogPermissionComplete.setOnClickListener {
47 | val intent =
48 | Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).setData(Uri.parse("package:$pacakageName"))
49 | startActivity(intent)
50 | dismiss()
51 | }
52 |
53 | return view
54 | }
55 |
56 | override fun onDestroyView() {
57 | super.onDestroyView()
58 | _binding = null
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_license.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
14 |
15 |
26 |
27 |
36 |
37 |
38 |
39 |
40 |
41 |
44 |
45 |
48 |
49 |
--------------------------------------------------------------------------------
/app/src/main/java/com/dongyang/android/youdongknowme/ui/view/alarm/AlarmActivity.kt:
--------------------------------------------------------------------------------
1 | package com.dongyang.android.youdongknowme.ui.view.alarm
2 |
3 | import android.content.Intent
4 | import android.view.View
5 | import com.dongyang.android.youdongknowme.R
6 | import com.dongyang.android.youdongknowme.data.local.entity.AlarmEntity
7 | import com.dongyang.android.youdongknowme.databinding.ActivityAlarmBinding
8 | import com.dongyang.android.youdongknowme.standard.base.BaseActivity
9 | import com.dongyang.android.youdongknowme.standard.util.mapDepartmentKoreanToCode
10 | import com.dongyang.android.youdongknowme.ui.view.detail.DetailActivity
11 | import org.koin.androidx.viewmodel.ext.android.viewModel
12 |
13 | class AlarmActivity : BaseActivity(), AlarmClickListener {
14 | override val layoutResourceId: Int = R.layout.activity_alarm
15 | override val viewModel: AlarmViewModel by viewModel()
16 |
17 | override fun initStartView() {
18 | setupToolbar()
19 | }
20 |
21 | private fun setupToolbar() {
22 | binding.alarmToolbar.apply {
23 | tvToolbarTitle.text = getString(R.string.alarm_title)
24 | btnToolbarExit.visibility = View.VISIBLE
25 | tvToolbarActionButton.text = getString(R.string.alarm_action_button_text)
26 | tvToolbarActionButton.visibility = View.VISIBLE
27 | }
28 | }
29 |
30 | override fun initDataBinding() = Unit
31 |
32 | override fun initAfterBinding() {
33 | viewModel.getAlarms()
34 |
35 | binding.alarmToolbar.btnToolbarExit.setOnClickListener {
36 | finish()
37 | }
38 | }
39 |
40 | // 아이템 클릭시 자세히 보기 화면으로 이동
41 | override fun itemClick(alarmEntity: AlarmEntity) {
42 | val departCode = mapDepartmentKoreanToCode(alarmEntity.department)
43 |
44 | alarmEntity.id?.let { viewModel.updateIsVisitedAlarm(true, it) }
45 |
46 | val intent = Intent(this, DetailActivity::class.java)
47 | intent.putExtra("departCode", departCode)
48 | intent.putExtra("boardNum", alarmEntity.num)
49 | startActivity(intent)
50 | }
51 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # DMU (Project DM for U)
2 |
3 | 
4 |
5 | 동양미래대에 대한 모든 정보를 학생들에게 **편리하고 빠르게** 제공하기 위해 만들어진 어플리케이션입니다.
6 |
7 |
8 |
9 | # Function
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | # Tech Stack
19 | `Kotlin`, **`MVVM`**, **`Koin`**, `Retrofit2`, `OkHttp`, `Gson`, `Jetpack`, `AAC`, `DataBinding`, `ViewModel`, `LiveData`, `Coroutine`, `Room`, `Flow`
20 |
21 |
22 |
23 | # System Architecture
24 |
25 | 
26 |
27 |
28 |
29 | # Android Architecture
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 | # Flow Chart
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 | # Environment
46 | - Android Studio Chipmunk | 2021.2.1
47 | - minSdkVersion 24
48 | - targetSdkVersion 32
49 | - Test Device | Galaxy Note 8
50 |
51 |
52 |
53 | # License
54 |
55 |
56 | **Copyright 2022 Jeongho Kim(hoyahozz)**
57 |
58 | Licensed under the Apache License, Version 2.0 (the "License");
59 | you may not use this file except in compliance with the License.
60 | You may obtain a copy of the License at
61 |
62 | http://www.apache.org/licenses/LICENSE-2.0
63 |
64 | Unless required by applicable law or agreed to in writing, software
65 | distributed under the License is distributed on an "AS IS" BASIS,
66 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
67 | See the License for the specific language governing permissions and
68 | limitations under the License.
69 |
--------------------------------------------------------------------------------
/app/src/main/java/com/dongyang/android/youdongknowme/ui/adapter/OnboardingDepartAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.dongyang.android.youdongknowme.ui.adapter
2 |
3 | import android.annotation.SuppressLint
4 | import android.view.LayoutInflater
5 | import android.view.ViewGroup
6 | import androidx.recyclerview.widget.RecyclerView
7 | import com.dongyang.android.youdongknowme.databinding.ItemOnboardingDepartBinding
8 | import com.dongyang.android.youdongknowme.ui.view.depart.DepartClickListener
9 |
10 | class OnboardingDepartAdapter : RecyclerView.Adapter() {
11 |
12 | private val item = ArrayList()
13 | private var itemClickListener: DepartClickListener? = null
14 | private var currentPosition = -1
15 | private var beforePosition = -1
16 |
17 | inner class ViewHolder(private val binding: ItemOnboardingDepartBinding) :
18 | RecyclerView.ViewHolder(binding.root) {
19 | @SuppressLint("UseCompatLoadingForColorStateLists")
20 | fun bind(item: String, position: Int) {
21 | binding.itemOnboardingDepartName.text = item
22 |
23 | binding.itemOnboardingDepartContainer.setOnClickListener {
24 | itemClickListener?.containerClick(position)
25 | }
26 | }
27 | }
28 |
29 | @SuppressLint("NotifyDataSetChanged")
30 | fun submitList(item: ArrayList) {
31 | this.item.clear()
32 | this.item.addAll(item)
33 | notifyDataSetChanged()
34 | }
35 |
36 | fun submitPosition(currentPosition: Int) {
37 | this.beforePosition = this.currentPosition
38 | this.currentPosition = currentPosition
39 | notifyItemChanged(beforePosition)
40 | notifyItemChanged(this.currentPosition)
41 | }
42 |
43 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
44 | return ViewHolder(
45 | ItemOnboardingDepartBinding.inflate(
46 | LayoutInflater.from(parent.context), parent, false
47 | )
48 | )
49 | }
50 |
51 | override fun onBindViewHolder(holder: ViewHolder, position: Int) {
52 | holder.bind(item[position], position)
53 | }
54 |
55 | override fun getItemCount(): Int = item.size
56 |
57 | fun setItemClickListener(listener: DepartClickListener) {
58 | itemClickListener = listener
59 | }
60 | }
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_alarm.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
10 |
15 |
16 |
25 |
26 |
35 |
36 |
40 |
41 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/app/src/main/java/com/dongyang/android/youdongknowme/standard/MyApplication.kt:
--------------------------------------------------------------------------------
1 | package com.dongyang.android.youdongknowme.standard
2 |
3 | import android.app.Application
4 | import android.content.Context
5 | import androidx.appcompat.app.AppCompatDelegate
6 | import androidx.lifecycle.Lifecycle
7 | import androidx.lifecycle.LifecycleEventObserver
8 | import androidx.lifecycle.LifecycleOwner
9 | import androidx.lifecycle.ProcessLifecycleOwner
10 | import com.dongyang.android.youdongknowme.data.local.SharedPreference
11 | import com.dongyang.android.youdongknowme.standard.di.*
12 | import com.google.firebase.FirebaseApp
13 | import org.koin.android.ext.koin.androidContext
14 | import org.koin.android.ext.koin.androidFileProperties
15 | import org.koin.core.context.GlobalContext.startKoin
16 | import timber.log.Timber
17 |
18 | /**
19 | * 앱 실행 시 가장 먼저 진입
20 | */
21 | class MyApplication : Application(), LifecycleEventObserver {
22 | companion object {
23 | var isForeground = false
24 |
25 | lateinit var instance: MyApplication
26 | fun applicationContext(): Context {
27 | return instance.applicationContext
28 | }
29 | }
30 |
31 | init {
32 | instance = this
33 | }
34 |
35 | override fun onCreate() {
36 | super.onCreate()
37 |
38 | AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)
39 |
40 | FirebaseApp.initializeApp(this)
41 |
42 | Timber.plant(object : Timber.DebugTree() {
43 | override fun log(priority: Int, tag: String?, message: String, t: Throwable?) {
44 | super.log(priority, "Debug[$tag]", message, t)
45 | }
46 | })
47 |
48 | // SharedPreference 초기화
49 | SharedPreference.getInstance(this)
50 |
51 | ProcessLifecycleOwner.get().lifecycle.addObserver(this)
52 |
53 | startKoin {
54 | androidContext(this@MyApplication)
55 | androidFileProperties()
56 | modules(listOf(databaseModule, repositoryModule, viewModelModule, networkModule, utilModule))
57 | }
58 | }
59 |
60 | override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
61 | if (event == Lifecycle.Event.ON_START) {
62 | isForeground = true
63 | } else if (event == Lifecycle.Event.ON_STOP) {
64 | isForeground = false
65 | }
66 | }
67 | }
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_depart.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
10 |
11 |
20 |
21 |
32 |
33 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/app/src/main/java/com/dongyang/android/youdongknowme/data/local/entity/OpenSourceEntity.kt:
--------------------------------------------------------------------------------
1 | package com.dongyang.android.youdongknowme.data.local.entity
2 |
3 | data class OpenSourceEntity(
4 | val name: String,
5 | val url: String,
6 | val license: String,
7 | ) {
8 | companion object {
9 | val openSourceList = listOf(
10 | OpenSourceEntity(
11 | "Firebase",
12 | "https://firebase.google.com/terms",
13 | "Apache License"
14 | ),
15 | OpenSourceEntity(
16 | "glide",
17 | "https://github.com/bumptech/glide/blob/master/LICENSE",
18 | "Apache License"
19 | ),
20 | OpenSourceEntity(
21 | "okhttp",
22 | "https://github.com/square/okhttp/blob/master/LICENSE.txt",
23 | "Apache License"
24 | ),
25 | OpenSourceEntity(
26 | "retrofit",
27 | "https://github.com/square/retrofit/blob/master/LICENSE.txt",
28 | "Apache License"
29 | ),
30 | OpenSourceEntity(
31 | "gson",
32 | "https://github.com/google/gson/blob/master/LICENSE",
33 | "Apache License"
34 | ),
35 | OpenSourceEntity(
36 | "AndroidViewAnimations",
37 | "https://github.com/daimajia/AndroidViewAnimations/blob/master/License",
38 | "MIT License"
39 | ),
40 | OpenSourceEntity(
41 | "lottie",
42 | "https://github.com/airbnb/lottie-android/blob/master/LICENSE",
43 | "Apache License"
44 | ),
45 | OpenSourceEntity(
46 | "MaterialCalendarView",
47 | "https://github.com/prolificinteractive/material-calendarview/blob/master/LICENSE",
48 | "MIT License"
49 | ),
50 | OpenSourceEntity(
51 | "CalendarView",
52 | "https://github.com/kizitonwose/CalendarView/blob/master/LICENSE.md",
53 | "MIT License"
54 | ),
55 | OpenSourceEntity(
56 | "flexbox-layout",
57 | "https://github.com/google/flexbox-layout/blob/main/LICENSE",
58 | "Apache License"
59 | ),
60 | )
61 | }
62 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/dongyang/android/youdongknowme/standard/util/Mapping.kt:
--------------------------------------------------------------------------------
1 | package com.dongyang.android.youdongknowme.standard.util
2 |
3 | fun mapKeywordEnglishToKorean(english: String): String {
4 | return when (english) {
5 | "exam" -> "시험"
6 | "signup" -> "수강"
7 | "speciallecture" -> "특강"
8 | "seasonalsemester" -> "계절학기"
9 | "leaveofabsence" -> "휴학"
10 | "returntoschool" -> "복학"
11 | "graduate" -> "졸업"
12 | "switchmajors" -> "전과"
13 | "givingupthesemester" -> "학기포기"
14 | "scholarship" -> "장학"
15 | "nationalscholarship" -> "국가장학"
16 | "registration" -> "등록"
17 | "employment" -> "채용"
18 | "contest" -> "공모전"
19 | "competition" -> "대회"
20 | "fieldtraining" -> "현장실습"
21 | "volunteer" -> "봉사"
22 | "dormitory" -> "기숙사"
23 | "group" -> "동아리"
24 | "studentcouncil" -> "학생회"
25 | else -> throw IllegalArgumentException("올바른 타입이 아닙니다.")
26 | }
27 | }
28 |
29 | fun mapDepartmentKoreanToCode(department: String): Int {
30 | return when (department) {
31 | "동양미래대학교" -> CODE.SCHOOL_CODE
32 | "기계공학과" -> CODE.MECHANICAL_ENGINE_CODE
33 | "기계설계공학과" -> CODE.MECHANICAL_DESIGN_CODE
34 | "자동화공학과" -> CODE.AUTOMATION_ENGINE_CODE
35 | "로봇소프트웨어과" -> CODE.ROBOT_SOFTWARE_CODE
36 | "컴퓨터소프트웨어공학과" -> CODE.COMPUTER_SOFTWARE_ENGINE_CODE
37 | "웹응용소프트웨어공학과" -> CODE.WEB_APP_SOFTWARE_ENGINE_CODE
38 | "인공지능소프트웨어공학과" -> CODE.ARTIFICIAL_ENGINE_CODE
39 | "전기공학과" -> CODE.ELECTRICAL_ENGINE_CODE
40 | "정보전자공학과" -> CODE.INFO_ELECTRONIC_ENGINE_CODE
41 | "반도체전자공학과" -> CODE.SEMICONDUCTOR_ENGINE_CODE
42 | "정보통신공학과" -> CODE.INFO_COMMUNICATION_ENGINE_CODE
43 | "생명화학공학과" -> CODE.BIOCHEMICAL_ENGINE_CODE
44 | "바이오융합공학과" -> CODE.BIO_CONVERGENCE_ENGINE_CODE
45 | "건축과" -> CODE.ARCHITECTURE_CODE
46 | "실내건축디자인과" -> CODE.INTERIOR_DESIGN_CODE
47 | "시각디자인과" -> CODE.VISUAL_DESIGN_CODE
48 | "경영학과" -> CODE.BUSINESS_ADMINISTRATION_CODE
49 | "세무회계학과" -> CODE.TAX_ACCOUNTING_CODE
50 | "유통마케팅학과" -> CODE.DISTRIBUTION_MARKETING_CODE
51 | "호텔관광학과" -> CODE.HOTEL_TOURISM_CODE
52 | "경영정보학과" -> CODE.MANAGEMENT_INFORMATION_CODE
53 | "빅데이터경영과" -> CODE.BIG_DATA_MANAGEMENT_CODE
54 | "자유전공학과" -> CODE.LIBERAL_MAJOR_CODE
55 | else -> throw IllegalArgumentException("올바른 타입이 아닙니다.")
56 | }
57 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/dongyang/android/youdongknowme/standard/base/BaseFragment.kt:
--------------------------------------------------------------------------------
1 | package com.dongyang.android.youdongknowme.standard.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.databinding.DataBindingUtil
8 | import androidx.databinding.ViewDataBinding
9 | import androidx.fragment.app.Fragment
10 | import com.dongyang.android.youdongknowme.ui.view.LoadingDialog
11 | import com.dongyang.android.youdongknowme.ui.view.util.toast
12 |
13 | abstract class BaseFragment : Fragment() {
14 |
15 | private var _binding: T? = null
16 | val binding get() = _binding!!
17 | abstract val layoutResourceId: Int
18 | abstract val viewModel: R
19 |
20 | private val loadingDialog: LoadingDialog by lazy {
21 | LoadingDialog(requireActivity())
22 | }
23 |
24 | override fun onCreateView(
25 | inflater: LayoutInflater,
26 | container: ViewGroup?,
27 | savedInstanceState: Bundle?
28 | ): View? {
29 | _binding = DataBindingUtil.inflate(inflater, layoutResourceId, container, false)
30 |
31 | return binding.root
32 | }
33 |
34 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
35 | super.onViewCreated(view, savedInstanceState)
36 | binding.lifecycleOwner = viewLifecycleOwner
37 |
38 | initStartView()
39 | initDataBinding()
40 | initAfterBinding()
41 | }
42 |
43 | override fun onDestroyView() {
44 | super.onDestroyView()
45 | _binding = null
46 | }
47 |
48 | protected fun showToast(message: String) {
49 | requireActivity().applicationContext.toast(message)
50 | }
51 |
52 |
53 | protected fun showLoading() {
54 | loadingDialog.show()
55 | }
56 |
57 | protected fun dismissLoading() {
58 | loadingDialog.dismiss()
59 | }
60 |
61 | /**
62 | * 레이아웃을 띄운 직후 호출.
63 | * 뷰나 액티비티의 속성 등을 초기화.
64 | * ex) 리사이클러뷰, 툴바, 드로어뷰.
65 | */
66 |
67 | abstract fun initStartView()
68 |
69 | /**
70 | * 두번째로 호출.
71 | * 데이터 바인딩 및 rxjava 설정.
72 | * ex) rxjava observe, databinding observe..
73 | */
74 |
75 | abstract fun initDataBinding()
76 |
77 | /**
78 | * 바인딩 이후에 할 일을 여기에 구현.
79 | * 그 외에 설정할 것이 있으면 이곳에서 설정.
80 | * 클릭 리스너도 이곳에서 설정.
81 | */
82 |
83 | abstract fun initAfterBinding()
84 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/dongyang/android/youdongknowme/ui/view/depart/DepartActivity.kt:
--------------------------------------------------------------------------------
1 | package com.dongyang.android.youdongknowme.ui.view.depart
2 |
3 | import androidx.recyclerview.widget.LinearLayoutManager
4 | import com.dongyang.android.youdongknowme.R
5 | import com.dongyang.android.youdongknowme.databinding.ActivityDepartBinding
6 | import com.dongyang.android.youdongknowme.standard.base.BaseActivity
7 | import com.dongyang.android.youdongknowme.ui.adapter.DepartAdapter
8 | import org.koin.androidx.viewmodel.ext.android.viewModel
9 |
10 | class DepartActivity : BaseActivity(), DepartClickListener {
11 |
12 | override val layoutResourceId: Int = R.layout.activity_depart
13 | override val viewModel: DepartViewModel by viewModel()
14 | private lateinit var adapter: DepartAdapter
15 | private lateinit var items: ArrayList
16 |
17 | override fun initStartView() {
18 | // 학과 리스트
19 | items =
20 | resources.getStringArray(R.array.dmu_department_list).toCollection(ArrayList())
21 |
22 | adapter = DepartAdapter().apply {
23 | submitList(items)
24 | setItemClickListener(this@DepartActivity)
25 | }
26 |
27 | binding.rvDepart.apply {
28 | this.adapter = this@DepartActivity.adapter
29 | this.layoutManager = LinearLayoutManager(this@DepartActivity)
30 | this.setHasFixedSize(true)
31 | }
32 | }
33 |
34 | override fun initDataBinding() {
35 | viewModel.myDepartment.observe(this) { department ->
36 | viewModel.setSelectPosition(items.indexOf(department))
37 | }
38 | }
39 |
40 | override fun initAfterBinding() {
41 | viewModel.selectDepartPosition.observe(this) {
42 | adapter.submitPosition(it)
43 |
44 | if (it != -1) getDepart(items)
45 | }
46 |
47 | binding.toolbarDepart.btnToolbarExit.setOnClickListener { finish() }
48 | }
49 |
50 | // 컨테이너 클릭 시 선택한 학과의 포지션 저장
51 | override fun containerClick(position: Int) {
52 | viewModel.setSelectPosition(position)
53 | }
54 |
55 | // 확인 버튼을 누르면 내부 DB에 학과를 담고 메인 액티비티로 이동
56 | private fun getDepart(items: ArrayList) {
57 | return binding.btnDepartComplete.setOnClickListener {
58 | viewModel.setDepartment(items[viewModel.selectDepartPosition.value ?: 0])
59 | setResult(RESULT_OK)
60 | finish()
61 | }
62 | }
63 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/dongyang/android/youdongknowme/ui/view/keyword/KeywordViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.dongyang.android.youdongknowme.ui.view.keyword
2 |
3 | import androidx.lifecycle.LiveData
4 | import androidx.lifecycle.MutableLiveData
5 | import androidx.lifecycle.viewModelScope
6 | import com.dongyang.android.youdongknowme.data.local.entity.KeywordEntity
7 | import com.dongyang.android.youdongknowme.data.repository.KeywordRepository
8 | import com.dongyang.android.youdongknowme.standard.base.BaseViewModel
9 | import kotlinx.coroutines.launch
10 |
11 | class KeywordViewModel(
12 | private val keywordRepository: KeywordRepository
13 | ) : BaseViewModel() {
14 |
15 | private val _localKeywordList: MutableLiveData> = MutableLiveData()
16 | val localKeywordList: LiveData> get() = _localKeywordList
17 |
18 | private val _checkKeywordList = MutableLiveData>(mutableSetOf())
19 | val checkKeywordList: LiveData> get() = _checkKeywordList
20 |
21 | fun getLocalKeywordList() {
22 | viewModelScope.launch {
23 | keywordRepository.getUserKeywords().collect { keywordList ->
24 | _localKeywordList.postValue(keywordList)
25 | }
26 | }
27 | }
28 |
29 | fun subscribeCheckedKeyword() {
30 | for (localKeyword in localKeywordList.value ?: emptyList()) {
31 | if (checkKeywordList.value?.contains(localKeyword.name) == true) {
32 | // 선택했던 데이터를 중첩해서 바꾸면 효율성이 떨어지고, 파이어베이스 구독에 문제가 생길 수 있으므로 구독 여부도 함께 체크
33 | if (!localKeyword.isSubscribe) {
34 | viewModelScope.launch {
35 | keywordRepository.updateUserKeywords(true, localKeyword.name)
36 | }
37 | }
38 | } else {
39 | if (localKeyword.isSubscribe) {
40 | viewModelScope.launch {
41 | keywordRepository.updateUserKeywords(false, localKeyword.name)
42 | }
43 | }
44 | }
45 | }
46 | }
47 |
48 | fun setAllKeywords(keyword: List) {
49 | _checkKeywordList.value = keyword.toSet()
50 | }
51 |
52 | fun setCheckedKeywords(keyword: String) {
53 | _checkKeywordList.value = _checkKeywordList.value?.plus(keyword) ?: setOf(keyword)
54 | }
55 |
56 | fun removeCheckedKeywords(keyword: String) {
57 | _checkKeywordList.value = _checkKeywordList.value?.minus(keyword) ?: setOf()
58 | }
59 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/dongyang/android/youdongknowme/data/repository/NoticeRepository.kt:
--------------------------------------------------------------------------------
1 | package com.dongyang.android.youdongknowme.data.repository
2 |
3 | import com.dongyang.android.youdongknowme.data.local.SharedPreference
4 | import com.dongyang.android.youdongknowme.data.remote.entity.Notice
5 | import com.dongyang.android.youdongknowme.data.remote.service.NoticeService
6 | import com.dongyang.android.youdongknowme.standard.network.ErrorResponseHandler
7 | import com.dongyang.android.youdongknowme.standard.network.NetworkResult
8 | import com.dongyang.android.youdongknowme.standard.network.RetrofitObject
9 |
10 | class NoticeRepository(
11 | private val errorResponseHandler: ErrorResponseHandler
12 | ) {
13 |
14 | fun getUserDepartment(): String {
15 | return SharedPreference.getDepartment()
16 | }
17 |
18 | suspend fun fetchUniversityNotices(page: Int): NetworkResult> {
19 | return try {
20 | val universityNotices = RetrofitObject.getNetwork().create(NoticeService::class.java)
21 | .getUniversityNotice(page, DEFAULT_SIZE)
22 |
23 | NetworkResult.Success(universityNotices)
24 | } catch (exception: Exception) {
25 | val error = errorResponseHandler.getError(exception)
26 | NetworkResult.Error(error)
27 | }
28 | }
29 |
30 | suspend fun fetchDepartmentNotices(
31 | page: Int
32 | ): NetworkResult> {
33 | return try {
34 | val departmentNotices = RetrofitObject.getNetwork().create(NoticeService::class.java)
35 | .getDepartmentNotice(getUserDepartment(), page, DEFAULT_SIZE)
36 | NetworkResult.Success(departmentNotices)
37 | } catch (exception: Exception) {
38 | val error = errorResponseHandler.getError(exception)
39 | NetworkResult.Error(error)
40 | }
41 | }
42 |
43 | suspend fun fetchSearchNotices(
44 | searchWord: String,
45 | page: Int
46 | ): NetworkResult> {
47 | return try {
48 | val searchNotices = RetrofitObject.getNetwork().create(NoticeService::class.java)
49 | .getSearchNotice(searchWord, getUserDepartment(), page, DEFAULT_SIZE)
50 | NetworkResult.Success(searchNotices)
51 | } catch (exception: Exception) {
52 | val error = errorResponseHandler.getError(exception)
53 | NetworkResult.Error(error)
54 | }
55 | }
56 |
57 | companion object {
58 | private const val DEFAULT_SIZE = 20
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_cafeteria_another.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
10 |
15 |
16 |
22 |
23 |
24 |
29 |
30 |
37 |
38 |
44 |
45 |
52 |
53 |
54 |
55 |
56 |
57 |
60 |
61 |
64 |
65 |
68 |
69 |
--------------------------------------------------------------------------------
/app/src/main/java/com/dongyang/android/youdongknowme/ui/view/cafeteria/CafeteriaContainer.kt:
--------------------------------------------------------------------------------
1 | package com.dongyang.android.youdongknowme.ui.view.cafeteria
2 |
3 | import android.view.View
4 | import androidx.core.content.ContextCompat
5 | import com.dongyang.android.youdongknowme.R
6 | import com.dongyang.android.youdongknowme.databinding.ItemCalendarDayBinding
7 | import com.kizitonwose.calendarview.CalendarView
8 | import com.kizitonwose.calendarview.model.CalendarDay
9 | import com.kizitonwose.calendarview.ui.ViewContainer
10 | import java.time.LocalDate
11 | import java.time.format.DateTimeFormatter
12 |
13 | class CafeteriaContainer(
14 | view: View,
15 | private val calendarView: CalendarView,
16 | private val viewModel: CafeteriaViewModel,
17 | ) : ViewContainer(view), CalendarInterface {
18 |
19 | private val bind = ItemCalendarDayBinding.bind(view)
20 | private lateinit var day: CalendarDay
21 |
22 | private val dateFormatter = DateTimeFormatter.ofPattern("d")
23 | private val dayFormatter = DateTimeFormatter.ofPattern("EEE")
24 | private val monthFormatter = DateTimeFormatter.ofPattern("MMM")
25 |
26 | init {
27 | view.setOnClickListener {
28 | viewModel.selectedDate.value?.let { selectedDate ->
29 | if (selectedDate != day.date) {
30 | notifyDateChanged(viewModel, calendarView, selectedDate, day.date)
31 | }
32 | }
33 | }
34 | }
35 |
36 | fun bind(day: CalendarDay) {
37 | this.day = day
38 | bind.apply {
39 | tvItemCalendarDate.text = dateFormatter.format(day.date)
40 | tvItemCalendarDay.text = dayFormatter.format(day.date)
41 | tvItemCalendarMonth.text = monthFormatter.format(day.date)
42 | }
43 |
44 | val (bgColor, textColor) = when (day.date) {
45 | viewModel.selectedDate.value -> R.color.blue300 to R.color.white
46 | LocalDate.now() -> R.color.gray200 to R.color.gray500
47 | else -> R.color.white to R.color.gray500
48 | }
49 |
50 | bind.mvItemCalendarContainer.setCardBackgroundColor(
51 | ContextCompat.getColor(
52 | view.context,
53 | bgColor
54 | )
55 | )
56 | setTextColor(textColor)
57 | }
58 |
59 | private fun setTextColor(colorRes: Int) {
60 | val color = ContextCompat.getColor(view.context, colorRes)
61 |
62 | bind.apply {
63 | tvItemCalendarDate.setTextColor(color)
64 | tvItemCalendarDay.setTextColor(color)
65 | tvItemCalendarMonth.setTextColor(color)
66 | }
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/app/src/main/java/com/dongyang/android/youdongknowme/data/local/SharedPreference.kt:
--------------------------------------------------------------------------------
1 | package com.dongyang.android.youdongknowme.data.local
2 |
3 | import android.app.Application
4 | import android.content.Context
5 | import android.content.SharedPreferences
6 | import com.dongyang.android.youdongknowme.R
7 |
8 | object SharedPreference {
9 | private var pref: SharedPreferences? = null
10 |
11 | fun getInstance(context: Context): SharedPreference {
12 | if (pref == null) {
13 | pref = context.getSharedPreferences(
14 | context.getString(R.string.shared_pref_key),
15 | Application.MODE_PRIVATE
16 | )
17 | }
18 | return this
19 | }
20 |
21 | // 학과 설정
22 | private const val DEPARTMENT = "DEPARTMENT"
23 | fun getDepartment(): String = pref?.getString(DEPARTMENT, "") ?: ""
24 | fun setDepartment(department: String) = pref?.edit()?.putString(DEPARTMENT, department)?.apply()
25 |
26 | // 학과 코드 설정
27 | private const val CODE = "CODE"
28 | fun getCode(): Int = pref?.getInt(CODE, 0) ?: 0
29 | fun setCode(code: Int) = pref?.edit()?.putInt(CODE, code)?.apply()
30 |
31 | // 학사 일정
32 | private const val SCHEDULE = "SCHEDULE"
33 | const val NO_SCHEDULE = "NO DATA"
34 | fun getSchedule(): String = pref?.getString(SCHEDULE, NO_SCHEDULE) ?: NO_SCHEDULE
35 | fun setSchedule(schedule: String) = pref?.edit()?.putString(SCHEDULE, schedule)?.apply()
36 |
37 | // 최초 접속 여부
38 | private const val FIRST_LAUNCH = "FIRST_LAUNCH"
39 | fun getIsFirstLaunch(): Boolean = pref?.getBoolean(FIRST_LAUNCH, true) ?: true
40 | fun setIsFirstLaunch(isFirstLaunch: Boolean) =
41 | pref?.edit()?.putBoolean(FIRST_LAUNCH, isFirstLaunch)?.apply()
42 |
43 | // 학교 알림 설정 여부
44 | private const val ACCESS_SCHOOL_ALARM = "ACCESS_SCHOOL_ALARM"
45 | fun getIsAccessSchoolAlarm(): Boolean = pref?.getBoolean(ACCESS_SCHOOL_ALARM, true) ?: true
46 | fun setIsAccessSchoolAlarm(isAccessSchoolAlarm: Boolean) =
47 | pref?.edit()?.putBoolean(ACCESS_SCHOOL_ALARM, isAccessSchoolAlarm)?.apply()
48 |
49 | // 학과 알림 설정 여부
50 | private const val ACCESS_DEPART_ALARM = "ACCESS_DEPART_ALARM"
51 | fun getIsAccessDepartAlarm(): Boolean = pref?.getBoolean(ACCESS_DEPART_ALARM, true) ?: true
52 | fun setIsAccessDepartAlarm(isAccessDepartAlarm: Boolean) =
53 | pref?.edit()?.putBoolean(ACCESS_DEPART_ALARM, isAccessDepartAlarm)?.apply()
54 |
55 | // FCM 토큰
56 | private const val FCM_TOKEN = "NO_TOKEN"
57 | fun getFCMToken(): String = pref?.getString(FCM_TOKEN, "0") ?: "0"
58 | fun setFcmToken(token: String) = pref?.edit()?.putString(FCM_TOKEN, token)?.apply()
59 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_menu_calendar.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_notice.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
11 |
12 |
24 |
25 |
39 |
40 |
51 |
52 |
59 |
60 |
--------------------------------------------------------------------------------
/app/src/main/java/com/dongyang/android/youdongknowme/data/repository/CafeteriaRepository.kt:
--------------------------------------------------------------------------------
1 | package com.dongyang.android.youdongknowme.data.repository
2 |
3 | import com.dongyang.android.youdongknowme.data.remote.entity.Cafeteria
4 | import com.dongyang.android.youdongknowme.data.remote.service.CafeteriaService
5 | import com.dongyang.android.youdongknowme.standard.network.ErrorResponseHandler
6 | import com.dongyang.android.youdongknowme.standard.network.NetworkResult
7 | import com.dongyang.android.youdongknowme.standard.network.RetrofitObject
8 | import com.dongyang.android.youdongknowme.standard.util.Weekdays
9 |
10 | class CafeteriaRepository(
11 | private val errorResponseHandler: ErrorResponseHandler
12 | ) {
13 | suspend fun fetchMenuList(): NetworkResult> {
14 | return try {
15 | val response =
16 | RetrofitObject.getNetwork().create(CafeteriaService::class.java).getMenuList()
17 | NetworkResult.Success(response)
18 | } catch (exception: Exception) {
19 | val error = errorResponseHandler.getError(exception)
20 | NetworkResult.Error(error)
21 | }
22 | }
23 |
24 | fun fetchDaysMenus(todayDay: Weekdays): List {
25 | return DaysMenu.values().filter { menu ->
26 | menu.operatingDays.contains(todayDay)
27 | }
28 | }
29 |
30 | enum class DaysMenu(
31 | val menuNameKr: String,
32 | val price: Int,
33 | val operatingDays: List,
34 | ) {
35 | SPAM_KIMCHI_FRIED_RICE("스팸 김치 볶음밥", 4_900, listOf(Weekdays.MONDAY, Weekdays.TUESDAY)),
36 | CHICKEN_MAYO_RICE("치킨 마요 덮밥", 4_900, listOf(Weekdays.WEDNESDAY)),
37 | SPICY_MAYO_RICE("불닭 마요 덮밥", 4_900, listOf(Weekdays.WEDNESDAY)),
38 | PORK_BELLY_RICE("삼겹살 덮밥", 5_500, listOf(Weekdays.THURSDAY)),
39 | JANGJORIM_BUTTER_RICE("장조림 버터 비빔밥", 4_500, listOf(Weekdays.FRIDAY)),
40 |
41 | RAMEN("라면", 3_500, Weekdays.values().toList()),
42 | CHEESE_RAMEN("치즈 라면", 4_000, Weekdays.values().toList()),
43 | SEAFOOD_RAMEN("해물짬뽕 라면", 4_500, Weekdays.values().toList()),
44 |
45 | CHAPAGETTI("짜파게티", 3_500, Weekdays.values().toList()),
46 | CHAPAGETTI_EGG_CHEESE("짜계치", 4_000, Weekdays.values().toList()),
47 | SPICY_RAMEN("불닭볶음면", 3_500, Weekdays.values().toList()),
48 | CARBONARA_SPICY_RAMEN("까르보 불닭볶음면", 3_800, Weekdays.values().toList()),
49 | CHEESE_SPICY_RAMEN("치즈 불닭볶음면", 4_000, Weekdays.values().toList()),
50 |
51 | PORK_CUTLET("돈까스", 5_000, Weekdays.values().toList()),
52 | CHEESE_PORK_CUTLET("치즈 돈까스", 5_500, Weekdays.values().toList()),
53 | BRISKET_CHICKEN_CUTLET("통가슴살 치킨까스", 5_200, Weekdays.values().toList()),
54 | SWEET_POTATO_CHEESE_PORK_CUTLET("고구마 치즈 돈까스", 6_000, Weekdays.values().toList()),
55 | HOMEMADE_KING_PORK_CUTLET("수제 왕 돈까스", 6_000, Weekdays.values().toList()),
56 | }
57 | }
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_calendar_day.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 |
9 |
10 |
21 |
22 |
29 |
30 |
39 |
40 |
49 |
50 |
59 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/dialog_permission.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
22 |
23 |
37 |
38 |
51 |
52 |
63 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/standard_toolbar.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
9 |
10 |
25 |
26 |
39 |
40 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
63 |
64 |
67 |
68 |
71 |
72 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%"=="" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%"=="" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 |
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 |
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 |
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if %ERRORLEVEL% equ 0 goto execute
44 |
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 |
51 | goto fail
52 |
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 |
57 | if exist "%JAVA_EXE%" goto execute
58 |
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 |
65 | goto fail
66 |
67 | :execute
68 | @rem Setup the command line
69 |
70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
71 |
72 |
73 | @rem Execute Gradle
74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
75 |
76 | :end
77 | @rem End local scope for the variables with windows NT shell
78 | if %ERRORLEVEL% equ 0 goto mainEnd
79 |
80 | :fail
81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
82 | rem the _cmd.exe /c_ return code!
83 | set EXIT_CODE=%ERRORLEVEL%
84 | if %EXIT_CODE% equ 0 set EXIT_CODE=1
85 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
86 | exit /b %EXIT_CODE%
87 |
88 | :mainEnd
89 | if "%OS%"=="Windows_NT" endlocal
90 |
91 | :omega
92 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
6 |
10 |
13 |
16 |
19 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_schedule.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
10 |
11 |
20 |
21 |
32 |
33 |
45 |
46 |
55 |
56 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
71 |
72 |
73 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
9 |
10 |
13 |
14 |
23 |
26 |
29 |
32 |
36 |
39 |
42 |
45 |
48 |
51 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
64 |
68 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_detail.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
9 |
10 |
17 |
18 |
32 |
33 |
45 |
46 |
57 |
58 |
59 |
60 |
68 |
69 |
--------------------------------------------------------------------------------
/app/src/main/java/com/dongyang/android/youdongknowme/ui/view/setting/OnboardingPermissionActivity.kt:
--------------------------------------------------------------------------------
1 | package com.dongyang.android.youdongknowme.ui.view.setting
2 |
3 | import android.Manifest
4 | import android.content.pm.PackageManager
5 | import android.content.res.ColorStateList
6 | import android.os.Build
7 | import androidx.core.content.ContextCompat
8 | import com.dongyang.android.youdongknowme.R
9 | import com.dongyang.android.youdongknowme.databinding.ActivityOnboardingPermissionBinding
10 | import com.dongyang.android.youdongknowme.standard.base.BaseActivity
11 | import com.dongyang.android.youdongknowme.ui.view.main.MainActivity
12 | import org.koin.androidx.viewmodel.ext.android.viewModel
13 |
14 | class OnboardingPermissionActivity :
15 | BaseActivity() {
16 |
17 | override val layoutResourceId: Int = R.layout.activity_onboarding_permission
18 | override val viewModel: SettingViewModel by viewModel()
19 |
20 | override fun initStartView() {
21 |
22 | setPermissionSwitch(false)
23 | setSpanText(binding.tvPermissionTitleMain, startIdx = 0, endIdx = 9)
24 |
25 | binding.btnPermissionComplete.setOnClickListener {
26 | val intent = MainActivity.createIntent(this@OnboardingPermissionActivity)
27 | startActivity(intent)
28 | finish()
29 | }
30 | }
31 |
32 | override fun initDataBinding() = Unit
33 |
34 | override fun initAfterBinding() {
35 | binding.switchPermission.setOnCheckedChangeListener { compoundButton, _ ->
36 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
37 | if (compoundButton.isChecked) {
38 | if (PackageManager.PERMISSION_GRANTED == ContextCompat.checkSelfPermission(
39 | this, Manifest.permission.POST_NOTIFICATIONS
40 | )
41 | ) {
42 | setPermissionSwitch(true)
43 | } else {
44 | val dialog = PermissionDialog(
45 | getString(R.string.dialog_permission_title),
46 | getString(R.string.dialog_permission_content),
47 | this.packageName
48 | )
49 | dialog.show(supportFragmentManager, "CustomDialog")
50 | }
51 | } else {
52 | setPermissionSwitch(false)
53 | }
54 | } else {
55 | if (compoundButton.isChecked) {
56 | setPermissionSwitch(true)
57 | } else {
58 | setPermissionSwitch(false)
59 | }
60 | }
61 | }
62 | }
63 |
64 | private fun setPermissionSwitch(isChecked: Boolean) {
65 | val resources = if (isChecked) {
66 | R.color.blue300
67 | } else {
68 | R.color.gray400
69 | }
70 |
71 | binding.switchPermission.compoundDrawableTintList =
72 | ColorStateList.valueOf(ContextCompat.getColor(this, resources))
73 | binding.switchPermission.setTextColor(getColor(resources))
74 | binding.mvSwitchPermission.strokeColor = getColor(resources)
75 | viewModel.setIsAccessUniversityAlarm(isChecked)
76 | viewModel.setIsAccessDepartAlarm(isChecked)
77 | }
78 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/dongyang/android/youdongknowme/standard/base/BaseActivity.kt:
--------------------------------------------------------------------------------
1 | package com.dongyang.android.youdongknowme.standard.base
2 |
3 | import android.os.Bundle
4 | import android.text.Spannable
5 | import android.text.SpannableStringBuilder
6 | import android.text.style.ForegroundColorSpan
7 | import android.widget.TextView
8 | import androidx.activity.enableEdgeToEdge
9 | import androidx.appcompat.app.AppCompatActivity
10 | import androidx.core.view.ViewCompat
11 | import androidx.core.view.WindowInsetsCompat
12 | import androidx.core.view.updatePadding
13 | import androidx.databinding.DataBindingUtil
14 | import androidx.databinding.ViewDataBinding
15 | import com.dongyang.android.youdongknowme.ui.view.LoadingDialog
16 | import com.dongyang.android.youdongknowme.ui.view.util.toast
17 |
18 | abstract class BaseActivity : AppCompatActivity() {
19 |
20 | lateinit var binding: T
21 | abstract val layoutResourceId: Int
22 | abstract val viewModel: R
23 |
24 | private val loadingDialog: LoadingDialog by lazy {
25 | LoadingDialog(this)
26 | }
27 |
28 | override fun onCreate(savedInstanceState: Bundle?) {
29 | super.onCreate(savedInstanceState)
30 | enableEdgeToEdge()
31 | binding = DataBindingUtil.setContentView(this, layoutResourceId)
32 | binding.lifecycleOwner = this
33 | setContentView(binding.root)
34 |
35 | ViewCompat.setOnApplyWindowInsetsListener(binding.root) { v, insets ->
36 | val inset = insets.getInsets(WindowInsetsCompat.Type.systemBars())
37 | v.updatePadding(
38 | top = inset.top,
39 | bottom = inset.bottom,
40 | left = inset.left,
41 | right = inset.right,
42 | )
43 | insets
44 | }
45 | initStartView()
46 | initDataBinding()
47 | initAfterBinding()
48 | }
49 |
50 | protected fun setSpanText(
51 | spanTextView: TextView,
52 | startIdx: Int,
53 | endIdx: Int,
54 | ) {
55 | SpannableStringBuilder(spanTextView.text).apply {
56 | setSpan(
57 | ForegroundColorSpan(getColor(com.dongyang.android.youdongknowme.R.color.blue300)),
58 | startIdx,
59 | endIdx,
60 | Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
61 | )
62 | spanTextView.text = this
63 | }
64 | }
65 |
66 | protected fun showToast(message: String) {
67 | applicationContext.toast(message)
68 | }
69 |
70 |
71 | protected fun showLoading() {
72 | loadingDialog.show()
73 | }
74 |
75 | protected fun dismissLoading() {
76 | loadingDialog.dismiss()
77 | }
78 |
79 | protected fun configureToolbar() {
80 | TODO()
81 | }
82 |
83 | /**
84 | * 레이아웃을 띄운 직후 호출.
85 | * 뷰나 액티비티의 속성 등을 초기화.
86 | * ex) 리사이클러뷰, 툴바, 드로어뷰.
87 | */
88 |
89 | abstract fun initStartView()
90 |
91 | /**
92 | * 두번째로 호출.
93 | * 데이터 바인딩 및 rxjava 설정.
94 | * ex) rxjava observe, databinding observe..
95 | */
96 |
97 | abstract fun initDataBinding()
98 |
99 | /**
100 | * 바인딩 이후에 할 일을 여기에 구현.
101 | * 그 외에 설정할 것이 있으면 이곳에서 설정.
102 | * 클릭 리스너도 이곳에서 설정.
103 | */
104 |
105 | abstract fun initAfterBinding()
106 |
107 | }
108 |
--------------------------------------------------------------------------------
/app/src/main/java/com/dongyang/android/youdongknowme/ui/view/schedule/ScheduleViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.dongyang.android.youdongknowme.ui.view.schedule
2 |
3 | import androidx.lifecycle.LiveData
4 | import androidx.lifecycle.MutableLiveData
5 | import androidx.lifecycle.viewModelScope
6 | import com.dongyang.android.youdongknowme.data.remote.entity.Schedule
7 | import com.dongyang.android.youdongknowme.data.remote.entity.ScheduleEntry
8 | import com.dongyang.android.youdongknowme.data.repository.ScheduleRepository
9 | import com.dongyang.android.youdongknowme.standard.base.BaseViewModel
10 | import com.dongyang.android.youdongknowme.standard.network.NetworkResult
11 | import com.dongyang.android.youdongknowme.ui.view.util.Event
12 | import com.prolificinteractive.materialcalendarview.CalendarDay
13 | import kotlinx.coroutines.launch
14 | import org.threeten.bp.LocalDate
15 | import java.util.Date
16 |
17 | /* 학사 일정 뷰모델 */
18 | class ScheduleViewModel(private val scheduleRepository: ScheduleRepository) : BaseViewModel() {
19 |
20 | private val _errorState: MutableLiveData> = MutableLiveData()
21 | val errorState: LiveData> = _errorState
22 |
23 | private val _isLoading: MutableLiveData = MutableLiveData()
24 | val isLoading: LiveData = _isLoading
25 |
26 | private val _isError: MutableLiveData = MutableLiveData()
27 | val isError: LiveData = _isError
28 |
29 | private val _scheduleList = MutableLiveData>()
30 | val scheduleList: LiveData> = _scheduleList
31 |
32 | private val _pickYear = MutableLiveData()
33 | val pickYear: LiveData = _pickYear
34 |
35 | private val _pickMonth = MutableLiveData()
36 | val pickMonth: LiveData = _pickMonth
37 |
38 | private var _currentYear = MutableLiveData()
39 | val currentYear: LiveData = _currentYear
40 |
41 | fun setPickedDate(date: CalendarDay) {
42 | _pickYear.value = date.year
43 | _pickMonth.value = date.month
44 | }
45 |
46 | fun setCurrentYear(date: LocalDate){
47 | _currentYear.value = date.year
48 | }
49 |
50 | fun getSchedules() {
51 | _isLoading.postValue(true)
52 | viewModelScope.launch {
53 | when (val result = scheduleRepository.fetchSchedules()) {
54 | is NetworkResult.Success -> {
55 | val scheduleList = result.data
56 |
57 | // 선택한 연월 조건에 따라 리스트 출력
58 | _scheduleList.postValue(getSchedulesForPickDate(scheduleList))
59 |
60 | _isError.postValue(false)
61 | _isLoading.postValue(false)
62 | }
63 |
64 | is NetworkResult.Error -> {
65 | handleError(result, _errorState)
66 | _isError.postValue(true)
67 | _isLoading.postValue(false)
68 | }
69 | }
70 | }
71 | }
72 |
73 | private fun getSchedulesForPickDate(list: List): List {
74 | return list
75 | .filter { schedule ->
76 | schedule.year == pickYear.value &&
77 | schedule.yearSchedules.any { it.month == pickMonth.value }
78 | }.flatMap { schedule ->
79 | schedule.yearSchedules
80 | .find { it.month == pickMonth.value }
81 | ?.scheduleEntries.orEmpty()
82 | }
83 | }
84 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/dongyang/android/youdongknowme/ui/view/main/MainViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.dongyang.android.youdongknowme.ui.view.main
2 |
3 | import androidx.lifecycle.LiveData
4 | import androidx.lifecycle.MutableLiveData
5 | import androidx.lifecycle.viewModelScope
6 | import com.dongyang.android.youdongknowme.data.remote.entity.Token
7 | import com.dongyang.android.youdongknowme.data.repository.MainRepository
8 | import com.dongyang.android.youdongknowme.standard.base.BaseViewModel
9 | import com.dongyang.android.youdongknowme.standard.network.NetworkResult
10 | import com.dongyang.android.youdongknowme.ui.view.util.Event
11 | import kotlinx.coroutines.launch
12 |
13 | class MainViewModel(private val mainRepository: MainRepository) : BaseViewModel() {
14 | private val _errorState: MutableLiveData> = MutableLiveData()
15 | val errorState: LiveData> = _errorState
16 |
17 | private val _isLoading: MutableLiveData = MutableLiveData()
18 | val isLoading: LiveData = _isLoading
19 |
20 | private val _isError: MutableLiveData = MutableLiveData()
21 | val isError: LiveData = _isError
22 |
23 | private val _myDepartment: MutableLiveData = MutableLiveData()
24 | val myDepartment: LiveData get() = _myDepartment
25 |
26 | private val _myTopics: MutableLiveData> = MutableLiveData()
27 | val myTopics: LiveData> get() = _myTopics
28 |
29 | private val _FCMToken: MutableLiveData = MutableLiveData()
30 | val FCMToken: LiveData get() = _FCMToken
31 |
32 | private val _isFirstLaunch: MutableLiveData = MutableLiveData(false)
33 | val isFirstLaunch: LiveData get() = _isFirstLaunch
34 |
35 | init {
36 | checkFirstLaunch()
37 | getUserDepart()
38 | getUserTopic()
39 | }
40 |
41 | private fun checkFirstLaunch() {
42 | if (mainRepository.getIsFirstLaunch()) {
43 | _isFirstLaunch.value = true
44 | }
45 | }
46 |
47 | private fun getUserDepart() {
48 | _myDepartment.value = mainRepository.getUserDepartment()
49 | }
50 |
51 | private fun getUserTopic() {
52 | viewModelScope.launch {
53 | _myTopics.value = mainRepository.getUserTopic()
54 | }
55 | }
56 |
57 | fun setFCMToken(token: String) {
58 | mainRepository.setFCMToken(token)
59 | _FCMToken.value = token
60 | }
61 |
62 | fun setIsFirstLaunch(boolean: Boolean) {
63 | mainRepository.setIsFirstLaunch(boolean)
64 | }
65 |
66 | fun setInitToken() {
67 | _isLoading.postValue(true)
68 |
69 | viewModelScope.launch {
70 | when (val result = mainRepository.setUserToken(
71 | Token(
72 | token = FCMToken.value.toString(),
73 | department = myDepartment.value ?: "",
74 | topics = myTopics.value ?: emptyList()
75 | )
76 | )) {
77 | is NetworkResult.Success -> {
78 | mainRepository.setIsFirstLaunch(false)
79 | _isFirstLaunch.postValue(false)
80 | _isLoading.postValue(false)
81 | _isError.postValue(false)
82 | }
83 |
84 | is NetworkResult.Error -> {
85 | handleError(result, _errorState)
86 | _isLoading.postValue(false)
87 | _isError.postValue(true)
88 | }
89 | }
90 | }
91 | }
92 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_logo_text.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
9 |
13 |
17 |
21 |
25 |
29 |
33 |
34 |
35 |
--------------------------------------------------------------------------------