├── app
├── .gitignore
├── src
│ ├── main
│ │ ├── assets
│ │ │ ├── 0.bmp
│ │ │ ├── 1.bmp
│ │ │ ├── 2.bmp
│ │ │ ├── 3.bmp
│ │ │ ├── 4.bmp
│ │ │ ├── 5.bmp
│ │ │ ├── 6.bmp
│ │ │ ├── 7.bmp
│ │ │ ├── 8.bmp
│ │ │ ├── 9.bmp
│ │ │ ├── a.bmp
│ │ │ ├── b.bmp
│ │ │ ├── c.bmp
│ │ │ ├── d.bmp
│ │ │ ├── e.bmp
│ │ │ ├── f.bmp
│ │ │ ├── g.bmp
│ │ │ ├── h.bmp
│ │ │ ├── i.bmp
│ │ │ ├── j.bmp
│ │ │ ├── k.bmp
│ │ │ ├── l.bmp
│ │ │ ├── m.bmp
│ │ │ ├── n.bmp
│ │ │ ├── o.bmp
│ │ │ ├── p.bmp
│ │ │ ├── q.bmp
│ │ │ ├── r.bmp
│ │ │ ├── s.bmp
│ │ │ ├── t.bmp
│ │ │ ├── u.bmp
│ │ │ ├── v.bmp
│ │ │ ├── w.bmp
│ │ │ ├── x.bmp
│ │ │ ├── y.bmp
│ │ │ └── z.bmp
│ │ ├── res
│ │ │ ├── mipmap-hdpi
│ │ │ │ ├── logo.png
│ │ │ │ └── logo_round.png
│ │ │ ├── mipmap-mdpi
│ │ │ │ ├── logo.png
│ │ │ │ └── logo_round.png
│ │ │ ├── mipmap-xhdpi
│ │ │ │ ├── logo.png
│ │ │ │ └── logo_round.png
│ │ │ ├── mipmap-xxhdpi
│ │ │ │ ├── logo.png
│ │ │ │ └── logo_round.png
│ │ │ ├── mipmap-xxxhdpi
│ │ │ │ ├── logo.png
│ │ │ │ └── logo_round.png
│ │ │ ├── drawable-nodpi
│ │ │ │ ├── seekbar_thumb.png
│ │ │ │ ├── side_nav_bar.webp
│ │ │ │ ├── login_background.webp
│ │ │ │ ├── notification_icon.png
│ │ │ │ ├── today_widget_4_2.webp
│ │ │ │ ├── splash_background.webp
│ │ │ │ └── this_week_background.webp
│ │ │ ├── values
│ │ │ │ ├── attrs.xml
│ │ │ │ ├── dimens.xml
│ │ │ │ ├── colors.xml
│ │ │ │ ├── styles.xml
│ │ │ │ ├── strings.xml
│ │ │ │ └── arrays.xml
│ │ │ ├── xml
│ │ │ │ ├── file_paths.xml
│ │ │ │ ├── network_security_config.xml
│ │ │ │ └── widget_provider_today_4_2.xml
│ │ │ ├── layout
│ │ │ │ ├── drawer_switch.xml
│ │ │ │ ├── activity_custom.xml
│ │ │ │ ├── fragment_check_score.xml
│ │ │ │ ├── widget_layout_item.xml
│ │ │ │ ├── fragment_check_score_show.xml
│ │ │ │ ├── activity_splash.xml
│ │ │ │ ├── activity_setting.xml
│ │ │ │ ├── nav_header_main.xml
│ │ │ │ ├── content_main.xml
│ │ │ │ ├── widget_layout_today.xml
│ │ │ │ ├── fragment_class_schedule.xml
│ │ │ │ ├── app_bar_main.xml
│ │ │ │ ├── activity_main.xml
│ │ │ │ ├── preference_dialog_layout.xml
│ │ │ │ ├── view_range.xml
│ │ │ │ ├── activity_login.xml
│ │ │ │ ├── activity_share.xml
│ │ │ │ ├── item_score_rv.xml
│ │ │ │ ├── fragment_this_week.xml
│ │ │ │ ├── fragment_check_score_login.xml
│ │ │ │ ├── widget_layout_item_draw.xml
│ │ │ │ ├── item_class_rv.xml
│ │ │ │ ├── fragment_today.xml
│ │ │ │ └── activity_about.xml
│ │ │ ├── menu
│ │ │ │ ├── activity_custom_menu.xml
│ │ │ │ ├── main.xml
│ │ │ │ └── activity_main_drawer.xml
│ │ │ └── drawable
│ │ │ │ ├── baseline_done_24.xml
│ │ │ │ ├── baseline_today_24.xml
│ │ │ │ ├── baseline_brightness_4_24.xml
│ │ │ │ ├── baseline_score_24.xml
│ │ │ │ └── baseline_settings_applications_24.xml
│ │ ├── java
│ │ │ └── top
│ │ │ │ └── itning
│ │ │ │ └── yunshuclassschedule
│ │ │ │ ├── util
│ │ │ │ ├── Glide4Modle.kt
│ │ │ │ ├── EventReceiver.kt
│ │ │ │ ├── ImageHash.kt
│ │ │ │ ├── Glide4Engine.kt
│ │ │ │ ├── FileUtils.kt
│ │ │ │ └── NetWorkUtils.kt
│ │ │ │ ├── ui
│ │ │ │ ├── widget
│ │ │ │ │ ├── TodayRemoteViewsService.kt
│ │ │ │ │ ├── TodayWidgetProvider.kt
│ │ │ │ │ └── ToadyRemoteViewsFactory.kt
│ │ │ │ ├── view
│ │ │ │ │ └── RoundBackChange.kt
│ │ │ │ ├── adapter
│ │ │ │ │ ├── ScoreRecyclerViewAdapter.kt
│ │ │ │ │ └── TodayRecyclerViewAdapter.kt
│ │ │ │ ├── fragment
│ │ │ │ │ ├── checkscore
│ │ │ │ │ │ └── CheckScoreShowFragment.kt
│ │ │ │ │ ├── CheckScoreFragment.kt
│ │ │ │ │ ├── ClassScheduleFragment.kt
│ │ │ │ │ ├── ThisWeekFragment.kt
│ │ │ │ │ └── setting
│ │ │ │ │ │ └── SettingsFragment.kt
│ │ │ │ └── activity
│ │ │ │ │ ├── AboutActivity.kt
│ │ │ │ │ ├── SettingActivity.kt
│ │ │ │ │ ├── SplashActivity.kt
│ │ │ │ │ └── LoginActivity.kt
│ │ │ │ ├── entity
│ │ │ │ ├── EventEntity.kt
│ │ │ │ ├── Hash.java
│ │ │ │ ├── DataEntity.java
│ │ │ │ ├── Score.java
│ │ │ │ └── ClassSchedule.java
│ │ │ │ ├── receiver
│ │ │ │ ├── TimeTickReceiver.kt
│ │ │ │ └── RemindReceiver.kt
│ │ │ │ ├── common
│ │ │ │ ├── BaseActivity.kt
│ │ │ │ ├── App.kt
│ │ │ │ └── ConstantPool.kt
│ │ │ │ └── service
│ │ │ │ ├── JobSchedulerService.kt
│ │ │ │ ├── TodayWidgetService.kt
│ │ │ │ └── CommonService.kt
│ │ └── AndroidManifest.xml
│ ├── test
│ │ └── java
│ │ │ └── top
│ │ │ └── itning
│ │ │ └── yunshuclassschedule
│ │ │ └── ExampleUnitTest.kt
│ └── androidTest
│ │ └── java
│ │ └── top
│ │ └── itning
│ │ └── yunshuclassschedule
│ │ └── ExampleInstrumentedTest.kt
├── proguard-rules.pro
└── build.gradle
├── settings.gradle
├── .gitattributes
├── extra
├── a.png
├── b.png
├── c.png
├── d.png
├── e.png
├── f.png
├── g.png
└── coolapk.png
├── keystore.jks
├── .gitignore
├── gradle.properties
├── gradlew.bat
├── README.md
└── gradlew
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | *.java linguist-language=kotlin
--------------------------------------------------------------------------------
/extra/a.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itning/YunShuClassSchedule/dev/extra/a.png
--------------------------------------------------------------------------------
/extra/b.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itning/YunShuClassSchedule/dev/extra/b.png
--------------------------------------------------------------------------------
/extra/c.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itning/YunShuClassSchedule/dev/extra/c.png
--------------------------------------------------------------------------------
/extra/d.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itning/YunShuClassSchedule/dev/extra/d.png
--------------------------------------------------------------------------------
/extra/e.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itning/YunShuClassSchedule/dev/extra/e.png
--------------------------------------------------------------------------------
/extra/f.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itning/YunShuClassSchedule/dev/extra/f.png
--------------------------------------------------------------------------------
/extra/g.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itning/YunShuClassSchedule/dev/extra/g.png
--------------------------------------------------------------------------------
/keystore.jks:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itning/YunShuClassSchedule/dev/keystore.jks
--------------------------------------------------------------------------------
/extra/coolapk.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itning/YunShuClassSchedule/dev/extra/coolapk.png
--------------------------------------------------------------------------------
/app/src/main/assets/0.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itning/YunShuClassSchedule/dev/app/src/main/assets/0.bmp
--------------------------------------------------------------------------------
/app/src/main/assets/1.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itning/YunShuClassSchedule/dev/app/src/main/assets/1.bmp
--------------------------------------------------------------------------------
/app/src/main/assets/2.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itning/YunShuClassSchedule/dev/app/src/main/assets/2.bmp
--------------------------------------------------------------------------------
/app/src/main/assets/3.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itning/YunShuClassSchedule/dev/app/src/main/assets/3.bmp
--------------------------------------------------------------------------------
/app/src/main/assets/4.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itning/YunShuClassSchedule/dev/app/src/main/assets/4.bmp
--------------------------------------------------------------------------------
/app/src/main/assets/5.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itning/YunShuClassSchedule/dev/app/src/main/assets/5.bmp
--------------------------------------------------------------------------------
/app/src/main/assets/6.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itning/YunShuClassSchedule/dev/app/src/main/assets/6.bmp
--------------------------------------------------------------------------------
/app/src/main/assets/7.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itning/YunShuClassSchedule/dev/app/src/main/assets/7.bmp
--------------------------------------------------------------------------------
/app/src/main/assets/8.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itning/YunShuClassSchedule/dev/app/src/main/assets/8.bmp
--------------------------------------------------------------------------------
/app/src/main/assets/9.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itning/YunShuClassSchedule/dev/app/src/main/assets/9.bmp
--------------------------------------------------------------------------------
/app/src/main/assets/a.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itning/YunShuClassSchedule/dev/app/src/main/assets/a.bmp
--------------------------------------------------------------------------------
/app/src/main/assets/b.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itning/YunShuClassSchedule/dev/app/src/main/assets/b.bmp
--------------------------------------------------------------------------------
/app/src/main/assets/c.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itning/YunShuClassSchedule/dev/app/src/main/assets/c.bmp
--------------------------------------------------------------------------------
/app/src/main/assets/d.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itning/YunShuClassSchedule/dev/app/src/main/assets/d.bmp
--------------------------------------------------------------------------------
/app/src/main/assets/e.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itning/YunShuClassSchedule/dev/app/src/main/assets/e.bmp
--------------------------------------------------------------------------------
/app/src/main/assets/f.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itning/YunShuClassSchedule/dev/app/src/main/assets/f.bmp
--------------------------------------------------------------------------------
/app/src/main/assets/g.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itning/YunShuClassSchedule/dev/app/src/main/assets/g.bmp
--------------------------------------------------------------------------------
/app/src/main/assets/h.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itning/YunShuClassSchedule/dev/app/src/main/assets/h.bmp
--------------------------------------------------------------------------------
/app/src/main/assets/i.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itning/YunShuClassSchedule/dev/app/src/main/assets/i.bmp
--------------------------------------------------------------------------------
/app/src/main/assets/j.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itning/YunShuClassSchedule/dev/app/src/main/assets/j.bmp
--------------------------------------------------------------------------------
/app/src/main/assets/k.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itning/YunShuClassSchedule/dev/app/src/main/assets/k.bmp
--------------------------------------------------------------------------------
/app/src/main/assets/l.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itning/YunShuClassSchedule/dev/app/src/main/assets/l.bmp
--------------------------------------------------------------------------------
/app/src/main/assets/m.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itning/YunShuClassSchedule/dev/app/src/main/assets/m.bmp
--------------------------------------------------------------------------------
/app/src/main/assets/n.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itning/YunShuClassSchedule/dev/app/src/main/assets/n.bmp
--------------------------------------------------------------------------------
/app/src/main/assets/o.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itning/YunShuClassSchedule/dev/app/src/main/assets/o.bmp
--------------------------------------------------------------------------------
/app/src/main/assets/p.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itning/YunShuClassSchedule/dev/app/src/main/assets/p.bmp
--------------------------------------------------------------------------------
/app/src/main/assets/q.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itning/YunShuClassSchedule/dev/app/src/main/assets/q.bmp
--------------------------------------------------------------------------------
/app/src/main/assets/r.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itning/YunShuClassSchedule/dev/app/src/main/assets/r.bmp
--------------------------------------------------------------------------------
/app/src/main/assets/s.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itning/YunShuClassSchedule/dev/app/src/main/assets/s.bmp
--------------------------------------------------------------------------------
/app/src/main/assets/t.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itning/YunShuClassSchedule/dev/app/src/main/assets/t.bmp
--------------------------------------------------------------------------------
/app/src/main/assets/u.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itning/YunShuClassSchedule/dev/app/src/main/assets/u.bmp
--------------------------------------------------------------------------------
/app/src/main/assets/v.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itning/YunShuClassSchedule/dev/app/src/main/assets/v.bmp
--------------------------------------------------------------------------------
/app/src/main/assets/w.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itning/YunShuClassSchedule/dev/app/src/main/assets/w.bmp
--------------------------------------------------------------------------------
/app/src/main/assets/x.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itning/YunShuClassSchedule/dev/app/src/main/assets/x.bmp
--------------------------------------------------------------------------------
/app/src/main/assets/y.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itning/YunShuClassSchedule/dev/app/src/main/assets/y.bmp
--------------------------------------------------------------------------------
/app/src/main/assets/z.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itning/YunShuClassSchedule/dev/app/src/main/assets/z.bmp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itning/YunShuClassSchedule/dev/app/src/main/res/mipmap-hdpi/logo.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itning/YunShuClassSchedule/dev/app/src/main/res/mipmap-mdpi/logo.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itning/YunShuClassSchedule/dev/app/src/main/res/mipmap-xhdpi/logo.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itning/YunShuClassSchedule/dev/app/src/main/res/mipmap-xxhdpi/logo.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itning/YunShuClassSchedule/dev/app/src/main/res/mipmap-xxxhdpi/logo.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/logo_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itning/YunShuClassSchedule/dev/app/src/main/res/mipmap-hdpi/logo_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/logo_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itning/YunShuClassSchedule/dev/app/src/main/res/mipmap-mdpi/logo_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/logo_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itning/YunShuClassSchedule/dev/app/src/main/res/mipmap-xhdpi/logo_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/logo_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itning/YunShuClassSchedule/dev/app/src/main/res/mipmap-xxhdpi/logo_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/logo_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itning/YunShuClassSchedule/dev/app/src/main/res/mipmap-xxxhdpi/logo_round.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-nodpi/seekbar_thumb.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itning/YunShuClassSchedule/dev/app/src/main/res/drawable-nodpi/seekbar_thumb.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-nodpi/side_nav_bar.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itning/YunShuClassSchedule/dev/app/src/main/res/drawable-nodpi/side_nav_bar.webp
--------------------------------------------------------------------------------
/app/src/main/res/drawable-nodpi/login_background.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itning/YunShuClassSchedule/dev/app/src/main/res/drawable-nodpi/login_background.webp
--------------------------------------------------------------------------------
/app/src/main/res/drawable-nodpi/notification_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itning/YunShuClassSchedule/dev/app/src/main/res/drawable-nodpi/notification_icon.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-nodpi/today_widget_4_2.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itning/YunShuClassSchedule/dev/app/src/main/res/drawable-nodpi/today_widget_4_2.webp
--------------------------------------------------------------------------------
/app/src/main/res/drawable-nodpi/splash_background.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itning/YunShuClassSchedule/dev/app/src/main/res/drawable-nodpi/splash_background.webp
--------------------------------------------------------------------------------
/app/src/main/res/drawable-nodpi/this_week_background.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itning/YunShuClassSchedule/dev/app/src/main/res/drawable-nodpi/this_week_background.webp
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /gradle
4 | /.idea
5 | /local.properties
6 | .DS_Store
7 | /build
8 | /captures
9 | .externalNativeBuild
10 | /app/bugly
11 | /app/release
12 |
--------------------------------------------------------------------------------
/app/src/main/res/values/attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/file_paths.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/drawer_switch.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 | 176dp
6 |
--------------------------------------------------------------------------------
/app/src/main/java/top/itning/yunshuclassschedule/util/Glide4Modle.kt:
--------------------------------------------------------------------------------
1 | package top.itning.yunshuclassschedule.util
2 |
3 | import com.bumptech.glide.annotation.GlideModule
4 | import com.bumptech.glide.module.AppGlideModule
5 |
6 | /**
7 | * @author itning
8 | */
9 | @GlideModule
10 | class Glide4Modle : AppGlideModule()
11 |
--------------------------------------------------------------------------------
/app/src/main/java/top/itning/yunshuclassschedule/util/EventReceiver.kt:
--------------------------------------------------------------------------------
1 | package top.itning.yunshuclassschedule.util
2 |
3 | /**
4 | * 事件接收
5 | *
6 | * @author itning
7 | */
8 | interface EventReceiver {
9 | /**
10 | * 触发事件
11 | *
12 | * @return 已消费返回真
13 | */
14 | fun eventTrigger(): Boolean
15 | }
16 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/network_security_config.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/widget_provider_today_4_2.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/activity_custom_menu.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/baseline_done_24.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/test/java/top/itning/yunshuclassschedule/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package top.itning.yunshuclassschedule
2 |
3 | import org.junit.Assert.assertEquals
4 | import org.junit.Test
5 |
6 | /**
7 | * Example local unit test, which will execute on the development machine (host).
8 | *
9 | * @see [Testing documentation](http://d.android.com/tools/testing)
10 | */
11 | class ExampleUnitTest {
12 | @Test
13 | fun addition_isCorrect() {
14 | assertEquals(4, (2 + 2).toLong())
15 | }
16 | }
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_custom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_check_score.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/widget_layout_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
12 |
--------------------------------------------------------------------------------
/app/src/main/java/top/itning/yunshuclassschedule/ui/widget/TodayRemoteViewsService.kt:
--------------------------------------------------------------------------------
1 | package top.itning.yunshuclassschedule.ui.widget
2 |
3 | import android.content.Intent
4 | import android.util.Log
5 | import android.widget.RemoteViewsService
6 |
7 | class TodayRemoteViewsService : RemoteViewsService() {
8 | override fun onGetViewFactory(intent: Intent?): RemoteViewsFactory {
9 | Log.d("TodayRemoteViewsService", "onGetViewFactory")
10 | return ToadyRemoteViewsFactory(this, intent)
11 | }
12 | }
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_check_score_show.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/baseline_today_24.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_splash.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_setting.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/baseline_brightness_4_24.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/baseline_score_24.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/nav_header_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/app/src/main/java/top/itning/yunshuclassschedule/entity/EventEntity.kt:
--------------------------------------------------------------------------------
1 | package top.itning.yunshuclassschedule.entity
2 |
3 | import top.itning.yunshuclassschedule.common.ConstantPool
4 |
5 | /**
6 | * 事件实体
7 | *
8 | * @author itning
9 | */
10 | class EventEntity {
11 | var id: ConstantPool.Int? = null
12 | var msg: String? = null
13 | var data: Any? = null
14 |
15 | constructor(id: ConstantPool.Int) {
16 | this.id = id
17 | }
18 |
19 | constructor(id: ConstantPool.Int, msg: String) {
20 | this.id = id
21 | this.msg = msg
22 | }
23 |
24 | constructor(id: ConstantPool.Int, msg: String, data: Any) {
25 | this.id = id
26 | this.msg = msg
27 | this.data = data
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/content_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
15 |
--------------------------------------------------------------------------------
/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
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 | android.useAndroidX=true
15 | android.enableJetifier=true
16 |
--------------------------------------------------------------------------------
/app/src/main/java/top/itning/yunshuclassschedule/receiver/TimeTickReceiver.kt:
--------------------------------------------------------------------------------
1 | package top.itning.yunshuclassschedule.receiver
2 |
3 | import android.content.BroadcastReceiver
4 | import android.content.Context
5 | import android.content.Intent
6 | import android.util.Log
7 |
8 | import org.greenrobot.eventbus.EventBus
9 |
10 | import top.itning.yunshuclassschedule.common.ConstantPool
11 | import top.itning.yunshuclassschedule.entity.EventEntity
12 |
13 | /**
14 | * 时间改变广播,包括用户手动设置时间,时区
15 | *
16 | * @author itning
17 | */
18 | class TimeTickReceiver : BroadcastReceiver() {
19 |
20 | override fun onReceive(context: Context, intent: Intent) {
21 | Log.d(TAG, "send time change event")
22 | EventBus.getDefault().post(EVENT_ENTITY)
23 | }
24 |
25 | companion object {
26 | private const val TAG = "TimeTickReceiver"
27 | private val EVENT_ENTITY = EventEntity(ConstantPool.Int.TIME_TICK_CHANGE)
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/widget_layout_today.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
13 |
14 |
23 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 |
7 | #ff212121
8 | #ff000000
9 | #ff80cbc4
10 |
11 | #f1ff4949
12 | #f0ff6e6e
13 | #f0c992ff
14 | #f0c88f6e
15 | #ef6e73ff
16 | #f0ffaf49
17 | #edffb7b7
18 |
19 | #b0bbfa
20 | #f53e3e3e
21 |
22 | #85C1D8
23 |
24 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/top/itning/yunshuclassschedule/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package top.itning.yunshuclassschedule
2 |
3 | import android.content.Intent
4 | import androidx.test.InstrumentationRegistry
5 | import androidx.test.runner.AndroidJUnit4
6 |
7 | import org.junit.Assert.assertEquals
8 | import org.junit.Test
9 | import org.junit.runner.RunWith
10 | import top.itning.yunshuclassschedule.service.CourseInfoService
11 |
12 | /**
13 | * Instrumented test, which will execute on an Android device.
14 | *
15 | * @see [Testing documentation](http://d.android.com/tools/testing)
16 | */
17 | @RunWith(AndroidJUnit4::class)
18 | class ExampleInstrumentedTest {
19 | @Test
20 | fun useAppContext() {
21 | // Context of the app under test.
22 | val appContext = InstrumentationRegistry.getTargetContext()
23 | appContext.startService(Intent(appContext, CourseInfoService::class.java))
24 |
25 | assertEquals("top.itning.yunshuclassschedule", appContext.packageName)
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/app/src/main/java/top/itning/yunshuclassschedule/entity/Hash.java:
--------------------------------------------------------------------------------
1 | package top.itning.yunshuclassschedule.entity;
2 |
3 | import org.greenrobot.greendao.annotation.Entity;
4 | import org.greenrobot.greendao.annotation.Generated;
5 | import org.greenrobot.greendao.annotation.Id;
6 | import org.greenrobot.greendao.annotation.NotNull;
7 |
8 | /**
9 | * 图片哈希
10 | *
11 | * @author itning
12 | */
13 | @Entity
14 | public class Hash {
15 | @Id
16 | private String id;
17 | @NotNull
18 | private String name;
19 |
20 | @Generated(hash = 1070788195)
21 | public Hash(String id, @NotNull String name) {
22 | this.id = id;
23 | this.name = name;
24 | }
25 |
26 | @Generated(hash = 1112031932)
27 | public Hash() {
28 | }
29 |
30 | public String getId() {
31 | return id;
32 | }
33 |
34 | public void setId(String id) {
35 | this.id = id;
36 | }
37 |
38 | public String getName() {
39 | return name;
40 | }
41 |
42 | public void setName(String name) {
43 | this.name = name;
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_class_schedule.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
18 |
19 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/app/src/main/java/top/itning/yunshuclassschedule/entity/DataEntity.java:
--------------------------------------------------------------------------------
1 | package top.itning.yunshuclassschedule.entity;
2 |
3 | import java.util.List;
4 |
5 | import top.itning.yunshuclassschedule.common.App;
6 | import top.itning.yunshuclassschedule.util.DateUtils;
7 |
8 | /**
9 | * 数据封装实体
10 | *
11 | * @author itning
12 | */
13 | public class DataEntity {
14 | private final List classScheduleList;
15 | private final List timeList;
16 |
17 | public DataEntity(App app) {
18 | classScheduleList = app.getDaoSession().getClassScheduleDao().loadAll();
19 | timeList = DateUtils.INSTANCE.getTimeList();
20 | }
21 |
22 | public List getClassScheduleList() {
23 | return classScheduleList;
24 | }
25 |
26 | public List getTimeList() {
27 | return timeList;
28 | }
29 |
30 | @Override
31 | public String toString() {
32 | return "DataEntity{" +
33 | "classScheduleList=" + classScheduleList +
34 | ", timeList=" + timeList +
35 | '}';
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/app/src/main/java/top/itning/yunshuclassschedule/common/BaseActivity.kt:
--------------------------------------------------------------------------------
1 | package top.itning.yunshuclassschedule.common
2 |
3 | import android.content.Intent
4 | import android.os.Bundle
5 |
6 | import androidx.annotation.Nullable
7 | import androidx.appcompat.app.AppCompatActivity
8 | import top.itning.yunshuclassschedule.entity.EventEntity
9 | import top.itning.yunshuclassschedule.service.CommonService
10 | import top.itning.yunshuclassschedule.service.RemindService
11 | import top.itning.yunshuclassschedule.service.TodayWidgetService
12 |
13 | /**
14 | * Base App Activity
15 | *
16 | * @author itning
17 | */
18 | abstract class BaseActivity : AppCompatActivity() {
19 |
20 | override fun onCreate(@Nullable savedInstanceState: Bundle?) {
21 | super.onCreate(savedInstanceState)
22 | startService(Intent(this, CommonService::class.java))
23 | startService(Intent(this, RemindService::class.java))
24 | startService(Intent(this, TodayWidgetService::class.java))
25 | }
26 |
27 | /**
28 | * 消息事件
29 | *
30 | * @param eventEntity what
31 | */
32 | abstract fun onMessageEvent(eventEntity: EventEntity)
33 | }
34 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/app_bar_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
14 |
15 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/main.xml:
--------------------------------------------------------------------------------
1 |
2 |
30 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
15 |
16 |
20 |
21 |
22 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/activity_main_drawer.xml:
--------------------------------------------------------------------------------
1 |
2 |
33 |
--------------------------------------------------------------------------------
/app/src/main/java/top/itning/yunshuclassschedule/util/ImageHash.kt:
--------------------------------------------------------------------------------
1 | package top.itning.yunshuclassschedule.util
2 |
3 | import android.graphics.Bitmap
4 | import android.graphics.Matrix
5 |
6 | /**
7 | * 图片指纹工具类
8 | *
9 | * @author itning
10 | */
11 | object ImageHash {
12 | /**
13 | * 计算指纹
14 | *
15 | * @param fromBitmap [Bitmap]
16 | * @return 指纹数据
17 | */
18 | fun calculateFingerPrint(fromBitmap: Bitmap): String {
19 | val stringBuilder = StringBuilder()
20 | val width = fromBitmap.width
21 | val height = fromBitmap.height
22 | // 设置想要的大小
23 | val newWidth = 8
24 | val newHeight = 8
25 | // 计算缩放比例
26 | val scaleWidth = newWidth.toFloat() / width
27 | val scaleHeight = newHeight.toFloat() / height
28 | // 取得想要缩放的matrix参数
29 | val matrix = Matrix()
30 | matrix.postScale(scaleWidth, scaleHeight)
31 | // 得到新的图片
32 | val newbm = Bitmap.createBitmap(fromBitmap, 0, 0, width, height, matrix, true)
33 | for (i in 0 until newbm.width) {
34 | for (j in 0 until newbm.height) {
35 | val pixel = newbm.getPixel(i, j)
36 | stringBuilder.append(Math.abs(pixel))
37 | }
38 | }
39 | newbm.recycle()
40 | fromBitmap.recycle()
41 | return stringBuilder.toString()
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/baseline_settings_applications_24.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/preference_dialog_layout.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
14 |
15 |
22 |
23 |
31 |
32 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/view_range.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
15 |
16 |
34 |
--------------------------------------------------------------------------------
/app/src/main/java/top/itning/yunshuclassschedule/ui/view/RoundBackChange.kt:
--------------------------------------------------------------------------------
1 | package top.itning.yunshuclassschedule.ui.view
2 |
3 | import android.content.Context
4 | import android.graphics.Canvas
5 | import android.graphics.Color
6 | import android.graphics.Paint
7 | import android.util.AttributeSet
8 | import android.view.View
9 | import androidx.annotation.Nullable
10 | import top.itning.yunshuclassschedule.R
11 |
12 | /**
13 | * @author itning
14 | */
15 | class RoundBackChange : View {
16 | private var color = -0x22000001
17 | private val mPaint = Paint()
18 |
19 | constructor(context: Context) : super(context, null)
20 |
21 | constructor(context: Context, @Nullable attrs: AttributeSet) : super(context, attrs) {
22 | //设置画笔宽度为10px
23 | val array = context.obtainStyledAttributes(attrs, R.styleable.RoundBackChange)
24 | color = array.getColor(R.styleable.RoundBackChange_self_color, color)
25 | array.recycle()
26 | //设置画笔颜色
27 | mPaint.color = color
28 | //设置画笔模式为填充
29 | mPaint.style = Paint.Style.FILL_AND_STROKE
30 | mPaint.strokeWidth = 10f
31 | mPaint.isAntiAlias = true
32 | }
33 |
34 | fun setBackColor(color: Int) {
35 | this.color = color
36 | mPaint.color = color
37 | }
38 |
39 | override fun onDraw(canvas: Canvas) {
40 | super.onDraw(canvas)
41 | canvas.drawColor(Color.TRANSPARENT)
42 | canvas.drawCircle((right - left - measuredWidth / 2).toFloat(), (top + measuredHeight / 2).toFloat(), (measuredWidth / 3).toFloat(), mPaint)
43 | }
44 |
45 | }
46 |
--------------------------------------------------------------------------------
/app/src/main/java/top/itning/yunshuclassschedule/ui/widget/TodayWidgetProvider.kt:
--------------------------------------------------------------------------------
1 | package top.itning.yunshuclassschedule.ui.widget
2 |
3 | import android.appwidget.AppWidgetManager
4 | import android.appwidget.AppWidgetProvider
5 | import android.content.Context
6 | import android.content.Intent
7 | import android.net.Uri
8 | import android.util.Log
9 | import android.widget.RemoteViews
10 |
11 | /**
12 | * 今天课程小部件
13 | *
14 | * @author itning
15 | */
16 | class TodayWidgetProvider : AppWidgetProvider() {
17 | override fun onUpdate(context: Context?, appWidgetManager: AppWidgetManager?, appWidgetIds: IntArray?) {
18 | Log.d(TAG, "onUpdate")
19 | appWidgetIds?.forEach {
20 | val remoteViews = RemoteViews(context?.packageName, top.itning.yunshuclassschedule.R.layout.widget_layout_today)
21 | val intent = Intent(context, TodayRemoteViewsService::class.java)
22 | intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, it)
23 | intent.data = Uri.parse(intent.toUri(Intent.URI_INTENT_SCHEME))
24 | remoteViews.setRemoteAdapter(top.itning.yunshuclassschedule.R.id.lv, intent)
25 | remoteViews.setEmptyView(top.itning.yunshuclassschedule.R.id.lv, top.itning.yunshuclassschedule.R.id.empty_view)
26 | appWidgetManager?.updateAppWidget(it, remoteViews)
27 | }
28 | super.onUpdate(context, appWidgetManager, appWidgetIds)
29 | }
30 |
31 | override fun onDisabled(context: Context?) {
32 | Log.d(TAG, "onDisabled")
33 | super.onDisabled(context)
34 | }
35 |
36 | companion object {
37 | private const val TAG = "TodayWidgetProvider"
38 | }
39 | }
--------------------------------------------------------------------------------
/app/src/main/java/top/itning/yunshuclassschedule/service/JobSchedulerService.kt:
--------------------------------------------------------------------------------
1 | package top.itning.yunshuclassschedule.service
2 |
3 | import android.app.job.JobParameters
4 | import android.app.job.JobService
5 | import android.content.Intent
6 | import android.os.Build
7 | import android.preference.PreferenceManager
8 | import android.util.Log
9 | import top.itning.yunshuclassschedule.ui.fragment.setting.SettingsFragment.Companion.FOREGROUND_SERVICE_STATUS
10 |
11 | /**
12 | * @author itning
13 | */
14 | class JobSchedulerService : JobService() {
15 |
16 | override fun onStartJob(params: JobParameters): Boolean {
17 | Log.d(TAG, "onStartJob(): params = [$params]")
18 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
19 | if (PreferenceManager.getDefaultSharedPreferences(this).getBoolean(FOREGROUND_SERVICE_STATUS, true)) {
20 | startForegroundService(Intent(this, CommonService::class.java))
21 | startForegroundService(Intent(this, RemindService::class.java))
22 | startForegroundService(Intent(this, TodayWidgetService::class.java))
23 | }
24 | } else {
25 | startService(Intent(this, CommonService::class.java))
26 | startService(Intent(this, RemindService::class.java))
27 | startService(Intent(this, TodayWidgetService::class.java))
28 | }
29 | jobFinished(params, false)
30 | return true
31 | }
32 |
33 | override fun onStopJob(params: JobParameters): Boolean {
34 | Log.d(TAG, "onStopJob(): params = [$params]")
35 | return false
36 | }
37 |
38 | companion object {
39 | private const val TAG = "JobSchedulerService"
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/app/src/main/java/top/itning/yunshuclassschedule/ui/adapter/ScoreRecyclerViewAdapter.kt:
--------------------------------------------------------------------------------
1 | package top.itning.yunshuclassschedule.ui.adapter
2 |
3 |
4 | import android.view.LayoutInflater
5 | import android.view.View
6 | import android.view.ViewGroup
7 |
8 | import androidx.annotation.NonNull
9 | import androidx.appcompat.widget.AppCompatTextView
10 | import androidx.recyclerview.widget.RecyclerView
11 | import top.itning.yunshuclassschedule.R
12 | import top.itning.yunshuclassschedule.entity.Score
13 |
14 | /**
15 | * @author itning
16 | */
17 | class ScoreRecyclerViewAdapter(@param:NonNull private val scoreList: List) : RecyclerView.Adapter() {
18 |
19 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
20 | return ViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.item_score_rv, parent, false))
21 | }
22 |
23 | override fun onBindViewHolder(holder: ViewHolder, position: Int) {
24 | val score = scoreList[position]
25 | holder.tvId.text = score.id
26 | holder.tvName.text = score.name
27 | holder.tvSemester.text = score.semester
28 | holder.tvGrade.text = score.grade
29 | holder.tvCredit.text = score.credit
30 | }
31 |
32 | override fun getItemCount(): Int {
33 | return scoreList.size
34 | }
35 |
36 | class ViewHolder internal constructor(itemView: View) : RecyclerView.ViewHolder(itemView) {
37 | val tvId: AppCompatTextView = itemView.findViewById(R.id.tv_id)
38 |
39 | val tvName: AppCompatTextView = itemView.findViewById(R.id.tv_name)
40 |
41 | val tvSemester: AppCompatTextView = itemView.findViewById(R.id.tv_semester)
42 |
43 | val tvGrade: AppCompatTextView = itemView.findViewById(R.id.tv_grade)
44 |
45 | val tvCredit: AppCompatTextView = itemView.findViewById(R.id.tv_credit)
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
16 |
17 |
21 |
22 |
27 |
28 |
31 |
32 |
33 |
34 |
35 |
36 |
45 |
46 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_login.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
20 |
21 |
32 |
33 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/app/src/main/java/top/itning/yunshuclassschedule/ui/fragment/checkscore/CheckScoreShowFragment.kt:
--------------------------------------------------------------------------------
1 | package top.itning.yunshuclassschedule.ui.fragment.checkscore
2 |
3 | import android.content.Context
4 | import android.os.Bundle
5 | import android.util.Log
6 | import android.view.LayoutInflater
7 | import android.view.View
8 | import android.view.ViewGroup
9 | import android.view.inputmethod.InputMethodManager
10 | import androidx.fragment.app.Fragment
11 | import androidx.recyclerview.widget.LinearLayoutManager
12 | import kotlinx.android.synthetic.main.fragment_check_score_show.*
13 | import top.itning.yunshuclassschedule.R
14 | import top.itning.yunshuclassschedule.entity.Score
15 | import top.itning.yunshuclassschedule.ui.adapter.ScoreRecyclerViewAdapter
16 |
17 | /**
18 | * 展示
19 | *
20 | * @author itning
21 | */
22 | class CheckScoreShowFragment : Fragment() {
23 | override fun onCreate(savedInstanceState: Bundle?) {
24 | super.onCreate(savedInstanceState)
25 | val inputMethodManager = requireActivity().getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
26 | inputMethodManager.hideSoftInputFromWindow(requireActivity().window.decorView.windowToken, 0)
27 | }
28 |
29 | override fun onDestroy() {
30 | Log.d(TAG, "on Destroy")
31 | super.onDestroy()
32 | }
33 |
34 | override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
35 | return inflater.inflate(R.layout.fragment_check_score_show, container, false)
36 | }
37 |
38 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
39 | arguments?.getParcelableArrayList("scoreList")?.let {
40 | //RecyclerView初始化
41 | val layout = LinearLayoutManager(requireContext())
42 | //列表再底部开始展示,反转后由上面开始展示
43 | layout.stackFromEnd = true
44 | //列表翻转
45 | layout.reverseLayout = true
46 | rv.layoutManager = layout
47 | rv.adapter = ScoreRecyclerViewAdapter(it)
48 | }
49 | }
50 |
51 | companion object {
52 | private const val TAG = "CheckScoreShowFragment"
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_share.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
10 |
11 |
15 |
16 |
24 |
25 |
29 |
30 |
38 |
39 |
47 |
48 |
--------------------------------------------------------------------------------
/app/src/main/java/top/itning/yunshuclassschedule/common/App.kt:
--------------------------------------------------------------------------------
1 | package top.itning.yunshuclassschedule.common
2 |
3 | import android.app.Application
4 | import android.content.ComponentCallbacks2
5 | import android.content.Context
6 | import android.content.SharedPreferences
7 | import android.content.res.Configuration
8 | import android.util.Log
9 | import com.tencent.bugly.crashreport.CrashReport
10 | import org.greenrobot.eventbus.EventBus
11 | import top.itning.yunshuclassschedule.AppActivityIndex
12 | import top.itning.yunshuclassschedule.entity.DaoMaster
13 | import top.itning.yunshuclassschedule.entity.DaoSession
14 | import top.itning.yunshuclassschedule.util.GlideApp
15 |
16 | /**
17 | * 应用基类
18 | *
19 | * @author itning
20 | */
21 | class App : Application() {
22 |
23 | lateinit var daoSession: DaoSession
24 |
25 | override fun onCreate() {
26 | // 程序创建的时候执行
27 | //EventBus add Index
28 | EventBus.builder().addIndex(AppActivityIndex()).installDefaultEventBus()
29 | //bugly
30 | CrashReport.initCrashReport(applicationContext, "439037c8de", false)
31 |
32 | val helper = DaoMaster.DevOpenHelper(this, ConstantPool.Str.DB_NAME.get())
33 | val db = helper.writableDb
34 | daoSession = DaoMaster(db).newSession()
35 | sharedPreferences = getSharedPreferences(ConstantPool.Str.SHARED_PREFERENCES_FILENAME.get(), Context.MODE_PRIVATE)
36 | super.onCreate()
37 | }
38 |
39 | override fun onTerminate() {
40 | // 程序终止的时候执行
41 | Log.d(TAG, "onTerminate")
42 | super.onTerminate()
43 | }
44 |
45 | override fun onLowMemory() {
46 | // 低内存的时候执行
47 | Log.d(TAG, "onLowMemory")
48 | GlideApp.get(this).clearMemory()
49 | super.onLowMemory()
50 | }
51 |
52 | override fun onTrimMemory(level: Int) {
53 | // 程序在内存清理的时候执行
54 | Log.d(TAG, "onTrimMemory:$level")
55 | if (level == ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) {
56 | GlideApp.get(this).clearMemory()
57 | }
58 | GlideApp.get(this).trimMemory(level)
59 | super.onTrimMemory(level)
60 | }
61 |
62 | override fun onConfigurationChanged(newConfig: Configuration) {
63 | Log.d(TAG, "onConfigurationChanged")
64 | super.onConfigurationChanged(newConfig)
65 | }
66 |
67 | companion object {
68 | private const val TAG = "App"
69 | lateinit var sharedPreferences: SharedPreferences
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_score_rv.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
15 |
16 |
23 |
24 |
30 |
31 |
37 |
38 |
39 |
46 |
47 |
55 |
56 |
63 |
64 |
65 |
--------------------------------------------------------------------------------
/app/src/main/java/top/itning/yunshuclassschedule/util/Glide4Engine.kt:
--------------------------------------------------------------------------------
1 | package top.itning.yunshuclassschedule.util
2 |
3 | import android.content.Context
4 | import android.graphics.drawable.Drawable
5 | import android.net.Uri
6 | import android.widget.ImageView
7 |
8 | import com.bumptech.glide.Priority
9 | import com.bumptech.glide.request.RequestOptions
10 | import com.zhihu.matisse.engine.ImageEngine
11 |
12 | /**
13 | * https://github.com/zhihu/Matisse/blob/master/sample/src/main/java/com/zhihu/matisse/sample/Glide4Engine.java
14 | * [ImageEngine] implementation using Glide.
15 | *
16 | * @author zhihu
17 | */
18 |
19 | class Glide4Engine : ImageEngine {
20 |
21 | override fun loadThumbnail(context: Context, resize: Int, placeholder: Drawable, imageView: ImageView, uri: Uri) {
22 | GlideApp.with(context)
23 | .asBitmap() // some .jpeg files are actually gif
24 | .load(uri)
25 | .apply(RequestOptions()
26 | .override(resize, resize)
27 | .placeholder(placeholder)
28 | .centerCrop())
29 | .into(imageView)
30 | }
31 |
32 | override fun loadGifThumbnail(context: Context, resize: Int, placeholder: Drawable, imageView: ImageView,
33 | uri: Uri) {
34 | GlideApp.with(context)
35 | .asBitmap() // some .jpeg files are actually gif
36 | .load(uri)
37 | .apply(RequestOptions()
38 | .override(resize, resize)
39 | .placeholder(placeholder)
40 | .centerCrop())
41 | .into(imageView)
42 | }
43 |
44 | override fun loadImage(context: Context, resizeX: Int, resizeY: Int, imageView: ImageView, uri: Uri) {
45 | GlideApp.with(context)
46 | .load(uri)
47 | .apply(RequestOptions()
48 | .override(resizeX, resizeY)
49 | .priority(Priority.HIGH)
50 | .fitCenter())
51 | .into(imageView)
52 | }
53 |
54 | override fun loadGifImage(context: Context, resizeX: Int, resizeY: Int, imageView: ImageView, uri: Uri) {
55 | GlideApp.with(context)
56 | .asGif()
57 | .load(uri)
58 | .apply(RequestOptions()
59 | .override(resizeX, resizeY)
60 | .priority(Priority.HIGH)
61 | .fitCenter())
62 | .into(imageView)
63 | }
64 |
65 | override fun supportAnimatedGif(): Boolean {
66 | return true
67 | }
68 | }
--------------------------------------------------------------------------------
/app/src/main/java/top/itning/yunshuclassschedule/receiver/RemindReceiver.kt:
--------------------------------------------------------------------------------
1 | package top.itning.yunshuclassschedule.receiver
2 |
3 | import android.content.BroadcastReceiver
4 | import android.content.Context
5 | import android.content.Intent
6 | import android.util.Log
7 |
8 | import org.greenrobot.eventbus.EventBus
9 |
10 | import top.itning.yunshuclassschedule.common.ConstantPool
11 | import top.itning.yunshuclassschedule.entity.ClassSchedule
12 | import top.itning.yunshuclassschedule.entity.EventEntity
13 |
14 | /**
15 | * 提醒广播
16 | *
17 | * @author itning
18 | */
19 | class RemindReceiver : BroadcastReceiver() {
20 |
21 | override fun onReceive(context: Context, intent: Intent) {
22 | Log.d(TAG, "on Receive")
23 | val type = intent.getStringExtra("type")
24 | val name = intent.getStringExtra("name")
25 | val location = intent.getStringExtra("location")
26 | val section = intent.getIntExtra("section", -1)
27 | val status = intent.getIntExtra("status", -1)
28 | val week = intent.getIntExtra("week", -1)
29 | if (section == -1 || status == -1 || week == -1) {
30 | Log.e(TAG, "section or status , week error ! section:$section status:$status week:$week")
31 | return
32 | }
33 | if (type == null || name == null || location == null) {
34 | Log.e(TAG, "null value ! type:$type name:$name location:$location")
35 | return
36 | }
37 | Log.d(TAG, "get data: type->$type name->$name location->$location section->$section status->$status week->$week")
38 | if (PHONE_MUTE == type) {
39 | if (status == 0) {
40 | Log.d(TAG, "PHONE_MUTE_OPEN")
41 | EventBus.getDefault().post(EventEntity(ConstantPool.Int.PHONE_MUTE_OPEN))
42 | } else {
43 | Log.d(TAG, "PHONE_MUTE_CANCEL")
44 | EventBus.getDefault().post(EventEntity(ConstantPool.Int.PHONE_MUTE_CANCEL))
45 | }
46 | }
47 | val classSchedule = ClassSchedule()
48 | classSchedule.section = section
49 | classSchedule.name = name
50 | classSchedule.location = location
51 | if (CLASS_REMINDER_UP == type) {
52 | Log.d(TAG, "CLASS_UP_REMIND")
53 | EventBus.getDefault().post(EventEntity(ConstantPool.Int.CLASS_UP_REMIND, "", classSchedule))
54 | }
55 | if (CLASS_REMINDER_DOWN == type) {
56 | Log.d(TAG, "CLASS_DOWN_REMIND")
57 | EventBus.getDefault().post(EventEntity(ConstantPool.Int.CLASS_DOWN_REMIND, "", classSchedule))
58 | }
59 | }
60 |
61 | companion object {
62 | private const val TAG = "RemindReceiver"
63 | private const val PHONE_MUTE = "phone_mute"
64 | private const val CLASS_REMINDER_UP = "class_reminder_up"
65 | private const val CLASS_REMINDER_DOWN = "class_reminder_down"
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/app/src/main/java/top/itning/yunshuclassschedule/entity/Score.java:
--------------------------------------------------------------------------------
1 | package top.itning.yunshuclassschedule.entity;
2 |
3 | import android.os.Parcel;
4 | import android.os.Parcelable;
5 |
6 | /**
7 | * 分数实体
8 | *
9 | * @author itning
10 | */
11 | public class Score implements Parcelable {
12 | /**
13 | * 序号
14 | */
15 | private String id;
16 | /**
17 | * 学期
18 | */
19 | private String semester;
20 | /**
21 | * 科目名称
22 | */
23 | private String name;
24 | /**
25 | * 成绩
26 | */
27 | private String grade;
28 | /**
29 | * 学分
30 | */
31 | private String credit;
32 |
33 | public String getId() {
34 | return id;
35 | }
36 |
37 | public void setId(String id) {
38 | this.id = id;
39 | }
40 |
41 | public String getSemester() {
42 | return semester;
43 | }
44 |
45 | public void setSemester(String semester) {
46 | this.semester = semester;
47 | }
48 |
49 | public String getName() {
50 | return name;
51 | }
52 |
53 | public void setName(String name) {
54 | this.name = name;
55 | }
56 |
57 | public String getGrade() {
58 | return grade;
59 | }
60 |
61 | public void setGrade(String grade) {
62 | this.grade = grade;
63 | }
64 |
65 | public String getCredit() {
66 | return credit;
67 | }
68 |
69 | public void setCredit(String credit) {
70 | this.credit = credit;
71 | }
72 |
73 | @Override
74 | public String toString() {
75 | return "Score{" +
76 | "id='" + id + '\'' +
77 | ", semester='" + semester + '\'' +
78 | ", name='" + name + '\'' +
79 | ", grade='" + grade + '\'' +
80 | ", credit='" + credit + '\'' +
81 | '}';
82 | }
83 |
84 | @Override
85 | public int describeContents() {
86 | return 0;
87 | }
88 |
89 | @Override
90 | public void writeToParcel(Parcel dest, int flags) {
91 | dest.writeString(id);
92 | dest.writeString(semester);
93 | dest.writeString(name);
94 | dest.writeString(grade);
95 | dest.writeString(credit);
96 | }
97 |
98 | public static final Creator CREATOR = new Creator() {
99 | @Override
100 | public Score createFromParcel(Parcel in) {
101 | Score score = new Score();
102 | score.id = in.readString();
103 | score.semester = in.readString();
104 | score.name = in.readString();
105 | score.grade = in.readString();
106 | score.credit = in.readString();
107 | return score;
108 | }
109 |
110 | @Override
111 | public Score[] newArray(int size) {
112 | return new Score[size];
113 | }
114 | };
115 | }
116 |
--------------------------------------------------------------------------------
/app/src/main/java/top/itning/yunshuclassschedule/util/FileUtils.kt:
--------------------------------------------------------------------------------
1 | package top.itning.yunshuclassschedule.util
2 |
3 | import android.content.Context
4 | import android.net.Uri
5 | import android.util.Log
6 | import android.widget.Toast
7 | import androidx.annotation.CheckResult
8 | import androidx.annotation.NonNull
9 | import com.tencent.bugly.crashreport.CrashReport
10 | import java.io.File
11 | import java.io.FileInputStream
12 | import java.io.IOException
13 | import java.io.InputStream
14 |
15 | /**
16 | * 文件工具类
17 | *
18 | * @author itning
19 | */
20 | object FileUtils {
21 | private const val TAG = "FileUtils"
22 | private const val MAX_IMAGE_FILE_SIZE = 20
23 |
24 | fun transferFile(@NonNull context: Context, @NonNull fromUri: Uri, @NonNull fileName: String) {
25 | if (!writeFile2Cache(context, fromUri)) {
26 | return
27 | }
28 | val file = File(context.cacheDir.toString() + File.separator + "cache")
29 | if (!file.canRead()) {
30 | Toast.makeText(context, "读取图片失败:", Toast.LENGTH_LONG).show()
31 | CrashReport.postCatchedException(Throwable("read image failure , file.canRead method return false"))
32 | return
33 | }
34 | // Get length of file in bytes
35 | val fileSizeInBytes = file.length()
36 | // Convert the bytes to Kilobytes (1 KB = 1024 Bytes)
37 | val fileSizeInKB = fileSizeInBytes / 1024
38 | // Convert the KB to MegaBytes (1 MB = 1024 KBytes)
39 | val fileSizeInMB = fileSizeInKB / 1024
40 | Log.d(TAG, "file size :" + fileSizeInKB + "KB")
41 | if (fileSizeInMB > MAX_IMAGE_FILE_SIZE) {
42 | Log.d(TAG, "this image too large :" + fileSizeInMB + "MB")
43 | Toast.makeText(context, "图片太大了", Toast.LENGTH_LONG).show()
44 | return
45 | }
46 | try {
47 | FileInputStream(file).channel.use { inChannel -> context.openFileOutput(fileName, Context.MODE_PRIVATE).channel.use { fileOutputStreamChannel -> fileOutputStreamChannel.transferFrom(inChannel, 0, inChannel.size()) } }
48 | } catch (e: IOException) {
49 | Log.e(TAG, " ", e)
50 | CrashReport.postCatchedException(e)
51 | Toast.makeText(context, "图片写入失败", Toast.LENGTH_LONG).show()
52 | }
53 |
54 | }
55 |
56 | @CheckResult
57 | private fun writeFile2Cache(@NonNull context: Context, @NonNull fromUri: Uri): Boolean {
58 | return try {
59 | context.contentResolver.openInputStream(fromUri)!!.toFile(context.cacheDir.toString() + File.separator + "cache")
60 | true
61 | } catch (e: Exception) {
62 | Log.e(TAG, " ", e)
63 | CrashReport.postCatchedException(e)
64 | Toast.makeText(context, "写入缓存失败:" + e.message, Toast.LENGTH_LONG).show()
65 | false
66 | }
67 | }
68 |
69 | private fun InputStream.toFile(path: String) {
70 | File(path).outputStream().use { this.copyTo(it) }
71 | }
72 | }
73 |
74 |
75 |
--------------------------------------------------------------------------------
/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
22 | # 代码混淆压缩比,在0~7之间,默认为5,一般不做修改
23 | -optimizationpasses 5
24 |
25 | # 混合时不使用大小写混合,混合后的类名为小写
26 | -dontusemixedcaseclassnames
27 |
28 | # 指定不去忽略非公共库的类
29 | -dontskipnonpubliclibraryclasses
30 |
31 | # 这句话能够使我们的项目混淆后产生映射文件
32 | # 包含有类名->混淆后类名的映射关系
33 | -verbose
34 |
35 | # 不做预校验,preverify是proguard的四个步骤之一,Android不需要preverify,去掉这一步能够加快混淆速度。
36 | -dontpreverify
37 |
38 | # 忽略警告,继续执行
39 | -ignorewarnings
40 |
41 | # 指定混淆是采用的算法,后面的参数是一个过滤器
42 | # 这个过滤器是谷歌推荐的算法,一般不做更改
43 | -optimizations !code/simplification/cast,!field/*,!class/merging/*
44 |
45 | -dontwarn javax.annotation.**
46 | -dontwarn javax.inject.**
47 |
48 | -keep class top.itning.yunshuclassschedule.entity.** { *; }
49 |
50 | # greenDAO 3
51 | -keepclassmembers class * extends org.greenrobot.greendao.AbstractDao {
52 | public static java.lang.String TABLENAME;
53 | }
54 | -keep class **$Properties
55 | -dontwarn org.greenrobot.greendao.rx.**
56 |
57 | #EventBus
58 | -keepattributes *Annotation*
59 | -keepclassmembers class ** {
60 | @org.greenrobot.eventbus.Subscribe ;
61 | }
62 | -keep enum org.greenrobot.eventbus.ThreadMode { *; }
63 |
64 | # Only required if you use AsyncExecutor
65 | -keepclassmembers class * extends org.greenrobot.eventbus.util.ThrowableFailureEvent {
66 | (java.lang.Throwable);
67 | }
68 |
69 | #Glide
70 | -keep public class * implements com.bumptech.glide.module.GlideModule
71 | -keep public class * extends com.bumptech.glide.AppGlideModule
72 | -keep public enum com.bumptech.glide.load.resource.bitmap.ImageHeaderParser$** {
73 | **[] $VALUES;
74 | public *;
75 | }
76 |
77 | #Bugly
78 | -dontwarn com.tencent.bugly.**
79 | -keep public class com.tencent.bugly.**{*;}
80 | -keep class android.support.**{*;}
81 |
82 | # Retain service method parameters when optimizing.
83 | -keepclassmembers,allowshrinking,allowobfuscation interface * {
84 | @retrofit2.http.* ;
85 | }
86 |
87 | # Ignore annotation used for build tooling.
88 | -dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement
89 |
90 | # Ignore JSR 305 annotations for embedding nullability information.
91 | -dontwarn javax.annotation.**
92 |
93 | # Guarded by a NoClassDefFoundError try/catch and only used when on the classpath.
94 | -dontwarn kotlin.Unit
95 |
96 | # Matisse
97 | -dontwarn com.squareup.picasso.**
--------------------------------------------------------------------------------
/app/src/main/java/top/itning/yunshuclassschedule/ui/activity/AboutActivity.kt:
--------------------------------------------------------------------------------
1 | package top.itning.yunshuclassschedule.ui.activity
2 |
3 | import android.content.Intent
4 | import android.content.pm.PackageManager
5 | import android.net.Uri
6 | import android.os.Bundle
7 | import android.util.Log
8 | import android.view.MenuItem
9 | import androidx.annotation.CheckResult
10 | import androidx.annotation.NonNull
11 | import androidx.appcompat.app.AppCompatActivity
12 | import kotlinx.android.synthetic.main.activity_about.*
13 | import org.greenrobot.eventbus.EventBus
14 | import org.greenrobot.eventbus.Subscribe
15 | import org.greenrobot.eventbus.ThreadMode
16 | import top.itning.yunshuclassschedule.R
17 | import top.itning.yunshuclassschedule.common.BaseActivity
18 | import top.itning.yunshuclassschedule.entity.EventEntity
19 | import top.itning.yunshuclassschedule.util.ThemeChangeUtil
20 |
21 | /**
22 | * 关于
23 | *
24 | * @author itning
25 | */
26 | class AboutActivity : BaseActivity() {
27 | override fun onCreate(savedInstanceState: Bundle?) {
28 | ThemeChangeUtil.changeTheme(this)
29 | super.onCreate(savedInstanceState)
30 | setContentView(R.layout.activity_about)
31 | EventBus.getDefault().register(this)
32 | initView()
33 | }
34 |
35 | private fun initView() {
36 | Log.d(TAG, "init view")
37 | //设置返回箭头
38 | val supportActionBar = supportActionBar
39 | if (supportActionBar != null) {
40 | supportActionBar.setDisplayHomeAsUpEnabled(true)
41 | supportActionBar.title = "关于"
42 | }
43 | tv_version.text = getPackageVersionName(this)
44 | cv_href.setOnClickListener { onCvHrefClicked() }
45 | }
46 |
47 | /**
48 | * 获取当前应用版本
49 | *
50 | * @param appCompatActivity [AppCompatActivity]
51 | * @return 版本信息
52 | */
53 | @CheckResult
54 | private fun getPackageVersionName(@NonNull appCompatActivity: AppCompatActivity): String {
55 | return try {
56 | appCompatActivity.packageManager.getPackageInfo(appCompatActivity.packageName, 0).versionName
57 | } catch (e: PackageManager.NameNotFoundException) {
58 | Log.w("SplashActivity", "Package name not found:", e)
59 | ""
60 | }
61 |
62 | }
63 |
64 | override fun onOptionsItemSelected(item: MenuItem): Boolean {
65 | when (item.itemId) {
66 | android.R.id.home -> {
67 | finish()
68 | }
69 | }
70 | return super.onOptionsItemSelected(item)
71 | }
72 |
73 | override fun onDestroy() {
74 | EventBus.getDefault().unregister(this)
75 | super.onDestroy()
76 | }
77 |
78 | @Subscribe(threadMode = ThreadMode.MAIN)
79 | override fun onMessageEvent(eventEntity: EventEntity) {
80 |
81 | }
82 |
83 | private fun onCvHrefClicked() {
84 | val uri = Uri.parse("https://github.com/itning/YunShuClassSchedule")
85 | startActivity(Intent(Intent.ACTION_VIEW, uri))
86 | }
87 |
88 | companion object {
89 | private const val TAG = "AboutActivity"
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/app/src/main/java/top/itning/yunshuclassschedule/entity/ClassSchedule.java:
--------------------------------------------------------------------------------
1 | package top.itning.yunshuclassschedule.entity;
2 |
3 | import org.greenrobot.greendao.annotation.Entity;
4 | import org.greenrobot.greendao.annotation.Id;
5 | import org.greenrobot.greendao.annotation.Generated;
6 |
7 | /**
8 | * 课程实体
9 | *
10 | * @author itning
11 | */
12 | @Entity
13 | public class ClassSchedule {
14 | /**
15 | * 课程编号
16 | */
17 | @Id
18 | private String id;
19 | /**
20 | * 星期几的课程
21 | */
22 | private int week;
23 | /**
24 | * 第几节课
25 | */
26 | private int section;
27 | /**
28 | * 课程名
29 | */
30 | private String name;
31 | /**
32 | * 地点
33 | */
34 | private String location;
35 | /**
36 | * 教师
37 | */
38 | private String teacher;
39 | /**
40 | * 周数
41 | */
42 | private String numberOfWeek;
43 |
44 | @Generated(hash = 61551471)
45 | public ClassSchedule(String id, int week, int section, String name,
46 | String location, String teacher, String numberOfWeek) {
47 | this.id = id;
48 | this.week = week;
49 | this.section = section;
50 | this.name = name;
51 | this.location = location;
52 | this.teacher = teacher;
53 | this.numberOfWeek = numberOfWeek;
54 | }
55 |
56 | @Generated(hash = 1679435099)
57 | public ClassSchedule() {
58 | }
59 |
60 | public String getId() {
61 | return id;
62 | }
63 |
64 | public void setId(String id) {
65 | this.id = id;
66 | }
67 |
68 | public int getWeek() {
69 | return week;
70 | }
71 |
72 | public void setWeek(int week) {
73 | this.week = week;
74 | }
75 |
76 | public int getSection() {
77 | return section;
78 | }
79 |
80 | public void setSection(int section) {
81 | this.section = section;
82 | }
83 |
84 | public String getName() {
85 | return name;
86 | }
87 |
88 | public void setName(String name) {
89 | this.name = name;
90 | }
91 |
92 | public String getLocation() {
93 | return location;
94 | }
95 |
96 | public void setLocation(String location) {
97 | this.location = location;
98 | }
99 |
100 | public String getTeacher() {
101 | return teacher;
102 | }
103 |
104 | public void setTeacher(String teacher) {
105 | this.teacher = teacher;
106 | }
107 |
108 | public String getNumberOfWeek() {
109 | return numberOfWeek;
110 | }
111 |
112 | public void setNumberOfWeek(String numberOfWeek) {
113 | this.numberOfWeek = numberOfWeek;
114 | }
115 |
116 | @Override
117 | public String toString() {
118 | return "ClassSchedule{" +
119 | "id='" + id + '\'' +
120 | ", week=" + week +
121 | ", section=" + section +
122 | ", name='" + name + '\'' +
123 | ", location='" + location + '\'' +
124 | ", teacher='" + teacher + '\'' +
125 | ", numberOfWeek='" + numberOfWeek + '\'' +
126 | '}';
127 | }
128 | }
129 |
--------------------------------------------------------------------------------
/app/src/main/java/top/itning/yunshuclassschedule/service/TodayWidgetService.kt:
--------------------------------------------------------------------------------
1 | package top.itning.yunshuclassschedule.service
2 |
3 | import android.app.Service
4 | import android.appwidget.AppWidgetManager
5 | import android.content.ComponentName
6 | import android.content.Intent
7 | import android.content.SharedPreferences
8 | import android.os.IBinder
9 | import android.util.Log
10 | import androidx.preference.PreferenceManager
11 | import org.greenrobot.eventbus.EventBus
12 | import org.greenrobot.eventbus.Subscribe
13 | import org.greenrobot.eventbus.ThreadMode
14 | import top.itning.yunshuclassschedule.R
15 | import top.itning.yunshuclassschedule.common.ConstantPool
16 | import top.itning.yunshuclassschedule.entity.EventEntity
17 | import top.itning.yunshuclassschedule.ui.fragment.setting.SettingsFragment
18 | import top.itning.yunshuclassschedule.ui.widget.TodayWidgetProvider
19 | import top.itning.yunshuclassschedule.util.ClassScheduleUtils
20 | import java.util.*
21 |
22 | /**
23 | * 小部件更新服务
24 | *
25 | * @author itning
26 | */
27 | class TodayWidgetService : Service(), SharedPreferences.OnSharedPreferenceChangeListener {
28 | private lateinit var sharedPreferences: SharedPreferences
29 |
30 | override fun onBind(intent: Intent?): IBinder? {
31 | throw UnsupportedOperationException("Not yet implemented")
32 | }
33 |
34 | override fun onCreate() {
35 | Log.d(TAG, "on Create")
36 | EventBus.getDefault().register(this)
37 | sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this)
38 | sharedPreferences.registerOnSharedPreferenceChangeListener(this)
39 | ClassScheduleUtils.startForegroundServer(this, TAG)
40 | super.onCreate()
41 | }
42 |
43 | override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
44 | Log.d(TAG, "on Start Command")
45 | return START_REDELIVER_INTENT
46 | }
47 |
48 | override fun onDestroy() {
49 | Log.d(TAG, "on Destroy")
50 | EventBus.getDefault().unregister(this)
51 | sharedPreferences.unregisterOnSharedPreferenceChangeListener(this)
52 | super.onDestroy()
53 | }
54 |
55 | @Subscribe(threadMode = ThreadMode.MAIN)
56 | fun onMessageEvent(eventEntity: EventEntity) {
57 | when (eventEntity.id) {
58 | ConstantPool.Int.TIME_TICK_CHANGE -> {
59 | val thisWidget = ComponentName(this, TodayWidgetProvider::class.java)
60 | val appWidgetManager = AppWidgetManager.getInstance(this)
61 | val appWidgetIds = appWidgetManager.getAppWidgetIds(thisWidget)
62 | Log.d(TAG, "appWidgetIds: ${Arrays.toString(appWidgetIds)}")
63 | appWidgetManager.notifyAppWidgetViewDataChanged(appWidgetIds, R.id.lv)
64 | }
65 | else -> {
66 |
67 | }
68 | }
69 | }
70 |
71 | override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) {
72 | if (key == SettingsFragment.FOREGROUND_SERVICE_STATUS) {
73 | if (sharedPreferences.getBoolean(SettingsFragment.FOREGROUND_SERVICE_STATUS, true)) {
74 | ClassScheduleUtils.startForegroundServer(this, TAG)
75 | } else {
76 | stopForeground(true)
77 | }
78 | }
79 | }
80 |
81 | companion object {
82 | private const val TAG = "TodayWidgetService"
83 | }
84 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # 云舒课表
2 | Android的开源课程表应用
3 |
4 | [](https://github.com/itning/YunShuClassSchedule/stargazers)
5 | [](https://github.com/itning/YunShuClassSchedule/network/members)
6 | [](https://github.com/itning/YunShuClassSchedule/watchers)
7 | [](https://github.com/itning?tab=followers)
8 |
9 | [](https://github.com/itning/YunShuClassSchedule/issues)
10 | [](https://github.com/itning/YunShuClassSchedule/blob/master/LICENSE)
11 | [](https://github.com/itning/YunShuClassSchedule/commits)
12 | [](https://github.com/itning/YunShuClassSchedule/releases)
13 | [](https://github.com/itning/YunShuClassSchedule)
14 | [](https://github.com/itning/hit-count)
15 | [](https://github.com/itning/YunShuClassSchedule)
16 |
17 | ## 不再维护
18 |
19 | 该项目写的很烂,没有进行分层,业务逻辑基本上都在``activity``中,未来会将该项目重构为使用``jetpack``的项目。
20 | 敬请期待。
21 |
22 | ## 下载
23 | [](https://www.coolapk.com/apk/top.itning.yunshuclassschedule)
24 | ## 功能
25 | - 今日课表
26 |
27 | - 本周课表
28 |
29 | - 上下课课程提醒
30 |
31 | - 上下课手机自动静音
32 |
33 | - 更换主题,背景图片
34 |
35 | - 查成绩
36 | ## 应用截图
37 | 
38 | 
39 | 
40 | 
41 | 
42 | 
43 | 
44 | ## 项目依赖库
45 | - [gson](https://github.com/google/gson)
46 | - [butterknife](https://github.com/JakeWharton/butterknife)
47 | - [eventbus](https://github.com/greenrobot/EventBus)
48 | - [greendao](https://github.com/greenrobot/greenDAO)
49 | - [bugly](https://bugly.qq.com)
50 | - [colorpreference](https://github.com/kizitonwose/colorpreference)
51 | - [matisse](https://github.com/zhihu/Matisse)
52 | - [glide](https://github.com/bumptech/glide)
53 | - [statusbarutil](https://github.com/laobie/StatusBarUtil)
54 | - [materialdatetimepicker](https://github.com/wdullaer/MaterialDateTimePicker)
55 | - [jsoup](https://github.com/jhy/jsoup)
56 | - [customactivityoncrash](https://github.com/Ereza/CustomActivityOnCrash)
57 | - [RangeSeekBar](https://github.com/Jay-Goo/RangeSeekBar)
58 | - [taptargetview](https://github.com/KeepSafe/TapTargetView)
59 |
--------------------------------------------------------------------------------
/app/src/main/java/top/itning/yunshuclassschedule/ui/fragment/CheckScoreFragment.kt:
--------------------------------------------------------------------------------
1 | package top.itning.yunshuclassschedule.ui.fragment
2 |
3 | import android.os.Bundle
4 | import android.util.Log
5 | import android.view.LayoutInflater
6 | import android.view.View
7 | import android.view.ViewGroup
8 | import androidx.fragment.app.Fragment
9 | import androidx.fragment.app.FragmentManager
10 | import org.greenrobot.eventbus.EventBus
11 | import org.greenrobot.eventbus.Subscribe
12 | import org.greenrobot.eventbus.ThreadMode
13 | import top.itning.yunshuclassschedule.R
14 | import top.itning.yunshuclassschedule.common.ConstantPool
15 | import top.itning.yunshuclassschedule.entity.EventEntity
16 | import top.itning.yunshuclassschedule.entity.Score
17 | import top.itning.yunshuclassschedule.ui.fragment.checkscore.CheckScoreLoginFragment
18 | import top.itning.yunshuclassschedule.ui.fragment.checkscore.CheckScoreShowFragment
19 | import top.itning.yunshuclassschedule.util.EventReceiver
20 | import java.util.*
21 |
22 | /**
23 | * 查成绩
24 | *
25 | * @author itning
26 | */
27 | class CheckScoreFragment : Fragment(), EventReceiver {
28 | private lateinit var mFragmentManager: FragmentManager
29 |
30 | override fun onCreate(savedInstanceState: Bundle?) {
31 | super.onCreate(savedInstanceState)
32 | EventBus.getDefault().register(this)
33 | }
34 |
35 | override fun onDestroy() {
36 | Log.d(TAG, "on Destroy")
37 | EventBus.getDefault().unregister(this)
38 | super.onDestroy()
39 | }
40 |
41 | override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
42 | val view = inflater.inflate(R.layout.fragment_check_score, container, false)
43 | mFragmentManager = childFragmentManager
44 | mFragmentManager.beginTransaction()
45 | .replace(R.id.frame_container, CheckScoreLoginFragment())
46 | .commit()
47 | return view
48 | }
49 |
50 | @Subscribe(threadMode = ThreadMode.MAIN)
51 | fun onMessageEvent(eventEntity: EventEntity) {
52 | when (eventEntity.id) {
53 | ConstantPool.Int.SCORE_LOGIN_SUCCESS -> {
54 | val checkScoreShowFragment = CheckScoreShowFragment()
55 | val bundle = Bundle()
56 |
57 | val scoreList = eventEntity.data as ArrayList
58 | bundle.putParcelableArrayList("scoreList", scoreList)
59 | checkScoreShowFragment.arguments = bundle
60 | mFragmentManager.beginTransaction()
61 | .replace(R.id.frame_container, checkScoreShowFragment)
62 | .addToBackStack("checkScoreShowFragment")
63 | .commit()
64 | }
65 | ConstantPool.Int.RETURN_LOGIN_FRAGMENT -> {
66 | mFragmentManager.beginTransaction()
67 | .replace(R.id.frame_container, CheckScoreLoginFragment())
68 | .commit()
69 | }
70 | else -> {
71 | }
72 | }
73 | }
74 |
75 | override fun eventTrigger(): Boolean {
76 | val backStackEntryCount = mFragmentManager.backStackEntryCount
77 | if (backStackEntryCount == 1) {
78 | mFragmentManager.popBackStackImmediate()
79 | return true
80 | }
81 | return false
82 | }
83 |
84 | companion object {
85 | private const val TAG = "CheckScoreFragment"
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_this_week.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
13 |
14 |
22 |
23 |
31 |
32 |
40 |
41 |
49 |
50 |
58 |
59 |
67 |
68 |
76 |
77 |
78 |
81 |
82 |
87 |
88 |
89 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_check_score_login.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
19 |
20 |
24 |
25 |
26 |
38 |
39 |
44 |
45 |
46 |
61 |
62 |
74 |
75 |
--------------------------------------------------------------------------------
/app/src/main/java/top/itning/yunshuclassschedule/common/ConstantPool.kt:
--------------------------------------------------------------------------------
1 | package top.itning.yunshuclassschedule.common
2 |
3 | /**
4 | * 常量池
5 | *
6 | * @author itning
7 | */
8 | class ConstantPool {
9 |
10 | enum class Str(private val value: String) {
11 | /**
12 | * 数据库名
13 | */
14 | DB_NAME("class-schedule.db"),
15 | /**
16 | * sharedPreferences 文件名
17 | */
18 | SHARED_PREFERENCES_FILENAME("class-schedule"),
19 | /**
20 | * 第一次进入app
21 | */
22 | FIRST_IN_APP("first_in_app"),
23 | /**
24 | * 周课表文字大小
25 | */
26 | WEEK_FONT_SIZE("class_font_size"),
27 | /**
28 | * 上一次的日期
29 | */
30 | LAST_DATE("last-date"),
31 | /**
32 | * 是否显示授课教师信息
33 | */
34 | TEACHER_INFO_STATUS("teacher_week_status"),
35 | /**
36 | * 下周一 日期
37 | */
38 | NEXT_WEEK_OF_MONDAY("this_week_of_sunday"),
39 | /**
40 | * 每天课程节数
41 | */
42 | CLASS_SECTION("class_section"),
43 | /**
44 | * 加入反馈群
45 | */
46 | ADD_GROUP_DIALOG_STATE("add_group_dialog_state"),
47 | /**
48 | * 是否已经引导过
49 | */
50 | NEW_USER_IS_STUDY("new_user_is_study");
51 |
52 | fun get(): String {
53 | return value
54 | }
55 | }
56 |
57 | enum class Int(private val value: kotlin.Int) {
58 | /**
59 | * 延迟进入主活动时间
60 | */
61 | DELAY_INTO_MAIN_ACTIVITY_TIME(1000),
62 | /**
63 | * 下载课程表信息错误
64 | */
65 | HTTP_ERROR(111),
66 | /**
67 | * 进入主活动
68 | */
69 | ENTER_HOME_ACTIVITY(112),
70 | /**
71 | * 退出间隔延迟
72 | */
73 | EXIT_DELAY(2000),
74 | /**
75 | * 时间改变
76 | */
77 | TIME_TICK_CHANGE(120),
78 | /**
79 | * 刷新本周课程fragment数据
80 | */
81 | REFRESH_WEEK_FRAGMENT_DATA(125),
82 | /**
83 | * 应用颜色改变
84 | */
85 | APP_COLOR_CHANGE(126),
86 | /**
87 | * 上课提醒
88 | */
89 | CLASS_UP_REMIND(127),
90 | /**
91 | * 下课提醒
92 | */
93 | CLASS_DOWN_REMIND(128),
94 | /**
95 | * 手机状态:取消静音
96 | */
97 | PHONE_MUTE_CANCEL(129),
98 | /**
99 | * 手机状态:开启静音
100 | */
101 | PHONE_MUTE_OPEN(130),
102 | /**
103 | * 课程信息数组更新
104 | */
105 | COURSE_INFO_ARRAY_UPDATE(131),
106 | /**
107 | * 需要重新初始化课程Fragment
108 | */
109 | REFRESH_CLASS_SCHEDULE_FRAGMENT(133),
110 | /**
111 | * 获取验证码和Cookie成功
112 | */
113 | GET_COOKIE_AND_IMAGE_OK(134),
114 | /**
115 | * 获取验证码和Cookie失败
116 | */
117 | GET_COOKIE_AND_IMAGE_FAILED(135),
118 | /**
119 | * 重新登陆
120 | */
121 | RE_LOGIN_SCORE(136),
122 | /**
123 | * 登陆时消息
124 | */
125 | SCORE_LOGIN_MSG(137),
126 | /**
127 | * 成绩查询成功
128 | */
129 | SCORE_LOGIN_SUCCESS(138),
130 | /**
131 | * 回到登陆页面
132 | */
133 | RETURN_LOGIN_FRAGMENT(139),
134 | /**
135 | * 课程周数改变(非持久)
136 | */
137 | CLASS_WEEK_CHANGE(140);
138 |
139 | fun get(): kotlin.Int {
140 | return value
141 | }
142 | }
143 | }
144 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | 云舒课表
3 | 打开导航抽屉
4 | 关闭导航抽屉
5 | 设置字体大小
6 | 欢迎使用
7 | 导入数据
8 | 更换背景图片
9 | 显示授课教师
10 | 姓名
11 | 学号
12 | 记住姓名和学号
13 | 登陆
14 | 课程名
15 | 地点
16 | 教师
17 | 粘贴该课程
18 | 复制该课程
19 | 软件施工:ITNING 舒露
20 | 原型设计:舒露
21 | 软件测试:舒露
22 | Github:YunShuClassSchedule
23 | Yun Shu™ SoftWare Series
24 | © 2018 ITNING.TOP ALL RIGHTS RESERVED
25 | 开始使用
26 | 星期一
27 | 星期二
28 | 星期三
29 | 星期四
30 | 星期五
31 | 星期六
32 | 星期日
33 | 课程表
34 | 查成绩
35 | 其它
36 | 设置
37 | 夜间模式
38 | 完成
39 | 导入课程数据
40 | 选择文件导入
41 | 导出课程数据
42 | 导出到文件
43 | 分享课程数据
44 | (╥﹏╥)\n发生了错误
45 | 重新打开APP
46 | 关闭APP
47 | 详细错误信息
48 | 详细错误信息
49 | 关闭
50 | 复制错误信息
51 | 已复制
52 | 错误信息
53 | 下一周
54 | 上一周
55 | 设置课程周数:
56 | 设为单周课程
57 | 设为双周课程
58 | 全部选择
59 | 清空选择
60 | 区间
61 | 今天没有课
62 |
63 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/widget_layout_item_draw.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
16 |
17 |
24 |
25 |
32 |
33 |
41 |
42 |
48 |
49 |
55 |
56 |
60 |
61 |
67 |
68 |
69 |
70 |
71 |
77 |
78 |
83 |
84 |
90 |
91 |
100 |
101 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 | apply plugin: 'org.greenrobot.greendao'
3 | apply plugin: 'kotlin-android'
4 | apply plugin: 'kotlin-kapt'
5 | apply plugin: 'kotlin-android-extensions'
6 | apply plugin: 'bugly'
7 |
8 | android {
9 | compileSdkVersion 28
10 | defaultConfig {
11 | applicationId "top.itning.yunshuclassschedule"
12 | minSdkVersion 21
13 | targetSdkVersion 28
14 | versionCode 64
15 | versionName "2.5.8"
16 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
17 | javaCompileOptions {
18 | annotationProcessorOptions {
19 | //填写自己的package name+自定义类名
20 | arguments = [eventBusIndex: 'top.itning.yunshuclassschedule.AppActivityIndex']
21 | }
22 | }
23 | resConfigs "zh", "en"
24 | }
25 | buildTypes {
26 | release {
27 | // 混淆
28 | minifyEnabled true
29 | // Zipalign优化
30 | zipAlignEnabled true
31 | // 移除无用的resource文件
32 | shrinkResources true
33 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
34 | }
35 | greendao {
36 | schemaVersion 3
37 | }
38 | }
39 | bugly {
40 | appId = '439037c8de'
41 | appKey = '037c8d58-2f72-4412-84bc-ba0b2340b7d3'
42 | }
43 | compileOptions {
44 | sourceCompatibility JavaVersion.VERSION_1_8
45 | targetCompatibility JavaVersion.VERSION_1_8
46 | }
47 | }
48 |
49 | dependencies {
50 | implementation fileTree(include: ['*.jar'], dir: 'libs')
51 | implementation 'androidx.appcompat:appcompat:1.1.0'
52 | implementation 'androidx.annotation:annotation:1.1.0'
53 | implementation 'com.google.android.material:material:1.1.0-alpha10'
54 | implementation 'androidx.gridlayout:gridlayout:1.0.0'
55 | implementation 'androidx.cardview:cardview:1.0.0'
56 | implementation 'androidx.preference:preference:1.1.0'
57 | implementation 'androidx.constraintlayout:constraintlayout:2.0.0-beta2'
58 | /*https://github.com/google/gson*/
59 | implementation 'com.google.code.gson:gson:2.8.5'
60 | /*https://github.com/greenrobot/EventBus*/
61 | implementation 'org.greenrobot:eventbus:3.1.1'
62 | kapt 'org.greenrobot:eventbus-annotation-processor:3.1.1'
63 | /*https://github.com/greenrobot/greenDAO*/
64 | implementation 'org.greenrobot:greendao:3.2.2'
65 | /*https://bugly.qq.com*/
66 | implementation 'com.tencent.bugly:crashreport:3.0.0'
67 | /*https://github.com/kizitonwose/colorpreference*/
68 | implementation 'com.github.kizitonwose.colorpreference:support:1.1.0'
69 | /*https://github.com/zhihu/Matisse*/
70 | implementation 'com.zhihu.android:matisse:0.5.2-beta4'
71 | /*https://github.com/bumptech/glide*/
72 | implementation 'com.github.bumptech.glide:glide:4.9.0'
73 | kapt 'com.github.bumptech.glide:compiler:4.9.0'
74 | /*https://github.com/laobie/StatusBarUtil*/
75 | implementation 'com.jaeger.statusbarutil:library:1.5.1'
76 | /*https://github.com/wdullaer/MaterialDateTimePicker*/
77 | implementation 'com.wdullaer:materialdatetimepicker:4.2.1'
78 | /*https://github.com/jhy/jsoup*/
79 | implementation 'org.jsoup:jsoup:1.12.1'
80 | /*https://github.com/Ereza/CustomActivityOnCrash*/
81 | implementation 'cat.ereza:customactivityoncrash:2.2.0'
82 | /*https://github.com/Hector1990/AutoWrapLineLayoutDemo*/
83 | implementation 'cn.wolfspider:autowraplinelayout:1.0.1'
84 | /*https://github.com/Jay-Goo/RangeSeekBar*/
85 | implementation 'com.github.Jay-Goo:RangeSeekBar:2.0.6'
86 | /*https://github.com/KeepSafe/TapTargetView*/
87 | implementation 'com.getkeepsafe.taptargetview:taptargetview:1.12.0'
88 |
89 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
90 |
91 | testImplementation 'junit:junit:4.12'
92 | androidTestImplementation 'androidx.test:runner:1.2.0'
93 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
94 | }
95 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_class_rv.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
16 |
17 |
24 |
25 |
32 |
33 |
41 |
42 |
48 |
49 |
55 |
56 |
60 |
61 |
67 |
68 |
69 |
70 |
71 |
77 |
78 |
83 |
84 |
90 |
91 |
100 |
101 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_today.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
13 |
14 |
19 |
20 |
21 |
28 |
29 |
41 |
42 |
54 |
55 |
68 |
69 |
81 |
82 |
83 |
84 |
85 |
86 |
92 |
93 |
--------------------------------------------------------------------------------
/app/src/main/java/top/itning/yunshuclassschedule/ui/activity/SettingActivity.kt:
--------------------------------------------------------------------------------
1 | package top.itning.yunshuclassschedule.ui.activity
2 |
3 |
4 | import android.content.Intent
5 | import android.content.SharedPreferences
6 | import android.os.Bundle
7 | import android.util.Log
8 | import android.view.MenuItem
9 | import androidx.preference.PreferenceFragmentCompat
10 | import androidx.preference.PreferenceManager
11 | import androidx.preference.PreferenceScreen
12 | import org.greenrobot.eventbus.EventBus
13 | import org.greenrobot.eventbus.Subscribe
14 | import org.greenrobot.eventbus.ThreadMode
15 | import top.itning.yunshuclassschedule.R
16 | import top.itning.yunshuclassschedule.common.BaseActivity
17 | import top.itning.yunshuclassschedule.common.ConstantPool
18 | import top.itning.yunshuclassschedule.entity.EventEntity
19 | import top.itning.yunshuclassschedule.service.CourseInfoService
20 | import top.itning.yunshuclassschedule.ui.fragment.setting.SettingsFragment
21 | import top.itning.yunshuclassschedule.ui.fragment.setting.SettingsFragment.Companion.FOREGROUND_SERVICE_STATUS
22 | import top.itning.yunshuclassschedule.util.ThemeChangeUtil
23 |
24 | /**
25 | * 设置Activity
26 | *
27 | * @author itning
28 | */
29 | class SettingActivity : BaseActivity(), PreferenceFragmentCompat.OnPreferenceStartScreenCallback, SharedPreferences.OnSharedPreferenceChangeListener {
30 | private lateinit var sharedPreferences: SharedPreferences
31 |
32 | override fun onCreate(savedInstanceState: Bundle?) {
33 | ThemeChangeUtil.changeTheme(this)
34 | super.onCreate(savedInstanceState)
35 | setContentView(R.layout.activity_setting)
36 | sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this)
37 | sharedPreferences.registerOnSharedPreferenceChangeListener(this)
38 | EventBus.getDefault().register(this)
39 | initView()
40 | }
41 |
42 | /**
43 | * 初始化View
44 | */
45 | private fun initView() {
46 | Log.d(TAG, "init view")
47 | //设置返回箭头
48 | val supportActionBar = supportActionBar
49 | if (supportActionBar != null) {
50 | supportActionBar.setDisplayHomeAsUpEnabled(true)
51 | supportActionBar.title = "设置"
52 | }
53 | val settingsFragment = SettingsFragment()
54 | supportFragmentManager.beginTransaction()
55 | .replace(R.id.frame_container, settingsFragment)
56 | .commit()
57 | }
58 |
59 | @Subscribe(threadMode = ThreadMode.MAIN)
60 | override fun onMessageEvent(eventEntity: EventEntity) {
61 | when (eventEntity.id) {
62 | ConstantPool.Int.APP_COLOR_CHANGE -> {
63 | ThemeChangeUtil.changeTheme(this)
64 | }
65 | else -> {
66 | }
67 | }
68 | }
69 |
70 | override fun onDestroy() {
71 | EventBus.getDefault().unregister(this)
72 | sharedPreferences.unregisterOnSharedPreferenceChangeListener(this)
73 | super.onDestroy()
74 | }
75 |
76 | override fun onOptionsItemSelected(item: MenuItem): Boolean {
77 | when (item.itemId) {
78 | android.R.id.home -> {
79 | finish()
80 | }
81 | }
82 | return super.onOptionsItemSelected(item)
83 | }
84 |
85 | override fun onPreferenceStartScreen(caller: PreferenceFragmentCompat, pref: PreferenceScreen): Boolean {
86 | val fragment = SettingsFragment()
87 | val args = Bundle()
88 | val key = pref.key
89 | args.putString(PreferenceFragmentCompat.ARG_PREFERENCE_ROOT, key)
90 | fragment.arguments = args
91 | supportFragmentManager
92 | .beginTransaction()
93 | .replace(R.id.frame_container, fragment)
94 | .addToBackStack(key)
95 | .commit()
96 | return true
97 | }
98 |
99 | override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) {
100 | if (key == FOREGROUND_SERVICE_STATUS) {
101 | if (sharedPreferences.getBoolean(FOREGROUND_SERVICE_STATUS, true)) {
102 | startService(Intent(this, CourseInfoService::class.java))
103 | }
104 | }
105 | }
106 |
107 | companion object {
108 | private const val TAG = "SettingActivity"
109 | }
110 | }
111 |
--------------------------------------------------------------------------------
/app/src/main/java/top/itning/yunshuclassschedule/util/NetWorkUtils.kt:
--------------------------------------------------------------------------------
1 | package top.itning.yunshuclassschedule.util
2 |
3 | import android.content.Context
4 | import android.location.LocationManager
5 | import android.net.ConnectivityManager
6 | import android.telephony.TelephonyManager
7 | import androidx.annotation.NonNull
8 |
9 |
10 | /**
11 | * https://www.jianshu.com/p/10ed9ae02775
12 | *
13 | * @author alic
14 | * @author itning
15 | */
16 | object NetWorkUtils {
17 | /**
18 | * 判断是否有网络连接
19 | *
20 | * @param context [Context]
21 | * @return 有返回true
22 | */
23 | fun isNetworkConnected(@NonNull context: Context): Boolean {
24 | // 获取手机所有连接管理对象(包括对wi-fi,net等连接的管理)
25 | val manager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
26 | // 获取NetworkInfo对象
27 | val networkInfo = manager.activeNetworkInfo
28 | //判断NetworkInfo对象是否为空
29 | return networkInfo != null && networkInfo.isAvailable
30 | }
31 |
32 | /**
33 | * 判断WIFI网络是否可用
34 | *
35 | * @param context [Context]
36 | * @return 是否可用
37 | */
38 | fun isMobileConnected(@NonNull context: Context): Boolean {
39 | //获取手机所有连接管理对象(包括对wi-fi,net等连接的管理)
40 | val manager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
41 | //获取NetworkInfo对象
42 | val networkInfo = manager.activeNetworkInfo
43 | //判断NetworkInfo对象是否为空 并且类型是否为MOBILE
44 | return networkInfo != null && networkInfo.type == ConnectivityManager.TYPE_MOBILE && networkInfo.isAvailable
45 | }
46 |
47 | /**
48 | * 获取当前网络连接的类型信息
49 | * 原生
50 | *
51 | * @param context [Context]
52 | * @return [ConnectivityManager]
53 | */
54 | fun getConnectedType(@NonNull context: Context): Int {
55 | //获取手机所有连接管理对象
56 | val manager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
57 | //获取NetworkInfo对象
58 | val networkInfo = manager.activeNetworkInfo
59 | return if (networkInfo != null && networkInfo.isAvailable) {
60 | //返回NetworkInfo的类型
61 | networkInfo.type
62 | } else -1
63 | }
64 |
65 | /**
66 | * 获取当前的网络状态 :没有网络-0:WIFI网络1:4G网络-4:3G网络-3:2G网络-2
67 | * 自定义
68 | *
69 | * @param context [Context]
70 | * @return 网络状态
71 | */
72 | fun getAPNType(@NonNull context: Context): Int {
73 | //结果返回值
74 | var netType = 0
75 | //获取手机所有连接管理对象
76 | val manager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
77 | //获取NetworkInfo对象
78 | val networkInfo = manager.activeNetworkInfo ?: return netType
79 | //NetworkInfo对象为空 则代表没有网络
80 | //否则 NetworkInfo对象不为空 则获取该networkInfo的类型
81 | val nType = networkInfo.type
82 | if (nType == ConnectivityManager.TYPE_WIFI) {
83 | //WIFI
84 | netType = 1
85 | } else if (nType == ConnectivityManager.TYPE_MOBILE) {
86 | val nSubType = networkInfo.subtype
87 | val telephonyManager = context.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
88 | //3G 联通的3G为UMTS或HSDPA 电信的3G为EVDO
89 | netType = if (nSubType == TelephonyManager.NETWORK_TYPE_LTE && !telephonyManager.isNetworkRoaming) {
90 | 4
91 | } else if (nSubType == TelephonyManager.NETWORK_TYPE_UMTS
92 | || nSubType == TelephonyManager.NETWORK_TYPE_HSDPA
93 | || nSubType == TelephonyManager.NETWORK_TYPE_EVDO_0 && !telephonyManager.isNetworkRoaming) {
94 | 3
95 | //2G 移动和联通的2G为GPRS或EGDE,电信的2G为CDMA
96 | } else if (nSubType == TelephonyManager.NETWORK_TYPE_GPRS
97 | || nSubType == TelephonyManager.NETWORK_TYPE_EDGE
98 | || nSubType == TelephonyManager.NETWORK_TYPE_CDMA && !telephonyManager.isNetworkRoaming) {
99 | 2
100 | } else {
101 | 2
102 | }
103 | }
104 | return netType
105 | }
106 |
107 | /**
108 | * 判断GPS是否打开
109 | * ACCESS_FINE_LOCATION权限
110 | *
111 | * @param context [Context]
112 | * @return 是否打开
113 | */
114 | fun isGPSEnabled(@NonNull context: Context): Boolean {
115 | //获取手机所有连接LOCATION_SERVICE对象
116 | val locationManager = context.getSystemService(Context.LOCATION_SERVICE) as LocationManager
117 | // 通过GPS卫星定位,定位级别可以精确到街(通过24颗卫星定位,在室外和空旷的地方定位准确、速度快)
118 | val gps = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)
119 | // 通过WLAN或移动网络(3G/2G)确定的位置(也称作AGPS,辅助GPS定位。主要用于在室内或遮盖物(建筑群或茂密的深林等)密集的地方定位)
120 | val network = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)
121 | return gps || network
122 | }
123 | }
124 |
--------------------------------------------------------------------------------
/app/src/main/java/top/itning/yunshuclassschedule/ui/activity/SplashActivity.kt:
--------------------------------------------------------------------------------
1 | package top.itning.yunshuclassschedule.ui.activity
2 |
3 | import android.app.NotificationManager
4 | import android.app.job.JobInfo
5 | import android.app.job.JobScheduler
6 | import android.content.ComponentName
7 | import android.content.Context
8 | import android.content.Intent
9 | import android.graphics.Point
10 | import android.os.Build
11 | import android.os.Bundle
12 | import android.os.Handler
13 | import android.preference.PreferenceManager
14 | import android.util.Log
15 | import kotlinx.android.synthetic.main.activity_splash.*
16 | import org.greenrobot.eventbus.EventBus
17 | import org.greenrobot.eventbus.Subscribe
18 | import org.greenrobot.eventbus.ThreadMode
19 | import top.itning.yunshuclassschedule.R
20 | import top.itning.yunshuclassschedule.common.App
21 | import top.itning.yunshuclassschedule.common.BaseActivity
22 | import top.itning.yunshuclassschedule.common.ConstantPool
23 | import top.itning.yunshuclassschedule.entity.EventEntity
24 | import top.itning.yunshuclassschedule.service.CourseInfoService
25 | import top.itning.yunshuclassschedule.service.JobSchedulerService
26 | import top.itning.yunshuclassschedule.util.GlideApp
27 |
28 | /**
29 | * 闪屏页
30 | *
31 | * @author itning
32 | */
33 | class SplashActivity : BaseActivity() {
34 | override fun onCreate(savedInstanceState: Bundle?) {
35 | super.onCreate(savedInstanceState)
36 | if (!isTaskRoot) {
37 | finish()
38 | return
39 | }
40 | setContentView(R.layout.activity_splash)
41 | EventBus.getDefault().register(this)
42 | initBackGroundImage()
43 |
44 | startService(Intent(this, CourseInfoService::class.java))
45 |
46 | initJobScheduler()
47 | startTime = System.currentTimeMillis()
48 |
49 | val notificationManager = applicationContext.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
50 | //勿扰权限判定
51 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && !notificationManager.isNotificationPolicyAccessGranted) {
52 | PreferenceManager.getDefaultSharedPreferences(this).edit().putBoolean("phone_mute_status", false).apply()
53 | }
54 | Handler().postDelayed({ this.enterMainActivity() }, ConstantPool.Int.DELAY_INTO_MAIN_ACTIVITY_TIME.get() - (System.currentTimeMillis() - startTime))
55 | }
56 |
57 | /**
58 | * 初始化背景图片
59 | */
60 | private fun initBackGroundImage() {
61 | val display = this.windowManager.defaultDisplay
62 | val size = Point()
63 | display.getSize(size)
64 | GlideApp
65 | .with(this)
66 | .load(R.drawable.splash_background)
67 | .override(size.x, size.y)
68 | .centerCrop()
69 | .into(iv_splash)
70 | }
71 |
72 | /**
73 | * init Job Scheduler
74 | */
75 | private fun initJobScheduler() {
76 | Log.d(TAG, "init Job Scheduler")
77 | val jobScheduler = getSystemService(Context.JOB_SCHEDULER_SERVICE) as JobScheduler
78 | jobScheduler.cancelAll()
79 | val jobInfo = JobInfo.Builder(1024, ComponentName(packageName, JobSchedulerService::class.java.name))
80 | //10 minutes
81 | .setPeriodic((10 * 60 * 1000).toLong())
82 | .setRequiredNetworkType(JobInfo.NETWORK_TYPE_NONE)
83 | .build()
84 | val schedule = jobScheduler.schedule(jobInfo)
85 | if (schedule <= 0) {
86 | Log.e(TAG, "schedule error!")
87 | }
88 | }
89 |
90 | /**
91 | * 进入主Activity
92 | */
93 | private fun enterMainActivity() {
94 | val intent: Intent = if (App.sharedPreferences.getBoolean(ConstantPool.Str.FIRST_IN_APP.get(), true)) {
95 | //第一次进入APP
96 | Intent(this, LoginActivity::class.java)
97 | } else {
98 | //非第一次,肯定已经登陆
99 | Intent(this, MainActivity::class.java)
100 | }
101 | startActivity(intent)
102 | finish()
103 | }
104 |
105 | @Subscribe(threadMode = ThreadMode.MAIN)
106 | override fun onMessageEvent(eventEntity: EventEntity) {
107 | when (eventEntity.id) {
108 | ConstantPool.Int.ENTER_HOME_ACTIVITY -> {
109 | Handler().postDelayed({ this.enterMainActivity() }, ConstantPool.Int.DELAY_INTO_MAIN_ACTIVITY_TIME.get() - (System.currentTimeMillis() - startTime))
110 | }
111 | else -> {
112 | }
113 | }
114 | }
115 |
116 | override fun onBackPressed() {
117 | //do nothing
118 | }
119 |
120 | override fun onDestroy() {
121 | EventBus.getDefault().unregister(this)
122 | super.onDestroy()
123 | }
124 |
125 | companion object {
126 | private const val TAG = "SplashActivity"
127 | private var startTime: Long = 0
128 | }
129 | }
130 |
--------------------------------------------------------------------------------
/app/src/main/res/values/arrays.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | - 1
5 | - 25
6 | - 50
7 |
8 |
9 |
10 | - 今天课程
11 | - 本周课程
12 |
13 |
14 | - today
15 | - week
16 |
17 |
18 |
19 | - 上课前1分钟
20 | - 上课前3分钟
21 | - 上课前5分钟
22 | - 上课前10分钟
23 | - 上课前30分钟
24 |
25 |
26 | - 1
27 | - 3
28 | - 5
29 | - 10
30 | - 30
31 |
32 |
33 |
34 | - 下课前1分钟
35 | - 下课前3分钟
36 | - 下课前5分钟
37 | - 下课前10分钟
38 | - 下课前30分钟
39 |
40 |
41 | - 1
42 | - 3
43 | - 5
44 | - 10
45 | - 30
46 |
47 |
48 |
49 | - 上课时
50 | - 上课前1分钟
51 | - 上课前3分钟
52 | - 上课前5分钟
53 | - 上课前10分钟
54 |
55 |
56 | - 0
57 | - 1
58 | - 3
59 | - 5
60 | - 10
61 |
62 |
63 |
64 | - 下课时
65 | - 下课前1分钟
66 | - 下课前3分钟
67 | - 下课前5分钟
68 | - 下课前10分钟
69 |
70 |
71 | - 0
72 | - 1
73 | - 3
74 | - 5
75 | - 10
76 |
77 |
78 |
79 | - #f44336
80 | - #e91e63
81 | - #9c27b0
82 | - #673ab7
83 | - #3f51b5
84 | - #2196f3
85 | - #03a9f4
86 | - #00bcd4
87 | - #009688
88 | - #4caf50
89 | - #8bc34a
90 | - #cddc39
91 | - #ffeb3b
92 | - #ffc107
93 | - #ff9800
94 | - #ff5722
95 | - #795548
96 | - #9e9e9e
97 | - #607d8b
98 |
99 |
100 |
101 | - #d32f2f
102 | - #c2185b
103 | - #7b1fa2
104 | - #512da8
105 | - #303f9f
106 | - #1976d2
107 | - #0288d1
108 | - #0097a7
109 | - #00796b
110 | - #388e3c
111 | - #689f38
112 | - #afb42b
113 | - #fbc02d
114 | - #ffa000
115 | - #f57c00
116 | - #e64a19
117 | - #5d4037
118 | - #616161
119 | - #455a64
120 |
121 |
122 |
123 | - #FF5252
124 | - #FF4081
125 | - #E040FB
126 | - #7C4DFF
127 | - #536DFE
128 | - #448AFF
129 | - #40C4FF
130 | - #18FFFF
131 | - #64FFDA
132 | - #69F0AE
133 | - #B2FF59
134 | - #EEFF41
135 | - #FFFF00
136 | - #FFD740
137 | - #FFAB40
138 | - #FF6E40
139 |
140 |
141 |
142 | - #de746c
143 | - #d14b78
144 | - #9e4fac
145 | - #917ab9
146 | - #6873b1
147 | - #9ccdf4
148 | - #b0bbfa
149 | - #b0edf4
150 | - #5ca19b
151 | - #73b776
152 | - #acc68e
153 | - #c9d181
154 | - #fff59f
155 | - #fdde81
156 | - #fac371
157 | - #fa9271
158 | - #806c65
159 | - #cccccc
160 | - #798387
161 |
162 |
--------------------------------------------------------------------------------
/app/src/main/java/top/itning/yunshuclassschedule/ui/fragment/ClassScheduleFragment.kt:
--------------------------------------------------------------------------------
1 | package top.itning.yunshuclassschedule.ui.fragment
2 |
3 | import android.os.Bundle
4 | import android.os.Parcelable
5 | import android.util.Log
6 | import android.view.LayoutInflater
7 | import android.view.View
8 | import android.view.ViewGroup
9 | import android.widget.Toast
10 | import androidx.annotation.Nullable
11 | import androidx.fragment.app.Fragment
12 | import androidx.fragment.app.FragmentStatePagerAdapter
13 | import androidx.preference.PreferenceManager
14 | import androidx.viewpager.widget.PagerAdapter
15 | import kotlinx.android.synthetic.main.fragment_class_schedule.*
16 | import org.greenrobot.eventbus.EventBus
17 | import org.greenrobot.eventbus.Subscribe
18 | import org.greenrobot.eventbus.ThreadMode
19 | import top.itning.yunshuclassschedule.R
20 | import top.itning.yunshuclassschedule.common.ConstantPool
21 | import top.itning.yunshuclassschedule.entity.EventEntity
22 | import top.itning.yunshuclassschedule.ui.fragment.setting.SettingsFragment.Companion.DEFAULT_SHOW_MAIN_FRAGMENT
23 | import top.itning.yunshuclassschedule.ui.fragment.setting.SettingsFragment.Companion.NOW_WEEK_NUM
24 | import top.itning.yunshuclassschedule.util.ThemeChangeUtil
25 | import java.util.*
26 |
27 | /**
28 | * 课程表
29 | *
30 | * @author itning
31 | */
32 | class ClassScheduleFragment : Fragment() {
33 |
34 | /**
35 | * 标题集合
36 | */
37 | private val titleList: MutableList
38 | /**
39 | * 片段集合
40 | */
41 | private val fragmentList: MutableList
42 |
43 | init {
44 | titleList = ArrayList()
45 | titleList.add("今天")
46 | titleList.add("本周")
47 | fragmentList = ArrayList()
48 | fragmentList.add(TodayFragment())
49 | fragmentList.add(ThisWeekFragment())
50 | }
51 |
52 | override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
53 | Log.d(TAG, "on Create View")
54 | return inflater.inflate(R.layout.fragment_class_schedule, container, false)
55 | }
56 |
57 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
58 | ThemeChangeUtil.setTabLayoutColor(requireContext(), tl)
59 | initData()
60 | //设置默认展示页面
61 | if (TODAY != PreferenceManager.getDefaultSharedPreferences(requireContext()).getString(DEFAULT_SHOW_MAIN_FRAGMENT, TODAY)) {
62 | vp.currentItem = 1
63 | tl.getTabAt(1)?.select()
64 | }
65 | }
66 |
67 | private fun initData() {
68 | //预加载
69 | vp.offscreenPageLimit = fragmentList.size
70 | vp.adapter = object : FragmentStatePagerAdapter(childFragmentManager) {
71 |
72 | override fun getCount(): Int {
73 | return fragmentList.size
74 | }
75 |
76 | override fun getItem(position: Int): Fragment {
77 | return fragmentList[position]
78 | }
79 |
80 | @Nullable
81 | override fun getPageTitle(position: Int): CharSequence {
82 | return titleList[position]
83 | }
84 |
85 | override fun getItemPosition(`object`: Any): Int {
86 | Log.d(TAG, "getItemPosition: $`object`")
87 | return PagerAdapter.POSITION_NONE
88 | }
89 |
90 | override fun restoreState(state: Parcelable?, loader: ClassLoader?) {
91 | try {
92 | super.restoreState(state, loader)
93 | } catch (e: Exception) {
94 | // null caught
95 | }
96 |
97 | }
98 | }
99 | tl.setupWithViewPager(vp)
100 | }
101 |
102 | override fun onCreate(savedInstanceState: Bundle?) {
103 | Log.d(TAG, "on Create")
104 | super.onCreate(savedInstanceState)
105 | EventBus.getDefault().register(this)
106 | }
107 |
108 | override fun onDestroy() {
109 | Log.d(TAG, "on Destroy")
110 | EventBus.getDefault().unregister(this)
111 | super.onDestroy()
112 | }
113 |
114 | @Subscribe(threadMode = ThreadMode.MAIN)
115 | fun onMessageEvent(eventEntity: EventEntity) {
116 | when (eventEntity.id) {
117 | ConstantPool.Int.APP_COLOR_CHANGE -> {
118 | ThemeChangeUtil.setTabLayoutColor(requireContext(), tl)
119 | }
120 | ConstantPool.Int.REFRESH_CLASS_SCHEDULE_FRAGMENT -> {
121 | val adapter = vp.adapter
122 | if (adapter == null) {
123 | Toast.makeText(requireContext(), "未找到适配器,尝试重新打开APP解决此问题", Toast.LENGTH_LONG).show()
124 | return
125 | }
126 | adapter.notifyDataSetChanged()
127 | }
128 | ConstantPool.Int.CLASS_WEEK_CHANGE -> {
129 | if (PreferenceManager.getDefaultSharedPreferences(context).getString(NOW_WEEK_NUM, "1") == eventEntity.msg) {
130 | tl.getTabAt(1)?.text = "本周"
131 | } else {
132 | tl.getTabAt(1)?.text = "第${eventEntity.msg}周"
133 | }
134 | }
135 | else -> {
136 | }
137 | }
138 | }
139 |
140 | companion object {
141 | private const val TAG = "ClassScheduleFragment"
142 | private const val TODAY = "today"
143 | }
144 | }
145 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Attempt to set APP_HOME
10 | # Resolve links: $0 may be a link
11 | PRG="$0"
12 | # Need this for relative symlinks.
13 | while [ -h "$PRG" ] ; do
14 | ls=`ls -ld "$PRG"`
15 | link=`expr "$ls" : '.*-> \(.*\)$'`
16 | if expr "$link" : '/.*' > /dev/null; then
17 | PRG="$link"
18 | else
19 | PRG=`dirname "$PRG"`"/$link"
20 | fi
21 | done
22 | SAVED="`pwd`"
23 | cd "`dirname \"$PRG\"`/" >/dev/null
24 | APP_HOME="`pwd -P`"
25 | cd "$SAVED" >/dev/null
26 |
27 | APP_NAME="Gradle"
28 | APP_BASE_NAME=`basename "$0"`
29 |
30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
31 | DEFAULT_JVM_OPTS=""
32 |
33 | # Use the maximum available, or set MAX_FD != -1 to use that value.
34 | MAX_FD="maximum"
35 |
36 | warn () {
37 | echo "$*"
38 | }
39 |
40 | die () {
41 | echo
42 | echo "$*"
43 | echo
44 | exit 1
45 | }
46 |
47 | # OS specific support (must be 'true' or 'false').
48 | cygwin=false
49 | msys=false
50 | darwin=false
51 | nonstop=false
52 | case "`uname`" in
53 | CYGWIN* )
54 | cygwin=true
55 | ;;
56 | Darwin* )
57 | darwin=true
58 | ;;
59 | MINGW* )
60 | msys=true
61 | ;;
62 | NONSTOP* )
63 | nonstop=true
64 | ;;
65 | esac
66 |
67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
68 |
69 | # Determine the Java command to use to start the JVM.
70 | if [ -n "$JAVA_HOME" ] ; then
71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
72 | # IBM's JDK on AIX uses strange locations for the executables
73 | JAVACMD="$JAVA_HOME/jre/sh/java"
74 | else
75 | JAVACMD="$JAVA_HOME/bin/java"
76 | fi
77 | if [ ! -x "$JAVACMD" ] ; then
78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
79 |
80 | Please set the JAVA_HOME variable in your environment to match the
81 | location of your Java installation."
82 | fi
83 | else
84 | JAVACMD="java"
85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
86 |
87 | Please set the JAVA_HOME variable in your environment to match the
88 | location of your Java installation."
89 | fi
90 |
91 | # Increase the maximum file descriptors if we can.
92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
93 | MAX_FD_LIMIT=`ulimit -H -n`
94 | if [ $? -eq 0 ] ; then
95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
96 | MAX_FD="$MAX_FD_LIMIT"
97 | fi
98 | ulimit -n $MAX_FD
99 | if [ $? -ne 0 ] ; then
100 | warn "Could not set maximum file descriptor limit: $MAX_FD"
101 | fi
102 | else
103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
104 | fi
105 | fi
106 |
107 | # For Darwin, add options to specify how the application appears in the dock
108 | if $darwin; then
109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
110 | fi
111 |
112 | # For Cygwin, switch paths to Windows format before running java
113 | if $cygwin ; then
114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
116 | JAVACMD=`cygpath --unix "$JAVACMD"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Escape application args
158 | save () {
159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
160 | echo " "
161 | }
162 | APP_ARGS=$(save "$@")
163 |
164 | # Collect all arguments for the java command, following the shell quoting and substitution rules
165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
166 |
167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
169 | cd "$(dirname "$0")"
170 | fi
171 |
172 | exec "$JAVACMD" "$@"
173 |
--------------------------------------------------------------------------------
/app/src/main/java/top/itning/yunshuclassschedule/ui/widget/ToadyRemoteViewsFactory.kt:
--------------------------------------------------------------------------------
1 | package top.itning.yunshuclassschedule.ui.widget
2 |
3 | import android.content.Context
4 | import android.content.Intent
5 | import android.graphics.Bitmap
6 | import android.graphics.Canvas
7 | import android.util.Log
8 | import android.view.LayoutInflater
9 | import android.view.View
10 | import android.widget.*
11 | import androidx.core.content.ContextCompat
12 | import androidx.preference.PreferenceManager
13 | import top.itning.yunshuclassschedule.R
14 | import top.itning.yunshuclassschedule.common.App
15 | import top.itning.yunshuclassschedule.common.ConstantPool
16 | import top.itning.yunshuclassschedule.entity.ClassSchedule
17 | import top.itning.yunshuclassschedule.entity.ClassScheduleDao
18 | import top.itning.yunshuclassschedule.ui.fragment.setting.SettingsFragment
19 | import top.itning.yunshuclassschedule.ui.view.RoundBackChange
20 | import top.itning.yunshuclassschedule.util.ClassScheduleUtils
21 | import top.itning.yunshuclassschedule.util.DateUtils
22 | import java.util.*
23 |
24 |
25 | /**
26 | * 适配器工厂
27 | *
28 | * @author itning
29 | */
30 | class ToadyRemoteViewsFactory(val context: Context, val intent: Intent?) : RemoteViewsService.RemoteViewsFactory {
31 | private var orderListBySection = mutableListOf()
32 | var width: Int = 0
33 | var height: Int = 0
34 | private val daoSession = (context.applicationContext as App).daoSession
35 | private val colorArray = IntArray(7)
36 |
37 | override fun onCreate() {
38 | val scale = context.resources.displayMetrics.density
39 | width = (325 * scale + 0.5f).toInt()
40 | height = (60 * scale + 0.5f).toInt()
41 | colorArray[0] = ContextCompat.getColor(context, R.color.class_color_1)
42 | colorArray[1] = ContextCompat.getColor(context, R.color.class_color_2)
43 | colorArray[2] = ContextCompat.getColor(context, R.color.class_color_3)
44 | colorArray[3] = ContextCompat.getColor(context, R.color.class_color_4)
45 | colorArray[4] = ContextCompat.getColor(context, R.color.class_color_5)
46 | colorArray[5] = ContextCompat.getColor(context, R.color.class_color_6)
47 | colorArray[6] = ContextCompat.getColor(context, R.color.class_color_7)
48 | }
49 |
50 | override fun onDataSetChanged() {
51 | Log.d(TAG, "onDataSetChanged")
52 | val nowWeekNum = (PreferenceManager.getDefaultSharedPreferences(context).getString(SettingsFragment.NOW_WEEK_NUM, "1")!!.toInt() - 1).toString()
53 | val section = App.sharedPreferences.getInt(ConstantPool.Str.CLASS_SECTION.get(), 5)
54 | orderListBySection = ClassScheduleUtils
55 | .orderListBySection(daoSession
56 | .classScheduleDao
57 | .queryBuilder()
58 | .where(ClassScheduleDao.Properties.Week.eq(DateUtils.week))
59 | .list()
60 | .filter { ClassScheduleUtils.isThisWeekOfClassSchedule(it, nowWeekNum) }
61 | .filter { it.section <= section }
62 | .toMutableList())
63 |
64 | }
65 |
66 | override fun onDestroy() {
67 | Log.d(TAG, "onDestroy")
68 | orderListBySection.clear()
69 | }
70 |
71 | override fun getCount(): Int {
72 | return orderListBySection.size
73 | }
74 |
75 | override fun getViewAt(position: Int): RemoteViews? {
76 | val classSchedule = orderListBySection[position]
77 | val relativeLayout = LayoutInflater.from(context).inflate(R.layout.widget_layout_item_draw, RelativeLayout(context))
78 | val name = relativeLayout.findViewById(R.id.tv_name)
79 | val location = relativeLayout.findViewById(R.id.tv_location)
80 | val time = relativeLayout.findViewById(R.id.tv_time)
81 | val round = relativeLayout.findViewById(R.id.round)
82 | round.setBackColor(colorArray[Random().nextInt(colorArray.size)])
83 | name.text = classSchedule.name
84 | location.text = classSchedule.location
85 | time.text = DateUtils.timeList[classSchedule.section - 1]
86 | if (position == 0 && ClassScheduleUtils.haveClassAfterTime(orderListBySection)) {
87 | val viewBottom = relativeLayout.findViewById(R.id.view_bottom)
88 | val viewTop = relativeLayout.findViewById(R.id.view_top)
89 | val viewLeft = relativeLayout.findViewById(R.id.view_left)
90 | val viewProgress = relativeLayout.findViewById(R.id.view_progress)
91 | val flNo = relativeLayout.findViewById(R.id.fl_no)
92 | flNo.visibility = View.INVISIBLE
93 | viewBottom.visibility = View.VISIBLE
94 | viewTop.visibility = View.VISIBLE
95 | viewLeft.visibility = View.VISIBLE
96 | viewProgress.visibility = View.VISIBLE
97 | val layoutParams = viewProgress.layoutParams
98 | layoutParams.width = DateUtils.getNowProgress(width, orderListBySection)
99 | viewProgress.layoutParams = layoutParams
100 | }
101 |
102 | val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
103 | relativeLayout.measure(width, height)
104 | relativeLayout.layout(0, 0, 0, 0)
105 | relativeLayout.draw(Canvas(bitmap))
106 |
107 | val remoteViews = RemoteViews(context.packageName, R.layout.widget_layout_item)
108 | remoteViews.setBitmap(R.id.iv, "setImageBitmap", bitmap)
109 | return remoteViews
110 | }
111 |
112 | override fun getLoadingView(): RemoteViews? {
113 | return null
114 | }
115 |
116 | override fun getViewTypeCount(): Int {
117 | return 1
118 | }
119 |
120 | override fun getItemId(position: Int): Long {
121 | return position.toLong()
122 | }
123 |
124 | override fun hasStableIds(): Boolean {
125 | return true
126 | }
127 |
128 | companion object {
129 | private const val TAG = "ToadyRemoteViewsFactory"
130 | }
131 | }
132 |
--------------------------------------------------------------------------------
/app/src/main/java/top/itning/yunshuclassschedule/ui/adapter/TodayRecyclerViewAdapter.kt:
--------------------------------------------------------------------------------
1 | package top.itning.yunshuclassschedule.ui.adapter
2 |
3 | import android.content.Context
4 | import android.graphics.Point
5 | import android.util.Log
6 | import android.view.LayoutInflater
7 | import android.view.View
8 | import android.view.ViewGroup
9 | import android.view.WindowManager
10 | import android.widget.FrameLayout
11 | import android.widget.TextView
12 | import android.widget.Toast
13 | import androidx.annotation.NonNull
14 | import androidx.core.content.ContextCompat
15 | import androidx.recyclerview.widget.RecyclerView
16 | import com.tencent.bugly.crashreport.CrashReport
17 | import top.itning.yunshuclassschedule.R
18 | import top.itning.yunshuclassschedule.entity.ClassSchedule
19 | import top.itning.yunshuclassschedule.ui.view.RoundBackChange
20 | import top.itning.yunshuclassschedule.util.ClassScheduleUtils
21 | import top.itning.yunshuclassschedule.util.DateUtils
22 | import top.itning.yunshuclassschedule.util.ThemeChangeUtil
23 | import java.util.*
24 |
25 | /**
26 | * 今天课程列表适配器
27 | *
28 | * @author itning
29 | */
30 | class TodayRecyclerViewAdapter(
31 | /**
32 | * 列表数据集合
33 | */
34 | @param:NonNull private val scheduleList: List,
35 | /**
36 | * [Context]
37 | */
38 | @param:NonNull private val context: Context) : RecyclerView.Adapter() {
39 | /**
40 | * 颜色数组
41 | */
42 | private val colorArray = IntArray(7)
43 | /**
44 | * 随机好的颜色集合
45 | */
46 | private val showColorList: ArrayList
47 | var viewProgress: View? = null
48 | private set
49 |
50 | init {
51 | Log.d(TAG, "new Today Recycler View Adapter")
52 | //数组赋值
53 | colorArray[0] = ContextCompat.getColor(context, R.color.class_color_1)
54 | colorArray[1] = ContextCompat.getColor(context, R.color.class_color_2)
55 | colorArray[2] = ContextCompat.getColor(context, R.color.class_color_3)
56 | colorArray[3] = ContextCompat.getColor(context, R.color.class_color_4)
57 | colorArray[4] = ContextCompat.getColor(context, R.color.class_color_5)
58 | colorArray[5] = ContextCompat.getColor(context, R.color.class_color_6)
59 | colorArray[6] = ContextCompat.getColor(context, R.color.class_color_7)
60 | //随机颜色集合构建
61 | val random = Random()
62 | showColorList = ArrayList(colorArray.size)
63 | do {
64 | val number = random.nextInt(colorArray.size)
65 | if (!showColorList.contains(number)) {
66 | showColorList.add(number)
67 | }
68 | } while (showColorList.size != colorArray.size)
69 | }
70 |
71 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
72 | Log.d(TAG, "onCreateViewHolder")
73 | return ViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.item_class_rv, parent, false))
74 | }
75 |
76 | override fun onBindViewHolder(holder: ViewHolder, position: Int) {
77 | Log.d(TAG, "onBindViewHolder pos->$position")
78 | if (position >= scheduleList.size) {
79 | scheduleList.forEach { Log.e(TAG, it.toString()) }
80 | CrashReport.postCatchedException(Throwable("onBindViewHolder scheduleList.size ${scheduleList.size}"))
81 | Toast.makeText(context, "内部数据错误,请联系开发者", Toast.LENGTH_LONG).show()
82 | }
83 | val classSchedule = scheduleList[position]
84 | holder.tvName.text = classSchedule.name
85 | holder.tvLocation.text = classSchedule.location
86 | holder.tvTime.text = DateUtils.timeList[classSchedule.section - 1]
87 | if (position >= showColorList.size) {
88 | val number = Random().nextInt(colorArray.size)
89 | holder.round.setBackColor(colorArray[number])
90 | } else {
91 | holder.round.setBackColor(colorArray[showColorList[position]])
92 | }
93 | //显示设置可见性
94 | holder.flNo.visibility = View.VISIBLE
95 | holder.viewBottom.visibility = View.INVISIBLE
96 | holder.viewTop.visibility = View.INVISIBLE
97 | holder.viewLeft.visibility = View.INVISIBLE
98 | holder.viewProgress.visibility = View.INVISIBLE
99 | ThemeChangeUtil.setProgressBackgroundResource(context, holder.viewProgress)
100 | ThemeChangeUtil.setBackgroundResources(context, holder.viewBottom, holder.viewTop, holder.viewLeft, holder.viewCenter)
101 | if (position == 0 && ClassScheduleUtils.haveClassAfterTime(scheduleList)) {
102 | //是当前正在或要上的课程
103 | holder.flNo.visibility = View.INVISIBLE
104 | holder.viewBottom.visibility = View.VISIBLE
105 | holder.viewTop.visibility = View.VISIBLE
106 | holder.viewLeft.visibility = View.VISIBLE
107 | holder.viewProgress.visibility = View.VISIBLE
108 | val display = (Objects.requireNonNull(context.getSystemService(Context.WINDOW_SERVICE)) as WindowManager).defaultDisplay
109 | val size = Point()
110 | display.getSize(size)
111 | val layoutParams = holder.viewProgress.layoutParams
112 | layoutParams.width = DateUtils.getNowProgress(size.x, scheduleList)
113 | holder.viewProgress.layoutParams = layoutParams
114 | viewProgress = holder.viewProgress
115 | }
116 | }
117 |
118 | override fun getItemCount(): Int {
119 | return scheduleList.size
120 | }
121 |
122 | class ViewHolder internal constructor(itemView: View) : RecyclerView.ViewHolder(itemView) {
123 | val viewLeft: View = itemView.findViewById(R.id.view_left)
124 |
125 | val viewTop: View = itemView.findViewById(R.id.view_top)
126 |
127 | val viewBottom: View = itemView.findViewById(R.id.view_bottom)
128 |
129 | val viewCenter: View = itemView.findViewById(R.id.view_center)
130 |
131 | val viewProgress: View = itemView.findViewById(R.id.view_progress)
132 |
133 | val round: RoundBackChange = itemView.findViewById(R.id.round)
134 |
135 | val flNo: FrameLayout = itemView.findViewById(R.id.fl_no)
136 |
137 | val tvName: TextView = itemView.findViewById(R.id.tv_name)
138 |
139 | val tvLocation: TextView = itemView.findViewById(R.id.tv_location)
140 |
141 | val tvTime: TextView = itemView.findViewById(R.id.tv_time)
142 | }
143 |
144 | companion object {
145 | private const val TAG = "TodayRecyclerAdapter"
146 | }
147 | }
148 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
22 |
23 |
26 |
29 |
32 |
35 |
36 |
37 |
47 |
51 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
75 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
107 |
111 |
115 |
120 |
125 |
129 |
130 |
131 |
132 |
135 |
136 |
137 |
138 |
139 |
140 |
145 |
148 |
149 |
150 |
151 |
--------------------------------------------------------------------------------
/app/src/main/java/top/itning/yunshuclassschedule/ui/fragment/ThisWeekFragment.kt:
--------------------------------------------------------------------------------
1 | package top.itning.yunshuclassschedule.ui.fragment
2 |
3 | import android.graphics.Point
4 | import android.graphics.drawable.Drawable
5 | import android.os.Bundle
6 | import android.util.Log
7 | import android.view.LayoutInflater
8 | import android.view.View
9 | import android.view.ViewGroup
10 | import android.widget.Toast
11 | import androidx.fragment.app.Fragment
12 | import androidx.preference.PreferenceManager
13 | import com.bumptech.glide.load.engine.DiskCacheStrategy
14 | import com.bumptech.glide.request.target.CustomViewTarget
15 | import com.bumptech.glide.request.transition.Transition
16 | import kotlinx.android.synthetic.main.fragment_this_week.*
17 | import org.greenrobot.eventbus.EventBus
18 | import org.greenrobot.eventbus.Subscribe
19 | import org.greenrobot.eventbus.ThreadMode
20 | import top.itning.yunshuclassschedule.R
21 | import top.itning.yunshuclassschedule.common.App
22 | import top.itning.yunshuclassschedule.common.ConstantPool
23 | import top.itning.yunshuclassschedule.entity.EventEntity
24 | import top.itning.yunshuclassschedule.ui.adapter.ClassScheduleItemLongClickListener
25 | import top.itning.yunshuclassschedule.ui.fragment.setting.SettingsFragment
26 | import top.itning.yunshuclassschedule.util.ClassScheduleUtils
27 | import top.itning.yunshuclassschedule.util.ClassScheduleUtils.COPY_LIST
28 | import top.itning.yunshuclassschedule.util.GlideApp
29 |
30 |
31 | /**
32 | * 本周
33 | *
34 | * @author itning
35 | */
36 | class ThisWeekFragment : Fragment() {
37 | private lateinit var mView: View
38 | private lateinit var clickListener: ClassScheduleItemLongClickListener
39 |
40 | override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
41 | Log.d(TAG, "on Create View")
42 | mView = inflater.inflate(R.layout.fragment_this_week, container, false)
43 | return mView
44 | }
45 |
46 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
47 | setViewBackground()
48 | val nowWeekNum = (PreferenceManager.getDefaultSharedPreferences(context).getString(SettingsFragment.NOW_WEEK_NUM, "1")!!.toInt() - 1).toString()
49 | val daoSession = (requireActivity().application as App).daoSession
50 | val classScheduleList = daoSession.classScheduleDao.loadAll()
51 | .filter { ClassScheduleUtils.isThisWeekOfClassSchedule(it, nowWeekNum) }
52 | .toMutableList()
53 | clickListener = ClassScheduleItemLongClickListener(requireActivity(), classScheduleList, COPY_LIST)
54 | ClassScheduleUtils.loadingView(classScheduleList, schedule_gridlayout, gl_header, clickListener, requireActivity())
55 | }
56 |
57 | override fun onCreate(savedInstanceState: Bundle?) {
58 | super.onCreate(savedInstanceState)
59 | EventBus.getDefault().register(this)
60 | }
61 |
62 | override fun onDestroy() {
63 | Log.d(TAG, "on Destroy")
64 | EventBus.getDefault().unregister(this)
65 | super.onDestroy()
66 | }
67 |
68 | @Subscribe(threadMode = ThreadMode.MAIN)
69 | fun onMessageEvent(eventEntity: EventEntity) {
70 | when (eventEntity.id) {
71 | ConstantPool.Int.REFRESH_WEEK_FRAGMENT_DATA -> {
72 | val nowWeekNum = (PreferenceManager.getDefaultSharedPreferences(context).getString(SettingsFragment.NOW_WEEK_NUM, "1")!!.toInt() - 1).toString()
73 | val daoSession = (requireActivity().application as App).daoSession
74 | val classScheduleList = daoSession.classScheduleDao.loadAll()
75 | .filter { ClassScheduleUtils.isThisWeekOfClassSchedule(it, nowWeekNum) }
76 | .toMutableList()
77 | clickListener = ClassScheduleItemLongClickListener(requireActivity(), classScheduleList, COPY_LIST)
78 | ClassScheduleUtils.loadingView(classScheduleList, schedule_gridlayout, gl_header, clickListener, requireActivity())
79 | }
80 | ConstantPool.Int.APP_COLOR_CHANGE -> {
81 | clickListener.updateBtnBackgroundTintList()
82 | }
83 | ConstantPool.Int.CLASS_WEEK_CHANGE -> {
84 | val nowWeekNum = (eventEntity.msg!!.toInt() - 1).toString()
85 | val daoSession = (requireActivity().application as App).daoSession
86 | val classScheduleList = daoSession.classScheduleDao.loadAll()
87 | .filter { ClassScheduleUtils.isThisWeekOfClassSchedule(it, nowWeekNum) }
88 | .toMutableList()
89 | clickListener = ClassScheduleItemLongClickListener(requireActivity(), classScheduleList, COPY_LIST)
90 | ClassScheduleUtils.loadingView(classScheduleList, schedule_gridlayout, gl_header, clickListener, requireActivity())
91 | }
92 | else -> {
93 | }
94 | }
95 | }
96 |
97 | /**
98 | * 设置视图背景
99 | */
100 | private fun setViewBackground() {
101 | val file = requireContext().getFileStreamPath("background_img")
102 | if (file.exists() && file.isFile && file.length() != 0L) {
103 | val display = requireActivity().windowManager.defaultDisplay
104 | val size = Point()
105 | display.getSize(size)
106 | Log.d(TAG, "screen width:" + size.x + " height:" + size.y)
107 | GlideApp
108 | .with(this)
109 | .load(file)
110 | .override(size.x, size.y)
111 | .diskCacheStrategy(DiskCacheStrategy.NONE)
112 | .skipMemoryCache(true)
113 | .into(object : CustomViewTarget(mView) {
114 |
115 | override fun onLoadFailed(errorDrawable: Drawable?) {
116 | Log.d(TAG, "on Load Failed : $errorDrawable")
117 | Toast.makeText(requireContext(), "图片加载失败", Toast.LENGTH_LONG).show()
118 | }
119 |
120 | override fun onResourceReady(resource: Drawable, transition: Transition?) {
121 | Log.d(TAG, "on Resource Ready : $resource")
122 | view.background = resource
123 | }
124 |
125 | override fun onResourceCleared(placeholder: Drawable?) {
126 | Log.d(TAG, "on Resource Cleared : $placeholder")
127 | view.background = placeholder
128 | }
129 | })
130 | } else {
131 | Log.d(TAG, "file is not exists , now use default background")
132 | mView.setBackgroundResource(R.drawable.this_week_background)
133 | }
134 | }
135 |
136 | companion object {
137 | private const val TAG = "ThisWeekFragment"
138 | }
139 | }
140 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_about.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
23 |
24 |
36 |
37 |
51 |
52 |
56 |
57 |
63 |
64 |
71 |
72 |
79 |
80 |
81 |
82 |
97 |
98 |
102 |
103 |
109 |
110 |
111 |
112 |
124 |
125 |
139 |
140 |
153 |
154 |
--------------------------------------------------------------------------------
/app/src/main/java/top/itning/yunshuclassschedule/service/CommonService.kt:
--------------------------------------------------------------------------------
1 | package top.itning.yunshuclassschedule.service
2 |
3 | import android.annotation.TargetApi
4 | import android.app.NotificationChannel
5 | import android.app.NotificationManager
6 | import android.app.Service
7 | import android.content.Context
8 | import android.content.Intent
9 | import android.content.IntentFilter
10 | import android.content.SharedPreferences
11 | import android.os.Build
12 | import android.os.IBinder
13 | import android.util.Log
14 | import android.widget.Toast
15 | import androidx.annotation.NonNull
16 | import androidx.preference.PreferenceManager
17 | import org.greenrobot.eventbus.EventBus
18 | import org.greenrobot.eventbus.Subscribe
19 | import org.greenrobot.eventbus.ThreadMode
20 | import top.itning.yunshuclassschedule.common.App
21 | import top.itning.yunshuclassschedule.common.ConstantPool
22 | import top.itning.yunshuclassschedule.entity.EventEntity
23 | import top.itning.yunshuclassschedule.receiver.TimeTickReceiver
24 | import top.itning.yunshuclassschedule.ui.fragment.setting.SettingsFragment.Companion.FOREGROUND_SERVICE_STATUS
25 | import top.itning.yunshuclassschedule.ui.fragment.setting.SettingsFragment.Companion.NOW_WEEK_NUM
26 | import top.itning.yunshuclassschedule.util.ClassScheduleUtils
27 | import top.itning.yunshuclassschedule.util.DateUtils.getNextMondayOfTimeInMillis
28 |
29 | /**
30 | * 公共服务
31 | *
32 | * @author itning
33 | */
34 | class CommonService : Service(), SharedPreferences.OnSharedPreferenceChangeListener {
35 | private lateinit var timeTickReceiver: TimeTickReceiver
36 | private lateinit var sharedPreferences: SharedPreferences
37 |
38 | override fun onCreate() {
39 | Log.d(TAG, "on Create")
40 | EventBus.getDefault().register(this)
41 | sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this)
42 | sharedPreferences.registerOnSharedPreferenceChangeListener(this)
43 | initNotificationChannel()
44 | ClassScheduleUtils.startForegroundServer(this, TAG)
45 | val filter = IntentFilter()
46 | filter.addAction(Intent.ACTION_TIME_TICK)
47 | //设置了系统时区
48 | filter.addAction(Intent.ACTION_TIMEZONE_CHANGED)
49 | //设置了系统时间
50 | filter.addAction(Intent.ACTION_TIME_CHANGED)
51 | timeTickReceiver = TimeTickReceiver()
52 | registerReceiver(timeTickReceiver, filter)
53 | }
54 |
55 | /**
56 | * 初始化通知渠道
57 | *
58 | * @since android 8.0
59 | */
60 | private fun initNotificationChannel() {
61 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
62 | Log.d(TAG, "Build.VERSION.SDK_INT :" + Build.VERSION.SDK_INT + " now create Notification Channel")
63 |
64 | var channelId = "class_reminder"
65 | var channelName = "课程提醒"
66 | var importance = NotificationManager.IMPORTANCE_HIGH
67 | createNotificationChannel(channelId, channelName, importance, true)
68 |
69 | channelId = "foreground_service"
70 | channelName = "前台服务"
71 | importance = NotificationManager.IMPORTANCE_NONE
72 | createNotificationChannel(channelId, channelName, importance, false)
73 | }
74 | }
75 |
76 | override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
77 | Log.d(TAG, "on Start Command")
78 | return START_REDELIVER_INTENT
79 | }
80 |
81 | override fun onDestroy() {
82 | EventBus.getDefault().unregister(this)
83 | unregisterReceiver(timeTickReceiver)
84 | sharedPreferences.unregisterOnSharedPreferenceChangeListener(this)
85 | }
86 |
87 | override fun onBind(intent: Intent): IBinder? {
88 | throw UnsupportedOperationException("Not yet implemented")
89 | }
90 |
91 | @Subscribe(threadMode = ThreadMode.MAIN)
92 | fun onMessageEvent(eventEntity: EventEntity) {
93 | when (eventEntity.id) {
94 | ConstantPool.Int.HTTP_ERROR -> {
95 | Toast.makeText(this, eventEntity.msg, Toast.LENGTH_LONG).show()
96 | }
97 | ConstantPool.Int.TIME_TICK_CHANGE -> {
98 | val currentTimeMillis = System.currentTimeMillis()
99 | if (isNewWeek(currentTimeMillis)) {
100 | val defaultSharedPreferences = PreferenceManager.getDefaultSharedPreferences(this)
101 | var i = defaultSharedPreferences.getString(NOW_WEEK_NUM, "1")!!.toInt()
102 | var lastTimeMillis = App.sharedPreferences.getLong(ConstantPool.Str.NEXT_WEEK_OF_MONDAY.get(), currentTimeMillis)
103 | while (true) {
104 | if (currentTimeMillis > lastTimeMillis) {
105 | Log.d(TAG, "currentTimeMillis > nextMondayOfTimeInMillis is true")
106 | val nextMondayOfTimeInMillis = getNextMondayOfTimeInMillis(lastTimeMillis)
107 | lastTimeMillis = nextMondayOfTimeInMillis
108 | i++
109 | continue
110 | }
111 | break
112 | }
113 | if (i > 50) {
114 | i = 1
115 | }
116 | Log.d(TAG, "Set week num $i")
117 | if (defaultSharedPreferences.edit().putString(NOW_WEEK_NUM, i.toString()).commit()) {
118 | App.sharedPreferences.edit().putLong(ConstantPool.Str.NEXT_WEEK_OF_MONDAY.get(), lastTimeMillis).apply()
119 | }
120 | }
121 | }
122 | else -> {
123 |
124 | }
125 | }
126 | }
127 |
128 | /**
129 | * 检查是不是新的一周
130 | */
131 | private fun isNewWeek(currentTimeMillis: Long): Boolean {
132 | val lastTimeMillis = App.sharedPreferences.getLong(ConstantPool.Str.NEXT_WEEK_OF_MONDAY.get(), currentTimeMillis)
133 | val isNewWeek = currentTimeMillis > lastTimeMillis
134 | Log.d(TAG, "Is new week ? $isNewWeek")
135 | return isNewWeek
136 | }
137 |
138 | /**
139 | * 创建通知渠道
140 | *
141 | * @param channelId 渠道ID
142 | * @param channelName 渠道名
143 | * @param importance 重要程度 [NotificationManager]
144 | */
145 | @TargetApi(Build.VERSION_CODES.O)
146 | private fun createNotificationChannel(@NonNull channelId: String, @NonNull channelName: String, importance: Int, showBadge: Boolean) {
147 | Log.d(TAG, "created Notification Channel id:$channelId name:$channelName importance:$importance")
148 | val channel = NotificationChannel(channelId, channelName, importance)
149 | channel.setShowBadge(showBadge)
150 | val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
151 | notificationManager.createNotificationChannel(channel)
152 | }
153 |
154 | override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) {
155 | if (key == FOREGROUND_SERVICE_STATUS) {
156 | if (sharedPreferences.getBoolean(FOREGROUND_SERVICE_STATUS, true)) {
157 | ClassScheduleUtils.startForegroundServer(this, TAG)
158 | } else {
159 | stopForeground(true)
160 | }
161 | }
162 | }
163 |
164 | companion object {
165 | private const val TAG = "CommonService"
166 | }
167 | }
168 |
--------------------------------------------------------------------------------
/app/src/main/java/top/itning/yunshuclassschedule/ui/fragment/setting/SettingsFragment.kt:
--------------------------------------------------------------------------------
1 | package top.itning.yunshuclassschedule.ui.fragment.setting
2 |
3 | import android.app.NotificationManager
4 | import android.content.Context
5 | import android.content.Intent
6 | import android.content.SharedPreferences
7 | import android.os.Build
8 | import android.os.Bundle
9 | import android.provider.Settings
10 | import android.util.Log
11 | import android.widget.Toast
12 | import androidx.appcompat.app.AlertDialog
13 | import androidx.preference.*
14 | import org.greenrobot.eventbus.EventBus
15 | import top.itning.yunshuclassschedule.R
16 | import top.itning.yunshuclassschedule.common.App
17 | import top.itning.yunshuclassschedule.common.ConstantPool
18 | import top.itning.yunshuclassschedule.entity.EventEntity
19 | import top.itning.yunshuclassschedule.util.DateUtils.getNextMondayOfTimeInMillis
20 | import top.itning.yunshuclassschedule.util.ThemeChangeUtil
21 |
22 | /**
23 | * 设置Fragment
24 | *
25 | * @author itning
26 | */
27 | class SettingsFragment : PreferenceFragmentCompat(), SharedPreferences.OnSharedPreferenceChangeListener {
28 |
29 | private lateinit var prefs: SharedPreferences
30 | private lateinit var defaultShowMainFragmentListPreference: ListPreference
31 | private lateinit var classReminderUpTime: ListPreference
32 | private lateinit var classReminderDownTime: ListPreference
33 | private lateinit var phoneMuteBeforeTime: ListPreference
34 | private lateinit var phoneMuteAfterTime: ListPreference
35 | private lateinit var nowWeekNumEditTextPreference: EditTextPreference
36 |
37 | override fun onCreate(savedInstanceState: Bundle?) {
38 | super.onCreate(savedInstanceState)
39 | prefs = PreferenceManager.getDefaultSharedPreferences(context)
40 | prefs.registerOnSharedPreferenceChangeListener(this)
41 | val bundle = arguments
42 | if (bundle == null) {
43 | defaultShowMainFragmentListPreference = findPreference(DEFAULT_SHOW_MAIN_FRAGMENT)!!
44 | defaultShowMainFragmentListPreference.summary = defaultShowMainFragmentListPreference.entry
45 | val foregroundServiceStatus: Preference = findPreference(FOREGROUND_SERVICE_STATUS)!!
46 | foregroundServiceStatus.setOnPreferenceChangeListener { _, newValue ->
47 | if (!(newValue as Boolean)) {
48 | AlertDialog.Builder(requireContext()).setTitle("注意")
49 | .setMessage("关闭后台常驻会导致提醒服务,手机自动静音服务不准确。建议您不要关闭!")
50 | .setCancelable(true)
51 | .setPositiveButton("我知道了", null)
52 | .show()
53 | }
54 | true
55 | }
56 | nowWeekNumEditTextPreference = findPreference(NOW_WEEK_NUM)!!
57 | nowWeekNumEditTextPreference.setOnPreferenceChangeListener { _, newValue ->
58 | if (newValue.toString() == "" || (Integer.valueOf(newValue.toString())) > 50) {
59 | Toast.makeText(requireContext(), "设置的值必须大于1且小于50", Toast.LENGTH_LONG).show()
60 | false
61 | } else {
62 | true
63 | }
64 | }
65 | nowWeekNumEditTextPreference.summary = "第${prefs.getString(NOW_WEEK_NUM, "1")}周"
66 | } else {
67 | when (bundle.getString(ARG_PREFERENCE_ROOT)) {
68 | "class_reminder" -> {
69 | classReminderUpTime = findPreference(CLASS_REMINDER_UP_TIME)!!
70 | classReminderDownTime = findPreference(CLASS_REMINDER_DOWN_TIME)!!
71 | classReminderUpTime.summary = classReminderUpTime.entry
72 | classReminderDownTime.summary = classReminderDownTime.entry
73 | }
74 | "phone_mute" -> {
75 | phoneMuteBeforeTime = findPreference(PHONE_MUTE_BEFORE_TIME)!!
76 | phoneMuteAfterTime = findPreference(PHONE_MUTE_AFTER_TIME)!!
77 | val phoneMuteStatus = findPreference(PHONE_MUTE_STATUS)!!
78 | phoneMuteStatus.setOnPreferenceChangeListener { _, newValue ->
79 | if (newValue as Boolean) {
80 | val notificationManager = requireContext().getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
81 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && !notificationManager.isNotificationPolicyAccessGranted) {
82 | Toast.makeText(requireContext(), "请授予免打扰权限", Toast.LENGTH_LONG).show()
83 | Toast.makeText(requireContext(), "权限授予后请重新开启自动静音", Toast.LENGTH_LONG).show()
84 | startActivity(Intent(Settings.ACTION_NOTIFICATION_POLICY_ACCESS_SETTINGS))
85 | return@setOnPreferenceChangeListener false
86 | } else {
87 | return@setOnPreferenceChangeListener true
88 | }
89 | }
90 | true
91 | }
92 | phoneMuteBeforeTime.summary = phoneMuteBeforeTime.entry
93 | phoneMuteAfterTime.summary = phoneMuteAfterTime.entry
94 | }
95 | }
96 | }
97 | }
98 |
99 | override fun onDestroyView() {
100 | Log.d(TAG, "on Destroy View")
101 | prefs.unregisterOnSharedPreferenceChangeListener(this)
102 | super.onDestroyView()
103 | }
104 |
105 | override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
106 | val bundle = arguments
107 | if (bundle == null) {
108 | setPreferencesFromResource(R.xml.preference_settings, rootKey)
109 | } else {
110 | setPreferencesFromResource(R.xml.preference_settings, bundle.getString(ARG_PREFERENCE_ROOT))
111 | }
112 | }
113 |
114 | override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) {
115 | when (key) {
116 | DEFAULT_SHOW_MAIN_FRAGMENT -> {
117 | defaultShowMainFragmentListPreference.summary = defaultShowMainFragmentListPreference.entry
118 | }
119 | CLASS_REMINDER_UP_TIME -> {
120 | classReminderUpTime.summary = classReminderUpTime.entry
121 | }
122 | CLASS_REMINDER_DOWN_TIME -> {
123 | classReminderDownTime.summary = classReminderDownTime.entry
124 | }
125 | PHONE_MUTE_BEFORE_TIME -> {
126 | phoneMuteBeforeTime.summary = phoneMuteBeforeTime.entry
127 | }
128 | PHONE_MUTE_AFTER_TIME -> {
129 | phoneMuteAfterTime.summary = phoneMuteAfterTime.entry
130 | }
131 | APP_COLOR_PRIMARY -> {
132 | ThemeChangeUtil.changeColor()
133 | }
134 | APP_COLOR_PRIMARY_DARK -> {
135 | ThemeChangeUtil.changeColor()
136 | }
137 | APP_COLOR_ACCENT -> {
138 | ThemeChangeUtil.changeColor()
139 | }
140 | APP_COLOR_PROGRESS -> {
141 | ThemeChangeUtil.changeColor()
142 | }
143 | NOW_WEEK_NUM -> {
144 | nowWeekNumEditTextPreference.summary = sharedPreferences.getString(key, "1")
145 | App.sharedPreferences.edit().putLong(ConstantPool.Str.NEXT_WEEK_OF_MONDAY.get(), getNextMondayOfTimeInMillis()).apply()
146 | EventBus.getDefault().post(EventEntity(ConstantPool.Int.TIME_TICK_CHANGE, ""))
147 | }
148 | }
149 | }
150 |
151 | companion object {
152 | private const val TAG = "SettingsFragment"
153 | const val CLASS_REMINDER_UP_TIME = "class_reminder_up_time"
154 | const val CLASS_REMINDER_DOWN_TIME = "class_reminder_down_time"
155 | const val PHONE_MUTE_STATUS = "phone_mute_status"
156 | const val PHONE_MUTE_BEFORE_TIME = "phone_mute_before_time"
157 | const val PHONE_MUTE_AFTER_TIME = "phone_mute_after_time"
158 | const val DEFAULT_SHOW_MAIN_FRAGMENT = "default_show_main_fragment"
159 | const val APP_COLOR_PRIMARY = "app_color_primary"
160 | const val APP_COLOR_PRIMARY_DARK = "app_color_primary_dark"
161 | const val APP_COLOR_ACCENT = "app_color_accent"
162 | const val APP_COLOR_PROGRESS = "app_color_progress"
163 | const val FOREGROUND_SERVICE_STATUS = "foreground_service_status"
164 | const val NOW_WEEK_NUM = "now_week_num"
165 | }
166 | }
167 |
--------------------------------------------------------------------------------
/app/src/main/java/top/itning/yunshuclassschedule/ui/activity/LoginActivity.kt:
--------------------------------------------------------------------------------
1 | package top.itning.yunshuclassschedule.ui.activity
2 |
3 | import android.app.Activity
4 | import android.content.ActivityNotFoundException
5 | import android.content.Intent
6 | import android.os.Bundle
7 | import android.util.Log
8 | import android.widget.Toast
9 | import androidx.appcompat.app.AlertDialog
10 | import androidx.preference.PreferenceManager
11 | import com.google.gson.Gson
12 | import com.jaeger.library.StatusBarUtil
13 | import kotlinx.android.synthetic.main.activity_login.*
14 | import org.greenrobot.eventbus.EventBus
15 | import org.greenrobot.eventbus.Subscribe
16 | import org.greenrobot.eventbus.ThreadMode
17 | import top.itning.yunshuclassschedule.R
18 | import top.itning.yunshuclassschedule.common.App
19 | import top.itning.yunshuclassschedule.common.BaseActivity
20 | import top.itning.yunshuclassschedule.common.ConstantPool
21 | import top.itning.yunshuclassschedule.entity.DataEntity
22 | import top.itning.yunshuclassschedule.entity.EventEntity
23 | import top.itning.yunshuclassschedule.ui.activity.ShareActivity.Companion.FILE_SELECT_CODE
24 | import top.itning.yunshuclassschedule.ui.fragment.setting.SettingsFragment
25 | import top.itning.yunshuclassschedule.util.DateUtils
26 | import top.itning.yunshuclassschedule.util.DateUtils.getNextMondayOfTimeInMillis
27 | import java.util.*
28 |
29 | /**
30 | * 登陆
31 | *
32 | * @author itning
33 | */
34 | class LoginActivity : BaseActivity() {
35 | override fun onCreate(savedInstanceState: Bundle?) {
36 | super.onCreate(savedInstanceState)
37 | setContentView(R.layout.activity_login)
38 | EventBus.getDefault().register(this)
39 | StatusBarUtil.setTransparent(this)
40 | initData()
41 | btn_custom.setOnClickListener { onCustomBtnClicked() }
42 | btn_share.setOnClickListener { onViewClicked() }
43 | }
44 |
45 | /**
46 | * 加载专业数据
47 | */
48 | private fun initData() {
49 | if (App.sharedPreferences.getBoolean(ConstantPool.Str.FIRST_IN_APP.get(), true)) {
50 | PreferenceManager.getDefaultSharedPreferences(this).edit()
51 | .putString(SettingsFragment.NOW_WEEK_NUM, "1")
52 | .apply()
53 | App.sharedPreferences.edit()
54 | .putLong(ConstantPool.Str.NEXT_WEEK_OF_MONDAY.get(), getNextMondayOfTimeInMillis())
55 | .putString("1", "08:20-09:50")
56 | .putString("2", "10:05-11:35")
57 | .putString("3", "12:55-14:25")
58 | .putString("4", "14:40-16:10")
59 | .putString("5", "17:30-20:00")
60 | .putString("6", "20:05-20:08")
61 | .putString("7", "20:10-20:15")
62 | .putString("8", "20:18-20:20")
63 | .putString("9", "20:30-20:35")
64 | .putString("10", "20:40-20:45")
65 | .putString("11", "20:50-21:01")
66 | .putString("12", "21:10-21:15").apply()
67 | }
68 | }
69 |
70 | @Subscribe(threadMode = ThreadMode.MAIN)
71 | override fun onMessageEvent(eventEntity: EventEntity) {
72 | }
73 |
74 | override fun onDestroy() {
75 | EventBus.getDefault().unregister(this)
76 | super.onDestroy()
77 | }
78 |
79 | /**
80 | * 消息事件
81 | *
82 | * @param what what
83 | */
84 | @Subscribe(threadMode = ThreadMode.MAIN)
85 | fun onMessageEvent(what: Int?) {
86 | Log.d(TAG, what!!.toString() + "")
87 | }
88 |
89 | /**
90 | * 自定义课程
91 | */
92 | private fun onCustomBtnClicked() {
93 | startActivity(Intent(this, CustomActivity::class.java))
94 | finish()
95 | }
96 |
97 | private fun onViewClicked() {
98 | val intent = Intent(Intent.ACTION_GET_CONTENT)
99 | intent.type = "*/*"
100 | intent.addCategory(Intent.CATEGORY_OPENABLE)
101 | try {
102 | startActivityForResult(Intent.createChooser(intent, "选择课程数据文件进行导入"), FILE_SELECT_CODE)
103 | } catch (e: ActivityNotFoundException) {
104 | Toast.makeText(this, "没有找到文件管理APP", Toast.LENGTH_SHORT).show()
105 | }
106 |
107 | }
108 |
109 | override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
110 | if (requestCode == FILE_SELECT_CODE && resultCode == Activity.RESULT_OK) {
111 | doImportFile(data!!)
112 | }
113 | super.onActivityResult(requestCode, resultCode, data)
114 | }
115 |
116 | private fun doImportFile(data: Intent) {
117 | try {
118 | val uri = data.data ?: run {
119 | Toast.makeText(this, "解析失败", Toast.LENGTH_LONG).show()
120 | return
121 | }
122 | Log.d(TAG, "File Uri: $uri")
123 | val openInputStream = contentResolver.openInputStream(uri) ?: run {
124 | Toast.makeText(this, "解析失败", Toast.LENGTH_LONG).show()
125 | return
126 | }
127 | val inputAsString = openInputStream.bufferedReader().use { it.readText() }
128 | val dataEntity = Gson().fromJson(inputAsString, DataEntity::class.java)
129 | val classScheduleList = dataEntity.classScheduleList
130 | val timeList = dataEntity.timeList
131 | if (classScheduleList == null || classScheduleList.isEmpty() || timeList == null || timeList.isEmpty()) {
132 | Toast.makeText(this, "解析失败", Toast.LENGTH_LONG).show()
133 | return
134 | }
135 | val timeListSize = timeList.size
136 | val classScheduleMaxSection = classScheduleList.map { it.section }.max() ?: 12
137 | if (timeListSize > 12 || classScheduleMaxSection > 12) {
138 | Toast.makeText(this, "最大课程数为12节课,解析失败", Toast.LENGTH_LONG).show()
139 | return
140 | }
141 | Log.d(TAG, "classScheduleMaxSection: $classScheduleMaxSection timeListSize: $timeListSize")
142 | val section = if (timeListSize < classScheduleMaxSection) {
143 | classScheduleMaxSection
144 | } else {
145 | timeListSize
146 | }
147 | AlertDialog.Builder(this)
148 | .setTitle("警告")
149 | .setMessage("即将导入课程数据,这会将原有课程信息清空,确定导入吗?")
150 | .setPositiveButton("确定") { _, _ ->
151 | val timeMap = TreeMap()
152 | for ((index, value) in timeList.withIndex()) {
153 | timeMap[index + 1] = value
154 | }
155 | if (!DateUtils.isDataLegitimate(timeMap, this)) {
156 | Toast.makeText(this, "解析失败", Toast.LENGTH_LONG).show()
157 | return@setPositiveButton
158 | }
159 | val edit = App.sharedPreferences.edit()
160 | for ((index, value) in timeList.withIndex()) {
161 | edit.putString((index + 1).toString(), value)
162 | }
163 | if (edit.commit()) {
164 | DateUtils.refreshTimeList()
165 | } else {
166 | Toast.makeText(this, "解析失败", Toast.LENGTH_LONG).show()
167 | return@setPositiveButton
168 | }
169 | val classScheduleDao = (application as App).daoSession.classScheduleDao
170 | classScheduleDao.deleteAll()
171 | classScheduleList.forEach { classScheduleDao.insert(it) }
172 | EventBus.getDefault().post(EventEntity(ConstantPool.Int.TIME_TICK_CHANGE, ""))
173 | if (classScheduleList.size.toLong() == classScheduleDao.count()) {
174 | if (App.sharedPreferences.edit()
175 | .putInt(ConstantPool.Str.CLASS_SECTION.get(), section)
176 | .commit()) {
177 | DateUtils.refreshTimeList()
178 | Toast.makeText(this, "导入成功", Toast.LENGTH_LONG).show()
179 | enterMainActivity()
180 | } else {
181 | Toast.makeText(this, "写入课程节数失败,请重试", Toast.LENGTH_LONG).show()
182 | }
183 | } else {
184 | Toast.makeText(this, "写入数据库失败,请重试", Toast.LENGTH_LONG).show()
185 | }
186 | }
187 | .setNegativeButton("取消", null)
188 | .show()
189 | } catch (e: Exception) {
190 | Log.e(TAG, " ", e)
191 | Toast.makeText(this, "解析失败", Toast.LENGTH_LONG).show()
192 | }
193 | }
194 |
195 | private fun enterMainActivity() {
196 | App.sharedPreferences.edit()
197 | .putBoolean(ConstantPool.Str.FIRST_IN_APP.get(), false)
198 | .apply()
199 | startActivity(Intent(this, MainActivity::class.java))
200 | finish()
201 | }
202 |
203 | companion object {
204 | private const val TAG = "LoginActivity"
205 | }
206 | }
207 |
--------------------------------------------------------------------------------