Shamrock/app/src/main/java/moe/fuqiuluo/shamrock/MainActivity.kt

376 lines
14 KiB
Kotlin

@file:OptIn(ExperimentalMaterial3Api::class, ExperimentalFoundationApi::class)
package moe.fuqiuluo.shamrock
import android.annotation.SuppressLint
import android.os.Bundle
import android.widget.Toast
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.annotation.ColorRes
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.core.FastOutLinearInEasing
import androidx.compose.animation.core.FastOutSlowInEasing
import androidx.compose.animation.core.MutableTransitionState
import androidx.compose.animation.core.TweenSpec
import androidx.compose.animation.scaleIn
import androidx.compose.animation.scaleOut
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.LocalIndication
import androidx.compose.foundation.background
import androidx.compose.foundation.indication
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.absolutePadding
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.pager.HorizontalPager
import androidx.compose.foundation.pager.PagerState
import androidx.compose.foundation.pager.rememberPagerState
import androidx.compose.material.ripple.rememberRipple
import androidx.compose.material3.Divider
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Surface
import androidx.compose.material3.TabRow
import androidx.compose.material3.TabRowDefaults
import androidx.compose.material3.TabRowDefaults.tabIndicatorOffset
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults.topAppBarColors
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.shadow
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalView
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.core.view.WindowCompat
import com.google.accompanist.systemuicontroller.rememberSystemUiController
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import moe.fuqiuluo.shamrock.ui.app.AppRuntime
import moe.fuqiuluo.shamrock.ui.app.Level
import moe.fuqiuluo.shamrock.ui.app.Logger
import moe.fuqiuluo.shamrock.ui.app.RuntimeState
import moe.fuqiuluo.shamrock.ui.fragment.DashboardFragment
import moe.fuqiuluo.shamrock.ui.fragment.HomeFragment
import moe.fuqiuluo.shamrock.ui.fragment.LabFragment
import moe.fuqiuluo.shamrock.ui.fragment.LogFragment
import moe.fuqiuluo.shamrock.ui.theme.LocalString
import moe.fuqiuluo.shamrock.ui.theme.ShamrockTheme
import moe.fuqiuluo.shamrock.ui.theme.TabDividerColor
import moe.fuqiuluo.shamrock.ui.theme.TabSelectedColor
import moe.fuqiuluo.shamrock.ui.theme.TabUnSelectedColor
import moe.fuqiuluo.shamrock.ui.theme.ToolbarColor
import moe.fuqiuluo.shamrock.ui.tools.NoIndication
import moe.fuqiuluo.shamrock.ui.tools.ShamrockTab
import java.lang.StringBuilder
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
CompositionLocalProvider(
LocalIndication provides NoIndication
) {
AppMainView()
}
WindowCompat.getInsetsController(window, LocalView.current).apply {
isAppearanceLightStatusBars = true
}
WindowCompat.setDecorFitsSystemWindows(window, true)
}
}
}
@Composable
private fun AppMainView() {
val scope = rememberCoroutineScope()
val ctx = LocalContext.current
val systemUiController = rememberSystemUiController()
val statusBarDarkIcons by remember { mutableStateOf(true) }
val navigationBarDarkIcons by remember { mutableStateOf(true) }
LaunchedEffect(systemUiController, statusBarDarkIcons, navigationBarDarkIcons) {
systemUiController.statusBarDarkContentEnabled = statusBarDarkIcons
systemUiController.navigationBarDarkContentEnabled = navigationBarDarkIcons
systemUiController.setStatusBarColor(Color.White)
}
// Home
val isFined = remember { mutableStateOf(false) }
val coreVersion = remember { mutableStateOf("1.0.0") }
val coreName = remember { mutableStateOf("Xposed") }
val coreCode = remember { mutableIntStateOf(1000) }
AppRuntime.state = remember {
RuntimeState(isFined, coreVersion, coreCode, coreName)
}
AppRuntime.logger = remember {
Logger(mutableStateOf(StringBuilder()), mutableListOf())
}
AppRuntime.AccountInfo.also {
it.uin = remember {
mutableStateOf("unknown")
}
it.nick = remember {
mutableStateOf("unknown")
}
}
@Suppress("LocalVariableName") val LocalString = LocalString
LaunchedEffect(isFined.value) {
if (isFined.value) {
AppRuntime.log("日志框架激活成功,开放操作许可。")
Toast.makeText(ctx, LocalString.frameworkYes, Toast.LENGTH_SHORT).show()
} else {
AppRuntime.log("日志框架处于未激活状态,请检查。")
Toast.makeText(ctx, LocalString.frameworkNo, Toast.LENGTH_SHORT).show()
}
}
//模拟激活事件测试
//LaunchedEffect(systemUiController) {
// delay(5000)
// isFined.value = true
// AppRuntime.AccountInfo.also {
// it.uin.value = "1372362033"
// it.nick.value = "伏秋洛啊~"
// }
//}
ShamrockTheme {
Surface(
modifier = Modifier.fillMaxSize(),
color = Color.White
) {
@Suppress("LocalVariableName") val TitlesWithIcon = LocalString.TitlesWithIcon
val state = rememberPagerState(
pageCount = { TitlesWithIcon.size },
initialPage = 0,
initialPageOffsetFraction = 0f,
)
Scaffold(
topBar = { ToolBar(
title = arrayOf(
"Clover", "CuteKitty", "Shamrock",
"Threeleaf", "CuteCat", "FuckingCat",
"XVideos", "Onlyfans", "Pornhub",
"Xposed", "LittleFox", "Springboot",
"Kotlin", "Rust & Android", "Dashabi",
"YYDS", "Amd Yes", "Gayhub",
"Yuzukkity", "HongKongDoll", "Xinrao"
).random()
) }
) {
val topPadding = it.calculateTopPadding()
Column(
modifier = Modifier
.padding(top = topPadding)
) {
TabRow(
modifier = Modifier
.width(1080.dp)
.background(Color.White)
.absolutePadding(left = 70.dp, right = 70.dp)
,
selectedTabIndex = state.currentPage,
divider = { },
containerColor = Color.White,
indicator = {
TabRowDefaults.Indicator(
Modifier.tabIndicatorOffset(it[state.currentPage]),
color = TabSelectedColor,
height = (3.3).dp
)
},
) {
TitlesWithIcon.forEachIndexed { index, titleWithIcon ->
AnimatedTab(scope, state, index, titleWithIcon)
}
}
Divider(
modifier = Modifier
.shadow(8.dp),
color = Color(0xBFDADADA),
thickness = 0.2.dp
)
HorizontalPager(
modifier = Modifier
.padding(top = 8.dp)
,
state = state,
) { page ->
when(page) {
0 -> HomeFragment(AppRuntime.state)
1 -> AppRuntime.AccountInfo.let {
DashboardFragment(it.nick.value, it.uin.value)
}
2 -> LogFragment(AppRuntime.logger)
3 -> LabFragment()
}
}
}
}
}
}
}
@Composable
private fun ToolBar(title: String) {
TopAppBar(
title = { Column {
Text(
text = title,
color = ToolbarColor,
fontWeight = FontWeight.Bold
)
Text(
text = arrayOf(
"A Framework Base On Xposed",
"今天吃什么好呢?",
"遇事不决,量子力学!",
"Just kkb?",
"いいよ,こいよ",
"伊已逝 吾亦逝",
"忆久意久 把义领",
"喵帕斯!",
"Creeper?",
"Make American Great Again!",
"TXHookPro",
"曾经有人失去了那个她",
"欲买桂花同载酒,终不似,少年游。",
"抚千窟为佑 看长安落花",
"どこにもない",
"春日和 かかってらしゃい"
).random(),
color = ToolbarColor,
fontSize = 14.sp
)
} },
modifier = Modifier
.fillMaxWidth(),
colors = topAppBarColors(
titleContentColor = Color.Black,
containerColor = Color.White,
scrolledContainerColor = Color.White,
navigationIconContentColor = Color.White
)
)
}
private val SELECTED_TABLE = arrayOf(
1, 2,
4, 8,
16, 32,
64, 128,
256, 512,
1024, 2048
)
@Composable
@SuppressLint("AutoboxingStateValueProperty")
private fun AnimatedTab(scope: CoroutineScope, state: PagerState, index: Int, titleWithIcon: Pair<String, Int>) {
val curSelected = index == state.currentPage
val lastSelectedState = remember {
mutableIntStateOf(0)
}
val enter = remember {
scaleIn(animationSpec = TweenSpec(150, easing = FastOutLinearInEasing))
}
val exit = remember {
scaleOut(animationSpec = TweenSpec(150, easing = FastOutSlowInEasing))
}
val defaultConst = SELECTED_TABLE[index * 2]
val selectedConst = SELECTED_TABLE[(index * 2) + 1]
val isFirst: Boolean = (lastSelectedState.value and defaultConst) != defaultConst
var icon: @Composable (() -> Unit)? = null
var text: @Composable (() -> Unit)? = null
if (curSelected) {
text = {
AnimatedVisibility(visibleState = MutableTransitionState(false).also {
it.targetState = isFirst || lastSelectedState.value and selectedConst == selectedConst
}, enter = enter, exit = exit, modifier = Modifier) {
Text(
text = titleWithIcon.first,
color = TabSelectedColor,
fontSize = 15.sp,
fontWeight = FontWeight.Bold,
modifier = Modifier
.padding(bottom = 5.dp)
.indication(
remember { MutableInteractionSource() },
rememberRipple(color = Color.Transparent)
)
)
}
}
} else {
icon = {
Icon(
painter = painterResource(id = titleWithIcon.second),
contentDescription = titleWithIcon.first,
tint = Color.Unspecified,
modifier = Modifier
.height(24.dp)
.width(24.dp)
.padding(bottom = 5.dp)
.indication(
remember { MutableInteractionSource() },
rememberRipple(color = Color.Transparent)
)
)
}
}
ShamrockTab(
selected = curSelected,
onClick = { scope.launch {
state.scrollToPage(index, 0f)
} },
text = text,
icon = icon,
selectedContentColor = Color.Transparent,
unselectedContentColor = Color.Transparent,
indication = null
)
lastSelectedState.value.let {
var tmp = it
if (isFirst) {
tmp = it or defaultConst
}
lastSelectedState.value = if (curSelected) tmp or selectedConst else tmp xor selectedConst
}
}
@Preview(showBackground = true)
@Composable
private fun MainPreview() {
AppMainView()
}