├── app ├── .gitignore ├── src │ ├── main │ │ ├── ic_launcher-web.png │ │ ├── res │ │ │ ├── drawable │ │ │ │ ├── bg_x.webp │ │ │ │ ├── camera_logo.webp │ │ │ │ ├── btn_bg_blue.xml │ │ │ │ ├── week_of_term_bg.xml │ │ │ │ ├── border_black.xml │ │ │ │ ├── bg_gradient.xml │ │ │ │ ├── border_stroke.xml │ │ │ │ ├── border_btn.xml │ │ │ │ ├── btn_press.xml │ │ │ │ ├── border_btn_blue.xml │ │ │ │ ├── selector_text_view.xml │ │ │ │ ├── selector_layout_btn.xml │ │ │ │ ├── selector_button.xml │ │ │ │ ├── shape_line.xml │ │ │ │ ├── selector_check_box_week.xml │ │ │ │ ├── ic_error_red_24dp.xml │ │ │ │ ├── ic_scan.xml │ │ │ │ └── ic_launcher_background.xml │ │ │ ├── drawable-xhdpi │ │ │ │ ├── bg_2.webp │ │ │ │ ├── bg_3.webp │ │ │ │ └── bg_4.webp │ │ │ ├── mipmap-hdpi │ │ │ │ ├── content_new.png │ │ │ │ ├── ic_launcher.png │ │ │ │ ├── ic_launcher_round.png │ │ │ │ └── ic_launcher_foreground.png │ │ │ ├── mipmap-mdpi │ │ │ │ ├── content_new.png │ │ │ │ ├── ic_launcher.png │ │ │ │ ├── ic_launcher_round.png │ │ │ │ └── ic_launcher_foreground.png │ │ │ ├── mipmap-xhdpi │ │ │ │ ├── content_new.png │ │ │ │ ├── ic_launcher.png │ │ │ │ ├── ic_launcher_round.png │ │ │ │ └── ic_launcher_foreground.png │ │ │ ├── mipmap-xxhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ ├── ic_launcher_round.png │ │ │ │ └── ic_launcher_foreground.png │ │ │ ├── mipmap-xxxhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ ├── ic_launcher_round.png │ │ │ │ └── ic_launcher_foreground.png │ │ │ ├── values │ │ │ │ ├── ic_launcher_background.xml │ │ │ │ ├── dimens.xml │ │ │ │ ├── colors.xml │ │ │ │ ├── styles.xml │ │ │ │ └── strings.xml │ │ │ ├── xml │ │ │ │ └── network_security_config.xml │ │ │ ├── mipmap-anydpi-v26 │ │ │ │ ├── ic_launcher.xml │ │ │ │ └── ic_launcher_round.xml │ │ │ ├── menu │ │ │ │ ├── menu_config.xml │ │ │ │ ├── menu_edit.xml │ │ │ │ ├── menu_course_details.xml │ │ │ │ ├── menu_login.xml │ │ │ │ ├── menu_set_time.xml │ │ │ │ └── menu_main.xml │ │ │ ├── layout │ │ │ │ ├── item_iv_bg.xml │ │ │ │ ├── fragment_item_list.xml │ │ │ │ ├── activity_login.xml │ │ │ │ ├── activity_set_time.xml │ │ │ │ ├── week_of_term_checkbox.xml │ │ │ │ ├── fragment_item.xml │ │ │ │ ├── item_time.xml │ │ │ │ ├── dialog_select_week_of_term.xml │ │ │ │ ├── fragment_login.xml │ │ │ │ ├── activity_config.xml │ │ │ │ ├── activity_course_details.xml │ │ │ │ ├── activity_main.xml │ │ │ │ └── activity_edit.xml │ │ │ └── drawable-v24 │ │ │ │ └── ic_launcher_foreground.xml │ │ ├── java │ │ │ └── com │ │ │ │ └── potato │ │ │ │ └── timetable │ │ │ │ ├── util │ │ │ │ ├── ShareUtils.java │ │ │ │ ├── DialogUtils.kt │ │ │ │ ├── HttpUtils.java │ │ │ │ ├── KeyStoreUtils.kt │ │ │ │ ├── Config.java │ │ │ │ ├── ExcelUtils.java │ │ │ │ ├── OkHttpUtils.java │ │ │ │ └── CalendarReminderUtils.java │ │ │ │ ├── help │ │ │ │ └── OneClickListener.kt │ │ │ │ ├── MyApplication.java │ │ │ │ ├── bean │ │ │ │ ├── Version.java │ │ │ │ ├── Send.java │ │ │ │ ├── Time.java │ │ │ │ └── Course.java │ │ │ │ ├── colleges │ │ │ │ ├── base │ │ │ │ │ ├── CollegeFactory.kt │ │ │ │ │ └── College.java │ │ │ │ └── CSUCollege.java │ │ │ │ └── ui │ │ │ │ ├── main │ │ │ │ └── DownloadReceiver.kt │ │ │ │ ├── config │ │ │ │ └── BgBtnAdapter.java │ │ │ │ ├── login │ │ │ │ ├── MyItemRecyclerViewAdapter.java │ │ │ │ ├── LoginActivity.java │ │ │ │ ├── ItemFragment.java │ │ │ │ └── LoginFragment.java │ │ │ │ ├── coursedetails │ │ │ │ └── CourseDetailsActivity.java │ │ │ │ ├── editcourse │ │ │ │ └── WeekOfTermSelectDialog.java │ │ │ │ └── settime │ │ │ │ └── SetTimeActivity.java │ │ └── AndroidManifest.xml │ ├── androidTest │ │ └── java │ │ │ └── com │ │ │ └── potato │ │ │ └── timetable │ │ │ ├── util │ │ │ └── KeyStoreUtilsTest.kt │ │ │ └── ExampleInstrumentedTest.java │ └── test │ │ └── java │ │ └── com │ │ └── potato │ │ └── timetable │ │ ├── colleges │ │ └── base │ │ │ └── CollegeFactoryTest.kt │ │ └── ExampleUnitTest.java ├── proguard-rules.pro └── build.gradle ├── settings.gradle ├── version.properties ├── ReadmeResourse ├── gui.png ├── Example.xls └── Excel_example.png ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── .gitignore ├── LICENSE ├── gradle.properties ├── README.md ├── .github └── workflows │ └── android.yml ├── gradlew.bat └── gradlew /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | /release 3 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | rootProject.name='Timetable' 3 | -------------------------------------------------------------------------------- /version.properties: -------------------------------------------------------------------------------- 1 | #Sat Apr 17 20:09:41 CST 2021 2 | versionName=1.0.14 3 | versionCode=29 4 | -------------------------------------------------------------------------------- /ReadmeResourse/gui.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Potato-DiGua/Timetable/HEAD/ReadmeResourse/gui.png -------------------------------------------------------------------------------- /ReadmeResourse/Example.xls: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Potato-DiGua/Timetable/HEAD/ReadmeResourse/Example.xls -------------------------------------------------------------------------------- /ReadmeResourse/Excel_example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Potato-DiGua/Timetable/HEAD/ReadmeResourse/Excel_example.png -------------------------------------------------------------------------------- /app/src/main/ic_launcher-web.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Potato-DiGua/Timetable/HEAD/app/src/main/ic_launcher-web.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/bg_x.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Potato-DiGua/Timetable/HEAD/app/src/main/res/drawable/bg_x.webp -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Potato-DiGua/Timetable/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/bg_2.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Potato-DiGua/Timetable/HEAD/app/src/main/res/drawable-xhdpi/bg_2.webp -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/bg_3.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Potato-DiGua/Timetable/HEAD/app/src/main/res/drawable-xhdpi/bg_3.webp -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/bg_4.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Potato-DiGua/Timetable/HEAD/app/src/main/res/drawable-xhdpi/bg_4.webp -------------------------------------------------------------------------------- /app/src/main/res/drawable/camera_logo.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Potato-DiGua/Timetable/HEAD/app/src/main/res/drawable/camera_logo.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/content_new.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Potato-DiGua/Timetable/HEAD/app/src/main/res/mipmap-hdpi/content_new.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Potato-DiGua/Timetable/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/content_new.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Potato-DiGua/Timetable/HEAD/app/src/main/res/mipmap-mdpi/content_new.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Potato-DiGua/Timetable/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/content_new.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Potato-DiGua/Timetable/HEAD/app/src/main/res/mipmap-xhdpi/content_new.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Potato-DiGua/Timetable/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Potato-DiGua/Timetable/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Potato-DiGua/Timetable/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Potato-DiGua/Timetable/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Potato-DiGua/Timetable/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Potato-DiGua/Timetable/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Potato-DiGua/Timetable/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Potato-DiGua/Timetable/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Potato-DiGua/Timetable/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Potato-DiGua/Timetable/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Potato-DiGua/Timetable/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Potato-DiGua/Timetable/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Potato-DiGua/Timetable/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /app/src/main/res/values/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #96D7FB 4 | -------------------------------------------------------------------------------- /app/src/main/res/xml/network_security_config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/btn_bg_blue.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/week_of_term_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/border_black.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Tue Nov 03 14:43:03 CST 2020 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-all.zip 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/caches 5 | /.idea/libraries 6 | /.idea/modules.xml 7 | /.idea/workspace.xml 8 | /.idea/navEditor.xml 9 | /.idea/assetWizardSettings.xml 10 | /.idea 11 | .DS_Store 12 | /build 13 | /captures 14 | .externalNativeBuild 15 | .cxx 16 | 17 | /keystore 18 | .gitmodules -------------------------------------------------------------------------------- /app/src/main/res/drawable/bg_gradient.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/border_stroke.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/border_btn.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/menu/menu_config.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/menu/menu_edit.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/btn_press.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/menu/menu_course_details.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/border_btn_blue.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/menu/menu_login.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/selector_text_view.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/selector_layout_btn.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/selector_button.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/shape_line.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/selector_check_box_week.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_error_red_24dp.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/menu/menu_set_time.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 9 | -------------------------------------------------------------------------------- /app/src/main/java/com/potato/timetable/util/ShareUtils.java: -------------------------------------------------------------------------------- 1 | package com.potato.timetable.util; 2 | 3 | import java.util.regex.Matcher; 4 | import java.util.regex.Pattern; 5 | 6 | public class ShareUtils { 7 | public static final String SHARE_URL="http://62.234.73.209/share"; 8 | public static boolean judgeURL(String url){ 9 | Matcher matcher=Pattern.compile("^"+SHARE_URL.replaceAll("\\.","\\\\.")+"/[a-z0-9]{24}/?$").matcher(url); 10 | return matcher.matches(); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/potato/timetable/util/KeyStoreUtilsTest.kt: -------------------------------------------------------------------------------- 1 | package com.potato.timetable.util 2 | 3 | import junit.framework.TestCase 4 | 5 | class KeyStoreUtilsTest : TestCase() { 6 | 7 | fun testGetKey() { 8 | assertNotNull(KeyStoreUtils.getKey()) 9 | } 10 | private val testData = "hello,World" 11 | fun testEncrypt() { 12 | } 13 | 14 | fun testDecrypt() { 15 | assertEquals(testData,KeyStoreUtils.decrypt(KeyStoreUtils.encrypt(testData))) 16 | } 17 | } -------------------------------------------------------------------------------- /app/src/main/java/com/potato/timetable/help/OneClickListener.kt: -------------------------------------------------------------------------------- 1 | package com.potato.timetable.help 2 | 3 | import android.view.View 4 | 5 | class OneClickListener(private val listener: View.OnClickListener) : View.OnClickListener { 6 | private var lastClickTime: Long = 0 7 | private val timeInterval = 500; 8 | override fun onClick(v: View?) { 9 | if (System.currentTimeMillis() - lastClickTime > timeInterval) { 10 | listener.onClick(v) 11 | } 12 | lastClickTime = System.currentTimeMillis() 13 | 14 | } 15 | } -------------------------------------------------------------------------------- /app/src/main/java/com/potato/timetable/MyApplication.java: -------------------------------------------------------------------------------- 1 | package com.potato.timetable; 2 | 3 | import android.app.Application; 4 | import android.content.Context; 5 | 6 | public class MyApplication extends Application { 7 | private static Application instance; 8 | @Override 9 | public void onCreate() { 10 | super.onCreate(); 11 | instance=this; 12 | } 13 | 14 | /** 15 | * 用于工具类实例化,UI不能使用,使用后无法被回收,造成内存泄漏 16 | * @return 17 | */ 18 | public static Context getApplication() { 19 | return instance; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_iv_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/test/java/com/potato/timetable/colleges/base/CollegeFactoryTest.kt: -------------------------------------------------------------------------------- 1 | package com.potato.timetable.colleges.base 2 | 3 | import com.potato.timetable.colleges.CSUCollege 4 | import junit.framework.TestCase 5 | 6 | class CollegeFactoryTest : TestCase() { 7 | 8 | fun testGetCollegeNameList() { 9 | println(CollegeFactory.collegeNameList) 10 | } 11 | 12 | fun testCreateCollege() { 13 | assertNull(CollegeFactory.createCollege(null)) 14 | assertNull(CollegeFactory.createCollege("")) 15 | assertTrue(CollegeFactory.createCollege(CSUCollege.NAME) is CSUCollege) 16 | } 17 | } -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_item_list.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/src/main/java/com/potato/timetable/bean/Version.java: -------------------------------------------------------------------------------- 1 | package com.potato.timetable.bean; 2 | 3 | /** 4 | * 用于app更新 5 | */ 6 | public class Version { 7 | private long versionCode;//版本号 8 | private String releaseName;//文件名 9 | 10 | public long getVersionCode() { 11 | return versionCode; 12 | } 13 | 14 | public void setVersionCode(long versionCode) { 15 | this.versionCode = versionCode; 16 | } 17 | 18 | public String getReleaseName() { 19 | return releaseName; 20 | } 21 | 22 | public void setReleaseName(String releaseName) { 23 | this.releaseName = releaseName; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /app/src/main/java/com/potato/timetable/util/DialogUtils.kt: -------------------------------------------------------------------------------- 1 | package com.potato.timetable.util 2 | 3 | import android.content.Context 4 | import androidx.appcompat.app.AlertDialog 5 | 6 | object DialogUtils { 7 | 8 | @JvmStatic 9 | fun showTipDialog(context: Context, tip: String) { 10 | showTipDialog(context, "提示", tip) 11 | } 12 | 13 | @JvmStatic 14 | fun showTipDialog(context: Context, title: String, tip: String) { 15 | AlertDialog.Builder(context) 16 | .setTitle(title) 17 | .setMessage(tip) 18 | .setPositiveButton("知道了", null) 19 | .create() 20 | .show() 21 | } 22 | } -------------------------------------------------------------------------------- /app/src/main/java/com/potato/timetable/util/HttpUtils.java: -------------------------------------------------------------------------------- 1 | package com.potato.timetable.util; 2 | 3 | 4 | public class HttpUtils { 5 | /** 6 | * ping 判断网络连通 7 | * 8 | * @return 9 | */ 10 | public static boolean isNetworkConnected() { 11 | try { 12 | //代表ping 3 次 超时时间为10秒 13 | Process p = Runtime.getRuntime().exec("ping -c 3 -w 10 www.baidu.com");//ping3次 14 | int status = p.waitFor(); 15 | if (status == 0) { 16 | //代表成功 17 | return true; 18 | } 19 | } catch (Exception e) { 20 | e.printStackTrace(); 21 | } 22 | 23 | return false; 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/java/com/potato/timetable/bean/Send.java: -------------------------------------------------------------------------------- 1 | package com.potato.timetable.bean; 2 | 3 | public class Send { 4 | private String status; 5 | private String message; 6 | private T data; 7 | 8 | public String getStatus() { 9 | return status; 10 | } 11 | 12 | public void setStatus(String status) { 13 | this.status = status; 14 | } 15 | 16 | public String getMessage() { 17 | return message; 18 | } 19 | 20 | public void setMessage(String message) { 21 | this.message = message; 22 | } 23 | 24 | public T getData() { 25 | return data; 26 | } 27 | 28 | public void setData(T data) { 29 | this.data = data; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_login.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 12 | 16 | 17 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_set_time.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 13 | 17 | -------------------------------------------------------------------------------- /app/src/main/res/layout/week_of_term_checkbox.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /app/src/main/java/com/potato/timetable/bean/Time.java: -------------------------------------------------------------------------------- 1 | package com.potato.timetable.bean; 2 | 3 | import androidx.annotation.NonNull; 4 | 5 | public class Time implements Cloneable{ 6 | private String start=""; 7 | private String end=""; 8 | 9 | public String getStart() { 10 | return start; 11 | } 12 | 13 | public void setStart(String start) { 14 | this.start = start; 15 | } 16 | 17 | public String getEnd() { 18 | return end; 19 | } 20 | 21 | public void setEnd(String end) { 22 | this.end = end; 23 | } 24 | 25 | @NonNull 26 | @Override 27 | public String toString() { 28 | 29 | return start.isEmpty()?"":start+" - "+end; 30 | } 31 | 32 | @NonNull 33 | @Override 34 | public Object clone() throws CloneNotSupportedException { 35 | return super.clone(); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 70dp 4 | 840dp 5 | 6 | 35dp 7 | 8 | 18sp 9 | 20sp 10 | 16sp 11 | 144dp 12 | 81dp 13 | 14 | 16sp 15 | 16 | 10sp 17 | 13sp 18 | 40dp 19 | 60dp 20 | 21 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/potato/timetable/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.potato.timetable; 2 | 3 | import android.content.Context; 4 | 5 | import androidx.test.platform.app.InstrumentationRegistry; 6 | import androidx.test.ext.junit.runners.AndroidJUnit4; 7 | 8 | import org.junit.Test; 9 | import org.junit.runner.RunWith; 10 | 11 | import static org.junit.Assert.*; 12 | 13 | /** 14 | * Instrumented test, which will execute on an Android device. 15 | * 16 | * @see Testing documentation 17 | */ 18 | @RunWith(AndroidJUnit4.class) 19 | public class ExampleInstrumentedTest { 20 | @Test 21 | public void useAppContext() { 22 | // Context of the app under test. 23 | Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); 24 | 25 | assertEquals("com.potato.timetable", appContext.getPackageName()); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /app/src/main/res/menu/menu_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 9 | 12 | 15 | 18 | 21 | 24 | 27 | -------------------------------------------------------------------------------- /app/src/main/java/com/potato/timetable/colleges/base/CollegeFactory.kt: -------------------------------------------------------------------------------- 1 | package com.potato.timetable.colleges.base 2 | 3 | import android.text.TextUtils 4 | import com.potato.timetable.colleges.CSUCollege 5 | import com.potato.timetable.colleges.ShmtuCollege 6 | import java.util.* 7 | import kotlin.collections.HashMap 8 | 9 | object CollegeFactory { 10 | private val collegeMap = HashMap>() 11 | 12 | init { 13 | collegeMap[CSUCollege.NAME] = CSUCollege::class.java 14 | collegeMap[ShmtuCollege.NAME] = ShmtuCollege::class.java 15 | } 16 | 17 | @JvmStatic 18 | val collegeNameList: List = ArrayList(collegeMap.keys) 19 | init { 20 | collegeNameList.sorted() 21 | } 22 | 23 | /** 24 | * 获取 25 | */ 26 | @JvmStatic 27 | fun createCollege(collegeName: String?): College? { 28 | if(TextUtils.isEmpty(collegeName)){ 29 | return null; 30 | } 31 | return collegeMap[collegeName]?.newInstance(); 32 | } 33 | 34 | 35 | } -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 19 | 26 | 27 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Potato-DiGua 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /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=-Xmx1536m 10 | # When configured, Gradle will run in incubating parallel mode. 11 | # This option should only be used with decoupled projects. More details, visit 12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 13 | # org.gradle.parallel=true 14 | # AndroidX package structure to make it clearer which packages are bundled with the 15 | # Android operating system, and which are packaged with your app's APK 16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn 17 | android.useAndroidX=true 18 | # Automatically convert third-party libraries to use AndroidX 19 | android.enableJetifier=true 20 | 21 | -------------------------------------------------------------------------------- /app/src/main/java/com/potato/timetable/ui/main/DownloadReceiver.kt: -------------------------------------------------------------------------------- 1 | package com.potato.timetable.ui.main 2 | 3 | import android.app.DownloadManager 4 | import android.content.BroadcastReceiver 5 | import android.content.Context 6 | import android.content.Intent 7 | import android.net.Uri 8 | import android.util.Log 9 | 10 | 11 | class DownloadReceiver(private val downloadID: Long) : BroadcastReceiver() { 12 | 13 | override fun onReceive(context: Context?, intent: Intent?) { 14 | if (intent?.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1) == downloadID) { 15 | val dm = context!!.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager 16 | val downloadFileUri = dm.getUriForDownloadedFile(downloadID) 17 | Log.d("download", downloadID.toString()) 18 | install(context, downloadFileUri) 19 | } 20 | } 21 | 22 | private fun install(context: Context?, uri: Uri) { 23 | val intent = Intent(Intent.ACTION_VIEW) 24 | //apk对应的MIME类型 25 | val type = "application/vnd.android.package-archive" 26 | intent.setDataAndType(uri, type); 27 | intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK).addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) 28 | context?.startActivity(intent) 29 | context?.unregisterReceiver(this) 30 | } 31 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![下载](https://img.shields.io/github/downloads/Potato-DiGua/Timetable/total) ![Release](https://img.shields.io/github/v/release/Potato-DiGua/Timetable) 2 | # LightTimetable 3 | ### [LightTimetable Flutter版](https://github.com/Potato-DiGua/LightTimetable-Flutter) 4 | 仿超级课程表/Android课程表/简洁 5 | 6 | --- 7 | ### 小轻课程表 8 | * 简洁 9 | * 支持Excel导入课程 10 | * 支持教务系统导入(中南大学) 11 | * 可设置背景和卡片透明度 12 | * 日程提醒(需设置上课时间) 13 | * 学生账号密码加密存储 14 | * 从github上检查是否有新版本 15 | * 无广告,秒开 16 | * apk小于3M 17 | 18 | --- 19 | ### 界面 20 | 21 | 22 | --- 23 | ### 注意事项 24 | Excel导入(因为使用jxl包所以**只支持xls文件**)
25 | 不支持冲突课程,如果冲突,会显示最后的课程
26 | **Excel格式示例** 27 | [![8shYx1.md.png](https://s1.ax1x.com/2020/03/19/8shYx1.md.png)](https://imgchr.com/i/8shYx1) 28 |

29 | 下载示例Excel 30 |

31 | 32 | **单元格格式:** 33 | 第一行为课程名
34 | 第二行为教师
35 | 第三行为上课的周数(单周,双周,周用[]括起来,周数也可以用英文,隔开,中间没有空格)
36 | 示例 **1-16[单周]** 或 **7,8[周]** 或**7,8,9,11-16[周]**
37 | 第四行为上课地点
38 | 39 | 同一单元格有两个课程空一行隔开
40 | 41 | 42 | 43 | **第一行必须为星期,第一列为节数,不能有多余的表头。**
44 | 一天只支持12节课。
45 | **Excel算上表头只支持(列数x行数)8x7**
46 | 47 | --- 48 | ##### 开发者的废话(可跳过) 49 | 因为超级课程表有很多多余的东西,而且想看课程表的话,打开速度很慢,不能秒开,所以就想模仿写一个精简版的,于是就有了本app 50 | -------------------------------------------------------------------------------- /app/src/main/java/com/potato/timetable/colleges/base/College.java: -------------------------------------------------------------------------------- 1 | package com.potato.timetable.colleges.base; 2 | 3 | import android.graphics.Bitmap; 4 | 5 | import com.potato.timetable.bean.Course; 6 | 7 | import java.util.List; 8 | 9 | public interface College { 10 | /** 11 | * 获取学校名字 12 | * 13 | * @return 14 | */ 15 | String getCollegeName(); 16 | 17 | /** 18 | * 登录 19 | * 20 | * @param account 21 | * @param pw 22 | * @param RandomCode 可为NULL,根据实际情况填写 23 | * @return 返回是否登录成功 24 | */ 25 | boolean login(String account, String pw, String RandomCode); 26 | 27 | /** 28 | * 获取课程 29 | * 30 | * @param term 课程学期 31 | * @return 32 | */ 33 | List getCourses(String term); 34 | 35 | /** 36 | * 获取验证码的BitMap 37 | * 38 | * @param dirPath 验证码图片保存路径 39 | * @return 40 | */ 41 | Bitmap getRandomCodeImg(String dirPath); 42 | 43 | /** 44 | * 获取课程学期选项 45 | * 46 | * @return 47 | */ 48 | String[] getTermOptions(); 49 | 50 | /** 51 | * 判断是否已经登陆 52 | * @return 53 | */ 54 | boolean isLogin(); 55 | 56 | /** 57 | * 配置okhttp是否自动重定向 58 | * @return 59 | */ 60 | boolean getFollowRedirects(); 61 | 62 | /** 63 | * 64 | * @return 验证码长度 65 | */ 66 | int getRandomCodeMaxLength(); 67 | } 68 | -------------------------------------------------------------------------------- /app/src/main/java/com/potato/timetable/ui/config/BgBtnAdapter.java: -------------------------------------------------------------------------------- 1 | package com.potato.timetable.ui.config; 2 | 3 | import android.content.Context; 4 | import android.view.LayoutInflater; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | import android.widget.BaseAdapter; 8 | import android.widget.ImageView; 9 | 10 | import com.potato.timetable.R; 11 | 12 | import java.util.ArrayList; 13 | import java.util.List; 14 | 15 | public class BgBtnAdapter extends BaseAdapter { 16 | private final LayoutInflater mLayoutInflater; 17 | 18 | public List bgIdList = new ArrayList<>(); 19 | 20 | public BgBtnAdapter(Context context) { 21 | mLayoutInflater = LayoutInflater.from(context); 22 | } 23 | 24 | @Override 25 | public int getCount() { 26 | return bgIdList.size(); 27 | } 28 | 29 | @Override 30 | public Object getItem(int i) { 31 | return bgIdList.get(i); 32 | } 33 | 34 | @Override 35 | public long getItemId(int i) { 36 | return i; 37 | } 38 | 39 | @Override 40 | public View getView(int i, View view, ViewGroup viewGroup) { 41 | if (view == null) { 42 | view = mLayoutInflater.inflate(R.layout.item_iv_bg, viewGroup, false); 43 | ImageView imageView = view.findViewById(R.id.item_iv); 44 | imageView.setImageResource(bgIdList.get(i)); 45 | } 46 | return view; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_time.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 18 | 27 | 28 | 34 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_scan.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #2196F3 4 | #1565C0 5 | #2962FF 6 | 7 | #ffc450 8 | #00BFFF 9 | #FFFFFF 10 | #D3D3D3 11 | #87CEFA 12 | #000000 13 | #ff9393 14 | #59f0a3 15 | #70eb55 16 | #76eaea 17 | #d58dfb 18 | #eaeff5 19 | #0C0B0B 20 | #F0F0F0 21 | #D0D0D0 22 | #99D0D0D0 23 | 24 | #CCFF5252 25 | #CC536DFE 26 | #CCE040FB 27 | #CCFF6E40 28 | #CCFF4081 29 | #CCFFAB40 30 | #CC7C4DFF 31 | #CCD3D3D3 32 | 33 | #0C0B0B 34 | 35 | #CCD3D3D3 36 | #CCD0D0D0 37 | 38 | #90CAF9 39 | 40 | -------------------------------------------------------------------------------- /.github/workflows/android.yml: -------------------------------------------------------------------------------- 1 | name: Android CI 2 | 3 | on: 4 | push: 5 | tags: 6 | - v* 7 | pull_request: 8 | tags: 9 | - v* 10 | 11 | jobs: 12 | build: 13 | 14 | runs-on: ubuntu-latest 15 | 16 | steps: 17 | - uses: actions/checkout@v2 18 | - name: set up JDK 1.8 19 | uses: actions/setup-java@v1 20 | with: 21 | java-version: 1.8 22 | 23 | - name: Checkout Android Keystore 24 | uses: actions/checkout@v2 25 | with: 26 | repository: Potato-DiGua/android-key-store 27 | token: ${{ secrets.TOKEN }} 28 | path: keystore 29 | 30 | - name: Build with Gradle 31 | run: bash ./gradlew assembleRelease 32 | 33 | - name: Create Release 34 | id: create_release 35 | uses: actions/create-release@v1 36 | env: 37 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 38 | with: 39 | tag_name: ${{ github.ref }} 40 | release_name: Release ${{ github.ref }} 41 | draft: false 42 | prerelease: false 43 | - name: Get Version Name 44 | uses: actions/github-script@v3 45 | id: get-version 46 | with: 47 | script: | 48 | const str=process.env.GITHUB_REF; 49 | return str.substring(str.indexOf("v")); 50 | result-encoding: string 51 | 52 | - name: Upload Release Asset 53 | id: upload-release-asset 54 | uses: actions/upload-release-asset@v1 55 | env: 56 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 57 | with: 58 | upload_url: ${{ steps.create_release.outputs.upload_url }} 59 | asset_path: app/build/outputs/apk/release/app-release.apk 60 | asset_name: LightTimetable-${{steps.get-version.outputs.result}}.apk 61 | asset_content_type: application/vnd.android.package-archiv 62 | 63 | - name: Archive production artifacts 64 | uses: actions/upload-artifact@v2 65 | with: 66 | name: build 67 | path: app/build/outputs 68 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 12 | 13 | 19 | 22 | 25 | 26 | 27 | 28 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 17 | 18 | 29 | 30 | 31 | 47 | 48 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 29 | 30 | 31 | 32 | 33 | 34 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /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 | 23 | -keep class com.potato.timetable.bean.* {*;} 24 | 25 | 26 | ##---------------Begin: proguard configuration for Gson ---------- 27 | # Gson uses generic type information stored in a class file when working with fields. Proguard 28 | # removes such information by default, so configure it to keep all of it. 29 | -keepattributes Signature 30 | 31 | # For using GSON @Expose annotation 32 | -keepattributes *Annotation* 33 | 34 | # Gson specific classes 35 | -dontwarn sun.misc.** 36 | 37 | #-keep class com.google.gson.stream.** { *; } 38 | 39 | # Application classes that will be serialized/deserialized over Gson 40 | -dontwarn com.google.gson.examples.android.model.** 41 | -keep class com.google.gson.examples.android.model.** { ; } 42 | 43 | # Prevent proguard from stripping interface information from TypeAdapter, TypeAdapterFactory, 44 | # JsonSerializer, JsonDeserializer instances (so they can be used in @JsonAdapter) 45 | -keep class * extends com.google.gson.TypeAdapter 46 | -keep class * implements com.google.gson.TypeAdapterFactory 47 | -keep class * implements com.google.gson.JsonSerializer 48 | -keep class * implements com.google.gson.JsonDeserializer 49 | 50 | # Prevent R8 from leaving Data object members always null 51 | -keepclassmembers,allowobfuscation class * { 52 | @com.google.gson.annotations.SerializedName ; 53 | } 54 | 55 | ##---------------End: proguard configuration for Gson ---------- 56 | 57 | -dontwarn org.jsoup.** 58 | -keep class org.jsoup.** {*;} -------------------------------------------------------------------------------- /app/src/main/java/com/potato/timetable/bean/Course.java: -------------------------------------------------------------------------------- 1 | package com.potato.timetable.bean; 2 | 3 | 4 | import androidx.annotation.NonNull; 5 | 6 | public class Course implements Cloneable, Comparable { 7 | private String name;//课程名 8 | private String teacher;//教授名字 9 | private int classLength = 0;//课程时长 10 | private int classStart = -1;//课程开始节数 11 | private String classRoom;//上课地点 12 | private int weekOfTerm = -1;//开始上课的周,用二进制后25位表示是否为本周 13 | private int dayOfWeek = 0;//在周几上课 值1-7 14 | 15 | public int getClassStart() { 16 | return classStart; 17 | } 18 | 19 | public void setClassStart(int classStart) { 20 | this.classStart = classStart; 21 | } 22 | 23 | public int getWeekOfTerm() { 24 | return weekOfTerm; 25 | } 26 | 27 | public void setWeekOfTerm(int weekOfTerm) { 28 | this.weekOfTerm = weekOfTerm; 29 | } 30 | 31 | public int getDayOfWeek() { 32 | return dayOfWeek; 33 | } 34 | 35 | public void setDayOfWeek(int dayOfWeek) { 36 | this.dayOfWeek = dayOfWeek; 37 | } 38 | 39 | public String getClassRoom() { 40 | return classRoom; 41 | } 42 | 43 | public void setClassRoom(String classRoom) { 44 | this.classRoom = classRoom; 45 | } 46 | 47 | public int getClassLength() { 48 | return classLength; 49 | } 50 | 51 | public void setClassLength(int classLength) { 52 | if (classLength <= 0) 53 | classLength = 1; 54 | else if (classLength > 12) 55 | classLength = 12; 56 | this.classLength = classLength; 57 | } 58 | 59 | public String getName() { 60 | return name; 61 | } 62 | 63 | public void setName(String name) { 64 | this.name = name; 65 | } 66 | 67 | public String getTeacher() { 68 | return teacher; 69 | } 70 | 71 | public void setTeacher(String teacher) { 72 | this.teacher = teacher; 73 | } 74 | 75 | @NonNull 76 | @Override 77 | public Object clone() throws CloneNotSupportedException { 78 | return super.clone(); 79 | } 80 | 81 | @Override 82 | public int compareTo(Course course) { 83 | int i = this.getDayOfWeek() - course.getDayOfWeek();//首先比较星期 84 | if (i == 0)//星期相同比较开始上课的时间 85 | { 86 | return this.getClassStart() - course.getClassStart(); 87 | } else { 88 | return i; 89 | } 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /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/java/com/potato/timetable/ui/login/MyItemRecyclerViewAdapter.java: -------------------------------------------------------------------------------- 1 | package com.potato.timetable.ui.login; 2 | 3 | import android.view.LayoutInflater; 4 | import android.view.View; 5 | import android.view.ViewGroup; 6 | import android.widget.TextView; 7 | 8 | import androidx.recyclerview.widget.RecyclerView; 9 | 10 | import com.potato.timetable.R; 11 | import com.potato.timetable.colleges.base.CollegeFactory; 12 | import com.potato.timetable.ui.login.ItemFragment.OnListFragmentInteractionListener; 13 | 14 | import org.jetbrains.annotations.NotNull; 15 | 16 | import java.util.List; 17 | 18 | /** 19 | * specified {@link OnListFragmentInteractionListener}. 20 | * 21 | */ 22 | public class MyItemRecyclerViewAdapter extends RecyclerView.Adapter { 23 | 24 | private final List collegeNameList; 25 | private final OnListFragmentInteractionListener mListener; 26 | 27 | public MyItemRecyclerViewAdapter(OnListFragmentInteractionListener listener) { 28 | collegeNameList= CollegeFactory.getCollegeNameList(); 29 | mListener = listener; 30 | } 31 | 32 | @NotNull 33 | @Override 34 | public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 35 | View view = LayoutInflater.from(parent.getContext()) 36 | .inflate(R.layout.fragment_item, parent, false); 37 | return new ViewHolder(view); 38 | } 39 | 40 | @Override 41 | public void onBindViewHolder(final ViewHolder holder, int position) { 42 | 43 | String name=collegeNameList.get(position); 44 | holder.mContentView.setText(name); 45 | 46 | holder.mView.setOnClickListener(v -> { 47 | if (null != mListener) { 48 | // Notify the active callbacks interface (the activity, if the 49 | // fragment is attached to one) that an item has been selected. 50 | mListener.onListFragmentInteraction(name); 51 | } 52 | }); 53 | } 54 | 55 | @Override 56 | public int getItemCount() { 57 | return collegeNameList.size(); 58 | } 59 | 60 | public static class ViewHolder extends RecyclerView.ViewHolder { 61 | public final View mView; 62 | public final TextView mContentView; 63 | 64 | public ViewHolder(View view) { 65 | super(view); 66 | mView = view; 67 | mContentView = view.findViewById(R.id.content); 68 | } 69 | 70 | @NotNull 71 | @Override 72 | public String toString() { 73 | return super.toString() + " '" + mContentView.getText() + "'"; 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /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 | 20 | 课程详情 21 | 设置课程时间 22 | 23 | 编辑课程 24 | 25 | 第%1$d周 26 | %1$s [%2$s] 27 | 28 | 29 | %1$s %2$d-%3$d节 30 | 31 | 32 | 33 | 34 | 课名 35 | 教室 36 | 周数 37 | 节数 38 | 老师 39 | 40 | 周一 41 | 周二 42 | 周三 43 | 周四 44 | 周五 45 | 周六 46 | 周日 47 | 48 | 49 | 导入Excel 50 | 修改当前周数 51 | 添加课程 52 | 从教务系统导入 53 | 54 | 55 | 编辑 56 | 未输入 57 | 保存 58 | 单双 59 | 示例:1,7,9,11–17,19(英文标点) 60 | 61 | 62 | 63 | 学号 64 | 密码 65 | 登录 66 | 验证码 67 | 教务系统登录 68 | 69 | 开始时间 70 | 结束时间 71 | 72 | 设置时间 73 | 删除所有时间 74 | 75 | 取消 76 | 确定 77 | 选择周数 78 | 79 | 清除所有日程 80 | 81 | 选择学校 82 | 83 | 84 | Hello blank fragment 85 | 86 | -------------------------------------------------------------------------------- /app/src/main/java/com/potato/timetable/ui/login/LoginActivity.java: -------------------------------------------------------------------------------- 1 | package com.potato.timetable.ui.login; 2 | 3 | import android.os.Bundle; 4 | import android.view.MenuItem; 5 | import android.widget.ImageView; 6 | 7 | import androidx.annotation.NonNull; 8 | import androidx.annotation.Nullable; 9 | import androidx.appcompat.app.ActionBar; 10 | import androidx.appcompat.app.AppCompatActivity; 11 | import androidx.fragment.app.FragmentManager; 12 | 13 | import com.potato.timetable.R; 14 | import com.potato.timetable.colleges.base.CollegeFactory; 15 | import com.potato.timetable.util.Config; 16 | import com.potato.timetable.util.Utils; 17 | 18 | public class LoginActivity extends AppCompatActivity implements ItemFragment.OnListFragmentInteractionListener { 19 | 20 | private FragmentManager fragmentManager; 21 | private LoginFragment loginFragment = null; 22 | private ItemFragment itemFragment = null; 23 | 24 | public static final String EXTRA_UPDATE_TIMETABLE = "update_timetable"; 25 | 26 | 27 | @Override 28 | protected void onCreate(@Nullable Bundle savedInstanceState) { 29 | super.onCreate(savedInstanceState); 30 | setContentView(R.layout.activity_login); 31 | 32 | init(); 33 | 34 | fragmentManager = getSupportFragmentManager();//初始化管理者 35 | String name = Config.getCollegeName(); 36 | if (!name.isEmpty() && CollegeFactory.getCollegeNameList().contains(name)) { 37 | fragmentManager.beginTransaction() 38 | .add(R.id.fragment_container, getLoginFragment()) 39 | .commit(); 40 | 41 | } else { 42 | //选择学校 43 | fragmentManager.beginTransaction() 44 | .add(R.id.fragment_container, getItemFragment()) 45 | .commit(); 46 | } 47 | } 48 | 49 | public LoginFragment getLoginFragment() { 50 | if (loginFragment == null) { 51 | loginFragment = new LoginFragment(); 52 | } 53 | return loginFragment; 54 | } 55 | 56 | public ItemFragment getItemFragment() { 57 | if (itemFragment == null) { 58 | itemFragment = ItemFragment.newInstance(1); 59 | } 60 | return itemFragment; 61 | } 62 | 63 | private void init() { 64 | setActionBar(); 65 | ImageView bgIv = findViewById(R.id.iv_bg); 66 | Utils.setBackGround(this, bgIv); 67 | 68 | Config.readSelectCollege(this); 69 | 70 | } 71 | 72 | private void setActionBar() { 73 | ActionBar actionBar = getSupportActionBar(); 74 | if (actionBar != null) { 75 | actionBar.setTitle(R.string.title_activity_login); 76 | actionBar.setDisplayHomeAsUpEnabled(true); 77 | } 78 | } 79 | 80 | @Override 81 | public boolean onOptionsItemSelected(@NonNull MenuItem item) { 82 | int id = item.getItemId(); 83 | if (id == android.R.id.home) { 84 | finish(); 85 | } else if (id == R.id.menu_select_college) { 86 | fragmentManager.beginTransaction() 87 | .replace(R.id.fragment_container, getItemFragment()) 88 | .commit(); 89 | } 90 | return super.onOptionsItemSelected(item); 91 | } 92 | 93 | @Override 94 | public void onListFragmentInteraction(String item) { 95 | Config.setCollegeName(item); 96 | Config.saveSelectCollege(this); 97 | fragmentManager.beginTransaction() 98 | .replace(R.id.fragment_container, getLoginFragment()) 99 | .commit(); 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /app/src/test/java/com/potato/timetable/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.potato.timetable; 2 | 3 | import com.potato.timetable.util.Utils; 4 | 5 | import org.junit.Test; 6 | 7 | import java.util.Calendar; 8 | import java.util.Date; 9 | import java.util.Random; 10 | 11 | import static org.junit.Assert.assertEquals; 12 | 13 | /** 14 | * Example local unit test, which will execute on the development machine (host). 15 | * 16 | * @see Testing documentation 17 | */ 18 | public class ExampleUnitTest { 19 | @Test 20 | public void test() { 21 | Date date = new Date(); 22 | Calendar calendar = Calendar.getInstance(); 23 | calendar.setTime(date); 24 | calendar.set(Calendar.HOUR_OF_DAY,0); 25 | // 时 26 | calendar.set(Calendar.HOUR_OF_DAY, 0); 27 | // 分 28 | calendar.set(Calendar.MINUTE, 0); 29 | // 秒 30 | calendar.set(Calendar.SECOND, 0); 31 | // 毫秒 32 | calendar.set(Calendar.MILLISECOND, 0); 33 | 34 | int dayOfWeek=calendar.get(Calendar.DAY_OF_WEEK); 35 | dayOfWeek--; 36 | calendar.add(Calendar.DATE,7-dayOfWeek); 37 | 38 | //年 39 | int year = calendar.get(Calendar.YEAR); 40 | //月 41 | int month = calendar.get(Calendar.MONTH) + 1; 42 | //日 43 | int day = calendar.get(Calendar.DAY_OF_MONTH); 44 | //获取系统时间 45 | //小时 46 | int hour = calendar.get(Calendar.HOUR_OF_DAY); 47 | //分钟 48 | int minute = calendar.get(Calendar.MINUTE); 49 | //秒 50 | int second = calendar.get(Calendar.SECOND); 51 | 52 | 53 | System.out.println("Calendar获取当前日期"+year+"年"+month+"月"+day+"日"+hour+":"+minute+":"+second); 54 | System.out.println(dayOfWeek); 55 | 56 | 57 | 58 | } 59 | 60 | /** 61 | * 自动化测试 62 | * Utils.getStringFromWeekOfTerm 63 | */ 64 | @Test 65 | public void autoTestgetStringFromWeekOfTerm() { 66 | int max = 0x1ffffff + 1; 67 | int maxWeekNum = 25; 68 | Random r = new Random(); 69 | for (int i = 0; i < 100; i++) { 70 | int random = r.nextInt(max); 71 | String result = Utils.getStringFromWeekOfTerm(random); 72 | System.out.println(result); 73 | System.out.println(Integer.toBinaryString(random)); 74 | 75 | String[] strings = result.split(" "); 76 | String[] s2 = strings[0].split(","); 77 | 78 | int a = 0; 79 | for (String str : s2) { 80 | if (str == null || str.isEmpty()) 81 | continue; 82 | if (str.contains("-")) { 83 | int space = 2; 84 | if (strings[1].equals("[周]")) { 85 | space = 1; 86 | } 87 | String[] strs = str.split("-"); 88 | if (strs.length != 2) { 89 | System.out.println("error"); 90 | return; 91 | } 92 | int p = Integer.valueOf(strs[0]); 93 | int q = Integer.valueOf(strs[1]); 94 | 95 | for (int n = p; n <= q; n += space) { 96 | a += 1 << (maxWeekNum - n); 97 | } 98 | } else { 99 | a += 1 << (maxWeekNum - Integer.valueOf(str)); 100 | } 101 | } 102 | assertEquals(random, a); 103 | } 104 | //System.out.println(Utils.getStringFromWeekOfTerm(Integer.valueOf("01111,01010,10101,01010,11111".replace(",",""),2))); 105 | } 106 | } -------------------------------------------------------------------------------- /app/src/main/res/layout/dialog_select_week_of_term.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 19 | 20 |