diff --git a/.idea/.name b/.idea/.name
new file mode 100644
index 0000000..5a570f6
--- /dev/null
+++ b/.idea/.name
@@ -0,0 +1 @@
+hhu
\ No newline at end of file
diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml
new file mode 100644
index 0000000..2e2a914
--- /dev/null
+++ b/.idea/codeStyles/Project.xml
@@ -0,0 +1,124 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ xmlns:android
+
+ ^$
+
+
+
+
+
+
+
+
+ xmlns:.*
+
+ ^$
+
+
+ BY_NAME
+
+
+
+
+
+
+ .*:id
+
+ http://schemas.android.com/apk/res/android
+
+
+
+
+
+
+
+
+ .*:name
+
+ http://schemas.android.com/apk/res/android
+
+
+
+
+
+
+
+
+ name
+
+ ^$
+
+
+
+
+
+
+
+
+ style
+
+ ^$
+
+
+
+
+
+
+
+
+ .*
+
+ ^$
+
+
+ BY_NAME
+
+
+
+
+
+
+ .*
+
+ http://schemas.android.com/apk/res/android
+
+
+ ANDROID_ATTRIBUTE_ORDER
+
+
+
+
+
+
+ .*
+
+ .*
+
+
+ BY_NAME
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml
new file mode 100644
index 0000000..79ee123
--- /dev/null
+++ b/.idea/codeStyles/codeStyleConfig.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/dictionaries/Mr_right.xml b/.idea/dictionaries/Mr_right.xml
new file mode 100644
index 0000000..c805775
--- /dev/null
+++ b/.idea/dictionaries/Mr_right.xml
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index 53ba2e5..7aa2f2d 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -1,29 +1,28 @@
plugins {
id("com.android.application")
id("kotlin-android")
+ id("kotlin-kapt")
}
-
android {
- val androidTargetSdkVersion: Int by rootProject.extra
- val androidMinSdkVersion: Int by rootProject.extra
+ val targetSdkVersion: Int by rootProject.extra
+ val minSdkVersion: Int by rootProject.extra
val androidBuildToolsVersion: String by rootProject.extra
- val androidCompileSdkVersion: Int by rootProject.extra
- val androidCompileNdkVersion: String by rootProject.extra
- val defaultManagerPackageName: String by rootProject.extra
+ val compileSdkVersion: Int by rootProject.extra
+ val compileNdkVersion: String by rootProject.extra
+ val packageName: String by rootProject.extra
val verCode: Int by rootProject.extra
val verName: String by rootProject.extra
-
- compileSdk = androidCompileSdkVersion
- ndkVersion = androidCompileNdkVersion
+ compileSdk = compileSdkVersion
+ ndkVersion = compileNdkVersion
buildToolsVersion = androidBuildToolsVersion
defaultConfig {
- applicationId = defaultManagerPackageName
- minSdk = androidMinSdkVersion
- targetSdk = androidTargetSdkVersion
+ applicationId = packageName
+ minSdk = minSdkVersion
+ targetSdk = targetSdkVersion
versionCode = verCode
versionName = verName
@@ -69,6 +68,14 @@ dependencies {
implementation(libs.bundles.accompanist)
implementation(libs.bundles.lifecycle)
implementation(libs.bundles.retrofit)
+ implementation(libs.bundles.room)
implementation(libs.bundles.thirdparty)
+ kapt("androidx.room:room-compiler:2.3.0")
+
+ implementation("androidx.appcompat:appcompat:1.3.1")
+
+ debugImplementation("androidx.compose.ui:ui-tooling:1.0.2")
+ androidTestImplementation("androidx.compose.ui:ui-test-junit4:1.0.2")
+
}
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 2d2cfa1..943fc2d 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -13,20 +13,23 @@
android:supportsRtl="true"
android:theme="@style/Theme.Hhu.NoActionBar"
android:usesCleartextTraffic="true">
-
+
diff --git a/app/src/main/java/github/sukieva/hhu/data/entity/Website.kt b/app/src/main/java/github/sukieva/hhu/data/entity/Website.kt
new file mode 100644
index 0000000..3a194be
--- /dev/null
+++ b/app/src/main/java/github/sukieva/hhu/data/entity/Website.kt
@@ -0,0 +1,17 @@
+package github.sukieva.hhu.data.entity
+
+import androidx.room.ColumnInfo
+import androidx.room.Entity
+import androidx.room.Index
+import androidx.room.PrimaryKey
+
+@Entity(indices = [Index(value = ["site_name"], unique = true)])
+data class Website(
+ @ColumnInfo(name = "site_name")
+ var siteName: String,
+ @ColumnInfo(name = "site_address")
+ var siteAddress: String
+) {
+ @PrimaryKey(autoGenerate = true)
+ var id: Long = 0
+}
diff --git a/app/src/main/java/github/sukieva/hhu/data/bean/Course.kt b/app/src/main/java/github/sukieva/hhu/data/entity/bean/Course.kt
similarity index 86%
rename from app/src/main/java/github/sukieva/hhu/data/bean/Course.kt
rename to app/src/main/java/github/sukieva/hhu/data/entity/bean/Course.kt
index 5eb68c4..d77cd35 100644
--- a/app/src/main/java/github/sukieva/hhu/data/bean/Course.kt
+++ b/app/src/main/java/github/sukieva/hhu/data/entity/bean/Course.kt
@@ -1,4 +1,4 @@
-package github.sukieva.hhu.data.bean
+package github.sukieva.hhu.data.entity.bean
data class Course(
diff --git a/app/src/main/java/github/sukieva/hhu/data/bean/LoginData.kt b/app/src/main/java/github/sukieva/hhu/data/entity/bean/LoginData.kt
similarity index 78%
rename from app/src/main/java/github/sukieva/hhu/data/bean/LoginData.kt
rename to app/src/main/java/github/sukieva/hhu/data/entity/bean/LoginData.kt
index a619663..8e1745f 100644
--- a/app/src/main/java/github/sukieva/hhu/data/bean/LoginData.kt
+++ b/app/src/main/java/github/sukieva/hhu/data/entity/bean/LoginData.kt
@@ -1,12 +1,13 @@
-package github.sukieva.hhu.data.bean
+package github.sukieva.hhu.data.entity.bean
+
import java.math.BigInteger
import java.security.MessageDigest
+
data class LoginData(
var username: String,
- var password: String,
- var captcha: String
+ var password: String
) {
init { // md5 加密(小写字母+数字)
val md = MessageDigest.getInstance("MD5")
diff --git a/app/src/main/java/github/sukieva/hhu/data/entity/bean/PostData.kt b/app/src/main/java/github/sukieva/hhu/data/entity/bean/PostData.kt
new file mode 100644
index 0000000..067d064
--- /dev/null
+++ b/app/src/main/java/github/sukieva/hhu/data/entity/bean/PostData.kt
@@ -0,0 +1,15 @@
+package github.sukieva.hhu.data.entity.bean
+
+
+data class PostData(
+ var maccount: String,
+ var mwid: String,
+ var mname: String,
+ var maid: String,
+ var minstitute: String,
+ var mgrade: String,
+ var mclass: String,
+ var mbuilding: String,
+ var mroom: String,
+ var mphone: String
+)
diff --git a/app/src/main/java/github/sukieva/hhu/data/bean/Rank.kt b/app/src/main/java/github/sukieva/hhu/data/entity/bean/Rank.kt
similarity index 84%
rename from app/src/main/java/github/sukieva/hhu/data/bean/Rank.kt
rename to app/src/main/java/github/sukieva/hhu/data/entity/bean/Rank.kt
index be5b4d9..eae309e 100644
--- a/app/src/main/java/github/sukieva/hhu/data/bean/Rank.kt
+++ b/app/src/main/java/github/sukieva/hhu/data/entity/bean/Rank.kt
@@ -1,4 +1,4 @@
-package github.sukieva.hhu.data.bean
+package github.sukieva.hhu.data.entity.bean
data class Rank(
var name: String,
diff --git a/app/src/main/java/github/sukieva/hhu/data/local/AppDatabase.kt b/app/src/main/java/github/sukieva/hhu/data/local/AppDatabase.kt
new file mode 100644
index 0000000..b63c521
--- /dev/null
+++ b/app/src/main/java/github/sukieva/hhu/data/local/AppDatabase.kt
@@ -0,0 +1,32 @@
+package github.sukieva.hhu.data.local
+
+import android.content.Context
+import androidx.room.Database
+import androidx.room.Room
+import androidx.room.RoomDatabase
+import github.sukieva.hhu.data.entity.Website
+import github.sukieva.hhu.data.local.dao.FavDao
+
+@Database(version = 1, exportSchema = false, entities = [Website::class])
+abstract class AppDatabase : RoomDatabase() {
+
+ abstract fun favDao(): FavDao
+
+
+ companion object { // 全局只创建一个数据库实例
+ private var instance: AppDatabase? = null
+
+ @Synchronized
+ fun getDatabase(context: Context): AppDatabase {
+ instance?.let {
+ return it
+ }
+ return Room.databaseBuilder(context.applicationContext, AppDatabase::class.java, "app_database")
+ .fallbackToDestructiveMigration() // 数据库升级时销毁,测试用
+ .build().apply {
+ instance = this
+ }
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/github/sukieva/hhu/data/local/dao/FavDao.kt b/app/src/main/java/github/sukieva/hhu/data/local/dao/FavDao.kt
new file mode 100644
index 0000000..f9b49a0
--- /dev/null
+++ b/app/src/main/java/github/sukieva/hhu/data/local/dao/FavDao.kt
@@ -0,0 +1,24 @@
+package github.sukieva.hhu.data.local.dao
+
+import androidx.room.Dao
+import androidx.room.Insert
+import androidx.room.Query
+import androidx.room.Update
+import github.sukieva.hhu.data.entity.Website
+
+@Dao
+interface FavDao {
+
+ @Insert
+ suspend fun insertWeb(website: Website): Long
+
+
+ @Query("select * from Website")
+ suspend fun loadAllWebs(): List
+
+ @Query("delete from Website")
+ suspend fun deleteAllWebs()
+
+ @Query("delete from Website where site_name = :siteName")
+ suspend fun deleteWebBySiteName(siteName: String): Int
+}
\ No newline at end of file
diff --git a/app/src/main/java/github/sukieva/hhu/data/remote/EasyOkhttp.kt b/app/src/main/java/github/sukieva/hhu/data/remote/EasyOkhttp.kt
new file mode 100644
index 0000000..8d41ffb
--- /dev/null
+++ b/app/src/main/java/github/sukieva/hhu/data/remote/EasyOkhttp.kt
@@ -0,0 +1,59 @@
+package github.sukieva.hhu.data.remote
+
+import okhttp3.*
+import java.io.IOException
+import java.util.concurrent.TimeUnit
+import kotlin.coroutines.resume
+import kotlin.coroutines.resumeWithException
+import kotlin.coroutines.suspendCoroutine
+
+object EasyOkhttp {
+
+ val sessionCookieJar = SessionCookieJar()
+
+ val okHttpClient = OkHttpClient().newBuilder()
+ .connectTimeout(10, TimeUnit.SECONDS)
+ .readTimeout(10, TimeUnit.SECONDS)
+ .cookieJar(sessionCookieJar)
+ .build()
+
+ fun sendHttpRequest(address: String, body: RequestBody? = null, callback: Callback) {
+ val request =
+ if (body != null) Request.Builder().url(address).post(body).build()
+ else Request.Builder().url(address).build()
+ okHttpClient.newCall(request).enqueue(callback)
+ }
+
+
+
+ suspend fun request(address: String, body: RequestBody? = null): String {
+ return suspendCoroutine {
+ sendHttpRequest(address, body, object : Callback {
+ override fun onFailure(call: Call, e: IOException) {
+ it.resumeWithException(e)
+ }
+
+ override fun onResponse(call: Call, response: Response) {
+ val resBody = response.body()?.string()
+ if (resBody != null) it.resume(resBody)
+ else it.resumeWithException(RuntimeException("response body is null"))
+ }
+
+ })
+ }
+ }
+
+
+ // https://stackoverflow.com/questions/38418809/add-cookies-to-retrofit-2-request
+ class SessionCookieJar : CookieJar {
+ private val cookieStore: HashMap> = HashMap()
+ override fun saveFromResponse(url: HttpUrl, cookies: List) {
+ cookieStore[url.host()] = cookies
+ }
+
+ override fun loadForRequest(url: HttpUrl): List {
+ val cookies = cookieStore[url.host()]
+ return cookies ?: ArrayList()
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/github/sukieva/hhu/network/JwxtService.kt b/app/src/main/java/github/sukieva/hhu/data/remote/retrofit/Api.kt
similarity index 52%
rename from app/src/main/java/github/sukieva/hhu/network/JwxtService.kt
rename to app/src/main/java/github/sukieva/hhu/data/remote/retrofit/Api.kt
index 357cf53..983db18 100644
--- a/app/src/main/java/github/sukieva/hhu/network/JwxtService.kt
+++ b/app/src/main/java/github/sukieva/hhu/data/remote/retrofit/Api.kt
@@ -1,25 +1,25 @@
-package github.sukieva.hhu.network
+package github.sukieva.hhu.data.remote.retrofit
-import github.sukieva.hhu.data.bean.LoginData
+import github.sukieva.hhu.data.entity.bean.LoginData
import retrofit2.Call
import retrofit2.http.Body
import retrofit2.http.GET
import retrofit2.http.POST
-interface JwxtService {
+interface Api {
@POST("j_spring_security_check")
- fun login(@Body data: LoginData): Call
+ fun login(@Body data: LoginData): Call
@GET("img/captcha.jpg")
- fun getCaptchaPic(): Call
+ fun getCaptchaPic(): Call
@GET("student/integratedQuery/scoreQuery/schemeScores/callback")
- fun getGrades(): Call
+ fun getGrades(): Call
@GET("student/integratedQuery/gpaRankingQuery/index/jdpmcx")
- fun getRank(): Call
+ fun getRank(): Call
}
\ No newline at end of file
diff --git a/app/src/main/java/github/sukieva/hhu/network/JwxtNetwork.kt b/app/src/main/java/github/sukieva/hhu/data/remote/retrofit/Network.kt
similarity index 64%
rename from app/src/main/java/github/sukieva/hhu/network/JwxtNetwork.kt
rename to app/src/main/java/github/sukieva/hhu/data/remote/retrofit/Network.kt
index 646a78e..05b23f5 100644
--- a/app/src/main/java/github/sukieva/hhu/network/JwxtNetwork.kt
+++ b/app/src/main/java/github/sukieva/hhu/data/remote/retrofit/Network.kt
@@ -1,24 +1,24 @@
-package github.sukieva.hhu.network
+package github.sukieva.hhu.data.remote.retrofit
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
-import github.sukieva.hhu.data.bean.LoginData
+import github.sukieva.hhu.data.entity.bean.LoginData
import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException
import kotlin.coroutines.suspendCoroutine
-object JwxtNetwork {
+object Network {
- private val jwxtService = ServiceCreator.create()
+ private val service = ServiceCreator.create()
- suspend fun login(data: LoginData) = jwxtService.login(data).await()
+ suspend fun login(data: LoginData) = service.login(data).await()
- suspend fun getCaptchaPic() = jwxtService.getCaptchaPic().await()
+ suspend fun getCaptchaPic() = service.getCaptchaPic().await()
- suspend fun getGrades() = jwxtService.getGrades().await()
+ suspend fun getGrades() = service.getGrades().await()
- suspend fun getRank() = jwxtService.getRank().await()
+ suspend fun getRank() = service.getRank().await()
private suspend fun Call.await(): T {
diff --git a/app/src/main/java/github/sukieva/hhu/data/remote/retrofit/ServiceCreator.kt b/app/src/main/java/github/sukieva/hhu/data/remote/retrofit/ServiceCreator.kt
new file mode 100644
index 0000000..4d183c6
--- /dev/null
+++ b/app/src/main/java/github/sukieva/hhu/data/remote/retrofit/ServiceCreator.kt
@@ -0,0 +1,29 @@
+package github.sukieva.hhu.data.remote.retrofit
+
+import github.sukieva.hhu.data.remote.EasyOkhttp.sessionCookieJar
+import okhttp3.OkHttpClient
+import retrofit2.Retrofit
+import retrofit2.converter.gson.GsonConverterFactory
+
+
+object ServiceCreator {
+ private const val BASE_URL = "http://jwxs.hhu.edu.cn/"
+
+ private val retrofit = Retrofit.Builder()
+ .baseUrl(BASE_URL)
+ .client(
+ OkHttpClient().newBuilder()
+ .cookieJar(sessionCookieJar)
+ .build()
+ )
+ .addConverterFactory(GsonConverterFactory.create())
+ .build()
+
+
+ fun create(serviceClass: Class): T = retrofit.create(serviceClass)
+
+ inline fun create(): T = create(T::class.java)
+
+
+}
+
diff --git a/app/src/main/java/github/sukieva/hhu/data/repository/LocalRepository.kt b/app/src/main/java/github/sukieva/hhu/data/repository/LocalRepository.kt
new file mode 100644
index 0000000..424b824
--- /dev/null
+++ b/app/src/main/java/github/sukieva/hhu/data/repository/LocalRepository.kt
@@ -0,0 +1,34 @@
+package github.sukieva.hhu.data.repository
+
+import github.sukieva.hhu.MyApp
+import github.sukieva.hhu.data.entity.Website
+import github.sukieva.hhu.data.local.AppDatabase
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.flow.*
+
+object LocalRepository {
+
+ private val favDao = AppDatabase.getDatabase(MyApp.context).favDao()
+
+ fun getWebsites(): Flow> = flow {
+ val websites = favDao.loadAllWebs()
+ emit(websites)
+ }.flowOn(Dispatchers.IO) // 通过 flowOn 切换到 IO 线程
+
+ suspend fun resetWebs() {
+ favDao.deleteAllWebs()
+ favDao.insertWeb(Website("奥蓝系统", "http://smst.hhu.edu.cn/Mobile/login.aspx"))
+ favDao.insertWeb(Website("教务系统", "http://jwxs.hhu.edu.cn/"))
+ favDao.insertWeb(Website("信息门户", "http://my.hhu.edu.cn/portal-web/html/index.html"))
+ }
+
+ suspend fun insertWeb(webSite: Website) = favDao.insertWeb(webSite)
+
+ suspend fun deleteWebByName(siteName: String) = favDao.deleteWebBySiteName(siteName)
+
+ suspend fun updateWeb(webSite: Website) {
+ deleteWebByName(webSite.siteName)
+ favDao.insertWeb(webSite)
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/github/sukieva/hhu/data/repository/RemoteRepository.kt b/app/src/main/java/github/sukieva/hhu/data/repository/RemoteRepository.kt
new file mode 100644
index 0000000..b12cad1
--- /dev/null
+++ b/app/src/main/java/github/sukieva/hhu/data/repository/RemoteRepository.kt
@@ -0,0 +1,57 @@
+package github.sukieva.hhu.data.repository
+
+import android.graphics.Bitmap
+import android.graphics.BitmapFactory
+import coil.request.ImageRequest
+import github.sukieva.hhu.data.remote.EasyOkhttp
+import github.sukieva.hhu.utils.LogUtil
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.flow.flow
+import kotlinx.coroutines.flow.flowOn
+import okhttp3.Call
+import okhttp3.Callback
+import okhttp3.Request
+import okhttp3.Response
+import java.io.IOException
+import java.io.InputStream
+import kotlin.concurrent.thread
+
+object RemoteRepository {
+
+ private const val BASE_URL = "http://jwxs.hhu.edu.cn/"
+ private const val captchaPicUrl = BASE_URL + "img/captcha.jpg"
+ private const val loginUrl = BASE_URL + "j_spring_security_check"
+ private const val gradesUrl = BASE_URL + "student/integratedQuery/scoreQuery/schemeScores/callback"
+ private const val rankUrl = BASE_URL + "student/integratedQuery/gpaRankingQuery/index/jdpmcx"
+ private const val TAG = "HTTP"
+
+
+ fun getCaptchaPic(): Bitmap? {
+ val request = Request.Builder().url(captchaPicUrl).build()
+ try {
+ val response = EasyOkhttp.okHttpClient.newCall(request).execute()
+ if (!response.isSuccessful) response.close()
+ if (response.body() != null) {
+ val `is`: InputStream? = response.body()!!.byteStream()
+ LogUtil.d(TAG, "==> Successfully get captchaPic")
+ return BitmapFactory.decodeStream(`is`)
+ }
+ } catch (e: Exception) {
+ LogUtil.d(TAG, "==> Fail to get captchaPic")
+ }
+ return null
+ }
+
+
+ fun getHitokoto() = flow {
+ try {
+ val hitoko = EasyOkhttp.request("https://v1.hitokoto.cn/?encode=text&c=i")
+ LogUtil.d("Hitokoto", "==> Hitokoto is $hitoko")
+ emit(hitoko)
+ } catch (e: Exception) {
+ e.printStackTrace()
+ LogUtil.d("Hitokoto", "Fail to get Hitokoto")
+ }
+ }.flowOn(Dispatchers.IO)
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/github/sukieva/hhu/data/repository/Repository.kt b/app/src/main/java/github/sukieva/hhu/data/repository/Repository.kt
new file mode 100644
index 0000000..01cd387
--- /dev/null
+++ b/app/src/main/java/github/sukieva/hhu/data/repository/Repository.kt
@@ -0,0 +1,8 @@
+package github.sukieva.hhu.data.repository
+
+interface Repository {
+
+ fun getWebsites() = LocalRepository.getWebsites()
+
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/github/sukieva/hhu/network/ServiceCreator.kt b/app/src/main/java/github/sukieva/hhu/network/ServiceCreator.kt
deleted file mode 100644
index a95e4ed..0000000
--- a/app/src/main/java/github/sukieva/hhu/network/ServiceCreator.kt
+++ /dev/null
@@ -1,42 +0,0 @@
-package github.sukieva.hhu.network
-
-import okhttp3.Cookie
-import okhttp3.CookieJar
-import okhttp3.HttpUrl
-import okhttp3.OkHttpClient
-import retrofit2.Retrofit
-import retrofit2.converter.gson.GsonConverterFactory
-
-
-object ServiceCreator {
- private const val BASE_URL = "http://jwxs.hhu.edu.cn/"
-
- private val retrofit = Retrofit.Builder()
- .baseUrl(BASE_URL)
- .client(
- OkHttpClient().newBuilder()
- .cookieJar(SessionCookieJar())
- .build()
- )
- .addConverterFactory(GsonConverterFactory.create())
- .build()
-
- fun create(serviceClass: Class): T = retrofit.create(serviceClass)
-
- inline fun create(): T = create(T::class.java)
-
- // https://stackoverflow.com/questions/38418809/add-cookies-to-retrofit-2-request
- class SessionCookieJar : CookieJar {
- private val cookieStore: HashMap> = HashMap()
- override fun saveFromResponse(url: HttpUrl, cookies: List) {
- cookieStore[url.host()] = cookies
- }
-
- override fun loadForRequest(url: HttpUrl): List {
- val cookies = cookieStore[url.host()]
- return cookies ?: ArrayList()
- }
- }
-
-}
-
diff --git a/app/src/main/java/github/sukieva/hhu/ui/activity/MainActivity.kt b/app/src/main/java/github/sukieva/hhu/ui/activity/MainActivity.kt
deleted file mode 100644
index bf25c67..0000000
--- a/app/src/main/java/github/sukieva/hhu/ui/activity/MainActivity.kt
+++ /dev/null
@@ -1,39 +0,0 @@
-package github.sukieva.hhu.ui.activity
-
-import android.os.Bundle
-import androidx.activity.compose.setContent
-import androidx.compose.foundation.layout.Column
-import androidx.compose.foundation.layout.fillMaxHeight
-import androidx.compose.ui.Modifier
-import github.sukieva.hhu.ui.activity.base.BaseActivity
-import github.sukieva.hhu.ui.activity.base.InitView
-import github.sukieva.hhu.ui.components.*
-import github.sukieva.hhu.utils.errorToast
-import github.sukieva.hhu.utils.infoToast
-
-class MainActivity : BaseActivity() {
-
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- setContent {
- InitView {
- HomeAppBar()
- CardCheckIn()
- CardGradeQuery()
- CardSchedule()
- ListCardFavourite()
- ListCardConfig()
- }
- }
- }
-
-
- override fun onResume() {
- super.onResume()
- "开始交互".errorToast()
- }
-
-
-}
-
diff --git a/app/src/main/java/github/sukieva/hhu/ui/activity/AboutActivity.kt b/app/src/main/java/github/sukieva/hhu/ui/activity/about/AboutActivity.kt
similarity index 96%
rename from app/src/main/java/github/sukieva/hhu/ui/activity/AboutActivity.kt
rename to app/src/main/java/github/sukieva/hhu/ui/activity/about/AboutActivity.kt
index f066ec5..4e9a3b5 100644
--- a/app/src/main/java/github/sukieva/hhu/ui/activity/AboutActivity.kt
+++ b/app/src/main/java/github/sukieva/hhu/ui/activity/about/AboutActivity.kt
@@ -1,4 +1,4 @@
-package github.sukieva.hhu.ui.activity
+package github.sukieva.hhu.ui.activity.about
import android.widget.ImageView
import android.widget.TextView
diff --git a/app/src/main/java/github/sukieva/hhu/ui/activity/base/BaseActivity.kt b/app/src/main/java/github/sukieva/hhu/ui/activity/base/BaseActivity.kt
index 692c919..064dba2 100644
--- a/app/src/main/java/github/sukieva/hhu/ui/activity/base/BaseActivity.kt
+++ b/app/src/main/java/github/sukieva/hhu/ui/activity/base/BaseActivity.kt
@@ -2,13 +2,9 @@ package github.sukieva.hhu.ui.activity.base
import android.os.Bundle
import androidx.activity.ComponentActivity
-import androidx.compose.foundation.layout.Column
-import androidx.compose.foundation.layout.fillMaxHeight
-import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Surface
import androidx.compose.runtime.Composable
-import androidx.compose.ui.Modifier
import github.sukieva.hhu.ui.theme.MyTheme
import github.sukieva.hhu.utils.ActivityCollector
@@ -30,11 +26,11 @@ open class BaseActivity : ComponentActivity() {
@Composable
fun InitView(content: @Composable () -> Unit) {
+
MyTheme {
Surface(color = MaterialTheme.colors.background) {
- Column(modifier = Modifier.fillMaxHeight()) {
- content()
- }
+ content()
}
}
+
}
\ No newline at end of file
diff --git a/app/src/main/java/github/sukieva/hhu/ui/activity/ConfigActivity.kt b/app/src/main/java/github/sukieva/hhu/ui/activity/config/ConfigActivity.kt
similarity index 57%
rename from app/src/main/java/github/sukieva/hhu/ui/activity/ConfigActivity.kt
rename to app/src/main/java/github/sukieva/hhu/ui/activity/config/ConfigActivity.kt
index f42ffb4..28fa1fe 100644
--- a/app/src/main/java/github/sukieva/hhu/ui/activity/ConfigActivity.kt
+++ b/app/src/main/java/github/sukieva/hhu/ui/activity/config/ConfigActivity.kt
@@ -1,18 +1,17 @@
-package github.sukieva.hhu.ui.activity
+package github.sukieva.hhu.ui.activity.config
import android.os.Bundle
import androidx.activity.compose.setContent
+import androidx.compose.material.ExperimentalMaterialApi
import github.sukieva.hhu.ui.activity.base.BaseActivity
-import github.sukieva.hhu.ui.activity.base.InitView
-import github.sukieva.hhu.ui.components.MaterialTopAppBar
class ConfigActivity : BaseActivity() {
+ @ExperimentalMaterialApi
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
+
setContent {
- InitView {
- MaterialTopAppBar()
- }
+ ConfigView()
}
}
}
\ No newline at end of file
diff --git a/app/src/main/java/github/sukieva/hhu/ui/activity/config/ConfigView.kt b/app/src/main/java/github/sukieva/hhu/ui/activity/config/ConfigView.kt
new file mode 100644
index 0000000..f0c42f1
--- /dev/null
+++ b/app/src/main/java/github/sukieva/hhu/ui/activity/config/ConfigView.kt
@@ -0,0 +1,211 @@
+package github.sukieva.hhu.ui.activity.config
+
+import androidx.compose.foundation.Image
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.layout.*
+import androidx.compose.foundation.lazy.LazyColumn
+import androidx.compose.material.*
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.filled.Clear
+import androidx.compose.material.icons.outlined.CheckCircleOutline
+import androidx.compose.material.icons.outlined.Save
+import androidx.compose.material.icons.rounded.ManageSearch
+import androidx.compose.material.icons.rounded.PendingActions
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.MutableState
+import androidx.compose.runtime.remember
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.text.TextStyle
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.dp
+import androidx.lifecycle.viewmodel.compose.viewModel
+import com.google.accompanist.insets.ProvideWindowInsets
+import github.sukieva.hhu.R
+import github.sukieva.hhu.ui.activity.base.InitView
+import github.sukieva.hhu.ui.components.ExpandableCard
+import github.sukieva.hhu.ui.components.ListCard
+import github.sukieva.hhu.ui.components.MaterialTopAppBar
+import github.sukieva.hhu.ui.components.MyScaffold
+import github.sukieva.hhu.ui.theme.fontHead
+import github.sukieva.hhu.utils.LogUtil
+import github.sukieva.hhu.utils.browse
+
+
+@ExperimentalMaterialApi
+@Composable
+fun ConfigView() {
+ val model: ConfigViewModel = viewModel()
+ model.showConfig()
+ ProvideWindowInsets(windowInsetsAnimationsEnabled = true) {
+ InitView {
+ MyScaffold(topBar = { ConfigAppBar() }) {
+ LazyColumn(modifier = Modifier.fillMaxHeight()) {
+ item { GradeItem() }
+ item { CheckInItem() }
+ item { ScheduleItem() }
+ }
+ }
+ }
+ }
+}
+
+@Composable
+fun ScheduleItem() {
+ ListCard(
+ title = stringResource(id = R.string.home_card_schedule),
+ icon = Icons.Rounded.PendingActions,
+ modifier = Modifier
+ .padding(start = 22.dp, top = 12.dp)
+ .height(50.dp)
+ .clickable {
+ browse("https://www.coolapk.com/apk/com.suda.yzune.wakeupschedule")
+ }
+ )
+}
+
+@ExperimentalMaterialApi
+@Composable
+fun GradeItem() {
+ ExpandableCard(
+ title = stringResource(id = R.string.home_card_results),
+ icon = Icons.Rounded.ManageSearch,
+ content = {
+ val model: ConfigViewModel = viewModel()
+ val accountState = remember { model.account }
+ val passwordState = remember { model.password }
+ Column {
+ MyTextField(
+ state = accountState,
+ label = "学号"
+ )
+ MyTextField(
+ state = passwordState,
+ label = "教务系统密码"
+ )
+ }
+ }
+ )
+
+}
+
+@ExperimentalMaterialApi
+@Composable
+fun CheckInItem() {
+ ExpandableCard(
+ title = stringResource(id = R.string.home_card_checkin),
+ icon = Icons.Outlined.CheckCircleOutline,
+ content = {
+ val model: ConfigViewModel = viewModel()
+ val wid = remember { model.wid }
+ val name = remember { model.name }
+ val aid = remember { model.aid }
+ val institute = remember { model.institute }
+ val grade = remember { model.grade }
+ val mclass = remember { model.mclass }
+ val building = remember { model.building }
+ val room = remember { model.room }
+ val phone = remember { model.phone }
+ Text(
+ text = "请对照健康打卡填写\n还需填写上面的学号",
+ color = MaterialTheme.colors.onSurface.copy(alpha = ContentAlpha.medium),
+ style = MaterialTheme.typography.caption,
+ modifier = Modifier.padding(start = 35.dp)
+ )
+ Column {
+ MyTextField(
+ state = wid,
+ label = "wid(无需修改 自动填写)",
+ readOnly = true
+ )
+ MyTextField(
+ state = name,
+ label = "姓名"
+ )
+ MyTextField(
+ state = aid,
+ label = "身份证号"
+ )
+ MyTextField(
+ state = institute,
+ label = "学院"
+ )
+ MyTextField(
+ state = grade,
+ label = "年级"
+ )
+ MyTextField(
+ state = mclass,
+ label = "班级"
+ )
+ MyTextField(
+ state = building,
+ label = "宿舍楼"
+ )
+ MyTextField(
+ state = room,
+ label = "宿舍号"
+ )
+ MyTextField(
+ state = phone,
+ label = "电话号码"
+ )
+ }
+ }
+ )
+
+}
+
+
+@Composable
+fun MyTextField(
+ state: MutableState,
+ label: String,
+ readOnly: Boolean = false
+) {
+ Row(
+ modifier = Modifier
+ .padding(top = 10.dp)
+ .fillMaxWidth(),
+ horizontalArrangement = Arrangement.Center
+ ) {
+ OutlinedTextField(
+ value = state.value,
+ readOnly = readOnly,
+ onValueChange = { state.value = it },
+ label = { Text(label) },
+ textStyle = TextStyle(color = MaterialTheme.colors.fontHead),
+ trailingIcon = @Composable {
+ Image(imageVector = Icons.Filled.Clear, // 清除图标
+ contentDescription = null,
+ modifier = Modifier.clickable { state.value = "" }) // 给图标添加点击事件,点击就清空text
+ },
+ modifier = Modifier.width(300.dp)
+ )
+ }
+
+}
+
+@Composable
+fun ConfigAppBar() {
+ val model: ConfigViewModel = viewModel()
+ MaterialTopAppBar(
+ title = stringResource(id = R.string.home_list_config),
+ actions = {
+ IconButton(onClick = {
+ model.saveConfig()
+ LogUtil.d("ConfigAppBar", "Save config")
+ }) {
+ Icon(Icons.Outlined.Save, contentDescription = "Save config")
+ }
+ }
+ )
+}
+
+
+@ExperimentalMaterialApi
+@Preview
+@Composable
+fun ConfigViewPreview() {
+ ConfigView()
+}
\ No newline at end of file
diff --git a/app/src/main/java/github/sukieva/hhu/ui/activity/config/ConfigViewModel.kt b/app/src/main/java/github/sukieva/hhu/ui/activity/config/ConfigViewModel.kt
new file mode 100644
index 0000000..106ba83
--- /dev/null
+++ b/app/src/main/java/github/sukieva/hhu/ui/activity/config/ConfigViewModel.kt
@@ -0,0 +1,68 @@
+package github.sukieva.hhu.ui.activity.config
+
+import androidx.compose.runtime.mutableStateOf
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.viewModelScope
+import github.sukieva.hhu.ui.components.InJavaScriptLocalObj
+import github.sukieva.hhu.utils.DataManager
+import github.sukieva.hhu.utils.infoToast
+import kotlinx.coroutines.launch
+
+class ConfigViewModel : ViewModel() {
+
+
+ var account = mutableStateOf("")
+ var password = mutableStateOf("")
+ var wid = mutableStateOf("")
+ var name = mutableStateOf("")
+ var aid = mutableStateOf("")
+ var institute = mutableStateOf("")
+ var grade = mutableStateOf("")
+ var mclass = mutableStateOf("")
+ var building = mutableStateOf("")
+ var room = mutableStateOf("")
+ var phone = mutableStateOf("")
+ val configUrl = "http://dailyreport.hhu.edu.cn/pdc/formDesign/showFormFilled?selfFormWid=A335B048C8456F75E0538101600A6A04&lwUserId=${account.value}"
+
+ fun saveConfig() {
+ viewModelScope.launch {
+ DataManager.saveData("account", account.value)
+ DataManager.saveData("password", password.value)
+ DataManager.saveData("wid", wid.value)
+ DataManager.saveData("name", name.value)
+ DataManager.saveData("aid", aid.value)
+ DataManager.saveData("institute", institute.value)
+ DataManager.saveData("grade", grade.value)
+ DataManager.saveData("mclass", mclass.value)
+ DataManager.saveData("building", building.value)
+ DataManager.saveData("room", room.value)
+ DataManager.saveData("phone", phone.value)
+ }
+ "已保存配置".infoToast()
+ }
+
+ fun showConfig() {
+ viewModelScope.launch {
+ account.value = DataManager.readData("account", "")
+ password.value = DataManager.readData("password", "")
+ wid.value = DataManager.readData("wid", "")
+ name.value = DataManager.readData("name", "")
+ aid.value = DataManager.readData("aid", "")
+ institute.value = DataManager.readData("institute", "")
+ grade.value = DataManager.readData("grade", "")
+ mclass.value = DataManager.readData("mclass", "")
+ building.value = DataManager.readData("building", "")
+ room.value = DataManager.readData("room", "")
+ phone.value = DataManager.readData("phone", "")
+ if (wid.value == "") wid.value = "A335B048C8456F75E0538101600A6A04"
+ return@launch
+ }
+ }
+
+ fun getHtml() {
+ val html = InJavaScriptLocalObj.webHtml
+ println(html)
+ }
+
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/github/sukieva/hhu/ui/activity/FavouriteActivity.kt b/app/src/main/java/github/sukieva/hhu/ui/activity/favourite/FavouriteActivity.kt
similarity index 50%
rename from app/src/main/java/github/sukieva/hhu/ui/activity/FavouriteActivity.kt
rename to app/src/main/java/github/sukieva/hhu/ui/activity/favourite/FavouriteActivity.kt
index 4122ca9..2c8a25d 100644
--- a/app/src/main/java/github/sukieva/hhu/ui/activity/FavouriteActivity.kt
+++ b/app/src/main/java/github/sukieva/hhu/ui/activity/favourite/FavouriteActivity.kt
@@ -1,24 +1,21 @@
-package github.sukieva.hhu.ui.activity
+package github.sukieva.hhu.ui.activity.favourite
import android.os.Bundle
import androidx.activity.compose.setContent
import github.sukieva.hhu.ui.activity.base.BaseActivity
-import github.sukieva.hhu.ui.activity.base.InitView
-import github.sukieva.hhu.ui.components.MaterialTopAppBar
-import github.sukieva.hhu.ui.components.MyWebView
class FavouriteActivity : BaseActivity() {
+
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
+
+ val siteAddress: String? = intent.getStringExtra("siteAddress")
+ val siteName: String? = intent.getStringExtra("siteName")
setContent {
- InitView {
- MaterialTopAppBar()
- MyWebView()
- }
+ FavouriteView(siteAddress, siteName)
}
}
-
}
\ No newline at end of file
diff --git a/app/src/main/java/github/sukieva/hhu/ui/activity/favourite/FavouriteView.kt b/app/src/main/java/github/sukieva/hhu/ui/activity/favourite/FavouriteView.kt
new file mode 100644
index 0000000..34e7858
--- /dev/null
+++ b/app/src/main/java/github/sukieva/hhu/ui/activity/favourite/FavouriteView.kt
@@ -0,0 +1,203 @@
+package github.sukieva.hhu.ui.activity.favourite
+
+import androidx.compose.foundation.gestures.detectTapGestures
+import androidx.compose.foundation.layout.*
+import androidx.compose.foundation.lazy.LazyColumn
+import androidx.compose.foundation.lazy.items
+import androidx.compose.material.*
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.outlined.OpenInBrowser
+import androidx.compose.material.icons.rounded.Add
+import androidx.compose.material.icons.rounded.Done
+import androidx.compose.material.icons.rounded.RestartAlt
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.remember
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.input.pointer.pointerInput
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.text.TextStyle
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.sp
+import androidx.lifecycle.viewmodel.compose.viewModel
+import github.sukieva.hhu.MyApp
+import github.sukieva.hhu.R
+import github.sukieva.hhu.data.entity.Website
+import github.sukieva.hhu.ui.activity.base.InitView
+import github.sukieva.hhu.ui.components.*
+import github.sukieva.hhu.ui.theme.fontHead
+import github.sukieva.hhu.utils.*
+
+
+@Composable
+fun FavouriteView(siteAddress: String? = null, siteName: String? = null) {
+ val model: FavouriteViewModel = viewModel()
+ if (siteAddress != null && siteName != null) {
+ LogUtil.d("FavouriteActivity", "==>$siteAddress")
+ InitView {
+ MyScaffold(topBar = { FavWebAppBar(siteAddress, siteName) }) {
+ MyWebView(siteAddress)
+ }
+ }
+ } else {
+ model.getWebs()
+ val websites = model.websites
+ InitView {
+ MyScaffold(topBar = { FavAppBar() }) {
+ LazyColumn(modifier = Modifier.fillMaxHeight()) {
+ items(websites) { website ->
+ FavListItem(website)
+ }
+ }
+ }
+ }
+ }
+}
+
+@Composable
+fun FavListItem(website: Website) {
+ val model: FavouriteViewModel = viewModel()
+ ListCard(
+ title = website.siteName,
+ modifier = Modifier
+ .padding(start = 5.dp, end = 5.dp, top = 12.dp, bottom = 12.dp)
+ .fillMaxWidth()
+ .height(50.dp)
+ .pointerInput(Unit) {
+ detectTapGestures(
+ onLongPress = {
+ alert(
+ message = MyApp.context.getString(R.string.dialog_press_message),
+ positive = MyApp.context.getString(R.string.dialog_press_confirm),
+ showNegative = true,
+ negative = MyApp.context.getString(R.string.dialog_press_cancel),
+ onPositiveClick = {
+ model.deleteWebByName(website.siteName)
+ model.refreshUI()
+ }
+ )
+ },
+ onTap = {
+ start {
+ putExtra("siteAddress", website.siteAddress)
+ putExtra("siteName", website.siteName)
+ }
+ }
+ )
+ }
+ )
+}
+
+@Composable
+fun FavWebAppBar(siteAddress: String, siteName: String) {
+ MaterialTopAppBar(
+ title = siteName,
+ actions = {
+ IconButton(onClick = { browse(siteAddress) }) {
+ Icon(Icons.Outlined.OpenInBrowser, contentDescription = "Browse by system")
+ }
+ }
+ )
+ if (siteName == "信息门户")
+ "信息门户请在浏览器中打开哦".warningToast()
+}
+
+
+@Composable
+fun FavAppBar() {
+ val model: FavouriteViewModel = viewModel()
+ val openDialog = remember { model.isOpenDialog }
+ MaterialTopAppBar(
+ title = stringResource(id = R.string.home_list_favourite),
+ actions = {
+ IconButton(onClick = {
+ model.isOpenDialog.value = true
+ openDialog.value = model.isOpenDialog.value
+ LogUtil.d("FavAppBar", "Add a new website")
+ }) {
+ Icon(Icons.Rounded.Add, contentDescription = "Add a website")
+ }
+ IconButton(onClick = {
+ MyApp.context.getString(R.string.appbar_reset).infoToast()
+ model.resetWeb()
+ model.refreshUI()
+ LogUtil.d("FavAppBar", "Reset websites")
+ }) {
+ Icon(Icons.Rounded.RestartAlt, contentDescription = "Reset websites")
+ }
+ }
+ )
+ if (openDialog.value) AddWebDialog()
+}
+
+@Composable
+fun AddWebDialog() {
+ val model: FavouriteViewModel = viewModel()
+ val webNameState = remember { model.webName }
+ val webUrlState = remember { model.webAddress }
+ AlertDialog(
+ onDismissRequest = {
+ model.isOpenDialog.value = false
+ model.clearDialog()
+ },
+ text = {
+ Column {
+ Text(
+ text = stringResource(id = R.string.dialog_title),
+ color = MaterialTheme.colors.secondary,
+ fontSize = 20.sp
+ )
+ Divider(
+ Modifier
+ .fillMaxWidth()
+ .padding(top = 10.dp)
+ )
+ Spacer(
+ modifier = Modifier
+ .fillMaxWidth()
+ .height(10.dp)
+ )
+ OutlinedTextField(
+ value = webNameState.value,
+ onValueChange = { model.webName.value = it },
+ label = { Text(stringResource(id = R.string.dialog_web_name)) },
+ textStyle = TextStyle(color = MaterialTheme.colors.fontHead),
+ maxLines = 1
+ )
+ OutlinedTextField(
+ value = webUrlState.value,
+ onValueChange = { model.webAddress.value = it },
+ label = { Text(stringResource(id = R.string.dialog_web_url)) },
+ textStyle = TextStyle(color = MaterialTheme.colors.fontHead),
+ placeholder = {
+ Text("https://baidu.com")
+ }
+ )
+ }
+ },
+ confirmButton = {
+ IconButton(onClick = {
+ if (model.checkNull() && model.checkUrl()) {
+ LogUtil.d("FavDialog", "Add Url ==> ${webUrlState.value}")
+ model.addWeb()
+ model.isOpenDialog.value = false
+ model.clearDialog()
+ model.refreshUI()
+ }
+ }) {
+ Icon(
+ Icons.Rounded.Done,
+ contentDescription = "Confirm button",
+ tint = MaterialTheme.colors.secondary,
+ modifier = Modifier.size(30.dp)
+ )
+ }
+ }
+ )
+}
+
+@Preview
+@Composable
+fun FavouriteViewPreview() {
+ FavouriteView()
+}
\ No newline at end of file
diff --git a/app/src/main/java/github/sukieva/hhu/ui/activity/favourite/FavouriteViewModel.kt b/app/src/main/java/github/sukieva/hhu/ui/activity/favourite/FavouriteViewModel.kt
new file mode 100644
index 0000000..923ceba
--- /dev/null
+++ b/app/src/main/java/github/sukieva/hhu/ui/activity/favourite/FavouriteViewModel.kt
@@ -0,0 +1,85 @@
+package github.sukieva.hhu.ui.activity.favourite
+
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.setValue
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.viewModelScope
+import github.sukieva.hhu.MyApp
+import github.sukieva.hhu.R
+import github.sukieva.hhu.data.entity.Website
+import github.sukieva.hhu.data.repository.LocalRepository
+import github.sukieva.hhu.utils.ActivityCollector
+import github.sukieva.hhu.utils.errorToast
+import github.sukieva.hhu.utils.start
+import kotlinx.coroutines.flow.collect
+import kotlinx.coroutines.launch
+import java.util.regex.Pattern
+
+class FavouriteViewModel : ViewModel() {
+
+ private val scope = viewModelScope
+ private val URL_VALIDATION_REGEX = "^((https|http)?://).*$"
+ var isOpenDialog = mutableStateOf(false)
+ var webName = mutableStateOf("")
+ var webAddress = mutableStateOf("")
+ var websites: List by mutableStateOf(emptyList())
+
+ fun getWebs() {
+ scope.launch {
+ LocalRepository.getWebsites().collect {
+ websites = it
+ }
+ }
+ }
+
+ fun addWeb() {
+ scope.launch {
+ val newWeb = Website(webName.value, webAddress.value)
+ for (website in websites) {
+ if (website.siteName == webName.value) {
+ LocalRepository.updateWeb(newWeb)
+ return@launch
+ }
+ }
+ LocalRepository.insertWeb(newWeb)
+ }
+ }
+
+ fun resetWeb() {
+ scope.launch {
+ LocalRepository.resetWebs()
+ }
+ }
+
+ fun clearDialog() {
+ webName.value = ""
+ webAddress.value = ""
+ }
+
+ fun deleteWebByName(name: String) {
+ scope.launch {
+ LocalRepository.deleteWebByName(name)
+ }
+ }
+
+ fun checkUrl(): Boolean {
+ if (Pattern.matches(URL_VALIDATION_REGEX, webAddress.value))
+ return true
+ MyApp.context.getString(R.string.dialog_error_not_valid).errorToast()
+ return false
+ }
+
+ fun checkNull(): Boolean {
+ if (webName.value == "" || webAddress.value == "") {
+ MyApp.context.getString(R.string.dialog_error_null).errorToast()
+ return false
+ }
+ return true
+ }
+
+ fun refreshUI() {
+ start()
+ ActivityCollector.finishTopActivity()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/github/sukieva/hhu/ui/activity/home/HomeActivity.kt b/app/src/main/java/github/sukieva/hhu/ui/activity/home/HomeActivity.kt
new file mode 100644
index 0000000..1517ead
--- /dev/null
+++ b/app/src/main/java/github/sukieva/hhu/ui/activity/home/HomeActivity.kt
@@ -0,0 +1,20 @@
+package github.sukieva.hhu.ui.activity.home
+
+import android.os.Bundle
+import androidx.activity.compose.setContent
+import github.sukieva.hhu.ui.activity.base.BaseActivity
+import github.sukieva.hhu.utils.errorToast
+
+class HomeActivity : BaseActivity() {
+
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContent {
+ HomeView()
+ }
+ }
+
+
+}
+
diff --git a/app/src/main/java/github/sukieva/hhu/ui/activity/home/HomeView.kt b/app/src/main/java/github/sukieva/hhu/ui/activity/home/HomeView.kt
new file mode 100644
index 0000000..58754b5
--- /dev/null
+++ b/app/src/main/java/github/sukieva/hhu/ui/activity/home/HomeView.kt
@@ -0,0 +1,155 @@
+package github.sukieva.hhu.ui.activity.home
+
+import android.content.Intent
+import androidx.compose.foundation.Image
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.padding
+import androidx.compose.material.MaterialTheme
+import androidx.compose.material.Text
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.outlined.Bookmarks
+import androidx.compose.material.icons.outlined.Extension
+import androidx.compose.material.icons.rounded.ManageSearch
+import androidx.compose.material.icons.rounded.PendingActions
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.collectAsState
+import androidx.compose.runtime.getValue
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.text.style.TextOverflow
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.dp
+import github.sukieva.hhu.MyApp
+import github.sukieva.hhu.R
+import github.sukieva.hhu.data.repository.RemoteRepository
+import github.sukieva.hhu.ui.activity.base.InitView
+import github.sukieva.hhu.ui.activity.config.ConfigActivity
+import github.sukieva.hhu.ui.activity.favourite.FavouriteActivity
+import github.sukieva.hhu.ui.activity.results.ResultsActivity
+import github.sukieva.hhu.ui.components.*
+import github.sukieva.hhu.ui.theme.Teal200
+import github.sukieva.hhu.utils.*
+
+
+@Composable
+fun HomeView() {
+ InitView {
+ MyScaffold(
+ topBar = { HomeAppBar() },
+ content = {
+ CardCheckIn()
+ CardGradeQuery()
+ CardSchedule()
+ ListCardFavourite()
+ ListCardConfig()
+ }
+ )
+ }
+}
+
+
+@Composable
+fun CardCheckIn() {
+ CardItem(
+ isLarge = true,
+ isActive = true,
+ onClick = { "点击了".infoToast() },
+ title = stringResource(id = R.string.home_card_checkin),
+ body = "已经打卡"
+ )
+}
+
+@Composable
+fun CardGradeQuery() {
+ CardItem(
+ title = stringResource(id = R.string.home_card_results),
+ body = "加油",
+ icon = Icons.Rounded.ManageSearch,
+ onClick = {
+ start()
+ }
+ )
+}
+
+@Composable
+fun CardSchedule() {
+ CardItem(
+ title = stringResource(id = R.string.home_card_schedule),
+ body = getDate(),
+ icon = Icons.Rounded.PendingActions,
+ onClick = {
+ try {
+ val intent = Intent(Intent.ACTION_VIEW)
+ intent.setClassName("com.suda.yzune.wakeupschedule", "com.suda.yzune.wakeupschedule.SplashActivity")
+ intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
+ MyApp.context.startActivity(intent)
+ } catch (e: Exception) {
+ "Wakeup Not Installed!".errorToast()
+ LogUtil.d("CardSchedule", "Schedule Error: not installed")
+ e.printStackTrace()
+ }
+ }
+ )
+}
+
+
+@Composable
+fun ListCardFavourite() {
+ ListCardItem(
+ title = stringResource(id = R.string.home_list_favourite),
+ icon = Icons.Outlined.Bookmarks,
+ onClick = {
+ start()
+ }
+ )
+}
+
+@Composable
+fun ListCardConfig() {
+ ListCardItem(
+ title = stringResource(id = R.string.home_list_config),
+ icon = Icons.Outlined.Extension,
+ onClick = {
+ start()
+ }
+ )
+}
+
+@Composable
+fun HomeAppBar() {
+ val hitoko by RemoteRepository.getHitokoto().collectAsState(initial = stringResource(id = R.string.home_subtitle))
+ MaterialAppBar(
+ modifier = Modifier.padding(top = 20.dp, bottom = 20.dp),
+ title = {
+ Column {
+ Text(text = stringResource(id = R.string.app_name), style = MaterialTheme.typography.h6)
+ Spacer(modifier = Modifier.height(10.dp))
+ Text(
+ text = hitoko,
+ color = Teal200,
+ style = MaterialTheme.typography.subtitle2,
+ maxLines = 1,
+ overflow = TextOverflow.Ellipsis
+ )
+ }
+ },
+ navigationIcon = {
+ Image(
+ painter = painterResource(R.drawable.home_logo),
+ contentDescription = "Home logo"
+ )
+ },
+ actions = {
+ HomeMenu()
+ }
+ )
+}
+
+@Preview
+@Composable
+fun HomeViewPreview() {
+ HomeView()
+}
\ No newline at end of file
diff --git a/app/src/main/java/github/sukieva/hhu/ui/activity/results/ResultsActivity.kt b/app/src/main/java/github/sukieva/hhu/ui/activity/results/ResultsActivity.kt
new file mode 100644
index 0000000..55d2922
--- /dev/null
+++ b/app/src/main/java/github/sukieva/hhu/ui/activity/results/ResultsActivity.kt
@@ -0,0 +1,23 @@
+package github.sukieva.hhu.ui.activity.results
+
+import android.os.Bundle
+import androidx.activity.compose.setContent
+import github.sukieva.hhu.ui.activity.base.BaseActivity
+
+class ResultsActivity : BaseActivity() {
+
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ val isLogin = intent.getBooleanExtra("isLogin", false)
+
+ setContent {
+ ResultsView()
+ }
+
+
+ }
+
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/github/sukieva/hhu/ui/activity/results/ResultsView.kt b/app/src/main/java/github/sukieva/hhu/ui/activity/results/ResultsView.kt
new file mode 100644
index 0000000..0522370
--- /dev/null
+++ b/app/src/main/java/github/sukieva/hhu/ui/activity/results/ResultsView.kt
@@ -0,0 +1,38 @@
+package github.sukieva.hhu.ui.activity.results
+
+import androidx.compose.foundation.Image
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.remember
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.lifecycle.viewmodel.compose.viewModel
+import github.sukieva.hhu.ui.activity.base.InitView
+import github.sukieva.hhu.ui.components.MaterialTopAppBar
+import github.sukieva.hhu.ui.components.MyScaffold
+
+
+@Composable
+fun ResultsView() {
+ InitView {
+ MyScaffold(topBar = { MaterialTopAppBar() }) {
+ //CaptchaPic()
+ }
+ }
+}
+
+@Composable
+fun CaptchaPic() {
+ val model: ResultsViewModel = viewModel()
+ if (!model.bitmapFlag)
+ model.getCaptchaPic()
+ val pic = remember { model.bitmap }
+ Image(
+ bitmap = pic.value,
+ contentDescription = "CaptchaPic"
+ )
+}
+
+@Composable
+@Preview
+fun ResultsViewPreview() {
+ ResultsView()
+}
\ No newline at end of file
diff --git a/app/src/main/java/github/sukieva/hhu/ui/activity/results/ResultsViewModel.kt b/app/src/main/java/github/sukieva/hhu/ui/activity/results/ResultsViewModel.kt
new file mode 100644
index 0000000..56671ac
--- /dev/null
+++ b/app/src/main/java/github/sukieva/hhu/ui/activity/results/ResultsViewModel.kt
@@ -0,0 +1,27 @@
+package github.sukieva.hhu.ui.activity.results
+
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.ui.graphics.ImageBitmap
+import androidx.compose.ui.graphics.asImageBitmap
+import androidx.lifecycle.ViewModel
+import github.sukieva.hhu.data.repository.RemoteRepository
+import kotlin.concurrent.thread
+
+class ResultsViewModel : ViewModel() {
+
+ var bitmapFlag: Boolean = false
+ var bitmap = mutableStateOf(ImageBitmap(20, 20))
+
+ fun getCaptchaPic() {
+ thread {
+ RemoteRepository.getCaptchaPic()?.let {
+ bitmap.value = it.asImageBitmap()
+ }
+ }
+ bitmapFlag = true
+ }
+
+
+}
+
+
diff --git a/app/src/main/java/github/sukieva/hhu/ui/components/ToolBar.kt b/app/src/main/java/github/sukieva/hhu/ui/components/AppBar.kt
similarity index 65%
rename from app/src/main/java/github/sukieva/hhu/ui/components/ToolBar.kt
rename to app/src/main/java/github/sukieva/hhu/ui/components/AppBar.kt
index 5bee6c4..1f1377f 100644
--- a/app/src/main/java/github/sukieva/hhu/ui/components/ToolBar.kt
+++ b/app/src/main/java/github/sukieva/hhu/ui/components/AppBar.kt
@@ -1,7 +1,7 @@
package github.sukieva.hhu.ui.components
-import androidx.compose.foundation.Image
-import androidx.compose.foundation.layout.*
+import androidx.compose.foundation.layout.RowScope
+import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.material.Icon
import androidx.compose.material.IconButton
import androidx.compose.material.MaterialTheme
@@ -11,18 +11,14 @@ import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.res.painterResource
-import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.google.accompanist.insets.LocalWindowInsets
import com.google.accompanist.insets.rememberInsetsPaddingValues
import com.google.accompanist.insets.ui.TopAppBar
-import github.sukieva.hhu.R
-import github.sukieva.hhu.ui.activity.base.InitView
-import github.sukieva.hhu.ui.theme.Teal200
import github.sukieva.hhu.utils.ActivityCollector
+
@Composable
fun MaterialTopAppBar(
title: String = "Title",
@@ -42,28 +38,6 @@ fun MaterialTopAppBar(
)
}
-@Composable
-fun HomeAppBar() {
- MaterialAppBar(
- modifier = Modifier.padding(top = 20.dp, bottom = 20.dp),
- title = {
- Column {
- Text(text = stringResource(id = R.string.app_name), style = MaterialTheme.typography.h6)
- Spacer(modifier = Modifier.height(10.dp))
- Text(text = stringResource(id = R.string.home_subtitle), color = Teal200, style = MaterialTheme.typography.subtitle2)
- }
- },
- navigationIcon = {
- Image(
- painter = painterResource(R.drawable.home_logo),
- contentDescription = "Home logo"
- )
- },
- actions = {
- HomeMenu()
- }
- )
-}
@Composable
fun MaterialAppBar(
@@ -93,8 +67,12 @@ fun MaterialAppBar(
@Preview
@Composable
-fun AppBarPreview() {
- InitView {
- HomeAppBar()
- }
+fun MaterialTopAppBarPreview() {
+ MaterialTopAppBar()
}
+
+@Preview
+@Composable
+fun MaterialAppBarPreview() {
+ MaterialAppBar()
+}
\ No newline at end of file
diff --git a/app/src/main/java/github/sukieva/hhu/ui/components/Card.kt b/app/src/main/java/github/sukieva/hhu/ui/components/Card.kt
index 62b1d07..ef889df 100644
--- a/app/src/main/java/github/sukieva/hhu/ui/components/Card.kt
+++ b/app/src/main/java/github/sukieva/hhu/ui/components/Card.kt
@@ -8,49 +8,14 @@ import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.CheckCircleOutline
-import androidx.compose.material.icons.rounded.ManageSearch
-import androidx.compose.material.icons.rounded.PendingActions
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.graphics.vector.ImageVector
-import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
-import github.sukieva.hhu.ui.activity.base.InitView
import github.sukieva.hhu.ui.theme.*
-import github.sukieva.hhu.utils.infoToast
-import github.sukieva.hhu.R
-
-@Composable
-fun CardCheckIn() {
- CardItem(
- isLarge = true,
- isActive = true,
- onClick = { "点击了".infoToast() },
- title = stringResource(id = R.string.home_card_checkin),
- body = "已经打卡"
- )
-}
-
-@Composable
-fun CardGradeQuery() {
- CardItem(
- title = stringResource(id = R.string.home_card_results),
- body = "加油",
- icon = Icons.Rounded.ManageSearch
- )
-}
-
-@Composable
-fun CardSchedule() {
- CardItem(
- title = stringResource(id = R.string.home_card_schedule),
- body = "今天无课",
- icon = Icons.Rounded.PendingActions
- )
-}
@Composable
@@ -119,8 +84,6 @@ fun CardItem(
@Preview
@Composable
-fun CardPreview() {
- InitView {
- CardItem()
- }
+fun CardItemPreview() {
+ CardItem()
}
\ No newline at end of file
diff --git a/app/src/main/java/github/sukieva/hhu/ui/components/ExpandableCard.kt b/app/src/main/java/github/sukieva/hhu/ui/components/ExpandableCard.kt
new file mode 100644
index 0000000..b3d1a6c
--- /dev/null
+++ b/app/src/main/java/github/sukieva/hhu/ui/components/ExpandableCard.kt
@@ -0,0 +1,79 @@
+package github.sukieva.hhu.ui.components
+
+import androidx.compose.animation.animateContentSize
+import androidx.compose.animation.core.LinearOutSlowInEasing
+import androidx.compose.animation.core.tween
+import androidx.compose.foundation.layout.*
+import androidx.compose.material.Card
+import androidx.compose.material.ExperimentalMaterialApi
+import androidx.compose.material.MaterialTheme
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.outlined.TravelExplore
+import androidx.compose.runtime.*
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Shape
+import androidx.compose.ui.graphics.vector.ImageVector
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.Dp
+import androidx.compose.ui.unit.dp
+
+
+@ExperimentalMaterialApi
+@Composable
+fun ExpandableCard(
+ title: String = "Title",
+ icon: ImageVector = Icons.Outlined.TravelExplore,
+ shape: Shape = MaterialTheme.shapes.medium,
+ content: @Composable () -> Unit = {},
+ padding: Dp = 12.dp
+) {
+ var expandedState by remember { mutableStateOf(false) }
+
+ Card(
+ modifier = Modifier
+ .fillMaxWidth()
+ .animateContentSize(
+ animationSpec = tween(
+ durationMillis = 300,
+ easing = LinearOutSlowInEasing
+ )
+ ),
+ shape = shape,
+ onClick = {
+ expandedState = !expandedState
+ },
+ backgroundColor = MaterialTheme.colors.background
+ ) {
+ Column(
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(padding)
+ ) {
+ Row(
+ verticalAlignment = Alignment.CenterVertically
+ ) {
+ ListCard(
+ modifier = Modifier
+ .padding(start = 10.dp, top = 12.dp)
+ .height(50.dp),
+ title = title,
+ icon = icon
+ )
+ }
+ if (expandedState) {
+ content()
+ }
+ }
+ }
+}
+
+
+@ExperimentalMaterialApi
+@Composable
+@Preview
+fun ExpandableCardPreview() {
+ ExpandableCard(
+ title = "My Title"
+ )
+}
\ No newline at end of file
diff --git a/app/src/main/java/github/sukieva/hhu/ui/components/List.kt b/app/src/main/java/github/sukieva/hhu/ui/components/List.kt
index 54f32f3..e403de4 100644
--- a/app/src/main/java/github/sukieva/hhu/ui/components/List.kt
+++ b/app/src/main/java/github/sukieva/hhu/ui/components/List.kt
@@ -7,61 +7,44 @@ import androidx.compose.material.Card
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.material.icons.Icons
-import androidx.compose.material.icons.outlined.Bookmarks
-import androidx.compose.material.icons.outlined.CheckCircleOutline
-import androidx.compose.material.icons.outlined.Extension
+import androidx.compose.material.icons.outlined.TravelExplore
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.graphics.vector.ImageVector
-import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
-import github.sukieva.hhu.R
-import github.sukieva.hhu.ui.activity.ConfigActivity
-import github.sukieva.hhu.ui.activity.FavouriteActivity
-import github.sukieva.hhu.ui.activity.base.InitView
import github.sukieva.hhu.ui.theme.fontBody
import github.sukieva.hhu.ui.theme.fontHead
-import github.sukieva.hhu.utils.start
-
-
-@Composable
-fun ListCardFavourite() {
- ListCardItem(
- title = stringResource(id = R.string.home_list_favourite),
- icon = Icons.Outlined.Bookmarks,
- onClick = {
- start()
- }
- )
-}
-
-@Composable
-fun ListCardConfig() {
- ListCardItem(
- title = stringResource(id = R.string.home_list_config),
- icon = Icons.Outlined.Extension,
- onClick = {
- start()
- }
- )
-}
@Composable
fun ListCardItem(
modifier: Modifier = Modifier,
title: String = "Title",
- icon: ImageVector = Icons.Outlined.CheckCircleOutline,
+ icon: ImageVector = Icons.Outlined.TravelExplore,
onClick: () -> Unit = {},
) {
- Card(
+ ListCard(
modifier = modifier
.padding(start = 25.dp, end = 25.dp, top = 20.dp)
.fillMaxWidth()
.height(50.dp)
.clickable { onClick() },
+ title = title,
+ icon = icon
+ )
+}
+
+
+@Composable
+fun ListCard(
+ modifier: Modifier = Modifier,
+ title: String = "Title",
+ icon: ImageVector = Icons.Outlined.TravelExplore
+) {
+ Card(
+ modifier = modifier,
shape = MaterialTheme.shapes.small,
backgroundColor = MaterialTheme.colors.background,
elevation = 0.dp
@@ -94,14 +77,10 @@ fun ListCardItem(
}
}
}
-
-
}
@Preview
@Composable
-fun ListPreview() {
- InitView {
- ListCardItem()
- }
+fun ListCardItemPreview() {
+ ListCardItem()
}
\ No newline at end of file
diff --git a/app/src/main/java/github/sukieva/hhu/ui/components/Menu.kt b/app/src/main/java/github/sukieva/hhu/ui/components/Menu.kt
index d3e317b..bf9749c 100644
--- a/app/src/main/java/github/sukieva/hhu/ui/components/Menu.kt
+++ b/app/src/main/java/github/sukieva/hhu/ui/components/Menu.kt
@@ -11,7 +11,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import github.sukieva.hhu.R
-import github.sukieva.hhu.ui.activity.AboutActivity
+import github.sukieva.hhu.ui.activity.about.AboutActivity
import github.sukieva.hhu.ui.theme.fontBody
import github.sukieva.hhu.utils.ActivityCollector
import github.sukieva.hhu.utils.browse
@@ -29,14 +29,23 @@ fun HomeMenu() {
expanded = expanded,
onDismissRequest = { expanded = false }
) {
- DropdownMenuItem(onClick = { ActivityCollector.finishAllActivity() }) {
+ DropdownMenuItem(onClick = {
+ ActivityCollector.finishAllActivity()
+ expanded = false
+ }) {
MaterialFont(stringResource(id = R.string.home_menu_exit))
}
Divider()
- DropdownMenuItem(onClick = { browse("https://github.com/SukiEva/Myhhu/issues") }) {
+ DropdownMenuItem(onClick = {
+ browse("https://github.com/SukiEva/Myhhu/issues")
+ expanded = false
+ }) {
MaterialFont(stringResource(id = R.string.home_menu_issue))
}
- DropdownMenuItem(onClick = { start() }) {
+ DropdownMenuItem(onClick = {
+ start()
+ expanded = false
+ }) {
MaterialFont(stringResource(id = R.string.home_menu_about))
}
}
diff --git a/app/src/main/java/github/sukieva/hhu/ui/components/Scaffold.kt b/app/src/main/java/github/sukieva/hhu/ui/components/Scaffold.kt
new file mode 100644
index 0000000..976b7ea
--- /dev/null
+++ b/app/src/main/java/github/sukieva/hhu/ui/components/Scaffold.kt
@@ -0,0 +1,21 @@
+package github.sukieva.hhu.ui.components
+
+import androidx.compose.foundation.layout.Column
+import androidx.compose.material.Scaffold
+import androidx.compose.runtime.Composable
+
+
+@Composable
+fun MyScaffold(
+ topBar: @Composable () -> Unit,
+ content: @Composable () -> Unit
+) {
+ Scaffold(
+ topBar = topBar,
+ content = {
+ Column {
+ content()
+ }
+ }
+ )
+}
\ No newline at end of file
diff --git a/app/src/main/java/github/sukieva/hhu/ui/components/WebView.kt b/app/src/main/java/github/sukieva/hhu/ui/components/WebView.kt
index 2607a97..88c444d 100644
--- a/app/src/main/java/github/sukieva/hhu/ui/components/WebView.kt
+++ b/app/src/main/java/github/sukieva/hhu/ui/components/WebView.kt
@@ -24,7 +24,7 @@ import github.sukieva.hhu.utils.LogUtil
import github.sukieva.hhu.utils.errorToast
import kotlinx.coroutines.launch
-@SuppressLint("SetJavaScriptEnabled")
+@SuppressLint("JavascriptInterface", "SetJavaScriptEnabled")
@Composable
fun MyWebView(
url: String = "https://github.com/SukiEva"
@@ -48,7 +48,7 @@ fun MyWebView(
//缩放操作
setSupportZoom(true)
builtInZoomControls = true
- displayZoomControls = true
+ displayZoomControls = false
//是否支持通过JS打开新窗口
javaScriptCanOpenWindowsAutomatically = true
//不加载缓存内容
@@ -105,6 +105,11 @@ fun CustomWebView(
override fun onPageFinished(view: WebView?, url: String?) {
super.onPageFinished(view, url)
onProgressChange(100)
+ view!!.loadUrl(
+ "javascript:window.java_obj.getSource("
+ + "document.getElementsByTagName('html')[0].innerHTML);"
+ )
+ //println(InJavaScriptLocalObj.webHtml)
}
override fun shouldOverrideUrlLoading(
@@ -150,6 +155,7 @@ fun CustomWebView(
this.webChromeClient = webViewChromeClient
//回调webSettings供调用方设置webSettings的相关配置
initSettings(this.settings)
+ addJavascriptInterface(InJavaScriptLocalObj, "java_obj")
webView = this
loadUrl(url)
}
@@ -162,3 +168,13 @@ fun CustomWebView(
}
}
}
+
+object InJavaScriptLocalObj {
+ var webHtml: String? = null
+
+ @JavascriptInterface
+ fun getSource(html: String?) {
+ webHtml = html
+ }
+}
+
diff --git a/app/src/main/java/github/sukieva/hhu/ui/theme/Color.kt b/app/src/main/java/github/sukieva/hhu/ui/theme/Color.kt
index 9425c08..b655b11 100644
--- a/app/src/main/java/github/sukieva/hhu/ui/theme/Color.kt
+++ b/app/src/main/java/github/sukieva/hhu/ui/theme/Color.kt
@@ -4,9 +4,7 @@ import androidx.compose.material.Colors
import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.Color
-val Purple200 = Color(0xFFBB86FC)
-val Purple500 = Color(0xFF6200EE)
-val Purple700 = Color(0xFF3700B3)
+val Purple700 = Color(0xC83700B3)
val Teal200 = Color(0xFF03DAC5)
val White = Color(0xffffffff)
diff --git a/app/src/main/java/github/sukieva/hhu/ui/theme/Theme.kt b/app/src/main/java/github/sukieva/hhu/ui/theme/Theme.kt
index 66ad36d..d08b047 100644
--- a/app/src/main/java/github/sukieva/hhu/ui/theme/Theme.kt
+++ b/app/src/main/java/github/sukieva/hhu/ui/theme/Theme.kt
@@ -10,17 +10,21 @@ import androidx.compose.ui.graphics.Color
import com.google.accompanist.systemuicontroller.rememberSystemUiController
private val DarkColorPalette = darkColors(
- primary = Black,
+ primary = Teal200,
primaryVariant = Purple700,
secondary = Teal200,
- background = ui_background_night
+ background = ui_background_night,
+ onBackground = White,
+ onSurface = White
)
private val LightColorPalette = lightColors(
- primary = White,
+ primary = Purple700,
primaryVariant = Purple700,
secondary = Teal200,
- background = ui_background
+ background = ui_background,
+ onBackground = Black,
+ onSurface = Black
/* Other default colors to override
background = Color.White,
diff --git a/app/src/main/java/github/sukieva/hhu/utils/ActivityCollector.kt b/app/src/main/java/github/sukieva/hhu/utils/ActivityCollector.kt
index c91414e..e6477fc 100644
--- a/app/src/main/java/github/sukieva/hhu/utils/ActivityCollector.kt
+++ b/app/src/main/java/github/sukieva/hhu/utils/ActivityCollector.kt
@@ -6,13 +6,15 @@ object ActivityCollector {
private val activities = ArrayList()
+
fun addActivity(activity: Activity) = activities.add(activity)
fun removeActivity(activity: Activity) = activities.remove(activity)
+ fun topActivity(): Activity = activities[activities.lastIndex]
fun finishTopActivity() {
- val topActivity = activities[activities.lastIndex]
+ val topActivity = topActivity()
if (!topActivity.isFinishing) topActivity.finish()
removeActivity(topActivity)
}
diff --git a/app/src/main/java/github/sukieva/hhu/utils/AppHelper.kt b/app/src/main/java/github/sukieva/hhu/utils/AppHelper.kt
new file mode 100644
index 0000000..072ffc3
--- /dev/null
+++ b/app/src/main/java/github/sukieva/hhu/utils/AppHelper.kt
@@ -0,0 +1,89 @@
+package github.sukieva.hhu.utils
+
+
+import android.content.Context
+import android.content.DialogInterface
+import android.content.Intent
+import android.net.Uri
+import android.widget.Button
+import android.widget.Toast
+import androidx.appcompat.app.AlertDialog
+import es.dmoral.toasty.Toasty
+import github.sukieva.hhu.MyApp
+import github.sukieva.hhu.R
+import java.time.LocalDateTime
+import java.time.format.DateTimeFormatter
+
+
+fun browse(url: String) {
+ val intent = Intent(Intent.ACTION_VIEW)
+ intent.data = Uri.parse(url)
+ intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
+ MyApp.context.startActivity(intent)
+}
+
+fun alert(
+ context: Context = ActivityCollector.topActivity(),
+ title: String = "(/ ̄ー ̄)/~~☆’.・.・:★’.・.・:☆",
+ message: String = "消息",
+ positive: String = "确认",
+ onPositiveClick: () -> Unit = {},
+ showNegative: Boolean = false,
+ negative: String = "取消",
+ onNegativeClick: () -> Unit = {}
+) {
+ AlertDialog.Builder(context, R.style.AlertDialogStyle).apply {
+ setTitle(title)
+ setMessage(message)
+ setCancelable(false)
+ setPositiveButton(positive) { _, _ ->
+ onPositiveClick()
+ }
+ if (showNegative) {
+ setNegativeButton(negative) { _, _ ->
+ onNegativeClick()
+ }
+ }
+ setCancelable(true)
+ show()
+ }
+}
+
+/* 范型实化
+ start(){
+ putExtra()
+ putExtra()
+ }
+ */
+inline fun start(block: Intent.() -> Unit = {}) {
+ val context = MyApp.context
+ val intent = Intent(context, T::class.java)
+ intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
+ intent.block()
+ context.startActivity(intent)
+}
+
+fun String.showToast(duration: Int = Toast.LENGTH_SHORT) =
+ Toasty.normal(MyApp.context, this, duration).show()
+
+
+fun String.infoToast(duration: Int = Toast.LENGTH_SHORT) =
+ Toasty.info(MyApp.context, this, duration, true).show()
+
+
+fun String.successToast(duration: Int = Toast.LENGTH_SHORT) =
+ Toasty.success(MyApp.context, this, duration, true).show()
+
+
+fun String.warningToast(duration: Int = Toast.LENGTH_SHORT) =
+ Toasty.warning(MyApp.context, this, duration, true).show()
+
+
+fun String.errorToast(duration: Int = Toast.LENGTH_SHORT) =
+ Toasty.error(MyApp.context, this, duration, true).show()
+
+
+fun getDate(): String {
+ val formatter = DateTimeFormatter.ofPattern("yyyy/MM/dd")
+ return LocalDateTime.now().format(formatter)
+}
\ No newline at end of file
diff --git a/app/src/main/java/github/sukieva/hhu/utils/DataManager.kt b/app/src/main/java/github/sukieva/hhu/utils/DataManager.kt
new file mode 100644
index 0000000..c53185c
--- /dev/null
+++ b/app/src/main/java/github/sukieva/hhu/utils/DataManager.kt
@@ -0,0 +1,50 @@
+package github.sukieva.hhu.utils
+
+import android.content.Context
+import androidx.datastore.core.DataStore
+import androidx.datastore.preferences.core.*
+import androidx.datastore.preferences.preferencesDataStore
+import github.sukieva.hhu.MyApp
+import kotlinx.coroutines.flow.first
+import kotlinx.coroutines.flow.map
+
+val Context.dataStore: DataStore by preferencesDataStore(name = "DataStore")
+
+object DataManager {
+
+ private var dataStore: DataStore = MyApp.context.dataStore
+
+
+ // 异步写入数据
+ suspend fun saveData(key: String, value: T) {
+ when (value) {
+ is Int -> dataStore.edit { it[intPreferencesKey(key)] = value }
+ is Long -> dataStore.edit { it[longPreferencesKey(key)] = value }
+ is String -> dataStore.edit { it[stringPreferencesKey(key)] = value }
+ is Boolean -> dataStore.edit { it[booleanPreferencesKey(key)] = value }
+ is Float -> dataStore.edit { it[floatPreferencesKey(key)] = value }
+ else -> throw IllegalArgumentException("This type can't be saved into DataStore")
+ }
+ }
+
+ // 异步获得数据
+ @Suppress("UNCHECKED_CAST")
+ suspend fun readData(key: String, default: T): T {
+ val data = when (default) {
+ is Int -> dataStore.data.map { it[intPreferencesKey(key)] ?: 0 }
+ is Long -> dataStore.data.map { it[longPreferencesKey(key)] ?: 0L }
+ is String -> dataStore.data.map { it[stringPreferencesKey(key)] ?: "" }
+ is Boolean -> dataStore.data.map { it[booleanPreferencesKey(key)] ?: Boolean }
+ is Float -> dataStore.data.map { it[floatPreferencesKey(key)] ?: 0f }
+ else -> throw IllegalArgumentException("This type can't be read")
+ }
+ //scope.launch { data.first() }
+ return data.first() as T
+ }
+
+ suspend fun clearData() {
+ dataStore.edit {
+ it.clear()
+ }
+ }
+}
diff --git a/app/src/main/java/github/sukieva/hhu/utils/LogUtil.kt b/app/src/main/java/github/sukieva/hhu/utils/LogUtil.kt
index 93506ff..900916a 100644
--- a/app/src/main/java/github/sukieva/hhu/utils/LogUtil.kt
+++ b/app/src/main/java/github/sukieva/hhu/utils/LogUtil.kt
@@ -13,7 +13,7 @@ object LogUtil {
private const val ERROR = 5
- private const val level = ERROR
+ private const val level = VERBOSE
fun v(tag: String, msg: String) {
if (level <= VERBOSE) Log.v(tag, msg)
diff --git a/app/src/main/java/github/sukieva/hhu/utils/Reified.kt b/app/src/main/java/github/sukieva/hhu/utils/Reified.kt
deleted file mode 100644
index a91596f..0000000
--- a/app/src/main/java/github/sukieva/hhu/utils/Reified.kt
+++ /dev/null
@@ -1,29 +0,0 @@
-package github.sukieva.hhu.utils
-
-
-import android.content.Intent
-import android.net.Uri
-import github.sukieva.hhu.MyApp
-
-
-fun browse(url: String) {
- val intent = Intent(Intent.ACTION_VIEW)
- intent.data = Uri.parse(url)
- intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
- MyApp.context.startActivity(intent)
-}
-
-
-/* 范型实化
- start(){
- putExtra()
- putExtra()
- }
- */
-inline fun start(block: Intent.() -> Unit = {}) {
- val context = MyApp.context
- val intent = Intent(context, T::class.java)
- intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
- intent.block()
- context.startActivity(intent)
-}
\ No newline at end of file
diff --git a/app/src/main/java/github/sukieva/hhu/utils/Toasty.kt b/app/src/main/java/github/sukieva/hhu/utils/Toasty.kt
deleted file mode 100644
index 238c01b..0000000
--- a/app/src/main/java/github/sukieva/hhu/utils/Toasty.kt
+++ /dev/null
@@ -1,38 +0,0 @@
-package github.sukieva.hhu.utils
-
-import android.widget.Toast
-import es.dmoral.toasty.Toasty
-import github.sukieva.hhu.MyApp
-
-
-fun String.showToast(duration: Int = Toast.LENGTH_SHORT) =
- Toasty.normal(MyApp.context, this, duration).show()
-
-
-fun String.infoToast(duration: Int = Toast.LENGTH_SHORT) =
- Toasty.info(MyApp.context, this, duration, true).show()
-
-
-fun String.successToast(duration: Int = Toast.LENGTH_SHORT) =
- Toasty.success(MyApp.context, this, duration, true).show()
-
-
-fun String.warningToast(duration: Int = Toast.LENGTH_SHORT) =
- Toasty.warning(MyApp.context, this, duration, true).show()
-
-
-fun String.errorToast(duration: Int = Toast.LENGTH_SHORT) =
- Toasty.error(MyApp.context, this, duration, true).show()
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/app/src/main/res/values-night/themes.xml b/app/src/main/res/values-night/themes.xml
index c19eb2b..f484723 100644
--- a/app/src/main/res/values-night/themes.xml
+++ b/app/src/main/res/values-night/themes.xml
@@ -24,4 +24,10 @@
- @color/about_bg_dark
- @color/white
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values-zh/strings.xml b/app/src/main/res/values-zh/strings.xml
index e5fd65e..dd5fb63 100644
--- a/app/src/main/res/values-zh/strings.xml
+++ b/app/src/main/res/values-zh/strings.xml
@@ -13,6 +13,17 @@
收藏
配置
+
+ 重置为默认值
+ 添加网址
+ 名称
+ 网址
+ 不能为空
+ 网址无效
+ \n确定移除网址?
+ 确定
+ 取消
+
关于
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index d8ceac4..870986a 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -13,6 +13,17 @@
Favorites
Config
+
+ Reset to default
+ Add a new website
+ Name
+ Url
+ Can\'t be empty
+ Url is invalid
+ \nSure to remove the URL?
+ Confirm
+ Cancel
+
About
A third-party app for hhuers
@@ -20,4 +31,5 @@
Can\'t find related apps
Something went wrong
+
\ No newline at end of file
diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml
index 56ea02f..636f75e 100644
--- a/app/src/main/res/values/themes.xml
+++ b/app/src/main/res/values/themes.xml
@@ -33,4 +33,19 @@
- @color/about_bg_light
- @color/white
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/build.gradle.kts b/build.gradle.kts
index ff05eb8..5c164fe 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -1,25 +1,33 @@
-// Top-level build file where you can add configuration options common to all sub-projects/modules.
+import org.eclipse.jgit.api.Git
+import org.eclipse.jgit.internal.storage.file.FileRepository
+
buildscript {
repositories {
google()
mavenCentral()
+ maven("https://jitpack.io")
}
dependencies {
classpath("com.android.tools.build:gradle:7.0.2")
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.5.21")
+ classpath("org.eclipse.jgit:org.eclipse.jgit:5.12.0.202106070339-r")
}
}
-val defaultManagerPackageName by extra("com.github.sukieva.hhuer")
-val verCode by extra(20210924)
-val verName by extra("1.0")
-val androidTargetSdkVersion by extra(30)
-val androidMinSdkVersion by extra(27)
-val androidBuildToolsVersion by extra("31.0.0")
-val androidCompileSdkVersion by extra(31)
-val androidCompileNdkVersion by extra("23.0.7599858")
+val repo = FileRepository(rootProject.file(".git"))
+val refId = repo.refDatabase.exactRef("refs/remotes/origin/dev-compose").objectId!!
+val commitCount = Git(repo).log().add(refId).call().count()
+val packageName by extra("com.github.sukieva.hhuer")
+val verCode by extra(commitCount + 1000)
+val verName by extra("1.0.0")
+val targetSdkVersion by extra(30)
+val minSdkVersion by extra(27)
+val androidBuildToolsVersion by extra("31.0.0")
+val compileSdkVersion by extra(31)
+val compileNdkVersion by extra("23.0.7599858")
+
tasks.register("Delete", Delete::class) {
delete(rootProject.buildDir)
diff --git a/settings.gradle.kts b/settings.gradle.kts
index d982e4d..771c4bc 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -20,14 +20,20 @@ dependencyResolutionManagement {
val accompanistVersion = "0.18.0"
val lifecycleVersion = "2.4.0-beta01"
val retrofitVersion = "2.9.0"
+ val roomVersion = "2.3.0"
+
// AndroidX
alias("androidx-core").to("androidx.core:core-ktx:1.6.0")
alias("androidx-activityCompose").to("androidx.activity:activity-compose:1.3.1")
+ alias("androidx-datastorePreferences").to("androidx.datastore:datastore-preferences:1.0.0")
+ alias("google-material").to("com.google.android.material:material:1.4.0")
bundle(
"androidx", listOf(
"androidx-core",
- "androidx-activityCompose"
+ "androidx-activityCompose",
+ "google-material",
+ "androidx-datastorePreferences" // DataStore Preferences
)
)
@@ -41,7 +47,7 @@ dependencyResolutionManagement {
// Compose
alias("compose-ui").to("androidx.compose.ui:ui:$composeVersion")
- alias("compose-toolingPreview").to("androidx.compose.ui:ui-tooling-preview:$composeVersion")
+ alias("compose-uiToolingPreview").to("androidx.compose.ui:ui-tooling-preview:$composeVersion")
alias("compose-foundation").to("androidx.compose.foundation:foundation:$composeVersion")
alias("compose-material").to("androidx.compose.material:material:$composeVersion")
alias("compose-materialIcons").to("androidx.compose.material:material-icons-core:$composeVersion")
@@ -50,12 +56,11 @@ dependencyResolutionManagement {
bundle(
"compose", listOf(
"compose-ui",
- "compose-toolingPreview", // Tooling support (Previews, etc.)
+ "compose-uiToolingPreview", // Tooling support (Previews, etc.)
"compose-foundation", // Foundation (Border, Background, Box, Image, Scroll, shapes, animations, etc.)
"compose-material", // Material Design
"compose-materialIcons", // Material design icons
- "compose-materialIconsExtended",
- "compose-uiTestJunit" // UI Tests
+ "compose-materialIconsExtended"
)
)
@@ -73,11 +78,13 @@ dependencyResolutionManagement {
// Lifecycle
alias("lifecycle-viewmodelCompose").to("androidx.lifecycle:lifecycle-viewmodel-compose:$lifecycleVersion")
- alias("lifecycle-runtimeKtx").to("androidx.lifecycle:lifecycle-runtime-ktx:2.3.1")
+ alias("lifecycle-runtimeKtx").to("androidx.lifecycle:lifecycle-runtime-ktx:$lifecycleVersion")
+ alias("lifecycle-livedataKtx").to("androidx.lifecycle:lifecycle-livedata-ktx:$lifecycleVersion")
bundle(
"lifecycle", listOf(
- "lifecycle-viewmodelCompose",
- "lifecycle-runtimeKtx"
+ "lifecycle-viewmodelCompose", // viewModel
+ "lifecycle-runtimeKtx", // Lifecycles only (without ViewModel or LiveData)
+ "lifecycle-livedataKtx", // liveData
)
)
@@ -91,15 +98,27 @@ dependencyResolutionManagement {
)
)
+ // Room
+ alias("room-runtime").to("androidx.room:room-runtime:$roomVersion")
+ alias("room-ktx").to("androidx.room:room-ktx:$roomVersion")
+ bundle(
+ "room", listOf(
+ "room-runtime",
+ "room-ktx"
+ )
+ )
+
// Third Party
alias("drakeet-about").to("com.drakeet.about:about:2.4.1")
alias("drakeet-multitype").to("com.drakeet.multitype:multitype:4.3.0")
alias("github-toasty").to("com.github.GrenderG:Toasty:1.5.2")
+ alias("coil-compose").to("io.coil-kt:coil-compose:1.3.2")
bundle(
"thirdparty", listOf(
"drakeet-about",
"drakeet-multitype",
- "github-toasty"
+ "github-toasty",
+ "coil-compose" // 网络加载远程图片
)
)
}