diff --git a/README.md b/README.md index 2965c17..eefaf6a 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,11 @@ # HFUT-Schedule(聚在工大) +
-[](https://f-droid.org/packages/com.hfut.schedule) +[![GitHub](https://img.shields.io/github/v/release/Chiu-xaH/HFUT-Schedule?logo=github&label=GitHub&style=for-the-badge)](https://github.com/Chiu-xaH/HFUT-Schedule/releases/latest) +[![F-Droid](https://img.shields.io/f-droid/v/com.hfut.schedule?logo=fdroid&style=for-the-badge)](https://f-droid.org/packages/com.hfut.schedule) +[![F-Droid](https://img.shields.io/github/v/release/Chiu-xaH/HFUT-Schedule?logo=gitee&label=Gitee&style=for-the-badge)](https://gitee.com/chiu-xah/HFUT-Schedule/releases/tag/Android) + +
## 说明: 作为本校23届学生,初到学校时了解到大家常用的可以查看课表、成绩、考试等信息的是若干微信小程序和网页,平台较多较分散,且冷启动加载速度较慢,功能较少,多数接口失效,使用起来感觉不便,恰本人那时刚学安卓开发,为解决痛点,并作为实战项目,本应用就诞生了,面向宣区校内同学(理论上合肥校区也可用)使用,更快的启动速度、更全面的功能、无广告设计 @@ -16,27 +19,21 @@ height="80">](https://f-droid.org/packages/com.hfut.schedule) ![导图](/img/mindMaster.png) ## 权限: -1.日历(将事项作为日程写入日历) - -2.存储(导入导出课程表文件) - -3.相机(洗浴扫码) +网络、日历(将聚焦事项作为日程写入日历)、存储(导入导出课程表文件)、相机(洗浴扫码) ## 使用: ### 环境要求 ARM架构,支持64 Bit软件、搭载Android 7.0 (SDK 26)及以上版本的设备,初次使用要接入互联网 ### 初次使用 -下载好APK安装包后,进行安装,保证接入互联网的环境下,填入学号与信息门户密码,点击登录,等待加载完毕即可使用。(最好留在课表页面等待加载完毕,因为要后台登录3个平台,有两个Toast弹完后即完全登录,友友们能不能稍作等待,登陆这一次以后几十天就不用了...) +从开头三个徽章之一下载好APK后,进行安装,保证接入互联网的环境下,填入学号与信息门户密码,点击登录,等待加载完毕即可使用。(最好留在课表页面等待加载完毕,因为要后台登录3个平台,有两个Toast弹完后即完全登录...) ### 后续使用 -完全登陆后获取所需的数据,会自动进行本地缓存,以后可随便断网看课表,登陆一次教务系统有效期只有3小时,另外两个平台(一卡通和智慧社区)有效期有足足几十天,不需要同学们经常登录刷新哈,关于更多细分说明在APP中子功能界面右上角会有说明按钮,点击可查看,有不懂的或者有Bug提交issue或发邮件 +完全登陆后会获取所需的数据,自动缓存,以后可随便断网看课表,登陆一次教务系统有效期只有3小时,另外两个平台(一卡通和智慧社区)有效期有几十天,不需要同学们经常登录刷新,关于更多细分说明在APP中子功能界面右上角会有说明按钮,点击可查看 ### 软件升级 如有更新,会在首页底栏【选项】显示小红点,点击此Tab,在选项界面会有标红卡片,提示新版本,点击下方请求更新,等待进度条即可 -已上架到F-Droid - ## [接口文档](markdown/API.md) 供校内学生们方便参考或学习 @@ -56,20 +53,26 @@ UI设计 Material You (Material Design 3) [Retrofit](https://github.com/square/retrofit) 网络请求 -[Gson](https://github.com/google/gson) JSON处理 +[Gson](https://github.com/google/gson) JSON解析 -[Haze](https://github.com/chrisbanes/haze) 实时模糊 +[Jsoup](https://github.com/jhy/jsoup) XML/HTML解析 -[Accompanist](https://github.com/google/accompanist) 透明状态栏 +[Zxing](https://github.com/zxing/zxing) 二维码 -[Monet](https://github.com/Kyant0/Monet) 莫奈取色(供SDK不支持M3取色平替) +[Haze](https://github.com/chrisbanes/haze) 实时模糊(SDK>=33) -[Dagger](https://github.com/google/dagger) Hilt注入 +[Accompanist](https://github.com/google/accompanist) 用做实现透明状态栏 -[Glide](https://github.com/bumptech/glide) 图片 +[Monet](https://github.com/Kyant0/Monet) 莫奈取色(供SDK<32不支持MY取色平替) + +[Dagger](https://github.com/google/dagger) Hilt注入,辅助莫奈取色功能 + +[Glide](https://github.com/bumptech/glide) 网络图片 [EdDSA Java](https://github.com/str4d/ed25519-java) 加密(供和风天气API使用) +[Konfetti](https://github.com/DanielMartinus/Konfetti) 礼花🎉动画 + ## [更新日志](markdown/UPDATE.md) ## 统计 diff --git a/app/build.gradle b/app/build.gradle index 1ee11a1..6fee81c 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -23,8 +23,8 @@ android { applicationId "com.hfut.schedule" minSdk 26 targetSdk 33 - versionCode 156 - versionName "4.13.4.1" + versionCode 157 + versionName "4.13.4.2" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" vectorDrawables { useSupportLibrary true @@ -145,6 +145,8 @@ dependencies { //implementation "androidx.biometric:biometric:1.1.0" //用于和风天气密钥生成的JWT implementation 'net.i2p.crypto:eddsa:0.3.0' + //礼花 + implementation 'nl.dionsegijn:konfetti-compose:2.0.5' //Fragment // implementation "androidx.fragment:fragment-ktx:1.8.5" } diff --git a/app/release/output-metadata.json b/app/release/output-metadata.json index 2daaedd..2c98324 100644 --- a/app/release/output-metadata.json +++ b/app/release/output-metadata.json @@ -11,8 +11,8 @@ "type": "SINGLE", "filters": [], "attributes": [], - "versionCode": 156, - "versionName": "4.13.4.1", + "versionCode": 157, + "versionName": "4.13.4.2", "outputFile": "app-release.apk" } ], diff --git a/app/src/main/java/com/hfut/schedule/activity/main/LoginActivity.kt b/app/src/main/java/com/hfut/schedule/activity/main/LoginActivity.kt index 015dd02..b0e921a 100644 --- a/app/src/main/java/com/hfut/schedule/activity/main/LoginActivity.kt +++ b/app/src/main/java/com/hfut/schedule/activity/main/LoginActivity.kt @@ -7,16 +7,33 @@ import android.os.Bundle import android.os.Handler import android.os.Looper import android.widget.Toast +import androidx.compose.animation.core.tween +import androidx.compose.animation.expandVertically +import androidx.compose.animation.scaleIn +import androidx.compose.animation.scaleOut +import androidx.compose.animation.shrinkVertically +import androidx.compose.material3.Scaffold import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment import androidx.lifecycle.lifecycleScope +import androidx.navigation.compose.NavHost +import androidx.navigation.compose.composable +import androidx.navigation.compose.rememberNavController import com.hfut.schedule.logic.utils.PermissionManager.checkAndRequestStoragePermission import com.hfut.schedule.logic.utils.SharePrefs import com.hfut.schedule.logic.utils.SharePrefs.prefs +import com.hfut.schedule.logic.utils.getCelebration import com.hfut.schedule.ui.activity.home.main.saved.Add import com.hfut.schedule.ui.activity.home.main.saved.NoNetWork import com.hfut.schedule.ui.activity.home.main.saved.getNum +import com.hfut.schedule.ui.activity.login.First +//import com.hfut.schedule.ui.activity.login.FirstUI import com.hfut.schedule.ui.activity.login.LoginUI +import com.hfut.schedule.ui.activity.login.UseAgreementUI +import com.hfut.schedule.ui.utils.NavigateManager +import com.hfut.schedule.ui.utils.NavigateManager.ANIMATION_SPEED import com.hfut.schedule.ui.utils.components.MyToast +import com.hfut.schedule.ui.utils.components.PartyAnimation import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.async import kotlinx.coroutines.launch @@ -31,11 +48,37 @@ class LoginActivity : BaseActivity() { val switchUpload = prefs.getBoolean("SWITCHUPLOAD",true ) var value = 0 + @SuppressLint("UnusedMaterial3ScaffoldPaddingParameter") @Composable override fun UI() { - if(startAcitivity && intent.getBooleanExtra("nologin",true)) { - NoNetWork(super.networkVm,super.loginVm,super.uiVm) - } else LoginUI(super.loginVm) + val navController = rememberNavController() + val first = if(prefs.getBoolean("canUse",false)) First.HOME.name else First.USE_AGREEMENT.name + NavHost( + navController = navController, + startDestination = first, + enterTransition = { + NavigateManager.fadeAnimation.enter + }, + exitTransition = { + NavigateManager.fadeAnimation.exit + } + ) { + composable(First.HOME.name) { + // 如果庆祝为true则庆祝 + val time = if(getCelebration()) 1L else 0L + PartyAnimation(timeSecond = time) { + if(startAcitivity && intent.getBooleanExtra("nologin",true)) { + NoNetWork(super.networkVm,super.loginVm,super.uiVm) + } else LoginUI(super.loginVm) + } + } + composable(First.USE_AGREEMENT.name) { + PartyAnimation { + UseAgreementUI(navController) + } + } + } + } //打开方式txt diff --git a/app/src/main/java/com/hfut/schedule/logic/enums/BottomBarItems.kt b/app/src/main/java/com/hfut/schedule/logic/enums/BottomBarItems.kt index b760b14..95b1715 100644 --- a/app/src/main/java/com/hfut/schedule/logic/enums/BottomBarItems.kt +++ b/app/src/main/java/com/hfut/schedule/logic/enums/BottomBarItems.kt @@ -1,8 +1,8 @@ package com.hfut.schedule.logic.enums -enum class BottomBarItems { - COURSES, - FOCUS, - SEARCH, - SETTINGS +enum class BottomBarItems(val page : Int) { + COURSES(0), + FOCUS(1), + SEARCH(2), + SETTINGS(3) } \ No newline at end of file diff --git a/app/src/main/java/com/hfut/schedule/logic/enums/CardBarItems.kt b/app/src/main/java/com/hfut/schedule/logic/enums/CardBarItems.kt index 8765bbc..a4853df 100644 --- a/app/src/main/java/com/hfut/schedule/logic/enums/CardBarItems.kt +++ b/app/src/main/java/com/hfut/schedule/logic/enums/CardBarItems.kt @@ -1,7 +1,7 @@ package com.hfut.schedule.logic.enums -enum class CardBarItems { - BILLS, - COUNT, - HOME +enum class CardBarItems(val page : Int) { + BILLS(0), + COUNT(1), + HOME(2) } \ No newline at end of file diff --git a/app/src/main/java/com/hfut/schedule/logic/enums/FixBarItems.kt b/app/src/main/java/com/hfut/schedule/logic/enums/FixBarItems.kt index 5f47711..4df30fb 100644 --- a/app/src/main/java/com/hfut/schedule/logic/enums/FixBarItems.kt +++ b/app/src/main/java/com/hfut/schedule/logic/enums/FixBarItems.kt @@ -1,5 +1,5 @@ package com.hfut.schedule.logic.enums -enum class FixBarItems { - Fix,About +enum class FixBarItems(val page : Int) { + Fix(0),About(1) } \ No newline at end of file diff --git a/app/src/main/java/com/hfut/schedule/logic/enums/GradeBarItems.kt b/app/src/main/java/com/hfut/schedule/logic/enums/GradeBarItems.kt index 682af99..a10c1b3 100644 --- a/app/src/main/java/com/hfut/schedule/logic/enums/GradeBarItems.kt +++ b/app/src/main/java/com/hfut/schedule/logic/enums/GradeBarItems.kt @@ -1,5 +1,5 @@ package com.hfut.schedule.logic.enums -enum class GradeBarItems { - GRADE,COUNT +enum class GradeBarItems(val page : Int) { + GRADE(0),COUNT(1) } \ No newline at end of file diff --git a/app/src/main/java/com/hfut/schedule/logic/enums/NewsBarItems.kt b/app/src/main/java/com/hfut/schedule/logic/enums/NewsBarItems.kt index 553d244..f72a0fe 100644 --- a/app/src/main/java/com/hfut/schedule/logic/enums/NewsBarItems.kt +++ b/app/src/main/java/com/hfut/schedule/logic/enums/NewsBarItems.kt @@ -1,5 +1,5 @@ package com.hfut.schedule.logic.enums -enum class NewsBarItems { - News,XuanCheng,School +enum class NewsBarItems(val page : Int) { + News(0),XuanCheng(1),School(2) } \ No newline at end of file diff --git a/app/src/main/java/com/hfut/schedule/logic/enums/ShowerBarItems.kt b/app/src/main/java/com/hfut/schedule/logic/enums/ShowerBarItems.kt index 03ab1e5..35841cc 100644 --- a/app/src/main/java/com/hfut/schedule/logic/enums/ShowerBarItems.kt +++ b/app/src/main/java/com/hfut/schedule/logic/enums/ShowerBarItems.kt @@ -1,5 +1,5 @@ package com.hfut.schedule.logic.enums -enum class ShowerBarItems { - HOME,BILLS,FUNCTION +enum class ShowerBarItems(val page : Int) { + HOME(0),BILLS(1),FUNCTION(2) } \ No newline at end of file diff --git a/app/src/main/java/com/hfut/schedule/logic/utils/DataStoreManager.kt b/app/src/main/java/com/hfut/schedule/logic/utils/DataStoreManager.kt index 1ee607e..2b175f3 100644 --- a/app/src/main/java/com/hfut/schedule/logic/utils/DataStoreManager.kt +++ b/app/src/main/java/com/hfut/schedule/logic/utils/DataStoreManager.kt @@ -3,25 +3,42 @@ package com.hfut.schedule.logic.utils import android.content.Context import androidx.datastore.core.DataStore import androidx.datastore.preferences.core.Preferences +import androidx.datastore.preferences.core.edit import androidx.datastore.preferences.core.intPreferencesKey import androidx.datastore.preferences.core.stringSetPreferencesKey import androidx.datastore.preferences.preferencesDataStore import com.hfut.schedule.App.MyApplication +import com.hfut.schedule.ui.utils.monet.dataStore +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.flow.map -class DataStoreManager { - //构建Preferences DataStore - private val Context.dataStore: DataStore by - preferencesDataStore(name = "DataStore")//文件名称 - //创建 DataStore 对象 - val dataStore = MyApplication.context.dataStore +object DataStoreManager { + private val Context.dataStore: DataStore by preferencesDataStore(name = "DataStore") + private val dataStore = MyApplication.context.dataStore - companion object { - val EXAMPLE_COUNTER = intPreferencesKey("example_counter") - val EXAMPLE_COUNTER_SET = stringSetPreferencesKey("example_counter_set") + private val ANIMATION_TYPE = intPreferencesKey("animation_type") + + suspend fun saveAnimationType(type: Int) { + dataStore.edit { preferences -> + preferences[ANIMATION_TYPE] = type + } } + + val animationTypeFlow: Flow = dataStore.data + .map { preferences -> + preferences[ANIMATION_TYPE] ?: 0 + } + + /* 用法 + val currentAnimationIndex by DataStoreManager.XXX.collectAsState(initial = 默认值) + */ } + + + // //fun main() { // val dataStore = DataStoreManager().dataStore diff --git a/app/src/main/java/com/hfut/schedule/logic/utils/Starter.kt b/app/src/main/java/com/hfut/schedule/logic/utils/Starter.kt index fb22c0b..cc6f3d6 100644 --- a/app/src/main/java/com/hfut/schedule/logic/utils/Starter.kt +++ b/app/src/main/java/com/hfut/schedule/logic/utils/Starter.kt @@ -91,4 +91,11 @@ object Starter { MyApplication.context.startActivity(it) } + fun emailMe() { + val it = Intent(Intent.ACTION_SENDTO, Uri.parse("mailto:zsh0908@outlook.com")) + it.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + MyApplication.context.startActivity(it) + } + + } diff --git a/app/src/main/java/com/hfut/schedule/logic/utils/getCelebration.kt b/app/src/main/java/com/hfut/schedule/logic/utils/getCelebration.kt new file mode 100644 index 0000000..6cb5182 --- /dev/null +++ b/app/src/main/java/com/hfut/schedule/logic/utils/getCelebration.kt @@ -0,0 +1,16 @@ +package com.hfut.schedule.logic.utils + +import com.google.gson.Gson +import com.hfut.schedule.App.MyApplication +import com.hfut.schedule.logic.beans.MyAPIResponse +import com.hfut.schedule.logic.utils.SharePrefs.prefs +import com.hfut.schedule.viewmodel.NetWorkViewModel + +fun getCelebration() : Boolean { + val json = prefs.getString("my",MyApplication.NullMy) + return try { + Gson().fromJson(json,MyAPIResponse::class.java).SettingsInfo.celebration + } catch (e: Exception) { + false + } +} \ No newline at end of file diff --git a/app/src/main/java/com/hfut/schedule/ui/activity/card/function/main/home.kt b/app/src/main/java/com/hfut/schedule/ui/activity/card/function/main/home.kt index 47f114c..cdd0c7c 100644 --- a/app/src/main/java/com/hfut/schedule/ui/activity/card/function/main/home.kt +++ b/app/src/main/java/com/hfut/schedule/ui/activity/card/function/main/home.kt @@ -27,7 +27,6 @@ import androidx.compose.material3.CardDefaults import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.FilledTonalIconButton import androidx.compose.material3.Icon -import androidx.compose.material3.IconButton import androidx.compose.material3.ListItem import androidx.compose.material3.MaterialTheme import androidx.compose.material3.ModalBottomSheet @@ -51,7 +50,6 @@ import androidx.compose.ui.res.painterResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import androidx.compose.ui.window.DialogProperties import androidx.navigation.NavHostController import com.hfut.schedule.App.MyApplication import com.hfut.schedule.R @@ -74,14 +72,14 @@ import com.hfut.schedule.ui.activity.home.search.functions.electric.EleUI import com.hfut.schedule.ui.activity.home.search.functions.loginWeb.loginWebUI import com.hfut.schedule.ui.activity.home.search.functions.shower.ShowerUI +import com.hfut.schedule.ui.utils.NavigateManager.turnTo +import com.hfut.schedule.ui.utils.NavigateManager.turnToAndClear import com.hfut.schedule.ui.utils.style.CardForListColor -import com.hfut.schedule.ui.utils.components.DividerText import com.hfut.schedule.ui.utils.components.DividerTextExpandedWith import com.hfut.schedule.ui.utils.components.MyCard import com.hfut.schedule.ui.utils.components.MyToast import com.hfut.schedule.ui.utils.components.WebDialog import com.hfut.schedule.ui.utils.style.Round -import com.hfut.schedule.ui.utils.components.WebViewScreen import kotlinx.coroutines.async import kotlinx.coroutines.delay import kotlinx.coroutines.launch @@ -578,13 +576,13 @@ fun HomeScreen(innerPadding : PaddingValues, vm : NetWorkViewModel, navControlle headlineContent = { Text(text = "账单") }, supportingContent = { Text(text = "按消费先后查看交易记录")}, leadingContent = { Icon(painter = painterResource(id = R.drawable.receipt_long), contentDescription = "") }, - modifier = Modifier.clickable { turnToBottomBar(navController,CardBarItems.BILLS.name) } + modifier = Modifier.clickable { turnToAndClear(navController,CardBarItems.BILLS.name) } ) ListItem( headlineContent = { Text(text = "统计") }, supportingContent = { Text(text = "按时间段归纳统计消费")}, leadingContent = { Icon(painter = painterResource(id = R.drawable.leaderboard), contentDescription = "") }, - modifier = Modifier.clickable { turnToBottomBar(navController,CardBarItems.COUNT.name) } + modifier = Modifier.clickable { turnToAndClear(navController,CardBarItems.COUNT.name) } ) ListItem( headlineContent = { Text(text = "充值") }, @@ -652,16 +650,6 @@ fun HomeScreen(innerPadding : PaddingValues, vm : NetWorkViewModel, navControlle } } -fun turnToBottomBar(navController : NavHostController,route : String) { - navController.navigate(route) { - popUpTo(navController.graph.startDestinationId) { - saveState = true - } - launchSingleTop = true - restoreState = true - } -} - @Composable fun limitRow(vmUI : UIViewModel) { val limit by remember { mutableStateOf(vmUI.CardValue.value?.autotrans_limite ?: prefs.getString("card_limit","0")) } diff --git a/app/src/main/java/com/hfut/schedule/ui/activity/card/main/CardUI.kt b/app/src/main/java/com/hfut/schedule/ui/activity/card/main/CardUI.kt index 49f37f0..adb7709 100644 --- a/app/src/main/java/com/hfut/schedule/ui/activity/card/main/CardUI.kt +++ b/app/src/main/java/com/hfut/schedule/ui/activity/card/main/CardUI.kt @@ -34,6 +34,8 @@ import androidx.compose.material3.Text import androidx.compose.material3.TopAppBar import androidx.compose.material3.TopAppBarDefaults import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember @@ -58,13 +60,18 @@ import com.hfut.schedule.logic.beans.NavigationBarItemData import com.hfut.schedule.logic.beans.zjgd.BillResponse import com.hfut.schedule.logic.beans.zjgd.records import com.hfut.schedule.logic.utils.AndroidVersion +import com.hfut.schedule.logic.utils.DataStoreManager import com.hfut.schedule.logic.utils.SharePrefs import com.hfut.schedule.logic.utils.SharePrefs.prefs import com.hfut.schedule.ui.activity.card.function.main.HomeScreen import com.hfut.schedule.ui.activity.card.bills.main.CardBills import com.hfut.schedule.ui.activity.card.counts.CardHome -import com.hfut.schedule.ui.activity.card.function.main.turnToBottomBar +//import com.hfut.schedule.ui.activity.card.function.main.turnToBottomBar import com.hfut.schedule.ui.activity.home.focus.funictions.GetZjgdCard +import com.hfut.schedule.ui.utils.NavigateManager +import com.hfut.schedule.ui.utils.NavigateManager.currentPage +import com.hfut.schedule.ui.utils.NavigateManager.turnTo +import com.hfut.schedule.ui.utils.NavigateManager.turnToAndClear import com.hfut.schedule.ui.utils.components.CustomTabRow import com.hfut.schedule.ui.utils.components.MyToast import com.hfut.schedule.ui.utils.style.bottomBarBlur @@ -90,7 +97,7 @@ fun CardUI(vm : NetWorkViewModel, vmUI : UIViewModel) { val navController = rememberNavController() var page by remember { mutableStateOf(1) } var loading by remember { mutableStateOf(true) } - var bottomBarItems by remember { mutableStateOf(CardBarItems.BILLS) } + var bottomBarItems by remember { mutableStateOf(CardBarItems.HOME) } val pagerState = rememberPagerState(pageCount = { 3 }) val titles = listOf("日","月","学期") @@ -151,6 +158,16 @@ fun CardUI(vm : NetWorkViewModel, vmUI : UIViewModel) { } } + + + val currentAnimationIndex by DataStoreManager.animationTypeFlow.collectAsState(initial = 0) +// 保存上一页页码 用于决定左右动画 + if(currentAnimationIndex == 2) { + LaunchedEffect(bottomBarItems) { + currentPage = bottomBarItems.page + } + } + val context = LocalContext.current Scaffold( modifier = Modifier.fillMaxSize(), @@ -223,7 +240,9 @@ fun CardUI(vm : NetWorkViewModel, vmUI : UIViewModel) { items[2] -> bottomBarItems = CardBarItems.COUNT } // atEnd = !atEnd - if (!selected) { turnToBottomBar(navController, route) } + if (!selected) { + turnToAndClear(navController, route) + } }, label = { Text(text = item.label) }, icon = { @@ -236,16 +255,12 @@ fun CardUI(vm : NetWorkViewModel, vmUI : UIViewModel) { } ) {innerPadding -> + val animation = NavigateManager.getAnimationType(currentAnimationIndex,bottomBarItems.page) + NavHost(navController = navController, startDestination = CardBarItems.HOME.name, - enterTransition = { - scaleIn(animationSpec = tween(durationMillis = animation)) + - expandVertically(expandFrom = Alignment.Top,animationSpec = tween(durationMillis = animation)) - }, - exitTransition = { - scaleOut(animationSpec = tween(durationMillis = animation)) + - shrinkVertically(shrinkTowards = Alignment.Top,animationSpec = tween(durationMillis = animation)) - }, + enterTransition = { animation.enter }, + exitTransition = { animation.exit }, modifier = Modifier .haze( state = hazeState, diff --git a/app/src/main/java/com/hfut/schedule/ui/activity/fix/about/About.kt b/app/src/main/java/com/hfut/schedule/ui/activity/fix/about/About.kt index 6edb6c8..67b8882 100644 --- a/app/src/main/java/com/hfut/schedule/ui/activity/fix/about/About.kt +++ b/app/src/main/java/com/hfut/schedule/ui/activity/fix/about/About.kt @@ -1,10 +1,9 @@ package com.hfut.schedule.ui.activity.fix.about -import android.content.Intent +//import com.hfut.schedule.ui.utils.componentsAbout + import android.graphics.Bitmap import android.graphics.Color -import android.net.Uri -import android.widget.Toast import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.Image import androidx.compose.foundation.clickable @@ -18,11 +17,8 @@ import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.size import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll -import androidx.compose.material3.Badge -import androidx.compose.material3.BadgedBox import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon import androidx.compose.material3.ListItem @@ -34,7 +30,6 @@ import androidx.compose.material3.TopAppBar import androidx.compose.material3.TopAppBarDefaults import androidx.compose.material3.rememberModalBottomSheetState import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember @@ -42,7 +37,6 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.asImageBitmap import androidx.compose.ui.graphics.toArgb -import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource import androidx.compose.ui.unit.dp import androidx.navigation.NavController @@ -51,18 +45,16 @@ import com.google.zxing.EncodeHintType import com.google.zxing.qrcode.QRCodeWriter import com.hfut.schedule.App.MyApplication import com.hfut.schedule.R -import com.hfut.schedule.viewmodel.LoginViewModel import com.hfut.schedule.logic.utils.APPVersion import com.hfut.schedule.logic.utils.ClipBoard import com.hfut.schedule.logic.utils.ShareAPK import com.hfut.schedule.logic.utils.Starter import com.hfut.schedule.ui.activity.home.cube.items.main.Screen import com.hfut.schedule.ui.activity.home.cube.items.subitems.update.VersionInfo -import com.hfut.schedule.ui.activity.home.cube.items.subitems.update.VersionInfoCard import com.hfut.schedule.ui.activity.home.cube.items.subitems.update.getUpdates import com.hfut.schedule.ui.utils.components.MyToast import com.hfut.schedule.ui.utils.style.Round - +import com.hfut.schedule.viewmodel.LoginViewModel import java.util.Hashtable @OptIn(ExperimentalFoundationApi::class, ExperimentalMaterial3Api::class) @@ -124,56 +116,23 @@ fun AboutUI(innerPadding : PaddingValues, vm : LoginViewModel,cubeShow : Boolean } } } -// val sheetState_github = rememberModalBottomSheetState(skipPartiallyExpanded = true) -// var showBottomSheet_github by remember { mutableStateOf(false) } -// if (showBottomSheet_github) { -// ModalBottomSheet( -// onDismissRequest = { showBottomSheet_github = false }, -// sheetState = sheetState_github, -// shape = Round(sheetState_github) -// ) { -// Scaffold( -// modifier = Modifier.fillMaxSize(), -// topBar = { -// TopAppBar( -// colors = TopAppBarDefaults.mediumTopAppBarColors( -// containerColor = androidx.compose.ui.graphics.Color.Transparent, -// titleContentColor = MaterialTheme.colorScheme.primary, -// ), -// title = { Text("Github") }, -// ) -// }, -// ) { innerPadding -> -// Column( -// modifier = Modifier -// .padding(innerPadding) -// .verticalScroll(rememberScrollState()) -// .fillMaxSize() -// ) { -// val context = LocalContext.current -// var markdownContent by remember { mutableStateOf("") } -// -// val markdownFileName = "README-zh_rCN.md" -// val inputStream = context.assets.open(markdownFileName) -// val bufferedReader = BufferedReader(InputStreamReader(inputStream)) -// markdownContent = bufferedReader.use { it.readText() } -// MarkdownText( -// markdown = markdownContent, -// modifier = Modifier.padding(15.dp) -// ) -// } -// } -// } -// } - if(!cubeShow) { - Spacer(modifier = Modifier.height(5.dp)) - VersionInfoCard() - Spacer(modifier = Modifier.height(18.dp)) + + val sheetState_info = rememberModalBottomSheetState(skipPartiallyExpanded = true) + var showBottomSheet_info by remember { mutableStateOf(false) } + if (showBottomSheet_info) { + ModalBottomSheet( + onDismissRequest = { showBottomSheet_info = false }, + sheetState = sheetState_info, + shape = Round(sheetState_info) + ) { + About() + } } + ListItem( headlineContent = { Text(text = "Github开源") }, - supportingContent = { Text(text = "欢迎来参观项目,如您想成为下个版本的构建者,来这里Fork项目并提交你的代码吧")}, + supportingContent = { Text(text = "如您想成为下个版本的构建者,来这里提交你的代码吧")}, leadingContent = { Icon( painterResource(R.drawable.github), @@ -188,21 +147,6 @@ fun AboutUI(innerPadding : PaddingValues, vm : LoginViewModel,cubeShow : Boolean // } } ) - ListItem( - headlineContent = { Text(text = "联系开发者") }, - leadingContent = { - Icon( - painterResource(R.drawable.mail), - contentDescription = "Localized description", - ) - }, - modifier = Modifier.clickable{ - val it = Intent(Intent.ACTION_SENDTO, Uri.parse("mailto:zsh0908@outlook.com")) - it.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) - MyApplication.context.startActivity(it) - } - ) - ListItem( headlineContent = { Text(text = "推广本应用") }, @@ -231,23 +175,6 @@ fun AboutUI(innerPadding : PaddingValues, vm : LoginViewModel,cubeShow : Boolean var showBadge by remember { mutableStateOf(false) } if (version.version != APPVersion.getVersionName()) showBadge = true - ListItem( - headlineContent = { Text(text = "获取更新") }, - supportingContent = { Text(text = if(version.version == APPVersion.getVersionName()) "当前为最新版本 ${APPVersion.getVersionName()}" else "当前版本 ${APPVersion.getVersionName()}\n最新版本 ${version.version}") }, - leadingContent = { - BadgedBox(badge = { - if(showBadge) - Badge(modifier = Modifier.size(7.dp)) }) { - Icon(painterResource(R.drawable.arrow_upward), contentDescription = "Localized description",) - } - }, - modifier = Modifier.clickable{ - if (version.version != APPVersion.getVersionName()) - Starter.startWebUrl(MyApplication.UpdateURL + "releases/download/Android/${version.version}.apk") - else Toast.makeText(MyApplication.context,"与云端版本一致", Toast.LENGTH_SHORT).show() - } - ) - ListItem( headlineContent = { Text(text = "本版本新特性") }, supportingContent = { Text(text = "查看此版本的更新内容")}, @@ -256,14 +183,10 @@ fun AboutUI(innerPadding : PaddingValues, vm : LoginViewModel,cubeShow : Boolean ) ListItem( - headlineContent = { Text(text = "版本日志") }, - supportingContent = { Text("查看历代版本的更新内容") }, - leadingContent = { - Icon(painterResource(R.drawable.crossword), contentDescription = "Localized description",) - }, - modifier = Modifier.clickable{ - Starter.startWebUrl("https://github.com/Chiu-xaH/HFUT-Schedule/blob/main/UPDATE.md") - } + headlineContent = { Text(text = "关于本应用") }, + supportingContent = { Text(text = "开源 构建 开发者")}, + modifier = Modifier.clickable { showBottomSheet_info = true }, + leadingContent = { Icon(painter = painterResource(id = R.drawable.info), contentDescription = "")} ) diff --git a/app/src/main/java/com/hfut/schedule/ui/activity/fix/about/AboutDeveloper.kt b/app/src/main/java/com/hfut/schedule/ui/activity/fix/about/AboutDeveloper.kt new file mode 100644 index 0000000..9745898 --- /dev/null +++ b/app/src/main/java/com/hfut/schedule/ui/activity/fix/about/AboutDeveloper.kt @@ -0,0 +1,182 @@ +package com.hfut.schedule.ui.activity.fix.about + +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll +import androidx.compose.material3.Button +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.FilledTonalButton +import androidx.compose.material3.FilledTonalIconButton +import androidx.compose.material3.Icon +import androidx.compose.material3.LargeTopAppBar +import androidx.compose.material3.ListItem +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBarDefaults +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.text.style.TextAlign +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import com.hfut.schedule.R +import com.hfut.schedule.logic.utils.Starter +import com.hfut.schedule.ui.utils.components.DividerTextExpandedWith +import com.hfut.schedule.ui.utils.components.ScrollText + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +@Preview +fun About() { + data class Build( + val languages : List, + val build : List, + val ui : String, + val jetpack : String + ) + val openSourceProjects = listOf( + "Okhttp" to "网络请求", + "Retrofit" to "网络请求", + "Gson" to "JSON解析", + "Jsoup" to "XML/HTML解析", + "Zxing" to "二维码", + "Haze" to "实时模糊(SDK>=33)", + "Accompanist" to "用做实现透明状态栏", + "Monet" to "莫奈取色(供SDK<32不支持MY取色平替)", + "Dagger" to "Hilt注入,辅助莫奈取色功能", + "Glide" to "网络图片", + "EdDSA Java" to "加密(供和风天气API使用)", + "Konfetti" to "礼花动画", + ) + val dependencies = Build( + jetpack = "Jetpack Compose", + ui = "Material Design 3 (Material You)", + languages = listOf("Kotlin","Java"), + build = listOf( "Gradle 8.3 With Groovy","OpenJDK 17"), + ) +// var showBottomSheet by remember { mutableStateOf(false) } +// UseAgreement(showBottomSheet, showBottomSheetChange = { showBottomSheet = false }) + + androidx.compose.material3.Scaffold( + topBar = { + LargeTopAppBar( + colors = TopAppBarDefaults.mediumTopAppBarColors( + containerColor = Color.Transparent, + titleContentColor = MaterialTheme.colorScheme.primary, + ), + title = { + Box(modifier = Modifier.fillMaxWidth()) { + Text( + text = "关于", + modifier = Modifier.fillMaxWidth(), + textAlign = TextAlign.Center, + //style = MaterialTheme.typography.titleLarge + ) + } + }, + navigationIcon = { + Column(modifier = Modifier + .padding(horizontal = 23.dp)) { + Spacer(modifier = Modifier.height(20.dp)) + Text( + text = "聚在工大", + fontSize = 38.sp, + color = MaterialTheme.colorScheme.secondaryContainer + ) + } + }, + ) + }, + bottomBar = { + Row(modifier = Modifier.padding(15.dp),horizontalArrangement = Arrangement.Center) { + Button( + onClick = { Starter.startWebUrl("https://github.com/Chiu-xaH/HFUT-Schedule") }, + modifier = Modifier + .fillMaxWidth() + .weight(.5f) + ) { + Text("给颗⭐") + } + + Spacer(modifier = Modifier.width(15.dp)) + FilledTonalButton( + onClick = { Starter.startWebUrl("https://github.com/Chiu-xaH") }, + modifier = Modifier + .fillMaxWidth() + .weight(.5f) + ) { + Text("我的Github") + } + } + }, + ) { innerPadding -> + Column(modifier = Modifier.padding(innerPadding).verticalScroll(rememberScrollState())) { + DividerTextExpandedWith("开发者") { + ListItem( + modifier = Modifier.clickable { + Starter.startWebUrl("https://github.com/Chiu-xaH") + }, + headlineContent = { ScrollText("Chiu-xaH") }, + leadingContent = { Icon(painterResource(R.drawable.github), null) }, + supportingContent = { + Text("一名热爱安卓的开发者,宣城校区23级计算机科学与技术专业(转)本科生") + }, + trailingContent = { + FilledTonalIconButton( + onClick = { + Starter.emailMe() + } + ) { + Icon(painterResource(R.drawable.mail),null) + } + } + ) + + } + + DividerTextExpandedWith("构建") { + val lans = dependencies.languages + for(index in lans.indices) { + ListItem( + headlineContent = { Text(lans[index]) }, + overlineContent = { Text("主体语言") } + ) + } + ListItem( + headlineContent = { Text(dependencies.ui) }, + overlineContent = { Text("UI设计") } + ) + ListItem( + headlineContent = { Text(dependencies.jetpack) }, + ) + val builds = dependencies.build + for(index in builds.indices) { + ListItem( + headlineContent = { Text(builds[index]) }, + overlineContent = { Text("构建 打包") } + ) + } + } + + DividerTextExpandedWith("开源") { + for(index in openSourceProjects.indices) { + ListItem( + headlineContent = { Text(openSourceProjects[index].first) }, + supportingContent = { Text(openSourceProjects[index].second) } + ) + } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/hfut/schedule/ui/activity/fix/fix/FixUI.kt b/app/src/main/java/com/hfut/schedule/ui/activity/fix/fix/FixUI.kt index 06d1da9..1d2e572 100644 --- a/app/src/main/java/com/hfut/schedule/ui/activity/fix/fix/FixUI.kt +++ b/app/src/main/java/com/hfut/schedule/ui/activity/fix/fix/FixUI.kt @@ -53,6 +53,7 @@ import com.hfut.schedule.logic.utils.CrashHandler import com.hfut.schedule.logic.utils.SharePrefs import com.hfut.schedule.logic.utils.SharePrefs.prefs import com.hfut.schedule.logic.utils.Starter +import com.hfut.schedule.logic.utils.Starter.emailMe import com.hfut.schedule.ui.activity.home.cube.items.main.Clear import com.hfut.schedule.ui.activity.home.cube.items.main.apiCheck import com.hfut.schedule.ui.activity.home.focus.funictions.getTimeStamp @@ -429,7 +430,7 @@ fun feedBackUI(vm : NetWorkViewModel) { ListItem( headlineContent = { Text(text = "或者通过电子邮件联系") }, leadingContent = { Icon(painter = painterResource(id = R.drawable.mail), contentDescription ="" )}, - modifier = Modifier.clickable { sendToMe() } + modifier = Modifier.clickable { emailMe() } ) } MyCard { diff --git a/app/src/main/java/com/hfut/schedule/ui/activity/fix/main/Fix.kt b/app/src/main/java/com/hfut/schedule/ui/activity/fix/main/Fix.kt index 1ea5544..05e08b0 100644 --- a/app/src/main/java/com/hfut/schedule/ui/activity/fix/main/Fix.kt +++ b/app/src/main/java/com/hfut/schedule/ui/activity/fix/main/Fix.kt @@ -30,6 +30,8 @@ import androidx.compose.material3.Text import androidx.compose.material3.TopAppBar import androidx.compose.material3.TopAppBarDefaults import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember @@ -51,10 +53,14 @@ import com.hfut.schedule.viewmodel.LoginViewModel import com.hfut.schedule.logic.enums.FixBarItems import com.hfut.schedule.logic.beans.NavigationBarItemData import com.hfut.schedule.logic.utils.AndroidVersion +import com.hfut.schedule.logic.utils.DataStoreManager import com.hfut.schedule.logic.utils.SharePrefs import com.hfut.schedule.logic.utils.SharePrefs.prefs import com.hfut.schedule.ui.activity.fix.about.AboutUI import com.hfut.schedule.ui.activity.fix.fix.FixUI +import com.hfut.schedule.ui.utils.NavigateManager +import com.hfut.schedule.ui.utils.NavigateManager.currentPage +import com.hfut.schedule.ui.utils.NavigateManager.turnToAndClear import com.hfut.schedule.ui.utils.style.bottomBarBlur import com.hfut.schedule.ui.utils.style.topBarBlur import dev.chrisbanes.haze.HazeState @@ -69,6 +75,16 @@ fun Fix(vm : LoginViewModel,vm2 : NetWorkViewModel) { var animation by remember { mutableStateOf(prefs.getInt("ANIMATION", MyApplication.Animation)) } val hazeState = remember { HazeState() } val navController = rememberNavController() + val currentAnimationIndex by DataStoreManager.animationTypeFlow.collectAsState(initial = 0) + var targetPage by remember { mutableStateOf(FixBarItems.Fix) } + // 保存上一页页码 用于决定左右动画 + if(currentAnimationIndex == 2) { + LaunchedEffect(targetPage) { + currentPage = targetPage.page + } + } + + val context = LocalContext.current Scaffold( modifier = Modifier.fillMaxSize(), @@ -125,15 +141,16 @@ fun Fix(vm : LoginViewModel,vm2 : NetWorkViewModel) { modifier = Modifier.scale(scale.value), interactionSource = interactionSource, onClick = { - if (!selected) { - navController.navigate(route) { - popUpTo(navController.graph.startDestinationId) { - saveState = true - } - launchSingleTop = true - restoreState = true + if(currentAnimationIndex == 2) { + when(item){ + items[0] -> targetPage = FixBarItems.Fix + items[0] -> targetPage = FixBarItems.About } } + + if (!selected) { + turnToAndClear(navController,route) + } }, label = { Text(text = item.label) }, icon = { @@ -146,16 +163,12 @@ fun Fix(vm : LoginViewModel,vm2 : NetWorkViewModel) { } ) {innerPadding -> + val animation = NavigateManager.getAnimationType(currentAnimationIndex,targetPage.page) + NavHost(navController = navController, startDestination = FixBarItems.Fix.name, - enterTransition = { - scaleIn(animationSpec = tween(durationMillis = animation)) + - expandVertically(expandFrom = Alignment.Top,animationSpec = tween(durationMillis = animation)) - }, - exitTransition = { - scaleOut(animationSpec = tween(durationMillis = animation)) + - shrinkVertically(shrinkTowards = Alignment.Top,animationSpec = tween(durationMillis = animation)) - }, + enterTransition = { animation.enter }, + exitTransition = { animation.exit }, modifier = Modifier .haze( state = hazeState, diff --git a/app/src/main/java/com/hfut/schedule/ui/activity/grade/main/GradeUI.kt b/app/src/main/java/com/hfut/schedule/ui/activity/grade/main/GradeUI.kt index 198acc7..b399b02 100644 --- a/app/src/main/java/com/hfut/schedule/ui/activity/grade/main/GradeUI.kt +++ b/app/src/main/java/com/hfut/schedule/ui/activity/grade/main/GradeUI.kt @@ -35,6 +35,8 @@ import androidx.compose.material3.TopAppBar import androidx.compose.material3.TopAppBarDefaults import androidx.compose.material3.rememberModalBottomSheetState import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.mutableStateOf @@ -55,12 +57,17 @@ import androidx.navigation.compose.rememberNavController import com.hfut.schedule.App.MyApplication import com.hfut.schedule.R import com.hfut.schedule.logic.beans.NavigationBarItemData +import com.hfut.schedule.logic.enums.FixBarItems import com.hfut.schedule.logic.enums.GradeBarItems import com.hfut.schedule.logic.utils.AndroidVersion +import com.hfut.schedule.logic.utils.DataStoreManager import com.hfut.schedule.logic.utils.SharePrefs.prefs import com.hfut.schedule.ui.activity.grade.analysis.GradeCountUI import com.hfut.schedule.ui.activity.grade.grade.community.GradeItemUI import com.hfut.schedule.ui.activity.grade.grade.jxglstu.GradeItemUIJXGLSTU +import com.hfut.schedule.ui.utils.NavigateManager +import com.hfut.schedule.ui.utils.NavigateManager.currentPage +import com.hfut.schedule.ui.utils.NavigateManager.turnToAndClear import com.hfut.schedule.ui.utils.components.MyCard import com.hfut.schedule.ui.utils.style.Round import com.hfut.schedule.ui.utils.style.bottomBarBlur @@ -86,6 +93,16 @@ fun GradeUI(ifSaved : Boolean,vm : NetWorkViewModel) { var showBottomSheet by remember { mutableStateOf(false) } val sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true) + val currentAnimationIndex by DataStoreManager.animationTypeFlow.collectAsState(initial = 0) + var targetPage by remember { mutableStateOf(GradeBarItems.GRADE) } + // 保存上一页页码 用于决定左右动画 + if(currentAnimationIndex == 2) { + LaunchedEffect(targetPage) { + currentPage = targetPage.page + } + } + + if (showBottomSheet) { ModalBottomSheet( onDismissRequest = { showBottomSheet= false }, @@ -180,15 +197,16 @@ fun GradeUI(ifSaved : Boolean,vm : NetWorkViewModel) { modifier = Modifier.scale(scale.value), interactionSource = interactionSource, onClick = { - if (!selected) { - navController.navigate(route) { - popUpTo(navController.graph.startDestinationId) { - saveState = true - } - launchSingleTop = true - restoreState = true + if(currentAnimationIndex == 2) { + when(item) { + items[0] -> targetPage = GradeBarItems.GRADE + items[1] -> targetPage = GradeBarItems.COUNT } } + + if (!selected) { + turnToAndClear(navController,route) + } }, label = { Text(text = item.label) }, icon = { @@ -201,16 +219,12 @@ fun GradeUI(ifSaved : Boolean,vm : NetWorkViewModel) { } ) { innerPadding -> - NavHost(navController = navController, + val animation = NavigateManager.getAnimationType(currentAnimationIndex,targetPage.page) + + NavHost(navController = navController, startDestination = GradeBarItems.GRADE.name, - enterTransition = { - scaleIn(animationSpec = tween(durationMillis = animation)) + - expandVertically(expandFrom = Alignment.Top,animationSpec = tween(durationMillis = animation)) - }, - exitTransition = { - scaleOut(animationSpec = tween(durationMillis = animation)) + - shrinkVertically(shrinkTowards = Alignment.Top,animationSpec = tween(durationMillis = animation)) - }, + enterTransition = { animation.enter }, + exitTransition = { animation.exit }, modifier = Modifier.haze(state = hazeState) ) { composable(GradeBarItems.GRADE.name) { diff --git a/app/src/main/java/com/hfut/schedule/ui/activity/home/calendar/communtiy/SavedCourseUISwap.kt b/app/src/main/java/com/hfut/schedule/ui/activity/home/calendar/communtiy/SavedCourseUISwap.kt index d781f87..b14f2a3 100644 --- a/app/src/main/java/com/hfut/schedule/ui/activity/home/calendar/communtiy/SavedCourseUISwap.kt +++ b/app/src/main/java/com/hfut/schedule/ui/activity/home/calendar/communtiy/SavedCourseUISwap.kt @@ -841,20 +841,14 @@ fun ScheduleTopDate(showAll: Boolean,today : LocalDate,blur : Boolean) { LazyVerticalGrid(columns = GridCells.Fixed(if(showAll)7 else 5),modifier = Modifier.padding(horizontal = 10.dp)){ items(if(showAll)7 else 5) { item -> val date = mondayOfCurrentWeek.plusDays(item.toLong()).toString() //YYYY-MM-DD 与考试对比 + val isToday = date == DateTimeManager.Date_yyyy_MM_dd if (Benweeks > 0) Text( text = date.substringAfter("-"), textAlign = TextAlign.Center, fontSize = if(showAll)12.sp else 14.sp, - color = if(date == DateTimeManager.Date_yyyy_MM_dd) MaterialTheme.colorScheme.onPrimaryContainer else MaterialTheme.colorScheme.primary, -// style = if(date == DateTimeManager.Date_yyyy_MM_dd) { -// TextStyle(shadow = Shadow( -// color = Color.Gray, -// offset = Offset(2.0f,2.0f), -// blurRadius = 7.0f -// )) -// } else TextStyle(), - fontWeight = if(date == DateTimeManager.Date_yyyy_MM_dd) FontWeight.Bold else FontWeight.Normal + color = if(isToday) MaterialTheme.colorScheme.onPrimaryContainer else MaterialTheme.colorScheme.primary, + fontWeight = if(isToday) FontWeight.Bold else FontWeight.Normal ) else Text( text = "未开学", diff --git a/app/src/main/java/com/hfut/schedule/ui/activity/home/cube/items/NavUIs/UIScreen.kt b/app/src/main/java/com/hfut/schedule/ui/activity/home/cube/items/NavUIs/UIScreen.kt index dad5da8..a4889e9 100644 --- a/app/src/main/java/com/hfut/schedule/ui/activity/home/cube/items/NavUIs/UIScreen.kt +++ b/app/src/main/java/com/hfut/schedule/ui/activity/home/cube/items/NavUIs/UIScreen.kt @@ -11,34 +11,25 @@ import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll import androidx.compose.material3.Icon import androidx.compose.material3.ListItem -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Slider -import androidx.compose.material3.SliderDefaults import androidx.compose.material3.Switch import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableFloatStateOf import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.res.painterResource import androidx.compose.ui.unit.dp import androidx.navigation.NavController -import com.hfut.schedule.App.MyApplication import com.hfut.schedule.R import com.hfut.schedule.logic.utils.AndroidVersion.canBlur -import com.hfut.schedule.logic.utils.SharePrefs -import com.hfut.schedule.logic.utils.SharePrefs.prefs import com.hfut.schedule.logic.utils.SharePrefs.saveBoolean +import com.hfut.schedule.ui.activity.home.cube.items.subitems.AnimationSetting import com.hfut.schedule.ui.activity.home.cube.items.subitems.monet.MonetColorItem import com.hfut.schedule.ui.utils.BlurManager -import com.hfut.schedule.ui.utils.components.DividerText import com.hfut.schedule.ui.utils.components.DividerTextExpandedWith -import com.hfut.schedule.ui.utils.components.MyToast -import java.math.BigDecimal -import java.math.RoundingMode @Composable fun UIScreen(navController: NavController, innerPaddings : PaddingValues, @@ -59,10 +50,6 @@ fun UIScreen(navController: NavController, innerPaddings : PaddingValues, saveBoolean("SWITCHBLUR",true,blur) - var sliderPosition by remember { mutableFloatStateOf((prefs.getInt("ANIMATION", MyApplication.Animation)).toFloat()) } - val bd = BigDecimal(sliderPosition.toString()) - val str = bd.setScale(0, RoundingMode.HALF_UP).toString() - SharePrefs.saveInt("ANIMATION",sliderPosition.toInt()) ListItem( headlineContent = { Text(text = "底栏标签") }, @@ -104,45 +91,16 @@ fun UIScreen(navController: NavController, innerPaddings : PaddingValues, BlurManager.setValue(animationBlur) } ) + val cor = rememberCoroutineScope() ListItem( - headlineContent = { Text(text = "全局动画速度") }, + headlineContent = { Text(text = "底栏转场动画") }, supportingContent = { - Column { - Text(text = "时长 $str ms 重启后生效") - Slider( - value = sliderPosition, - onValueChange = { - sliderPosition = it - SharePrefs.saveInt("ANIMATION",sliderPosition.toInt()) - }, - colors = SliderDefaults.colors( - thumbColor = MaterialTheme.colorScheme.secondary, - activeTrackColor = MaterialTheme.colorScheme.secondary, - inactiveTrackColor = MaterialTheme.colorScheme.secondaryContainer, - ), - steps = 19, - valueRange = 0f..1000f - ) - } - }, - leadingContent = { Icon(painterResource(R.drawable.schedule), contentDescription = "Localized description",) }, - trailingContent = { }, - ) - - ListItem( - headlineContent = { Text(text = "界面转场动画") }, - supportingContent = { - Text("自定义同级页面之间进行转场的动画") + Text("自定义底栏切换页面进行转场的动画") }, leadingContent = { Icon(painterResource(R.drawable.animation), contentDescription = "Localized description",) }, -// trailingContent = { }, - modifier = Modifier.clickable { - MyToast("正在开发") -// animationBlur = !animationBlur -// BlurManager.setValue(animationBlur) - } ) + AnimationSetting() } DividerTextExpandedWith("主题色") { diff --git a/app/src/main/java/com/hfut/schedule/ui/activity/home/cube/items/subitems/AnimationSetting.kt b/app/src/main/java/com/hfut/schedule/ui/activity/home/cube/items/subitems/AnimationSetting.kt new file mode 100644 index 0000000..5649d5f --- /dev/null +++ b/app/src/main/java/com/hfut/schedule/ui/activity/home/cube/items/subitems/AnimationSetting.kt @@ -0,0 +1,131 @@ +package com.hfut.schedule.ui.activity.home.cube.items.subitems + +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.lazy.LazyRow +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.CardDefaults +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.OutlinedCard +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.hfut.schedule.logic.utils.DataStoreManager +import com.hfut.schedule.ui.utils.NavigateManager +import com.hfut.schedule.ui.utils.NavigateManager.ANIMATION_SPEED +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch + +// DataStore 用法 +@Composable +@Preview +fun AnimationSetting() { + val lists = listOf( + NavigateManager.upDownAnimation, + NavigateManager.centerAnimation, + NavigateManager.getLeftRightAnimation(0), + NavigateManager.fadeAnimation, + NavigateManager.nullAnimation + ) + val currentAnimationIndex by DataStoreManager.animationTypeFlow.collectAsState(initial = 0) + + LazyRow() { + item { Spacer(Modifier.width(10.dp)) } + items(lists.size) { index -> + Spacer(Modifier.width(5.dp)) + AnimationCard(lists[index],currentAnimationIndex,index) + } + item { + Spacer(Modifier.width(15.dp)) + } + } +} + +@Composable +fun AnimationCard(animation : NavigateManager. TransferAnimation, currentAnimationIndex : Int, index : Int) { + val isSelected = currentAnimationIndex == index + + val cor = rememberCoroutineScope() + Column(verticalArrangement = Arrangement.Center, + horizontalAlignment = Alignment.CenterHorizontally) { + OutlinedCard ( + modifier = Modifier + .width(100.dp) + .height(180.dp) + .clickable { + // 点击选择应用动画 标记selected=true selected只能存在一个true + cor.launch { DataStoreManager.saveAnimationType(index) } + }, + border = CardDefaults.outlinedCardBorder(enabled = isSelected), + shape = RoundedCornerShape(16.dp), + ) { + Box ( + modifier = Modifier.fillMaxSize().padding(5.dp), + ) { + var visible by remember { mutableStateOf(true) } + LaunchedEffect(Unit) { + while (true) { + visible = !visible + delay((ANIMATION_SPEED * 2).toLong()) // 延迟时间可以根据需要调整 + } + } + + androidx.compose.animation.AnimatedVisibility( + visible = visible, + enter = animation.enter, + exit = animation.exit, + modifier = Modifier.align(Alignment.Center) + ) { + Box( + modifier = Modifier + .fillMaxSize() + .background(MaterialTheme.colorScheme.primaryContainer, shape = RoundedCornerShape(14.dp)) + ) { + Text("2", modifier = Modifier.align(Alignment.Center)) + } + } + androidx.compose.animation.AnimatedVisibility( + visible = !visible, + enter = animation.enter, + exit = animation.exit, + modifier = Modifier.align(Alignment.Center) + ) { + Box( + modifier = Modifier + .fillMaxSize() + .background(MaterialTheme.colorScheme.primaryContainer.copy(.5f), shape = RoundedCornerShape(14.dp)) + ) { + Text("1", modifier = Modifier.align(Alignment.Center)) + } + } + } + } + Spacer(Modifier.height(2.dp)) + Text(text = animation.remark, style = MaterialTheme.typography.titleSmall, + color = if(isSelected) MaterialTheme.colorScheme.onPrimaryContainer else Color.Gray, + fontWeight = if(isSelected) FontWeight.Bold else FontWeight.Normal + ) + } + +} diff --git a/app/src/main/java/com/hfut/schedule/ui/activity/home/cube/items/subitems/Test.kt b/app/src/main/java/com/hfut/schedule/ui/activity/home/cube/items/subitems/Test.kt index 2a5b716..fc14237 100644 --- a/app/src/main/java/com/hfut/schedule/ui/activity/home/cube/items/subitems/Test.kt +++ b/app/src/main/java/com/hfut/schedule/ui/activity/home/cube/items/subitems/Test.kt @@ -89,9 +89,16 @@ import com.hfut.schedule.ui.utils.style.CardForListColor import com.hfut.schedule.ui.utils.style.RowHorizal import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.launch +import nl.dionsegijn.konfetti.compose.KonfettiView +import nl.dionsegijn.konfetti.core.Party +import nl.dionsegijn.konfetti.core.Position +import nl.dionsegijn.konfetti.core.emitter.Emitter +import nl.dionsegijn.konfetti.core.models.Shape +import nl.dionsegijn.konfetti.core.models.Size +import java.util.concurrent.TimeUnit import kotlin.math.roundToInt -@OptIn(ExperimentalMaterial3Api::class, ExperimentalSharedTransitionApi::class) +@OptIn(ExperimentalSharedTransitionApi::class) @Composable fun TEST(innerPaddings : PaddingValues) { // Column (modifier = Modifier.padding(innerPaddings)){ @@ -224,44 +231,85 @@ fun TEST(innerPaddings : PaddingValues) { // // // Gesture() // } - val listSnacks = listOf( - Snack("桌面","des",R.drawable.home), - Snack("搜索","des",R.drawable.search), - Snack("动画","des",R.drawable.animation), - Snack("堆栈","des",R.drawable.stacks) + + + val party = Party( + emitter = Emitter(duration = 5, TimeUnit.SECONDS).perSecond(30) ) - SharedTransitionLayout { - val navController = rememberNavController() - NavHost( - navController = navController, - startDestination = "home" - ) { - composable("home") { - HomeScreen( - navController, - this@SharedTransitionLayout, - this@composable, - listSnacks, - innerPaddings - ) - } - composable( - "details/{item}", - arguments = listOf(navArgument("item") { type = NavType.IntType }) - ) { backStackEntry -> - val id = backStackEntry.arguments?.getInt("item") - val snack = listSnacks[id!!] - DetailsScreen( - navController, - id, - snack, - this@SharedTransitionLayout, - this@composable - ) + Box() { + KonfettiView( + modifier = Modifier.fillMaxSize(), + parties = listOf(party), + ) + val listSnacks = listOf( + Snack("桌面","des",R.drawable.home), + Snack("搜索","des",R.drawable.search), + Snack("动画","des",R.drawable.animation), + Snack("堆栈","des",R.drawable.stacks) + ) + + SharedTransitionLayout { + val navController = rememberNavController() + NavHost( + navController = navController, + startDestination = "home" + ) { + composable("home") { + HomeScreen( + navController, + this@SharedTransitionLayout, + this@composable, + listSnacks, + innerPaddings + ) + } + composable( + "details/{item}", + arguments = listOf(navArgument("item") { type = NavType.IntType }) + ) { backStackEntry -> + val id = backStackEntry.arguments?.getInt("item") + val snack = listSnacks[id!!] + DetailsScreen( + navController, + id, + snack, + this@SharedTransitionLayout, + this@composable + ) + } } } } + +} + +@Composable +@Preview +fun t() { + val partyTopStart = Party( + emitter = Emitter(duration = 1, TimeUnit.SECONDS).perSecond(30), + position = Position.Relative(0.0,0.0) + ) + val partyTopEnd = Party( + emitter = Emitter(duration = 1, TimeUnit.SECONDS).perSecond(30), + position = Position.Relative(1.0,0.0) + ) + val partyBottomStart = Party( + emitter = Emitter(duration = 1, TimeUnit.SECONDS).perSecond(30), + position = Position.Relative(0.0,1.0) + ) + val partyBottomEnd = Party( + emitter = Emitter(duration = 1, TimeUnit.SECONDS).perSecond(30), + position = Position.Relative(1.0,1.0) + ) + + Box(modifier = Modifier.fillMaxSize()) { + KonfettiView( + modifier = Modifier.fillMaxSize(), + parties = listOf(partyTopStart,partyTopEnd,partyBottomStart,partyBottomEnd), + ) + } } @OptIn(ExperimentalAnimationGraphicsApi::class) diff --git a/app/src/main/java/com/hfut/schedule/ui/activity/home/cube/items/subitems/update/UpdateItem.kt b/app/src/main/java/com/hfut/schedule/ui/activity/home/cube/items/subitems/update/UpdateItem.kt index 4dea33a..5f7114f 100644 --- a/app/src/main/java/com/hfut/schedule/ui/activity/home/cube/items/subitems/update/UpdateItem.kt +++ b/app/src/main/java/com/hfut/schedule/ui/activity/home/cube/items/subitems/update/UpdateItem.kt @@ -31,15 +31,15 @@ import com.hfut.schedule.ui.utils.style.CardForListColor @SuppressLint("SuspiciousIndentation") @Composable fun VersionInfoCard() { - if(APPVersion.getVersionName().contains("Preview")) { - Card( - elevation = CardDefaults.cardElevation(defaultElevation = 15.dp), - modifier = Modifier - .fillMaxWidth() - .padding(horizontal = 15.dp, vertical = 5.dp), - shape = MaterialTheme.shapes.medium, - ) { ListItem(headlineContent = { Text(text = APPVersion.getVersionName(), fontSize = 28.sp) }) } - } else +// if(APPVersion.getVersionName().contains("Preview")) { +// Card( +// elevation = CardDefaults.cardElevation(defaultElevation = 15.dp), +// modifier = Modifier +// .fillMaxWidth() +// .padding(horizontal = 15.dp, vertical = 5.dp), +// shape = MaterialTheme.shapes.medium, +// ) { ListItem(headlineContent = { Text(text = APPVersion.getVersionName(), fontSize = 28.sp) }) } +// } else Card( elevation = CardDefaults.cardElevation(defaultElevation = 15.dp), modifier = Modifier @@ -48,22 +48,22 @@ fun VersionInfoCard() { shape = MaterialTheme.shapes.medium, colors = CardForListColor() ) { - ListItem(headlineContent = { Text(text = "聚在工大 " + APPVersion.getVersionName(), fontSize = 28.sp) }) + ListItem(headlineContent = { Text(text = "版本 " + APPVersion.getVersionName(), fontSize = 28.sp) }) Row { ListItem( - overlineContent = { Text(text = "2025-01-27") }, - leadingContent = { Icon(painter = painterResource(id = R.drawable.sdk), contentDescription = "") }, - headlineContent = { ScrollText(text = "第${APPVersion.getVersionCode()}次更新") }, - modifier = Modifier.weight(.5f) - ) - ListItem( - headlineContent = { Text(text = "Chiu-xaH\ntinyvan") }, - overlineContent = { Text(text = "构建") }, - leadingContent = { Icon(painter = painterResource(id = R.drawable.support), contentDescription = "") }, - modifier = Modifier.weight(.5f).clickable { - MyToast("想成为下个版本的构建者吗?跟随 设置-维护关于-开源主页") - } + overlineContent = { Text(text = "2025-01-30") }, + leadingContent = { Icon(painter = painterResource(id = R.drawable.code), contentDescription = "") }, + headlineContent = { Text(text = "版本号 ${APPVersion.getVersionCode()}") }, +// modifier = Modifier.weight(.5f) ) +// ListItem( +// headlineContent = { Text(text = "Chiu-xaH") }, +// overlineContent = { Text(text = "构建") }, +// leadingContent = { Icon(painter = painterResource(id = R.drawable.support), contentDescription = "") }, +// modifier = Modifier.weight(.5f).clickable { +// MyToast("想成为下个版本的构建者吗?跟随 设置-维护关于-开源主页") +// } +// ) } } } @@ -75,9 +75,11 @@ fun VersionInfo() { Spacer(Modifier.height(3.dp)) VersionInfoCard() DividerTextExpandedWith(text = "新特性") { - UpdateItems("新增 邮箱","可在此处查看自己的学生邮箱,用于接收高校优惠的验证码", UpdateType.ADD) - UpdateItems("修复 校园网在合肥校区的某些Bug", null, UpdateType.FIX) - UpdateItems("优化 部分界面的显示", null, UpdateType.OPTIMIZE) + UpdateItems("新增 节日开屏礼花", null, UpdateType.ADD) + UpdateItems("新增 用户协议", null, UpdateType.ADD) + UpdateItems("新增 底栏转场动画", "位于选项-界面显示,有5种动画自定义", UpdateType.ADD) + UpdateItems("重构 关于", "删减冗余的选项;新增 关于本应用,位于 选项-维护关于", UpdateType.RENEW) + UpdateItems("移除 转场动画时长自定义", "强制所有动画为默认值400ms", UpdateType.DEGREE) } } diff --git a/app/src/main/java/com/hfut/schedule/ui/activity/home/cube/main/SettingsUI.kt b/app/src/main/java/com/hfut/schedule/ui/activity/home/cube/main/SettingsUI.kt index a520431..d8e72e1 100644 --- a/app/src/main/java/com/hfut/schedule/ui/activity/home/cube/main/SettingsUI.kt +++ b/app/src/main/java/com/hfut/schedule/ui/activity/home/cube/main/SettingsUI.kt @@ -39,6 +39,7 @@ import com.hfut.schedule.ui.activity.home.cube.items.NavUIs.NetWorkScreen import com.hfut.schedule.ui.activity.home.cube.items.main.Screen import com.hfut.schedule.ui.activity.home.cube.items.NavUIs.UIScreen import com.hfut.schedule.ui.activity.home.cube.items.subitems.TEST +import com.hfut.schedule.ui.utils.NavigateManager @SuppressLint("SuspiciousIndentation", "UnusedMaterial3ScaffoldPaddingParameter") @OptIn(ExperimentalMaterial3Api::class) @@ -73,10 +74,10 @@ fun SettingsScreen(vm : NetWorkViewModel navController = navController, startDestination = Screen.HomeScreen.route, enterTransition = { - scaleIn(animationSpec = tween(durationMillis = animation)) + expandVertically(expandFrom = Alignment.CenterVertically,animationSpec = tween(durationMillis = animation)) + NavigateManager.centerAnimation.enter }, exitTransition = { - scaleOut(animationSpec = tween(durationMillis = animation)) + shrinkVertically(shrinkTowards = Alignment.CenterVertically,animationSpec = tween(durationMillis = animation)) + NavigateManager.centerAnimation.exit } ) { diff --git a/app/src/main/java/com/hfut/schedule/ui/activity/home/main/login/LoginSuccessBar.kt b/app/src/main/java/com/hfut/schedule/ui/activity/home/main/login/LoginSuccessBar.kt index 45d2e6c..4c8cb45 100644 --- a/app/src/main/java/com/hfut/schedule/ui/activity/home/main/login/LoginSuccessBar.kt +++ b/app/src/main/java/com/hfut/schedule/ui/activity/home/main/login/LoginSuccessBar.kt @@ -38,6 +38,8 @@ import androidx.compose.material3.TopAppBar import androidx.compose.material3.TopAppBarDefaults import androidx.compose.material3.rememberModalBottomSheetState import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember @@ -67,6 +69,7 @@ import com.hfut.schedule.ui.activity.home.cube.main.SettingsScreen import com.hfut.schedule.ui.activity.home.focus.main.TodayScreen import com.hfut.schedule.logic.enums.BottomBarItems.* import com.hfut.schedule.logic.utils.APPVersion +import com.hfut.schedule.logic.utils.DataStoreManager import com.hfut.schedule.ui.activity.home.calendar.communtiy.CourseDetailApi import com.hfut.schedule.ui.activity.home.calendar.jxglstu.CalendarScreen import com.hfut.schedule.ui.activity.home.main.saved.texts @@ -84,6 +87,9 @@ import com.hfut.schedule.ui.activity.home.search.functions.notifications.getNoti import com.hfut.schedule.ui.activity.home.search.functions.totalCourse.CourseTotalForApi import com.hfut.schedule.ui.activity.home.search.functions.webLab.LabUI import com.hfut.schedule.ui.activity.home.search.main.SearchFuncs +import com.hfut.schedule.ui.utils.NavigateManager +import com.hfut.schedule.ui.utils.NavigateManager.currentPage +import com.hfut.schedule.ui.utils.NavigateManager.turnToAndClear import com.hfut.schedule.ui.utils.components.CustomTabRow import com.hfut.schedule.ui.utils.components.DividerText import com.hfut.schedule.ui.utils.components.DividerTextExpandedWith @@ -113,7 +119,7 @@ fun SuccessUI(vm : NetWorkViewModel, grade : String, vm2 : LoginViewModel, vmUI val navController = rememberNavController() var isEnabled by remember { mutableStateOf(false) } var showlable by remember { mutableStateOf(switch) } - var bottomBarItems by remember { mutableStateOf(COURSES) } + val hazeState = remember { HazeState() } var showBadge by remember { mutableStateOf(false) } if (getUpdates().version != APPVersion.getVersionName()) showBadge = true @@ -184,9 +190,12 @@ fun SuccessUI(vm : NetWorkViewModel, grade : String, vm2 : LoginViewModel, vmUI } } + + + var swapUI by remember { mutableStateOf(JXGLSTU) } var isFriend by remember { mutableStateOf(false) } - + var bottomBarItems by remember { mutableStateOf(COURSES) } val sheetState_multi = rememberModalBottomSheetState(skipPartiallyExpanded = true) var showBottomSheet_multi by remember { mutableStateOf(false) } if (showBottomSheet_multi) { @@ -212,8 +221,14 @@ fun SuccessUI(vm : NetWorkViewModel, grade : String, vm2 : LoginViewModel, vmUI var today by remember { mutableStateOf(LocalDate.now()) } - var searchText by remember { mutableStateOf("") } + var searchText by remember { mutableStateOf("") } + val currentAnimationIndex by DataStoreManager.animationTypeFlow.collectAsState(initial = 0) + if(currentAnimationIndex == 2) { + LaunchedEffect(bottomBarItems) { + currentPage = bottomBarItems.page + } + } Scaffold( modifier = Modifier.fillMaxSize(), @@ -341,18 +356,14 @@ fun SuccessUI(vm : NetWorkViewModel, grade : String, vm2 : LoginViewModel, vmUI enabled = isEnabled, onClick = { saveString("tip","0000") - if(item == items[0]) bottomBarItems = COURSES - if(item == items[1]) bottomBarItems = FOCUS - if(item == items[2]) bottomBarItems = SEARCH - if(item == items[3]) bottomBarItems = SETTINGS + when(item) { + items[0] -> bottomBarItems = COURSES + items[1] -> bottomBarItems = FOCUS + items[2] -> bottomBarItems = SEARCH + items[3] -> bottomBarItems = SETTINGS + } if (!selected) { - navController.navigate(route) { - popUpTo(navController.graph.startDestinationId) { - saveState = true - } - launchSingleTop = true - restoreState = true - } + turnToAndClear(navController,route) } }, label = { Text(text = item.label) }, @@ -370,16 +381,12 @@ fun SuccessUI(vm : NetWorkViewModel, grade : String, vm2 : LoginViewModel, vmUI } } ) { innerPadding -> + val animation = NavigateManager.getAnimationType(currentAnimationIndex,bottomBarItems.page) + NavHost(navController = navController, startDestination = COURSES.name, - enterTransition = { - scaleIn(animationSpec = tween(durationMillis = animation)) + - expandVertically(expandFrom = Alignment.Top,animationSpec = tween(durationMillis = animation)) - }, - exitTransition = { - scaleOut(animationSpec = tween(durationMillis = animation)) + - shrinkVertically(shrinkTowards = Alignment.Top,animationSpec = tween(durationMillis = animation)) - }, + enterTransition = { animation.enter }, + exitTransition = { animation.exit }, modifier = Modifier .haze( state = hazeState, diff --git a/app/src/main/java/com/hfut/schedule/ui/activity/home/main/saved/SavedUIBar.kt b/app/src/main/java/com/hfut/schedule/ui/activity/home/main/saved/SavedUIBar.kt index 7bfc997..591c696 100644 --- a/app/src/main/java/com/hfut/schedule/ui/activity/home/main/saved/SavedUIBar.kt +++ b/app/src/main/java/com/hfut/schedule/ui/activity/home/main/saved/SavedUIBar.kt @@ -42,6 +42,8 @@ import androidx.compose.material3.TopAppBar import androidx.compose.material3.TopAppBarDefaults import androidx.compose.material3.rememberModalBottomSheetState import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember @@ -69,6 +71,7 @@ import com.hfut.schedule.logic.enums.BottomBarItems.* import com.hfut.schedule.logic.beans.NavigationBarItemData import com.hfut.schedule.logic.utils.APPVersion import com.hfut.schedule.logic.utils.AndroidVersion.canBlur +import com.hfut.schedule.logic.utils.DataStoreManager import com.hfut.schedule.logic.utils.DateTimeManager import com.hfut.schedule.logic.utils.DateTimeManager.Benweeks import com.hfut.schedule.logic.utils.DateTimeManager.Date_MM_dd @@ -92,6 +95,11 @@ import com.hfut.schedule.ui.activity.home.search.functions.totalCourse.CourseTot import com.hfut.schedule.ui.activity.home.search.functions.webLab.LabUI import com.hfut.schedule.ui.activity.home.search.main.SearchFuncs import com.hfut.schedule.ui.activity.home.search.main.SearchScreen +import com.hfut.schedule.ui.activity.login.First +import com.hfut.schedule.ui.utils.NavigateManager +import com.hfut.schedule.ui.utils.NavigateManager.ANIMATION_SPEED +import com.hfut.schedule.ui.utils.NavigateManager.currentPage +import com.hfut.schedule.ui.utils.NavigateManager.turnToAndClear import com.hfut.schedule.ui.utils.components.CustomTabRow import com.hfut.schedule.ui.utils.components.DividerText import com.hfut.schedule.ui.utils.components.DividerTextExpandedWith @@ -124,7 +132,7 @@ fun NoNetWork(vm : NetWorkViewModel, vm2 : LoginViewModel, vmUI : UIViewModel) { var showlable by remember { mutableStateOf(switch) } val hazeState = remember { HazeState() } - var bottomBarItems by remember { mutableStateOf(FOCUS) } +// var bottomBarItems by remember { mutableStateOf(FOCUS) } var showBadge by remember { mutableStateOf(false) } if (getUpdates().version != APPVersion.getVersionName()) showBadge = true val switchblur = prefs.getBoolean("SWITCHBLUR", canBlur) @@ -134,13 +142,19 @@ fun NoNetWork(vm : NetWorkViewModel, vm2 : LoginViewModel, vmUI : UIViewModel) { //if (savenum != getnum) showBadge2 = true val animation by remember { mutableStateOf(prefs.getInt("ANIMATION", MyApplication.Animation)) } + + //Log.d("动画",animation.toString()) //判定是否以聚焦作为第一页 - val first : String = when (prefs.getBoolean("SWITCHFOCUS",true)) { - true -> FOCUS.name - false -> COURSES.name + val first = when (prefs.getBoolean("SWITCHFOCUS",true)) { + true -> FOCUS + false -> COURSES } + // 按下底栏按钮后,要准备去的导航 + var targetPage by remember { mutableStateOf(first) } + // 记录上一个 + var showAll by remember { mutableStateOf(false) } var findCourse by remember { mutableStateOf(false) } @@ -210,7 +224,7 @@ fun NoNetWork(vm : NetWorkViewModel, vm2 : LoginViewModel, vmUI : UIViewModel) { } } } - + val currentAnimationIndex by DataStoreManager.animationTypeFlow.collectAsState(initial = 0) if (showBottomSheet_multi) { ModalBottomSheet(onDismissRequest = { showBottomSheet_multi = false }, sheetState = sheetState_multi, modifier = Modifier, @@ -250,6 +264,14 @@ fun NoNetWork(vm : NetWorkViewModel, vm2 : LoginViewModel, vmUI : UIViewModel) { var showSearch by remember { mutableStateOf(false) } vmUI.findNewCourse.observeForever(Observer) if(findCourse) vmUI.findNewCourse.removeObserver(Observer) + + // 保存上一页页码 用于决定左右动画 + if(currentAnimationIndex == 2) { + LaunchedEffect(targetPage) { + currentPage = targetPage.page + } + } + Scaffold( modifier = Modifier.fillMaxSize(), //.blur(blurRadius, BlurredEdgeTreatment.Unbounded), @@ -264,8 +286,8 @@ fun NoNetWork(vm : NetWorkViewModel, vm2 : LoginViewModel, vmUI : UIViewModel) { ), title = { - if(bottomBarItems != SEARCH) { - ScrollText(texts(bottomBarItems)) + if(targetPage != SEARCH) { + ScrollText(texts(targetPage)) } else { if(!showSearch) { ScrollText(texts(SEARCH)) @@ -277,7 +299,7 @@ fun NoNetWork(vm : NetWorkViewModel, vm2 : LoginViewModel, vmUI : UIViewModel) { } }, actions = { - when(bottomBarItems){ + when(targetPage){ COURSES -> { CourseTotalForApi(vm=vm, isIconOrText = true) IconButton(onClick = { @@ -327,7 +349,7 @@ fun NoNetWork(vm : NetWorkViewModel, vm2 : LoginViewModel, vmUI : UIViewModel) { // if(bottomBarItems != FOCUS) // Divider() // } - when(bottomBarItems){ + when(targetPage){ COURSES -> ScheduleTopDate(showAll,today,blur) FOCUS -> CustomTabRow(pagerState, titles, blur) // SEARCH -> SearchFuncs() @@ -367,19 +389,14 @@ fun NoNetWork(vm : NetWorkViewModel, vm2 : LoginViewModel, vmUI : UIViewModel) { modifier = Modifier.scale(scale.value), interactionSource = interactionSource, onClick = { - if(item == items[0]) bottomBarItems = COURSES - if(item == items[1]) bottomBarItems = FOCUS - if(item == items[2]) bottomBarItems = SEARCH - if(item == items[3]) bottomBarItems = SETTINGS - // atEnd = !atEnd + when(item) { + items[0] -> targetPage = COURSES + items[1] -> targetPage = FOCUS + items[2] -> targetPage = SEARCH + items[3] -> targetPage = SETTINGS + } if (!selected) { - navController.navigate(route) { - popUpTo(navController.graph.startDestinationId) { - saveState = true - } - launchSingleTop = true - restoreState = true - } + turnToAndClear(navController,route) } }, label = { Text(text = item.label) }, @@ -397,23 +414,15 @@ fun NoNetWork(vm : NetWorkViewModel, vm2 : LoginViewModel, vmUI : UIViewModel) { } } ) { innerPadding -> + val animation = NavigateManager.getAnimationType(currentAnimationIndex,targetPage.page) NavHost( navController = navController, - startDestination = first, - enterTransition = { - // fadeIn(animationSpec = tween(durationMillis = animation)) + - scaleIn(animationSpec = tween(durationMillis = animation)) + - expandVertically(expandFrom = Alignment.Top,animationSpec = tween(durationMillis = animation)) - }, - exitTransition = { - // fadeOut(animationSpec = tween(durationMillis = animation)) + - scaleOut(animationSpec = tween(durationMillis = animation)) + - shrinkVertically(shrinkTowards = Alignment.Top,animationSpec = tween(durationMillis = animation)) - }, + startDestination = first.name, + enterTransition = { animation.enter }, + exitTransition = { animation.exit }, modifier = Modifier .haze( state = hazeState, - //backgroundColor = MaterialTheme.colorScheme.surface, )) { composable(COURSES.name) { Scaffold(modifier = Modifier.pointerInput(Unit) { diff --git a/app/src/main/java/com/hfut/schedule/ui/activity/login/LoginUI.kt b/app/src/main/java/com/hfut/schedule/ui/activity/login/LoginUI.kt index ad19444..f216892 100644 --- a/app/src/main/java/com/hfut/schedule/ui/activity/login/LoginUI.kt +++ b/app/src/main/java/com/hfut/schedule/ui/activity/login/LoginUI.kt @@ -16,8 +16,12 @@ import androidx.compose.animation.core.Spring import androidx.compose.animation.core.animateFloatAsState import androidx.compose.animation.core.spring import androidx.compose.animation.core.tween +import androidx.compose.animation.expandVertically import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut +import androidx.compose.animation.scaleIn +import androidx.compose.animation.scaleOut +import androidx.compose.animation.shrinkVertically import androidx.compose.animation.with import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.interaction.collectIsPressedAsState @@ -77,6 +81,9 @@ import androidx.compose.ui.text.style.TextDecoration import androidx.compose.ui.unit.IntSize import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp +import androidx.navigation.compose.NavHost +import androidx.navigation.compose.composable +import androidx.navigation.compose.rememberNavController import com.hfut.schedule.App.MyApplication import com.hfut.schedule.R import com.hfut.schedule.viewmodel.LoginViewModel @@ -90,6 +97,7 @@ import com.hfut.schedule.logic.utils.SharePrefs.saveString import com.hfut.schedule.logic.utils.SharePrefs.prefs import com.hfut.schedule.logic.utils.Starter.noLogin import com.hfut.schedule.ui.activity.home.cube.items.main.FirstCube +import com.hfut.schedule.ui.utils.NavigateManager.ANIMATION_SPEED import com.hfut.schedule.ui.utils.components.MyToast import com.hfut.schedule.ui.utils.style.Round import kotlinx.coroutines.CoroutineScope @@ -186,8 +194,17 @@ fun SavedClick() { } else noLogin() } +// +//@Composable +//fun FirstUI(vm: LoginViewModel) { +// +//} + +enum class First { + HOME,USE_AGREEMENT +} + -@RequiresApi(Build.VERSION_CODES.O) @SuppressLint("SuspiciousIndentation") @OptIn(ExperimentalMaterial3Api::class) @Composable @@ -201,6 +218,7 @@ fun LoginUI(vm : LoginViewModel) { // val hazeState = remember { HazeState() } + if (showBottomSheet) { ModalBottomSheet( onDismissRequest = { @@ -279,7 +297,6 @@ fun LoginUI(vm : LoginViewModel) { .padding(innerPadding) .fillMaxSize()) { TwoTextField(vm) - //Text(text = "欢迎使用") } } } @@ -288,7 +305,7 @@ fun LoginUI(vm : LoginViewModel) { @Composable fun AnimatedWelcomeScreen() { val welcomeTexts = listOf( - "你好", "(。・ω・)ノ゙", "欢迎使用", "ヾ(*゚▽゚)ノ", "Hello","(^-^*)", "Hola", "U。・x・)ノ", "Bonjour","\(≧▽≦)/" + "你好", "(。・ω・)ノ゙", "欢迎使用", "ヾ(*゚▽゚)ノ","Hello", "*。٩(ˊωˋ*)و✧*。","Hola", "(⸝•̀֊•́⸝)", "Bonjour","\(≧▽≦)/" ) var currentIndex by remember { mutableStateOf(0) } LaunchedEffect(Unit) { diff --git a/app/src/main/java/com/hfut/schedule/ui/activity/login/UssAgreement.kt b/app/src/main/java/com/hfut/schedule/ui/activity/login/UssAgreement.kt new file mode 100644 index 0000000..590e539 --- /dev/null +++ b/app/src/main/java/com/hfut/schedule/ui/activity/login/UssAgreement.kt @@ -0,0 +1,187 @@ +package com.hfut.schedule.ui.activity.login + +import android.app.Activity +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.material3.Button +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.FilledTonalButton +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.LargeTopAppBar +import androidx.compose.material3.ListItem +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBarDefaults +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.dp +import androidx.navigation.NavHostController +import com.hfut.schedule.R +import com.hfut.schedule.logic.utils.AndroidVersion.canBlur +import com.hfut.schedule.logic.utils.SharePrefs +import com.hfut.schedule.logic.utils.SharePrefs.prefs +import com.hfut.schedule.ui.utils.NavigateManager +import com.hfut.schedule.ui.utils.components.MyToast +import com.hfut.schedule.ui.utils.style.bottomBarBlur +import com.hfut.schedule.ui.utils.style.topBarBlur +import dev.chrisbanes.haze.HazeState +import dev.chrisbanes.haze.haze +import nl.dionsegijn.konfetti.compose.KonfettiView +import nl.dionsegijn.konfetti.core.Party +import nl.dionsegijn.konfetti.core.Position +import nl.dionsegijn.konfetti.core.emitter.Emitter +import java.util.concurrent.TimeUnit + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +//@Preview +fun UseAgreementUI(navController : NavHostController) { + val hazeState = remember { HazeState() } + val switchblur = prefs.getBoolean("SWITCHBLUR", canBlur) + var blur by remember { mutableStateOf(switchblur) } + + + val argeements = listOf( + "本应用所使用权限为:网络、日历(用于向日历写入聚焦日程)、存储(用于导入导出课程表文件)、相机(用于洗浴扫码),均由用户自由决定是否授予", + "本应用已在Github开源,F-Droid上架,无任何盈利、广告、恶意等行为", + "本应用不代表学校官方,如侵害到您的权益请联系邮件zsh0908@outlook.com", + "本应用推荐但不限于合肥工业大学宣城校区在校生使用,不对未登录用户做强制要求,可通过游客模式进入", + "本应用存在开发者自己的服务端,会收集一些不敏感的数据帮助改善使用体验,开发者承诺不会泄露数据,且用户可自由选择开启与否", + "开发者只负责分发由自己签名的版本(签名为O=Chiu xaH ST=Anhui L=Xuancheng),其他签名版本不对此负责", + "最后编辑于 2025-01-29 22:11 v1" + ) + val developerInfo = mapOf( + "contact" to "zsh0908@outlook.com", + "github" to "Chiu-xaH", + "profile" to "一名热爱安卓的开发者,宣城校区23级计算机科学与技术专业(转)本科生" + ) + val context = LocalContext.current + + val partyTopStart = Party( + emitter = Emitter(duration = 1, TimeUnit.SECONDS).perSecond(30), + position = Position.Relative(0.0,0.0) + ) + val partyTopEnd = Party( + emitter = Emitter(duration = 1, TimeUnit.SECONDS).perSecond(30), + position = Position.Relative(1.0,0.0) + ) + val partyBottomStart = Party( + emitter = Emitter(duration = 1, TimeUnit.SECONDS).perSecond(30), + position = Position.Relative(0.0,1.0) + ) + val partyBottomEnd = Party( + emitter = Emitter(duration = 1, TimeUnit.SECONDS).perSecond(30), + position = Position.Relative(1.0,1.0) + ) + + Box(modifier = Modifier.fillMaxSize()) { + KonfettiView( + modifier = Modifier.fillMaxSize(), + parties = listOf(partyTopStart,partyTopEnd,partyBottomStart,partyBottomEnd), + ) + androidx.compose.material3.Scaffold( + topBar = { + LargeTopAppBar( + colors = TopAppBarDefaults.mediumTopAppBarColors( + containerColor = Color.Transparent, + titleContentColor = MaterialTheme.colorScheme.primary, + ), + title = { + Box(modifier = Modifier.fillMaxWidth()) { + Text( + text = "用户协议", + modifier = Modifier.fillMaxWidth(), + textAlign = TextAlign.Center, + //style = MaterialTheme.typography.titleLarge + ) + } + }, + actions = { + // Row { + IconButton(onClick = { + (context as? Activity)?.finish() + }) { + Icon( + painterResource(id = R.drawable.close), + contentDescription = "", + tint = MaterialTheme.colorScheme.primary + ) + } + // Text(text = " ") + /// } + + }, + navigationIcon = { + AnimatedWelcomeScreen() + }, + modifier = Modifier.topBarBlur(hazeState,blur) + ) + }, + bottomBar = { + Box(modifier = Modifier.bottomBarBlur(hazeState, blur)) { + Row(modifier = Modifier.padding(15.dp),horizontalArrangement = Arrangement.Center) { + Button( + onClick = { + SharePrefs.saveBoolean("canUse", default = false, save = true) + NavigateManager.turnToAndClear(navController, First.HOME.name) + }, + modifier = Modifier + .fillMaxWidth() + .weight(.5f) + ) { + Text("同意") + } + Spacer(modifier = Modifier.width(15.dp)) + FilledTonalButton( + onClick = { + MyToast("已关闭APP") + (context as Activity).finish() + }, + modifier = Modifier + .fillMaxWidth() + .weight(.5f) + ) { + SharePrefs.saveBoolean("canUse", default = false, save = false) + Text("拒绝") + } + } + } + }, + ) { innerPadding -> + Column( + modifier = Modifier + .fillMaxSize().haze(hazeState) + ) { + LazyColumn { + item { Spacer(modifier = Modifier.height(innerPadding.calculateTopPadding())) } + items(argeements.size) { index -> + val item = argeements[index] + ListItem( + headlineContent = { Text(item) }, + leadingContent = { Text((index+1).toString()) } + ) + } + item { Spacer(modifier = Modifier.height(innerPadding.calculateBottomPadding())) } + } + } + } + } +} diff --git a/app/src/main/java/com/hfut/schedule/ui/activity/news/main/NewsActivityUI.kt b/app/src/main/java/com/hfut/schedule/ui/activity/news/main/NewsActivityUI.kt index 461c4f7..a18f4fd 100644 --- a/app/src/main/java/com/hfut/schedule/ui/activity/news/main/NewsActivityUI.kt +++ b/app/src/main/java/com/hfut/schedule/ui/activity/news/main/NewsActivityUI.kt @@ -38,7 +38,6 @@ import androidx.compose.material.icons.filled.Close import androidx.compose.material.icons.filled.Search import androidx.compose.material3.AssistChip import androidx.compose.material3.BadgedBox -import androidx.compose.material3.CircularProgressIndicator import com.hfut.schedule.ui.utils.components.LoadingUI import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExtendedFloatingActionButton @@ -55,6 +54,8 @@ import androidx.compose.material3.TextFieldDefaults import androidx.compose.material3.TopAppBar import androidx.compose.material3.TopAppBarDefaults import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember @@ -76,12 +77,17 @@ import com.hfut.schedule.viewmodel.NetWorkViewModel import com.hfut.schedule.logic.enums.NewsBarItems import com.hfut.schedule.logic.beans.NavigationBarItemData import com.hfut.schedule.logic.utils.AndroidVersion +import com.hfut.schedule.logic.utils.DataStoreManager import com.hfut.schedule.logic.utils.Encrypt import com.hfut.schedule.logic.utils.SharePrefs -import com.hfut.schedule.ui.activity.card.function.main.turnToBottomBar +//import com.hfut.schedule.ui.activity.card.function.main.turnToBottomBar import com.hfut.schedule.ui.activity.news.home.NewsItem import com.hfut.schedule.ui.activity.news.departments.SchoolsUI import com.hfut.schedule.ui.activity.news.xuancheng.XuanquNewsUI +import com.hfut.schedule.ui.utils.NavigateManager +import com.hfut.schedule.ui.utils.NavigateManager.currentPage +import com.hfut.schedule.ui.utils.NavigateManager.turnTo +import com.hfut.schedule.ui.utils.NavigateManager.turnToAndClear import com.hfut.schedule.ui.utils.components.MyToast import com.hfut.schedule.ui.utils.style.bottomBarBlur import com.hfut.schedule.ui.utils.style.topBarBlur @@ -104,7 +110,18 @@ fun NewsActivityUI(vm: NetWorkViewModel) { val switchblur = SharePrefs.prefs.getBoolean("SWITCHBLUR", AndroidVersion.canBlur) val blur by remember { mutableStateOf(switchblur) } val hazeState = remember { HazeState() } - var bottomBarItems by remember { mutableStateOf(NewsBarItems.News) } +// var bottomBarItems by remember { mutableStateOf(NewsBarItems.News) } + val currentAnimationIndex by DataStoreManager.animationTypeFlow.collectAsState(initial = 0) + var targetPage by remember { mutableStateOf(NewsBarItems.News) } + // 保存上一页页码 用于决定左右动画 + if(currentAnimationIndex == 2) { + LaunchedEffect(targetPage) { + currentPage = targetPage.page + } + } + + + Scaffold( modifier = Modifier.fillMaxSize(), topBar = { @@ -117,7 +134,7 @@ fun NewsActivityUI(vm: NetWorkViewModel) { ), title = { Text("通知公告") }, actions = { - if(bottomBarItems == NewsBarItems.XuanCheng) { + if(targetPage == NewsBarItems.XuanCheng) { IconButton(onClick = { MyToast("正在开发") }) { @@ -173,13 +190,15 @@ fun NewsActivityUI(vm: NetWorkViewModel) { interactionSource = interactionSource, onClick = { // atEnd = !atEnd - bottomBarItems = when(item) { - items[0] -> NewsBarItems.News - items[1] -> NewsBarItems.XuanCheng - items[2] -> NewsBarItems.School - else -> NewsBarItems.News + if(currentAnimationIndex == 2) { + targetPage = when(item) { + items[0] -> NewsBarItems.News + items[1] -> NewsBarItems.XuanCheng + items[2] -> NewsBarItems.School + else -> NewsBarItems.News + } } - if (!selected) { turnToBottomBar(navController, route) } + if (!selected) { turnToAndClear(navController, route) } }, label = { Text(text = item.label) }, icon = { @@ -192,16 +211,13 @@ fun NewsActivityUI(vm: NetWorkViewModel) { } ) {innerPadding -> + + val animation = NavigateManager.getAnimationType(currentAnimationIndex,targetPage.page) + NavHost(navController = navController, startDestination = NewsBarItems.News.name, - enterTransition = { - scaleIn(animationSpec = tween(durationMillis = animation)) + - expandVertically(expandFrom = Alignment.Top,animationSpec = tween(durationMillis = animation)) - }, - exitTransition = { - scaleOut(animationSpec = tween(durationMillis = animation)) + - shrinkVertically(shrinkTowards = Alignment.Top,animationSpec = tween(durationMillis = animation)) - }, + enterTransition = { animation.enter }, + exitTransition = { animation.exit }, modifier = Modifier.haze(state = hazeState)) { composable(NewsBarItems.News.name) { Scaffold { diff --git a/app/src/main/java/com/hfut/schedule/ui/activity/nologin/NoLoginUI.kt b/app/src/main/java/com/hfut/schedule/ui/activity/nologin/NoLoginUI.kt index 5f56a4c..f1f2fa4 100644 --- a/app/src/main/java/com/hfut/schedule/ui/activity/nologin/NoLoginUI.kt +++ b/app/src/main/java/com/hfut/schedule/ui/activity/nologin/NoLoginUI.kt @@ -36,6 +36,8 @@ import androidx.compose.material3.TopAppBar import androidx.compose.material3.TopAppBarDefaults import androidx.compose.material3.rememberModalBottomSheetState import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember @@ -56,6 +58,7 @@ import com.hfut.schedule.logic.beans.NavigationBarItemData import com.hfut.schedule.logic.enums.BottomBarItems import com.hfut.schedule.logic.utils.APPVersion import com.hfut.schedule.logic.utils.AndroidVersion +import com.hfut.schedule.logic.utils.DataStoreManager import com.hfut.schedule.logic.utils.SharePrefs import com.hfut.schedule.logic.utils.Starter import com.hfut.schedule.ui.activity.home.cube.items.subitems.MyAPIItem @@ -66,6 +69,9 @@ import com.hfut.schedule.ui.activity.home.search.functions.notifications.Notific import com.hfut.schedule.ui.activity.home.search.functions.notifications.getNotifications import com.hfut.schedule.ui.activity.home.search.functions.webLab.LabUI import com.hfut.schedule.ui.activity.home.search.main.SearchFuncs +import com.hfut.schedule.ui.utils.NavigateManager +import com.hfut.schedule.ui.utils.NavigateManager.currentPage +import com.hfut.schedule.ui.utils.NavigateManager.turnToAndClear import com.hfut.schedule.ui.utils.components.CustomTabRow import com.hfut.schedule.ui.utils.components.DividerText import com.hfut.schedule.ui.utils.components.DividerTextExpandedWith @@ -93,7 +99,6 @@ fun NoLoginUI(vm : NetWorkViewModel,vm2 : LoginViewModel,vmUI : UIViewModel) { var showlable by remember { mutableStateOf(switch) } val hazeState = remember { HazeState() } - var bottomBarItems by remember { mutableStateOf(BottomBarItems.SEARCH) } var showBadge by remember { mutableStateOf(false) } if (getUpdates().version != APPVersion.getVersionName()) showBadge = true val switchblur = SharePrefs.prefs.getBoolean("SWITCHBLUR", AndroidVersion.canBlur) @@ -101,8 +106,9 @@ fun NoLoginUI(vm : NetWorkViewModel,vm2 : LoginViewModel,vmUI : UIViewModel) { val animation by remember { mutableStateOf(SharePrefs.prefs.getInt("ANIMATION", MyApplication.Animation)) } - val first : String = BottomBarItems.SEARCH.name + val first = BottomBarItems.SEARCH + var bottomBarItems by remember { mutableStateOf(first) } val sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true) @@ -112,6 +118,13 @@ fun NoLoginUI(vm : NetWorkViewModel,vm2 : LoginViewModel,vmUI : UIViewModel) { CoroutineScope(Job()).launch { NetWorkUpdateNoLogin(vm2) } + val currentAnimationIndex by DataStoreManager.animationTypeFlow.collectAsState(initial = 0) +// var targetPage by remember { mutableStateOf(FixBarItems.Fix) } + // 保存上一页页码 用于决定左右动画 + LaunchedEffect(bottomBarItems) { + currentPage = bottomBarItems.page + } + if (showBottomSheet) { @@ -273,13 +286,7 @@ fun NoLoginUI(vm : NetWorkViewModel,vm2 : LoginViewModel,vmUI : UIViewModel) { if(item == items[2]) bottomBarItems = BottomBarItems.SETTINGS // atEnd = !atEnd if (!selected) { - navController.navigate(route) { - popUpTo(navController.graph.startDestinationId) { - saveState = true - } - launchSingleTop = true - restoreState = true - } + turnToAndClear(navController,route) } }, label = { Text(text = item.label) }, @@ -297,19 +304,13 @@ fun NoLoginUI(vm : NetWorkViewModel,vm2 : LoginViewModel,vmUI : UIViewModel) { } } ) { innerPadding -> + val animation = NavigateManager.getAnimationType(currentAnimationIndex,bottomBarItems.page) + NavHost( navController = navController, - startDestination = first, - enterTransition = { - // fadeIn(animationSpec = tween(durationMillis = animation)) + - scaleIn(animationSpec = tween(durationMillis = animation)) + - expandVertically(expandFrom = Alignment.Top,animationSpec = tween(durationMillis = animation)) - }, - exitTransition = { - // fadeOut(animationSpec = tween(durationMillis = animation)) + - scaleOut(animationSpec = tween(durationMillis = animation)) + - shrinkVertically(shrinkTowards = Alignment.Top,animationSpec = tween(durationMillis = animation)) - }, + startDestination = first.name, + enterTransition = { animation.enter }, + exitTransition = { animation.exit }, modifier = Modifier .haze( state = hazeState, diff --git a/app/src/main/java/com/hfut/schedule/ui/activity/shower/main/ShowerGuaguaUI.kt b/app/src/main/java/com/hfut/schedule/ui/activity/shower/main/ShowerGuaguaUI.kt index 35eb1ff..ed33f16 100644 --- a/app/src/main/java/com/hfut/schedule/ui/activity/shower/main/ShowerGuaguaUI.kt +++ b/app/src/main/java/com/hfut/schedule/ui/activity/shower/main/ShowerGuaguaUI.kt @@ -28,9 +28,12 @@ import androidx.compose.material3.Text import androidx.compose.material3.TopAppBar import androidx.compose.material3.TopAppBarDefaults import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.scale @@ -47,11 +50,16 @@ import com.hfut.schedule.viewmodel.GuaGuaViewModel import com.hfut.schedule.logic.enums.ShowerBarItems import com.hfut.schedule.logic.beans.NavigationBarItemData import com.hfut.schedule.logic.utils.AndroidVersion +import com.hfut.schedule.logic.utils.DataStoreManager import com.hfut.schedule.logic.utils.SharePrefs -import com.hfut.schedule.ui.activity.card.function.main.turnToBottomBar +//import com.hfut.schedule.ui.activity.card.function.main.turnToBottomBar import com.hfut.schedule.ui.activity.shower.bills.GuaguaBills import com.hfut.schedule.ui.activity.shower.function.GuaGuaSettings import com.hfut.schedule.ui.activity.shower.home.main.GuaguaStart +import com.hfut.schedule.ui.utils.NavigateManager +import com.hfut.schedule.ui.utils.NavigateManager.currentPage +import com.hfut.schedule.ui.utils.NavigateManager.turnTo +import com.hfut.schedule.ui.utils.NavigateManager.turnToAndClear import com.hfut.schedule.ui.utils.style.bottomBarBlur import com.hfut.schedule.ui.utils.style.topBarBlur import com.hfut.schedule.viewmodel.NetWorkViewModel @@ -68,6 +76,17 @@ fun ShowerGuaGua(vm: GuaGuaViewModel,netVm : NetWorkViewModel) { val switchblur = SharePrefs.prefs.getBoolean("SWITCHBLUR", AndroidVersion.canBlur) val blur by remember { mutableStateOf(switchblur) } val hazeState = remember { HazeState() } + + val currentAnimationIndex by DataStoreManager.animationTypeFlow.collectAsState(initial = 0) + var targetPage by remember { mutableStateOf(ShowerBarItems.HOME) } + // 保存上一页页码 用于决定左右动画 + if(currentAnimationIndex == 2) { + LaunchedEffect(targetPage) { + currentPage = targetPage.page + } + } + + Scaffold( modifier = Modifier.fillMaxSize(), topBar = { @@ -129,7 +148,14 @@ fun ShowerGuaGua(vm: GuaGuaViewModel,netVm : NetWorkViewModel) { interactionSource = interactionSource, onClick = { // atEnd = !atEnd - if (!selected) { turnToBottomBar(navController, route) } + if(currentAnimationIndex == 2) { + when(item) { + items[0] -> targetPage = ShowerBarItems.HOME + items[1] -> targetPage = ShowerBarItems.BILLS + items[2] -> targetPage = ShowerBarItems.FUNCTION + } + } + if (!selected) { turnToAndClear(navController, route) } }, label = { Text(text = item.label) }, icon = { @@ -142,16 +168,12 @@ fun ShowerGuaGua(vm: GuaGuaViewModel,netVm : NetWorkViewModel) { } ) {innerPadding -> + val animation = NavigateManager.getAnimationType(currentAnimationIndex,targetPage.page) + NavHost(navController = navController, startDestination = ShowerBarItems.HOME.name, - enterTransition = { - scaleIn(animationSpec = tween(durationMillis = animation)) + - expandVertically(expandFrom = Alignment.Top,animationSpec = tween(durationMillis = animation)) - }, - exitTransition = { - scaleOut(animationSpec = tween(durationMillis = animation)) + - shrinkVertically(shrinkTowards = Alignment.Top,animationSpec = tween(durationMillis = animation)) - }, + enterTransition = { animation.enter }, + exitTransition = { animation.exit }, modifier = Modifier .haze( state = hazeState, diff --git a/app/src/main/java/com/hfut/schedule/ui/utils/NavigateManager.kt b/app/src/main/java/com/hfut/schedule/ui/utils/NavigateManager.kt index cf33ed7..65d1740 100644 --- a/app/src/main/java/com/hfut/schedule/ui/utils/NavigateManager.kt +++ b/app/src/main/java/com/hfut/schedule/ui/utils/NavigateManager.kt @@ -1,9 +1,56 @@ package com.hfut.schedule.ui.utils +//import androidx.compose.animation.AnimatedVisibility +import androidx.compose.animation.EnterTransition +import androidx.compose.animation.ExitTransition +import androidx.compose.animation.core.tween +import androidx.compose.animation.expandVertically +import androidx.compose.animation.fadeIn +import androidx.compose.animation.fadeOut +import androidx.compose.animation.scaleIn +import androidx.compose.animation.scaleOut +import androidx.compose.animation.shrinkVertically +import androidx.compose.animation.slideInHorizontally +import androidx.compose.animation.slideOutHorizontally +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.lazy.LazyRow +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.CardDefaults +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.OutlinedCard +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp import androidx.navigation.NavHostController +import com.hfut.schedule.logic.utils.DataStoreManager +import com.hfut.schedule.ui.utils.NavigateManager.ANIMATION_SPEED +import com.hfut.schedule.ui.utils.components.DividerTextExpandedWith +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch object NavigateManager { - fun turnToBottomBar(navController : NavHostController, route : String) { + data class TransferAnimation(val remark : String,val enter : EnterTransition, val exit : ExitTransition) + + fun turnTo(navController : NavHostController, route : String) { navController.navigate(route) { popUpTo(navController.graph.startDestinationId) { saveState = true @@ -12,4 +59,117 @@ object NavigateManager { restoreState = true } } -} \ No newline at end of file + + fun turnToAndClear(navController: NavHostController, route: String) { + navController.navigate(route) { + popUpTo(navController.graph.startDestinationId) { + inclusive = true + } + launchSingleTop = true + restoreState = true + } + } + + const val ANIMATION_SPEED = 400 + + private val enterAnimation1 = scaleIn(animationSpec = tween(durationMillis = ANIMATION_SPEED)) + + expandVertically(expandFrom = Alignment.Top,animationSpec = tween(durationMillis = ANIMATION_SPEED)) + private val exitAnimation1 = scaleOut(animationSpec = tween(durationMillis = ANIMATION_SPEED)) + + shrinkVertically(shrinkTowards = Alignment.Top,animationSpec = tween(durationMillis = ANIMATION_SPEED)) + val upDownAnimation = TransferAnimation("底栏吸附",enterAnimation1, exitAnimation1) + + private val enterAnimation2 = scaleIn(animationSpec = tween(durationMillis = ANIMATION_SPEED)) + + expandVertically(expandFrom = Alignment.CenterVertically,animationSpec = tween(durationMillis = ANIMATION_SPEED)) + private val exitAnimation2 = scaleOut(animationSpec = tween(durationMillis = ANIMATION_SPEED)) + + shrinkVertically(shrinkTowards = Alignment.CenterVertically,animationSpec = tween(durationMillis = ANIMATION_SPEED)) + val centerAnimation = TransferAnimation("向中心运动",enterAnimation2, exitAnimation2) + + private val enterAnimationFade = fadeIn(animationSpec = tween(durationMillis = ANIMATION_SPEED)) + + private val exitAnimationFade = fadeOut(animationSpec = tween(durationMillis = ANIMATION_SPEED)) + + val fadeAnimation = TransferAnimation("淡入淡出", enterAnimationFade, exitAnimationFade) + + private val enterAnimationNull = fadeIn(animationSpec = tween(durationMillis = 0)) + + private val exitAnimationNull = fadeOut(animationSpec = tween(durationMillis = 0)) + + val nullAnimation = TransferAnimation("无", enterAnimationNull, exitAnimationNull) + + + // 左右动画 + private val enterAnimationLeft = slideInHorizontally( + initialOffsetX = { fullWidth -> -fullWidth }, + animationSpec = tween(durationMillis = ANIMATION_SPEED) + ) +// + fadeIn(animationSpec = tween(durationMillis = ANIMATION_SPEED)) + + private val exitAnimationLeft = slideOutHorizontally( + targetOffsetX = { fullWidth -> -fullWidth }, + animationSpec = tween(durationMillis = ANIMATION_SPEED) + ) +// + fadeOut(animationSpec = tween(durationMillis = ANIMATION_SPEED)) + + private val leftToRightAnimation = TransferAnimation("从左向右运动", enterAnimationLeft, exitAnimationLeft) + + private val enterAnimationRight = slideInHorizontally( + initialOffsetX = { fullWidth -> fullWidth }, + animationSpec = tween(durationMillis = ANIMATION_SPEED) + ) +// + fadeIn(animationSpec = tween(durationMillis = ANIMATION_SPEED)) + + private val exitAnimationRight = slideOutHorizontally( + targetOffsetX = { fullWidth -> fullWidth }, + animationSpec = tween(durationMillis = ANIMATION_SPEED) + ) +// + fadeOut(animationSpec = tween(durationMillis = ANIMATION_SPEED)) + + private val rightToLeftAnimation = TransferAnimation("从右向左运动", enterAnimationRight, exitAnimationRight) + + + + var currentPage = 0 // 默认值 + /* + 用法 + var targetPage by remember { mutableStateOf(first) } + // 保存上一页页码 用于决定左右动画 + LaunchedEffect(targetPage) { + currentPage = targetPage.page + } + onclick按钮赋予点击: + when(item) { + items[0] -> targetPage = COURSES + items[1] -> targetPage = FOCUS + items[2] -> targetPage = SEARCH + items[3] -> targetPage = SETTINGS + } + if (!selected) { + turnToAndClear(navController,route) + } + */ + + fun getLeftRightAnimation(targetPage : Int) : TransferAnimation { + val enterAnimation3 = if (currentPage > targetPage) { + leftToRightAnimation.enter + } else { + rightToLeftAnimation.enter + } + val exitAnimation3 = if (currentPage > targetPage) { + rightToLeftAnimation.exit + } else { + leftToRightAnimation.exit + } + return TransferAnimation("左右运动",enterAnimation3, exitAnimation3) + } + + fun getAnimationType(index : Int,targetPage: Int = 0) : TransferAnimation { + return when(index) { + 0 -> upDownAnimation + 1 -> centerAnimation + 2 -> getLeftRightAnimation(targetPage) + 3 -> fadeAnimation + 4 -> nullAnimation + else -> upDownAnimation + } + } +} diff --git a/app/src/main/java/com/hfut/schedule/ui/utils/components/PartyAnimation.kt b/app/src/main/java/com/hfut/schedule/ui/utils/components/PartyAnimation.kt new file mode 100644 index 0000000..84f389d --- /dev/null +++ b/app/src/main/java/com/hfut/schedule/ui/utils/components/PartyAnimation.kt @@ -0,0 +1,41 @@ +package com.hfut.schedule.ui.utils.components + +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.zIndex +import nl.dionsegijn.konfetti.compose.KonfettiView +import nl.dionsegijn.konfetti.core.Party +import nl.dionsegijn.konfetti.core.Position +import nl.dionsegijn.konfetti.core.emitter.Emitter +import java.util.concurrent.TimeUnit + +@Composable +fun PartyAnimation(timeSecond : Long = 3,content : @Composable () -> Unit) { + val partyTopStart = Party( + emitter = Emitter(duration = timeSecond, TimeUnit.SECONDS).perSecond(30), + position = Position.Relative(0.0,0.0) + ) + val partyTopEnd = Party( + emitter = Emitter(duration = timeSecond, TimeUnit.SECONDS).perSecond(30), + position = Position.Relative(1.0,0.0) + ) + val partyBottomStart = Party( + emitter = Emitter(duration = timeSecond, TimeUnit.SECONDS).perSecond(30), + position = Position.Relative(0.0,1.0) + ) + val partyBottomEnd = Party( + emitter = Emitter(duration = timeSecond, TimeUnit.SECONDS).perSecond(30), + position = Position.Relative(1.0,1.0) + ) + + Box(modifier = Modifier.fillMaxSize()) { + KonfettiView( + modifier = Modifier.fillMaxSize().zIndex(1f), + parties = listOf(partyTopStart,partyTopEnd,partyBottomStart,partyBottomEnd), + ) + content() + } +} + diff --git "a/markdown/\350\201\232\345\234\250\345\267\245\345\244\247\345\257\222\345\201\207\346\233\264\346\226\260\350\256\241\345\210\222.txt" "b/markdown/\350\201\232\345\234\250\345\267\245\345\244\247\345\257\222\345\201\207\346\233\264\346\226\260\350\256\241\345\210\222.txt" index 370b170..a4ffb96 100644 --- "a/markdown/\350\201\232\345\234\250\345\267\245\345\244\247\345\257\222\345\201\207\346\233\264\346\226\260\350\256\241\345\210\222.txt" +++ "b/markdown/\350\201\232\345\234\250\345\267\245\345\244\247\345\257\222\345\201\207\346\233\264\346\226\260\350\256\241\345\210\222.txt" @@ -1,17 +1,17 @@ 聚在工大寒假更新计划 -1.动效(转场)自定义(技术:封装全局Animation和Blur的Manager,OPP思维)(必做) -3.天气详情、预警聚焦通知(技术:UI设计) +3.天气详情、预警聚焦通知(技术:UI设计) 6.网费缴纳(必做) 10.图书检索翻页、二级界面、更多信息 11.成绩的两个数据源打通(技术:列表匹配)(必做) -12.邮箱 13.课程全局收藏体系(技术:数据库) 14.无感教务登录(技术:功能接口设计) 15.培养方案重写(土木分方向) +1.动效(转场)自定义(技术:封装全局Animation和Blur的Manager,OPP思维)(必做) +12.邮箱 4.下学期课程汇总图标显示Bug(必做) 7.网、电上弹卡片位置优化(必做) 8.课程汇总右上角按钮间距效果优化(必做)