完成UI界面设计
|
@ -0,0 +1,15 @@
|
||||||
|
*.iml
|
||||||
|
.gradle
|
||||||
|
/local.properties
|
||||||
|
/.idea/caches
|
||||||
|
/.idea/libraries
|
||||||
|
/.idea/modules.xml
|
||||||
|
/.idea/workspace.xml
|
||||||
|
/.idea/navEditor.xml
|
||||||
|
/.idea/assetWizardSettings.xml
|
||||||
|
.DS_Store
|
||||||
|
/build
|
||||||
|
/captures
|
||||||
|
.externalNativeBuild
|
||||||
|
.cxx
|
||||||
|
local.properties
|
|
@ -0,0 +1 @@
|
||||||
|
/build
|
|
@ -0,0 +1,98 @@
|
||||||
|
plugins {
|
||||||
|
id("com.android.application")
|
||||||
|
id("org.jetbrains.kotlin.android")
|
||||||
|
kotlin("plugin.serialization")
|
||||||
|
}
|
||||||
|
|
||||||
|
android {
|
||||||
|
namespace = "moe.fuqiuluo.shamrock"
|
||||||
|
compileSdk = 33
|
||||||
|
|
||||||
|
defaultConfig {
|
||||||
|
applicationId = "moe.fuqiuluo.shamrock"
|
||||||
|
minSdk = 24
|
||||||
|
targetSdk = 33
|
||||||
|
versionCode = 2
|
||||||
|
versionName = "1.0.0"
|
||||||
|
|
||||||
|
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||||
|
vectorDrawables {
|
||||||
|
useSupportLibrary = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
buildTypes {
|
||||||
|
release {
|
||||||
|
isMinifyEnabled = false
|
||||||
|
proguardFiles(
|
||||||
|
getDefaultProguardFile("proguard-android-optimize.txt"),
|
||||||
|
"proguard-rules.pro"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
compileOptions {
|
||||||
|
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||||
|
targetCompatibility = JavaVersion.VERSION_1_8
|
||||||
|
}
|
||||||
|
kotlinOptions {
|
||||||
|
jvmTarget = "1.8"
|
||||||
|
}
|
||||||
|
buildFeatures {
|
||||||
|
compose = true
|
||||||
|
}
|
||||||
|
composeOptions {
|
||||||
|
kotlinCompilerExtensionVersion = "1.4.3"
|
||||||
|
}
|
||||||
|
packaging {
|
||||||
|
resources {
|
||||||
|
excludes += "/META-INF/{AL2.0,LGPL2.1}"
|
||||||
|
excludes += "/META-INF/*"
|
||||||
|
excludes += "/META-INF/NOTICE.txt"
|
||||||
|
excludes += "/META-INF/DEPENDENCIES.txt"
|
||||||
|
excludes += "/META-INF/NOTICE"
|
||||||
|
excludes += "/META-INF/LICENSE"
|
||||||
|
excludes += "/META-INF/DEPENDENCIES"
|
||||||
|
excludes += "/META-INF/notice.txt"
|
||||||
|
excludes += "/META-INF/dependencies.txt"
|
||||||
|
excludes += "/META-INF/LGPL2.1"
|
||||||
|
excludes += "/META-INF/ASL2.0"
|
||||||
|
excludes += "/META-INF/INDEX.LIST"
|
||||||
|
excludes += "/META-INF/io.netty.versions.properties"
|
||||||
|
excludes += "/META-INF/INDEX.LIST"
|
||||||
|
excludes += "/META-INF/LICENSE.txt"
|
||||||
|
excludes += "/META-INF/license.txt"
|
||||||
|
excludes += "/META-INF/*.kotlin_module"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation("androidx.core:core-ktx:1.9.0")
|
||||||
|
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.6.1")
|
||||||
|
implementation("androidx.activity:activity-compose:1.7.2")
|
||||||
|
implementation(platform("androidx.compose:compose-bom:2023.06.01"))
|
||||||
|
implementation("androidx.compose.ui:ui")
|
||||||
|
implementation("androidx.compose.ui:ui-graphics")
|
||||||
|
implementation("androidx.compose.ui:ui-tooling-preview")
|
||||||
|
implementation("androidx.compose.material3:material3")
|
||||||
|
//noinspection GradleDynamicVersion
|
||||||
|
implementation("com.google.accompanist:accompanist-pager:0.31.5+")
|
||||||
|
//noinspection GradleDynamicVersion
|
||||||
|
implementation("com.google.accompanist:accompanist-systemuicontroller:0.31.5+")
|
||||||
|
//noinspection GradleDynamicVersion useless
|
||||||
|
// implementation("androidx.constraintlayout:constraintlayout-compose:1.1.0+")
|
||||||
|
implementation("io.coil-kt:coil:2.4.0")
|
||||||
|
implementation("io.coil-kt:coil-compose:2.4.0")
|
||||||
|
|
||||||
|
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.1")
|
||||||
|
|
||||||
|
implementation(project(":xposed"))
|
||||||
|
|
||||||
|
testImplementation("junit:junit:4.13.2")
|
||||||
|
androidTestImplementation("androidx.test.ext:junit:1.1.5")
|
||||||
|
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
|
||||||
|
androidTestImplementation(platform("androidx.compose:compose-bom:2023.06.01"))
|
||||||
|
androidTestImplementation("androidx.compose.ui:ui-test-junit4")
|
||||||
|
debugImplementation("androidx.compose.ui:ui-tooling")
|
||||||
|
debugImplementation("androidx.compose.ui:ui-test-manifest")
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
# Add project specific ProGuard rules here.
|
||||||
|
# You can control the set of applied configuration files using the
|
||||||
|
# proguardFiles setting in build.gradle.
|
||||||
|
#
|
||||||
|
# For more details, see
|
||||||
|
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||||
|
|
||||||
|
# If your project uses WebView with JS, uncomment the following
|
||||||
|
# and specify the fully qualified class name to the JavaScript interface
|
||||||
|
# class:
|
||||||
|
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||||
|
# public *;
|
||||||
|
#}
|
||||||
|
|
||||||
|
# Uncomment this to preserve the line number information for
|
||||||
|
# debugging stack traces.
|
||||||
|
#-keepattributes SourceFile,LineNumberTable
|
||||||
|
|
||||||
|
# If you keep the line number information, uncomment this to
|
||||||
|
# hide the original source file name.
|
||||||
|
#-renamesourcefileattribute SourceFile
|
|
@ -0,0 +1,20 @@
|
||||||
|
{
|
||||||
|
"version": 3,
|
||||||
|
"artifactType": {
|
||||||
|
"type": "APK",
|
||||||
|
"kind": "Directory"
|
||||||
|
},
|
||||||
|
"applicationId": "moe.fuqiuluo.shamrock",
|
||||||
|
"variantName": "release",
|
||||||
|
"elements": [
|
||||||
|
{
|
||||||
|
"type": "SINGLE",
|
||||||
|
"filters": [],
|
||||||
|
"attributes": [],
|
||||||
|
"versionCode": 2,
|
||||||
|
"versionName": "1.0.0",
|
||||||
|
"outputFile": "app-release.apk"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"elementType": "File"
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
package moe.fuqiuluo.shamrock
|
||||||
|
|
||||||
|
import androidx.test.platform.app.InstrumentationRegistry
|
||||||
|
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||||
|
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
|
||||||
|
import org.junit.Assert.*
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instrumented test, which will execute on an Android device.
|
||||||
|
*
|
||||||
|
* See [testing documentation](http://d.android.com/tools/testing).
|
||||||
|
*/
|
||||||
|
@RunWith(AndroidJUnit4::class)
|
||||||
|
class ExampleInstrumentedTest {
|
||||||
|
@Test
|
||||||
|
fun useAppContext() {
|
||||||
|
// Context of the app under test.
|
||||||
|
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
|
||||||
|
assertEquals("moe.fuqiuluo.shamrock", appContext.packageName)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,63 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
|
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||||
|
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||||
|
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
|
||||||
|
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||||
|
|
||||||
|
<application
|
||||||
|
android:name=".app.MyApplication"
|
||||||
|
android:zygotePreloadName="@string/app_name"
|
||||||
|
android:allowBackup="true"
|
||||||
|
android:dataExtractionRules="@xml/data_extraction_rules"
|
||||||
|
android:fullBackupContent="@xml/backup_rules"
|
||||||
|
android:icon="@mipmap/ic_launcher"
|
||||||
|
android:label="@string/app_name"
|
||||||
|
android:roundIcon="@mipmap/ic_launcher_round"
|
||||||
|
android:supportsRtl="true"
|
||||||
|
android:theme="@style/Theme.Shamrock"
|
||||||
|
tools:targetApi="31">
|
||||||
|
<activity
|
||||||
|
android:name=".MainActivity"
|
||||||
|
android:exported="true"
|
||||||
|
android:label="@string/app_name"
|
||||||
|
android:theme="@style/Theme.Shamrock"
|
||||||
|
tools:ignore="RedundantLabel">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
|
||||||
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
|
</intent-filter>
|
||||||
|
</activity>
|
||||||
|
|
||||||
|
<provider
|
||||||
|
android:authorities="moe.fuqiuluo.xqbot.provider"
|
||||||
|
android:name=".ui.service.MultifunctionalProvider"
|
||||||
|
android:exported="true"
|
||||||
|
android:grantUriPermissions="true"
|
||||||
|
tools:ignore="ExportedContentProvider" />
|
||||||
|
|
||||||
|
<meta-data
|
||||||
|
android:name="xposedmodule"
|
||||||
|
android:value="true" />
|
||||||
|
<meta-data
|
||||||
|
android:name="xposeddescription"
|
||||||
|
android:value="A Bot Framework" />
|
||||||
|
<meta-data
|
||||||
|
android:name="xposedminversion"
|
||||||
|
android:value="23" />
|
||||||
|
|
||||||
|
<!--适配华为(huawei)刘海屏-->
|
||||||
|
<meta-data
|
||||||
|
android:name="android.notch_support"
|
||||||
|
android:value="true"/>
|
||||||
|
<!--适配小米(xiaomi)刘海屏-->
|
||||||
|
<meta-data
|
||||||
|
android:name="notch.config"
|
||||||
|
android:value="portrait|landscape" />
|
||||||
|
</application>
|
||||||
|
|
||||||
|
</manifest>
|
|
@ -0,0 +1,376 @@
|
||||||
|
@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()
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
package moe.fuqiuluo.shamrock.app
|
||||||
|
|
||||||
|
import android.app.Application
|
||||||
|
|
||||||
|
class MyApplication: Application() {
|
||||||
|
}
|
|
@ -0,0 +1,69 @@
|
||||||
|
package moe.fuqiuluo.shamrock.ui.app
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.icu.text.SimpleDateFormat
|
||||||
|
import android.util.Log
|
||||||
|
import androidx.compose.runtime.MutableIntState
|
||||||
|
import androidx.compose.runtime.MutableState
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import java.util.Date
|
||||||
|
|
||||||
|
object AppRuntime {
|
||||||
|
@SuppressLint("SimpleDateFormat")
|
||||||
|
private val format = SimpleDateFormat("[HH:mm:ss] ")
|
||||||
|
|
||||||
|
lateinit var state: RuntimeState
|
||||||
|
|
||||||
|
lateinit var logger: Logger
|
||||||
|
|
||||||
|
object AccountInfo {
|
||||||
|
lateinit var uin: MutableState<String>
|
||||||
|
|
||||||
|
lateinit var nick: MutableState<String>
|
||||||
|
}
|
||||||
|
|
||||||
|
fun log(msg: String, level: Level = Level.INFO) {
|
||||||
|
if (::logger.isInitialized) {
|
||||||
|
val format = "%s%s %s".format(format.format(Date()), level.name, msg)
|
||||||
|
|
||||||
|
val builder = logger.logCache.value
|
||||||
|
val start = builder.length
|
||||||
|
val end = start + format.length
|
||||||
|
|
||||||
|
builder.append(format)
|
||||||
|
logger.logRanges.add(Logger.LogRange(start, end, level))
|
||||||
|
} else {
|
||||||
|
Log.e("AppRuntime", "logger is not initialized")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class RuntimeState(
|
||||||
|
val isFined: MutableState<Boolean>,
|
||||||
|
val coreVersion: MutableState<String>,
|
||||||
|
val coreCode: MutableIntState,
|
||||||
|
val coreName: MutableState<String>
|
||||||
|
) {
|
||||||
|
val attrMap = mutableMapOf<String, String>()
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class Level(
|
||||||
|
val color: Color
|
||||||
|
) {
|
||||||
|
DEBUG(Color(0xFF4CAF50)),
|
||||||
|
INFO(Color(0xff6c6c6c)),
|
||||||
|
WARN(Color(0xFFFF9800)),
|
||||||
|
ERROR(Color(0xFFE91E63)),
|
||||||
|
}
|
||||||
|
|
||||||
|
class Logger(
|
||||||
|
val logCache: MutableState<StringBuilder>,
|
||||||
|
val logRanges: MutableList<LogRange>,
|
||||||
|
) {
|
||||||
|
data class LogRange(
|
||||||
|
val start: Int,
|
||||||
|
val end: Int,
|
||||||
|
val level: Level
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,181 @@
|
||||||
|
package moe.fuqiuluo.shamrock.ui.fragment
|
||||||
|
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.clickable
|
||||||
|
import androidx.compose.foundation.indication
|
||||||
|
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||||
|
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.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.height
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.width
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.graphics.painter.Painter
|
||||||
|
import androidx.compose.ui.res.painterResource
|
||||||
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.unit.sp
|
||||||
|
import moe.fuqiuluo.shamrock.R
|
||||||
|
import moe.fuqiuluo.shamrock.ui.tools.IosSwitch
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun NoticeBox(
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
text: String,
|
||||||
|
onClick: (() -> Unit)? = null
|
||||||
|
) {
|
||||||
|
Box(
|
||||||
|
modifier = modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.indication(remember { MutableInteractionSource() }, null)
|
||||||
|
.background(
|
||||||
|
color = Color(0xFFf4f4f4),
|
||||||
|
shape = RoundedCornerShape(12.dp)
|
||||||
|
)
|
||||||
|
.clickable(enabled = onClick != null) {
|
||||||
|
onClick?.invoke()
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(
|
||||||
|
top = 10.dp,
|
||||||
|
bottom = 10.dp
|
||||||
|
)
|
||||||
|
.fillMaxWidth(),
|
||||||
|
horizontalArrangement = Arrangement.Start,
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(10.dp)
|
||||||
|
.width(20.dp)
|
||||||
|
.height(20.dp),
|
||||||
|
painter = painterResource(id = R.drawable.round_warning_24),
|
||||||
|
contentDescription = "WarningIcon",
|
||||||
|
tint = Color(0xFF838383)
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
text = text,
|
||||||
|
fontSize = 11.sp,
|
||||||
|
color = Color(0xff6c6c6c)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun ActionBox(
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
painter: Painter,
|
||||||
|
title: String,
|
||||||
|
content: @Composable (textColor: Color) -> Unit
|
||||||
|
) {
|
||||||
|
val textColor = Color(0xff6c6c6c)
|
||||||
|
Box(
|
||||||
|
modifier = modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.indication(remember { MutableInteractionSource() }, null)
|
||||||
|
.background(
|
||||||
|
color = Color(0xFFf4f4f4),
|
||||||
|
shape = RoundedCornerShape(12.dp)
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(
|
||||||
|
top = 10.dp,
|
||||||
|
bottom = 10.dp
|
||||||
|
)
|
||||||
|
.fillMaxWidth(),
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
horizontalArrangement = Arrangement.Start,
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(start = 10.dp)
|
||||||
|
.width(20.dp)
|
||||||
|
.height(20.dp),
|
||||||
|
painter = painter,
|
||||||
|
contentDescription = "ActionIcon",
|
||||||
|
tint = Color.Unspecified
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
modifier = Modifier.padding(start = 6.dp),
|
||||||
|
text = title,
|
||||||
|
fontSize = 12.sp,
|
||||||
|
color = textColor
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
Row(
|
||||||
|
modifier = Modifier.padding(8.dp)
|
||||||
|
) {
|
||||||
|
content.invoke(textColor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun ActionSwitch(
|
||||||
|
text: String,
|
||||||
|
isSwitch: Boolean,
|
||||||
|
onValueChanged: (Boolean) -> Unit,
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(2.dp)
|
||||||
|
.fillMaxWidth(),
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
modifier = Modifier,
|
||||||
|
text = text,
|
||||||
|
fontSize = 13.sp
|
||||||
|
)
|
||||||
|
Row(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
horizontalArrangement = Arrangement.End
|
||||||
|
) {
|
||||||
|
IosSwitch(
|
||||||
|
switchValue = isSwitch,
|
||||||
|
buttonHeight = 22.dp,
|
||||||
|
onValueChanged = onValueChanged
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview(showBackground = true)
|
||||||
|
@Composable
|
||||||
|
private fun NoticeBoxPreview() {
|
||||||
|
NoticeBox(
|
||||||
|
text = "该模块仅适用于QQ版本8.9.68及以上的版本。\n" +
|
||||||
|
"同时声明本项目仅用于学习与交流,请于24小时内删除。\n" +
|
||||||
|
"同时开源贡献者均享受免责条例。"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview(showBackground = true)
|
||||||
|
@Composable
|
||||||
|
private fun ActionBoxPreview() {
|
||||||
|
ActionBox(
|
||||||
|
painter = painterResource(id = R.drawable.ic_help_512),
|
||||||
|
title = "使用帮助 & 教程"
|
||||||
|
) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,318 @@
|
||||||
|
package moe.fuqiuluo.shamrock.ui.fragment
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.SharedPreferences
|
||||||
|
import android.os.Build
|
||||||
|
import android.widget.Toast
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
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.rememberScrollState
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.foundation.verticalScroll
|
||||||
|
import androidx.compose.material3.Divider
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.Surface
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.draw.clip
|
||||||
|
import androidx.compose.ui.graphics.Brush
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.modifier.modifierLocalMapOf
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.compose.ui.res.painterResource
|
||||||
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.unit.sp
|
||||||
|
import androidx.core.content.edit
|
||||||
|
import coil.compose.AsyncImagePainter
|
||||||
|
import coil.compose.rememberAsyncImagePainter
|
||||||
|
import coil.request.ImageRequest
|
||||||
|
import coil.size.Size
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import moe.fuqiuluo.shamrock.R
|
||||||
|
import moe.fuqiuluo.shamrock.ui.app.AppRuntime
|
||||||
|
import moe.fuqiuluo.shamrock.ui.app.Level
|
||||||
|
import moe.fuqiuluo.shamrock.ui.theme.TabSelectedColor
|
||||||
|
import moe.fuqiuluo.shamrock.ui.theme.TabUnSelectedColor
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun DashboardFragment(
|
||||||
|
nick: String,
|
||||||
|
uin: String
|
||||||
|
) {
|
||||||
|
val scope = rememberCoroutineScope()
|
||||||
|
val ctx = LocalContext.current
|
||||||
|
val preferences = ctx.getSharedPreferences("config", 0)
|
||||||
|
|
||||||
|
Surface(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize(),
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.verticalScroll(rememberScrollState())
|
||||||
|
.padding(16.dp)
|
||||||
|
) {
|
||||||
|
AccountCard(nick, uin)
|
||||||
|
InformationCard()
|
||||||
|
FunctionCard(scope, ctx, preferences, "功能设置")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun FunctionCard(
|
||||||
|
scope: CoroutineScope,
|
||||||
|
ctx: Context,
|
||||||
|
preferences: SharedPreferences,
|
||||||
|
title: String
|
||||||
|
) {
|
||||||
|
ActionBox(
|
||||||
|
modifier = Modifier.padding(top = 12.dp),
|
||||||
|
painter = painterResource(id = R.drawable.round_api_24),
|
||||||
|
title = title
|
||||||
|
) {
|
||||||
|
Column {
|
||||||
|
Divider(
|
||||||
|
modifier = Modifier,
|
||||||
|
color = TabUnSelectedColor,
|
||||||
|
thickness = 0.2.dp
|
||||||
|
)
|
||||||
|
|
||||||
|
Function(
|
||||||
|
title = "强制平板模式",
|
||||||
|
desc = "强制QQ使用平板模式,实现共存登录。",
|
||||||
|
descColor = TabSelectedColor,
|
||||||
|
isSwitch = preferences.getBoolean("tablet", false)
|
||||||
|
) {
|
||||||
|
preferences.edit { putBoolean("tablet", it) }
|
||||||
|
scope.launch { Toast.makeText(ctx, "重启QQ生效", Toast.LENGTH_SHORT).show() }
|
||||||
|
}
|
||||||
|
|
||||||
|
Function(
|
||||||
|
title = "HTTP回调",
|
||||||
|
desc = "OneBot标准的HTTPAPI回调,Shamrock作为Client。",
|
||||||
|
descColor = TabSelectedColor,
|
||||||
|
isSwitch = !preferences.getString("webhook", "").isNullOrBlank()
|
||||||
|
) {
|
||||||
|
|
||||||
|
//preferences.edit { putBoolean("webhook", it) }
|
||||||
|
scope.launch { Toast.makeText(ctx, "重启QQ生效", Toast.LENGTH_SHORT).show() }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Function(
|
||||||
|
title = "主动WebSocket",
|
||||||
|
desc = "OneBot标准WebSocket,Shamrock作为Server。",
|
||||||
|
descColor = TabSelectedColor,
|
||||||
|
isSwitch = preferences.getBoolean("ws", false)
|
||||||
|
) {
|
||||||
|
preferences.edit { putBoolean("ws", it) }
|
||||||
|
scope.launch { Toast.makeText(ctx, "重启QQ生效", Toast.LENGTH_SHORT).show() }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Function(
|
||||||
|
title = "被动WebSocket",
|
||||||
|
desc = "OneBot标准WebSocket,Shamrock作为Client。",
|
||||||
|
descColor = TabSelectedColor,
|
||||||
|
isSwitch = !preferences.getString("ws_api", "").isNullOrBlank()
|
||||||
|
) {
|
||||||
|
|
||||||
|
scope.launch { Toast.makeText(ctx, "重启QQ生效", Toast.LENGTH_SHORT).show() }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Function(
|
||||||
|
title = "专业级接口",
|
||||||
|
desc = "如果你不知道你在做什么,请不要开启本功能。",
|
||||||
|
descColor = Color.Red,
|
||||||
|
isSwitch = preferences.getBoolean("pro_api", false)
|
||||||
|
) {
|
||||||
|
preferences.edit { putBoolean("pro_api", it) }
|
||||||
|
scope.launch { Toast.makeText(ctx, "重启QQ生效", Toast.LENGTH_SHORT).show() }
|
||||||
|
AppRuntime.log("专业级API = $it", Level.WARN)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun Function(
|
||||||
|
title: String,
|
||||||
|
desc: String? = null,
|
||||||
|
descColor: Color? = null,
|
||||||
|
isSwitch: Boolean,
|
||||||
|
onClick: (Boolean) -> Unit
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.absolutePadding(left = 8.dp, right = 8.dp, top = 12.dp, bottom = 0.dp)
|
||||||
|
) {
|
||||||
|
if (desc != null && descColor != null) {
|
||||||
|
Text(
|
||||||
|
modifier = Modifier.padding(2.dp),
|
||||||
|
text = desc,
|
||||||
|
color = descColor,
|
||||||
|
fontSize = 11.sp
|
||||||
|
)
|
||||||
|
}
|
||||||
|
ActionSwitch(
|
||||||
|
text = title,
|
||||||
|
isSwitch = isSwitch
|
||||||
|
) {
|
||||||
|
onClick(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun InformationCard() {
|
||||||
|
ActionBox(
|
||||||
|
modifier = Modifier.padding(top = 12.dp),
|
||||||
|
painter = painterResource(id = R.drawable.round_info_24),
|
||||||
|
title = "数据信息"
|
||||||
|
) {
|
||||||
|
Column {
|
||||||
|
Divider(
|
||||||
|
modifier = Modifier,
|
||||||
|
color = TabUnSelectedColor,
|
||||||
|
thickness = 0.2.dp
|
||||||
|
)
|
||||||
|
|
||||||
|
InfoItem(
|
||||||
|
title = "系统版本",
|
||||||
|
content = "${Build.VERSION.RELEASE} (API ${Build.VERSION.SDK_INT})"
|
||||||
|
)
|
||||||
|
|
||||||
|
InfoItem(title = "设备", content = "${Build.BRAND} ${Build.MODEL}")
|
||||||
|
|
||||||
|
InfoItem(title = "系统架构", content = Build.SUPPORTED_ABIS.joinToString())
|
||||||
|
|
||||||
|
InfoItem(
|
||||||
|
title = "累计调用次数",
|
||||||
|
content = "114514"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun InfoItem(
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
titleColor: Color = Color(0xFF5A5A5A),
|
||||||
|
contentColor: Color = Color(0xFF5A5A5A),
|
||||||
|
title: String,
|
||||||
|
content: String
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.absolutePadding(left = 8.dp, right = 8.dp, top = 12.dp, bottom = 0.dp)
|
||||||
|
.fillMaxWidth(),
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = title,
|
||||||
|
fontSize = 14.sp,
|
||||||
|
color = titleColor
|
||||||
|
)
|
||||||
|
|
||||||
|
Row(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
horizontalArrangement = Arrangement.End
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = content,
|
||||||
|
fontSize = 14.sp,
|
||||||
|
color = contentColor
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun AccountCard(
|
||||||
|
nick: String,
|
||||||
|
uin: String
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.background(
|
||||||
|
Brush.linearGradient(
|
||||||
|
listOf(Color(0xFF2196F3), Color(0xFF00BCD4))
|
||||||
|
), shape = RoundedCornerShape(12.dp)
|
||||||
|
),
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
|
) {
|
||||||
|
val painter = kotlin.runCatching {
|
||||||
|
rememberAsyncImagePainter(model = ImageRequest.Builder(LocalContext.current)
|
||||||
|
.data("https://q.qlogo.cn/g?b=qq&nk=$uin&s=100")
|
||||||
|
.crossfade(true)
|
||||||
|
.size(Size.ORIGINAL)
|
||||||
|
.build())
|
||||||
|
}.onSuccess {
|
||||||
|
when(it.state){
|
||||||
|
is AsyncImagePainter.State.Success ->{
|
||||||
|
|
||||||
|
}
|
||||||
|
is AsyncImagePainter.State.Loading ->{
|
||||||
|
}
|
||||||
|
is AsyncImagePainter.State.Error ->{
|
||||||
|
AppRuntime.log("头像拉取失败,请检查网络连接。", Level.ERROR)
|
||||||
|
}
|
||||||
|
else -> {}
|
||||||
|
}
|
||||||
|
}.getOrDefault(painterResource(id = R.drawable.ic_letter_q))
|
||||||
|
|
||||||
|
Icon(
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(
|
||||||
|
start = 15.dp,
|
||||||
|
end = 5.dp
|
||||||
|
)
|
||||||
|
.width(45.dp)
|
||||||
|
.height(45.dp)
|
||||||
|
.clip(RoundedCornerShape(36.dp))
|
||||||
|
,
|
||||||
|
painter = painter,
|
||||||
|
contentDescription = "HeadLogo",
|
||||||
|
tint = Color.Unspecified
|
||||||
|
)
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(20.dp),
|
||||||
|
verticalArrangement = Arrangement.Top,
|
||||||
|
horizontalAlignment = Alignment.Start,
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = nick,
|
||||||
|
color = Color.White,
|
||||||
|
fontSize = 14.sp
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
text = "QQ号:$uin",
|
||||||
|
color = Color.White,
|
||||||
|
fontSize = 14.sp
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
private fun PreViewDashBoard() {
|
||||||
|
DashboardFragment("测试昵称", "100001")
|
||||||
|
}
|
|
@ -0,0 +1,163 @@
|
||||||
|
package moe.fuqiuluo.shamrock.ui.fragment
|
||||||
|
|
||||||
|
import android.widget.Toast
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
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.rememberScrollState
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.foundation.verticalScroll
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.Surface
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.MutableIntState
|
||||||
|
import androidx.compose.runtime.MutableState
|
||||||
|
import androidx.compose.runtime.mutableIntStateOf
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Brush
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.compose.ui.res.painterResource
|
||||||
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.unit.sp
|
||||||
|
import moe.fuqiuluo.shamrock.R
|
||||||
|
import moe.fuqiuluo.shamrock.ui.app.RuntimeState
|
||||||
|
import moe.fuqiuluo.shamrock.ui.theme.LocalString
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun HomeFragment(
|
||||||
|
runtime: RuntimeState
|
||||||
|
) {
|
||||||
|
val scope = rememberCoroutineScope()
|
||||||
|
val ctx = LocalContext.current
|
||||||
|
|
||||||
|
Surface(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize(),
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.verticalScroll(rememberScrollState())
|
||||||
|
.padding(16.dp)
|
||||||
|
) {
|
||||||
|
StatusCardBoard(runtime.isFined, runtime.coreVersion, runtime.coreCode, runtime.coreName)
|
||||||
|
|
||||||
|
NoticeBox(
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(top = 12.dp),
|
||||||
|
text = LocalString.legalWarning,
|
||||||
|
) {
|
||||||
|
Toast.makeText(ctx, arrayOf(
|
||||||
|
"请严格遵守哦!", "点我又不能下崽...", "家人们谁懂啊!", "别点啦,记得遵守规则啊!", "CRC:06f77ca1"
|
||||||
|
).random(), Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionBox(
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(top = 12.dp),
|
||||||
|
painter = painterResource(id = R.drawable.ic_help_512),
|
||||||
|
title = "使用教程 & 注意事项"
|
||||||
|
) { textColor ->
|
||||||
|
Text(text = """
|
||||||
|
Q:如何使用呢?
|
||||||
|
A:在Xposed/Lsposed中激活模块,选中目标应用重新后强行停止目标应用并重新启动即可。
|
||||||
|
Q:冻结封号是怎么回事?
|
||||||
|
A:也许未来的某个时刻,会加强检测吧。亦或许你发了什么不干净的东西呢。
|
||||||
|
Q:Shamrock有模块冲突?
|
||||||
|
A:目前没有发现模块冲突。
|
||||||
|
Q:Shamrock需求权限?
|
||||||
|
A:Shamrock使用到了Net权限,去实现HTTPAPI和WebSocket的一些请求,请确保你所设置的端口未被占用。当你使用来自一些Android机器人框架的插件,请确保本APP的存活,否则将无法运行;当你使用来自OneBot标准的相关接口时,无需保证APP的存活。
|
||||||
|
Q:Shamrock运行原理?
|
||||||
|
A:使用Xposed框架,将代码插入到QQ运行时,并在QQ内使用Ktor框架放出外部可用的API接口,采用Provider/DynamicBroadcast与实现模块与目标进程数据交互,无需额外的储存权限。
|
||||||
|
Q:兼容性框架支持有哪些?
|
||||||
|
A:
|
||||||
|
1,支持载入一些Android机器人框架的插件(如QR词库插件)。
|
||||||
|
2,支持OneBot12标准,但不会更新支持之后的OneBot标准(特殊性)。
|
||||||
|
3,原始支持来自Native/Jvm的插件。
|
||||||
|
""".trimIndent(),
|
||||||
|
color = textColor,
|
||||||
|
fontSize = 12.sp
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun StatusCardBoard(
|
||||||
|
isRight: MutableState<Boolean>,
|
||||||
|
version: MutableState<String>,
|
||||||
|
code: MutableIntState,
|
||||||
|
core: MutableState<String>
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.background(
|
||||||
|
Brush.linearGradient(
|
||||||
|
listOf(Color(0xFF03AA9A), Color(0xFF4DB8AD))
|
||||||
|
), shape = RoundedCornerShape(12.dp)
|
||||||
|
),
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(
|
||||||
|
start = 25.dp,
|
||||||
|
end = 5.dp
|
||||||
|
)
|
||||||
|
.width(20.dp)
|
||||||
|
.height(20.dp),
|
||||||
|
painter = painterResource(id = if (isRight.value) R.drawable.round_near_me_24 else
|
||||||
|
R.drawable.round_near_me_disabled_24),
|
||||||
|
contentDescription = "StatusIcon",
|
||||||
|
tint = Color.White
|
||||||
|
)
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(20.dp)
|
||||||
|
.fillMaxWidth(),
|
||||||
|
verticalArrangement = Arrangement.Top,
|
||||||
|
horizontalAlignment = Alignment.Start,
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = if (isRight.value) LocalString.frameworkYesLite else LocalString.frameworkNoLite,
|
||||||
|
color = Color.White,
|
||||||
|
fontSize = 14.sp
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
text = "${version.value} (${code.intValue}) - ${core.value}",
|
||||||
|
color = Color.White,
|
||||||
|
fontSize = 14.sp
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview(showBackground = true)
|
||||||
|
@Composable
|
||||||
|
private fun MainPreview() {
|
||||||
|
val isFined = remember { mutableStateOf(false) }
|
||||||
|
val coreVersion = remember { mutableStateOf("1.0.0") }
|
||||||
|
val coreName = remember { mutableStateOf("Xposed") }
|
||||||
|
val coreCode = remember { mutableIntStateOf(1000) }
|
||||||
|
|
||||||
|
val runtime = remember {
|
||||||
|
RuntimeState(isFined, coreVersion, coreCode, coreName)
|
||||||
|
}
|
||||||
|
|
||||||
|
HomeFragment(runtime)
|
||||||
|
}
|
|
@ -0,0 +1,139 @@
|
||||||
|
package moe.fuqiuluo.shamrock.ui.fragment
|
||||||
|
|
||||||
|
import android.widget.Toast
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.absolutePadding
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.rememberScrollState
|
||||||
|
import androidx.compose.foundation.verticalScroll
|
||||||
|
import androidx.compose.material3.Divider
|
||||||
|
import androidx.compose.material3.Surface
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.MutableState
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
|
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.tooling.preview.Preview
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.unit.sp
|
||||||
|
import androidx.core.content.edit
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import moe.fuqiuluo.shamrock.R
|
||||||
|
import moe.fuqiuluo.shamrock.ui.theme.LocalString
|
||||||
|
import moe.fuqiuluo.shamrock.ui.theme.TabUnSelectedColor
|
||||||
|
import moe.fuqiuluo.shamrock.ui.tools.NoticeTextDialog
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun LabFragment() {
|
||||||
|
val scope = rememberCoroutineScope()
|
||||||
|
val ctx = LocalContext.current
|
||||||
|
val preferences = ctx.getSharedPreferences("config", 0)
|
||||||
|
|
||||||
|
Surface(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize(),
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.verticalScroll(rememberScrollState())
|
||||||
|
.padding(16.dp)
|
||||||
|
) {
|
||||||
|
val showNoticeDialog = remember { mutableStateOf(false) }
|
||||||
|
NoticeBox(text = LocalString.labWarning) {
|
||||||
|
showNoticeDialog.value = true
|
||||||
|
}
|
||||||
|
if (showNoticeDialog.value) {
|
||||||
|
NoticeTextDialog(
|
||||||
|
openDialog = showNoticeDialog,
|
||||||
|
title = "温馨提示",
|
||||||
|
text = "实验室功能会导致一些奇怪的问题,请谨慎使用!"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionBox(
|
||||||
|
modifier = Modifier.padding(top = 12.dp),
|
||||||
|
painter = painterResource(id = R.drawable.baseline_preview_24),
|
||||||
|
title = "显示设置"
|
||||||
|
) {
|
||||||
|
Column {
|
||||||
|
Divider(
|
||||||
|
modifier = Modifier,
|
||||||
|
color = TabUnSelectedColor,
|
||||||
|
thickness = 0.2.dp
|
||||||
|
)
|
||||||
|
|
||||||
|
Function(
|
||||||
|
title = "中二病模式",
|
||||||
|
desc = "也许会导致奇怪的问题,大抵就是你看不懂罢了。",
|
||||||
|
descColor = it,
|
||||||
|
isSwitch = preferences.getBoolean("2B", false)
|
||||||
|
) {
|
||||||
|
preferences.edit { putBoolean("2B", it) }
|
||||||
|
scope.launch { Toast.makeText(ctx, "重启生效哦~", Toast.LENGTH_SHORT).show() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionBox(
|
||||||
|
modifier = Modifier.padding(top = 12.dp),
|
||||||
|
painter = painterResource(id = R.drawable.round_logo_dev_24),
|
||||||
|
title = "实验功能"
|
||||||
|
) {
|
||||||
|
Column {
|
||||||
|
Divider(
|
||||||
|
modifier = Modifier,
|
||||||
|
color = TabUnSelectedColor,
|
||||||
|
thickness = 0.2.dp
|
||||||
|
)
|
||||||
|
|
||||||
|
Function(
|
||||||
|
title = "自动清理QQ垃圾",
|
||||||
|
desc = "也许会导致奇怪的问题。",
|
||||||
|
descColor = it,
|
||||||
|
isSwitch = preferences.getBoolean("auto_clear", false)
|
||||||
|
) {
|
||||||
|
preferences.edit { putBoolean("auto_clear", it) }
|
||||||
|
scope.launch { Toast.makeText(ctx, "重启QQ生效", Toast.LENGTH_SHORT).show() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun Function(
|
||||||
|
title: String,
|
||||||
|
desc: String,
|
||||||
|
descColor: Color,
|
||||||
|
isSwitch: Boolean,
|
||||||
|
onClick: (Boolean) -> Unit
|
||||||
|
) {
|
||||||
|
Column(modifier = Modifier
|
||||||
|
.absolutePadding(left = 8.dp, right = 8.dp, top = 12.dp, bottom = 0.dp)
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
modifier = Modifier.padding(2.dp),
|
||||||
|
text = desc,
|
||||||
|
color = descColor,
|
||||||
|
fontSize = 11.sp
|
||||||
|
)
|
||||||
|
ActionSwitch(text = title, isSwitch = isSwitch) {
|
||||||
|
onClick(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview(showBackground = true)
|
||||||
|
@Composable
|
||||||
|
private fun LabPreView() {
|
||||||
|
LabFragment()
|
||||||
|
}
|
|
@ -0,0 +1,126 @@
|
||||||
|
package moe.fuqiuluo.shamrock.ui.fragment
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.indication
|
||||||
|
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||||
|
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.fillMaxSize
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.rememberScrollState
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.foundation.verticalScroll
|
||||||
|
import androidx.compose.material3.Surface
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.text.AnnotatedString
|
||||||
|
import androidx.compose.ui.text.ParagraphStyle
|
||||||
|
import androidx.compose.ui.text.SpanStyle
|
||||||
|
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 moe.fuqiuluo.shamrock.ui.app.Logger
|
||||||
|
import java.lang.StringBuilder
|
||||||
|
import java.util.Collections.EMPTY_LIST
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun LogFragment(
|
||||||
|
logger: Logger
|
||||||
|
) {
|
||||||
|
val scope = rememberCoroutineScope()
|
||||||
|
Surface(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize(),
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(16.dp)
|
||||||
|
) {
|
||||||
|
NoticeBox(text = "日志仅保留最新的${Short.MAX_VALUE}条,超出部分会自动删除,如有需要请做好保留。")
|
||||||
|
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(top = 12.dp)
|
||||||
|
.fillMaxSize()
|
||||||
|
.indication(remember { MutableInteractionSource() }, null)
|
||||||
|
.background(
|
||||||
|
color = Color(0xFFf4f4f4),
|
||||||
|
shape = RoundedCornerShape(12.dp)
|
||||||
|
)
|
||||||
|
.verticalScroll(rememberScrollState())
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(
|
||||||
|
start = 10.dp,
|
||||||
|
end = 10.dp,
|
||||||
|
top = 10.dp,
|
||||||
|
bottom = 10.dp
|
||||||
|
),
|
||||||
|
horizontalArrangement = Arrangement.Start,
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
|
) {
|
||||||
|
@Suppress("UNCHECKED_CAST") val text = remember {
|
||||||
|
mutableStateOf(
|
||||||
|
AnnotatedString(
|
||||||
|
text = "",
|
||||||
|
spanStyles = EMPTY_LIST as List<AnnotatedString.Range<SpanStyle>>,
|
||||||
|
paragraphStyles = EMPTY_LIST as List<AnnotatedString.Range<ParagraphStyle>>
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
LaunchedEffect(logger.logCache.value.length) {
|
||||||
|
val spanStyles = mutableListOf<AnnotatedString.Range<SpanStyle>>()
|
||||||
|
val paragraphStyles = mutableListOf<AnnotatedString.Range<ParagraphStyle>>()
|
||||||
|
logger.logRanges.forEach {
|
||||||
|
spanStyles.add(AnnotatedString.Range(
|
||||||
|
SpanStyle(
|
||||||
|
color = it.level.color
|
||||||
|
), it.start, it.end
|
||||||
|
))
|
||||||
|
paragraphStyles.add(AnnotatedString.Range(
|
||||||
|
ParagraphStyle(
|
||||||
|
textAlign = TextAlign.Start
|
||||||
|
), it.start, it.end
|
||||||
|
))
|
||||||
|
}
|
||||||
|
text.value = AnnotatedString(
|
||||||
|
text = logger.logCache.value.toString(),
|
||||||
|
spanStyles = spanStyles,
|
||||||
|
paragraphStyles = paragraphStyles
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
Text(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
text = text.value,
|
||||||
|
fontSize = 12.sp,
|
||||||
|
color = Color(0xff6c6c6c),
|
||||||
|
)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("UnrememberedMutableState")
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
private fun LogPreview() {
|
||||||
|
LogFragment(
|
||||||
|
Logger(mutableStateOf(StringBuilder()), mutableListOf())
|
||||||
|
)
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
package moe.fuqiuluo.shamrock.ui.service
|
||||||
|
|
||||||
|
import android.content.ContentProvider
|
||||||
|
import android.content.ContentValues
|
||||||
|
import android.database.Cursor
|
||||||
|
import android.net.Uri
|
||||||
|
|
||||||
|
class MultifunctionalProvider: ContentProvider() {
|
||||||
|
override fun insert(uri: Uri, content: ContentValues?): Uri {
|
||||||
|
|
||||||
|
|
||||||
|
return uri
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreate(): Boolean {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun query(
|
||||||
|
p0: Uri,
|
||||||
|
p1: Array<out String>?,
|
||||||
|
p2: String?,
|
||||||
|
p3: Array<out String>?,
|
||||||
|
p4: String?
|
||||||
|
): Cursor? {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getType(p0: Uri): String? {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun delete(p0: Uri, p1: String?, p2: Array<out String>?): Int {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun update(p0: Uri, p1: ContentValues?, p2: String?, p3: Array<out String>?): Int {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
package moe.fuqiuluo.shamrock.ui.theme
|
||||||
|
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
|
||||||
|
val Purple80 = Color(0xFFD0BCFF)
|
||||||
|
val PurpleGrey80 = Color(0xFFCCC2DC)
|
||||||
|
val Pink80 = Color(0xFFEFB8C8)
|
||||||
|
|
||||||
|
val Purple40 = Color(0xFF6650a4)
|
||||||
|
val PurpleGrey40 = Color(0xFF625b71)
|
||||||
|
val Pink40 = Color(0xFF7D5260)
|
||||||
|
|
||||||
|
val ToolbarColor = Color(0xFF6f6f6f)
|
||||||
|
|
||||||
|
val TabSelectedColor = Color(0xFF5A5A5A)
|
||||||
|
val TabUnSelectedColor = Color(0xFF6f6f6f)
|
||||||
|
val TabDividerColor = Color(0xFFBEBEBE)
|
|
@ -0,0 +1,75 @@
|
||||||
|
@file:Suppress(
|
||||||
|
"SpellCheckingInspection", "unused", "PropertyName",
|
||||||
|
"ClassName", "NonAsciiCharacters"
|
||||||
|
)
|
||||||
|
package moe.fuqiuluo.shamrock.ui.theme
|
||||||
|
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.ReadOnlyComposable
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import moe.fuqiuluo.shamrock.R
|
||||||
|
|
||||||
|
private val LocalStringDefault = Default()
|
||||||
|
private val LocalString2B = Chūnibyō()
|
||||||
|
|
||||||
|
val LocalString: VarString
|
||||||
|
@ReadOnlyComposable
|
||||||
|
@Composable
|
||||||
|
get() {
|
||||||
|
val ctx = LocalContext.current
|
||||||
|
val sharedPreferences = ctx.getSharedPreferences("config", 0)
|
||||||
|
return if (!sharedPreferences.getBoolean("2B", false)) {
|
||||||
|
LocalStringDefault
|
||||||
|
} else {
|
||||||
|
LocalString2B
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private open class Chūnibyō: Default() {
|
||||||
|
init {
|
||||||
|
TitlesWithIcon = arrayOf(
|
||||||
|
"玄天" to R.drawable.round_home_24,
|
||||||
|
"天穹" to R.drawable.round_dashboard_24,
|
||||||
|
"无极" to R.drawable.round_monitor_heart_24,
|
||||||
|
"飘渺" to R.drawable.round_logo_dev_24
|
||||||
|
)
|
||||||
|
frameworkYes = "仙路已通"
|
||||||
|
frameworkNo = "鬼怪横行"
|
||||||
|
frameworkYesLite = "五行已备"
|
||||||
|
frameworkNoLite = "需待东风"
|
||||||
|
legalWarning = "白榆,北辰,曜魄,应星,云川当方位不乱,即可作于无极之域。\n" +
|
||||||
|
"执明起,至除免于灾祸。\n" +
|
||||||
|
"元冥浩浩,非凡不可动之。"
|
||||||
|
labWarning = "寒酥降矣,梅熟日久,莫不可测。"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private open class Default: VarString(
|
||||||
|
TitlesWithIcon = arrayOf(
|
||||||
|
"主页" to R.drawable.round_home_24,
|
||||||
|
"状态" to R.drawable.round_dashboard_24,
|
||||||
|
"日志" to R.drawable.round_monitor_heart_24,
|
||||||
|
"Lab" to R.drawable.round_logo_dev_24
|
||||||
|
), "框架已激活", "框架未激活",
|
||||||
|
"已激活", "未激活",
|
||||||
|
legalWarning = "该模块仅适用于目标版本8.9.68及以上的版本。\n" +
|
||||||
|
"同时声明本项目仅用于学习与交流,请于24小时内删除。\n" +
|
||||||
|
"同时开源贡献者均享受免责条例。",
|
||||||
|
labWarning = "实验室功能,可能会导致出乎意料的BUG!",
|
||||||
|
"日志"
|
||||||
|
)
|
||||||
|
|
||||||
|
open class VarString(
|
||||||
|
var TitlesWithIcon: Array<Pair<String, Int>>,
|
||||||
|
var frameworkYes: String,
|
||||||
|
var frameworkNo: String,
|
||||||
|
|
||||||
|
var frameworkYesLite: String,
|
||||||
|
var frameworkNoLite: String,
|
||||||
|
|
||||||
|
var legalWarning: String,
|
||||||
|
|
||||||
|
var labWarning: String,
|
||||||
|
|
||||||
|
var logTitle: String
|
||||||
|
)
|
|
@ -0,0 +1,71 @@
|
||||||
|
package moe.fuqiuluo.shamrock.ui.theme
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
|
import android.os.Build
|
||||||
|
import androidx.compose.foundation.isSystemInDarkTheme
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.darkColorScheme
|
||||||
|
import androidx.compose.material3.dynamicDarkColorScheme
|
||||||
|
import androidx.compose.material3.dynamicLightColorScheme
|
||||||
|
import androidx.compose.material3.lightColorScheme
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.SideEffect
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.graphics.toArgb
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.compose.ui.platform.LocalView
|
||||||
|
import androidx.core.view.WindowCompat
|
||||||
|
|
||||||
|
private val DarkColorScheme = darkColorScheme(
|
||||||
|
primary = Color(0xFFD0BCFF),
|
||||||
|
secondary = Color(0xFFCCC2DC),
|
||||||
|
tertiary = Color(0xFFEFB8C8)
|
||||||
|
)
|
||||||
|
|
||||||
|
private val LightColorScheme = lightColorScheme(
|
||||||
|
primary = Color.White,
|
||||||
|
secondary = Color.White,
|
||||||
|
tertiary = Color(0xFF7D5260),
|
||||||
|
surface = Color(0xFFFFFBFE),
|
||||||
|
|
||||||
|
/* Other default colors to override
|
||||||
|
background = Color(0xFFFFFBFE),
|
||||||
|
onPrimary = Color.White,
|
||||||
|
onSecondary = Color.White,
|
||||||
|
onTertiary = Color.White,
|
||||||
|
onBackground = Color(0xFF1C1B1F),
|
||||||
|
onSurface = Color(0xFF1C1B1F),
|
||||||
|
*/
|
||||||
|
)
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun ShamrockTheme(
|
||||||
|
darkTheme: Boolean = isSystemInDarkTheme(),
|
||||||
|
// Dynamic color is available on Android 12+
|
||||||
|
dynamicColor: Boolean = true,
|
||||||
|
content: @Composable () -> Unit
|
||||||
|
) {
|
||||||
|
val colorScheme = when {
|
||||||
|
dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
|
||||||
|
val context = LocalContext.current
|
||||||
|
if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context)
|
||||||
|
}
|
||||||
|
|
||||||
|
darkTheme -> DarkColorScheme
|
||||||
|
else -> LightColorScheme
|
||||||
|
}
|
||||||
|
val view = LocalView.current
|
||||||
|
if (!view.isInEditMode) {
|
||||||
|
SideEffect {
|
||||||
|
val window = (view.context as Activity).window
|
||||||
|
window.statusBarColor = colorScheme.primary.toArgb()
|
||||||
|
WindowCompat.getInsetsController(window, view).isAppearanceLightStatusBars = darkTheme
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MaterialTheme(
|
||||||
|
colorScheme = colorScheme,
|
||||||
|
typography = Typography,
|
||||||
|
content = content
|
||||||
|
)
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
package moe.fuqiuluo.shamrock.ui.theme
|
||||||
|
|
||||||
|
import androidx.compose.material3.Typography
|
||||||
|
import androidx.compose.ui.text.TextStyle
|
||||||
|
import androidx.compose.ui.text.font.FontFamily
|
||||||
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
|
import androidx.compose.ui.unit.sp
|
||||||
|
|
||||||
|
// Set of Material typography styles to start with
|
||||||
|
val Typography = Typography(
|
||||||
|
bodyLarge = TextStyle(
|
||||||
|
fontFamily = FontFamily.Default,
|
||||||
|
fontWeight = FontWeight.Normal,
|
||||||
|
fontSize = 16.sp,
|
||||||
|
lineHeight = 24.sp,
|
||||||
|
letterSpacing = 0.5.sp
|
||||||
|
)
|
||||||
|
/* Other default text styles to override
|
||||||
|
titleLarge = TextStyle(
|
||||||
|
fontFamily = FontFamily.Default,
|
||||||
|
fontWeight = FontWeight.Normal,
|
||||||
|
fontSize = 22.sp,
|
||||||
|
lineHeight = 28.sp,
|
||||||
|
letterSpacing = 0.sp
|
||||||
|
),
|
||||||
|
labelSmall = TextStyle(
|
||||||
|
fontFamily = FontFamily.Default,
|
||||||
|
fontWeight = FontWeight.Medium,
|
||||||
|
fontSize = 11.sp,
|
||||||
|
lineHeight = 16.sp,
|
||||||
|
letterSpacing = 0.5.sp
|
||||||
|
)
|
||||||
|
*/
|
||||||
|
)
|
|
@ -0,0 +1,73 @@
|
||||||
|
package moe.fuqiuluo.shamrock.ui.tools
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.material3.AlertDialog
|
||||||
|
import androidx.compose.material3.Button
|
||||||
|
import androidx.compose.material3.ButtonDefaults
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.MutableState
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.unit.sp
|
||||||
|
import moe.fuqiuluo.shamrock.ui.theme.ShamrockTheme
|
||||||
|
import moe.fuqiuluo.shamrock.ui.theme.TabSelectedColor
|
||||||
|
import moe.fuqiuluo.shamrock.ui.theme.TabUnSelectedColor
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun NoticeTextDialog(
|
||||||
|
openDialog: MutableState<Boolean>,
|
||||||
|
title: String,
|
||||||
|
text: String
|
||||||
|
) {
|
||||||
|
AlertDialog(
|
||||||
|
shape = RoundedCornerShape(12.dp),
|
||||||
|
onDismissRequest = {
|
||||||
|
openDialog.value = false
|
||||||
|
},
|
||||||
|
title = {
|
||||||
|
Text(
|
||||||
|
text = title,
|
||||||
|
fontSize = 16.sp,
|
||||||
|
color = TabSelectedColor
|
||||||
|
)
|
||||||
|
},
|
||||||
|
text = {
|
||||||
|
Text(
|
||||||
|
text,
|
||||||
|
fontSize = 14.sp,
|
||||||
|
color = TabUnSelectedColor
|
||||||
|
)
|
||||||
|
},
|
||||||
|
confirmButton = {
|
||||||
|
Button(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth(),
|
||||||
|
onClick = {
|
||||||
|
openDialog.value = false
|
||||||
|
},
|
||||||
|
colors = ButtonDefaults.buttonColors(
|
||||||
|
containerColor = Color(0xFF2196F3),
|
||||||
|
contentColor = Color.White
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
Text("我知道了")
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
private fun NoticeDialogPreView() {
|
||||||
|
ShamrockTheme {
|
||||||
|
NoticeTextDialog(openDialog = remember {
|
||||||
|
mutableStateOf(true)
|
||||||
|
}, "Notice", "Text")
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
package moe.fuqiuluo.shamrock.ui.tools
|
||||||
|
|
||||||
|
operator fun <T> List<T>.get(range: IntRange): List<T> {
|
||||||
|
return this.subList(range.first, range.last)
|
||||||
|
}
|
||||||
|
|
||||||
|
val <T> List<T>.last: T
|
||||||
|
get() = this.last()
|
|
@ -0,0 +1,47 @@
|
||||||
|
package moe.fuqiuluo.shamrock.ui.tools
|
||||||
|
|
||||||
|
import androidx.compose.animation.animateColorAsState
|
||||||
|
import androidx.compose.animation.core.animateFloatAsState
|
||||||
|
import androidx.compose.animation.core.tween
|
||||||
|
import androidx.compose.foundation.Canvas
|
||||||
|
import androidx.compose.foundation.gestures.detectTapGestures
|
||||||
|
import androidx.compose.foundation.layout.size
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.derivedStateOf
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
|
import androidx.compose.runtime.saveable.rememberSaveable
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.geometry.CornerRadius
|
||||||
|
import androidx.compose.ui.geometry.Offset
|
||||||
|
import androidx.compose.ui.geometry.lerp
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.input.pointer.pointerInput
|
||||||
|
import androidx.compose.ui.platform.LocalDensity
|
||||||
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import androidx.compose.ui.unit.Dp
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import androidx.compose.animation.core.tween
|
||||||
|
import androidx.compose.foundation.Canvas
|
||||||
|
import androidx.compose.foundation.gestures.DraggableState
|
||||||
|
import androidx.compose.foundation.gestures.Orientation
|
||||||
|
import androidx.compose.foundation.gestures.detectTapGestures
|
||||||
|
import androidx.compose.foundation.gestures.draggable
|
||||||
|
import androidx.compose.foundation.gestures.rememberDraggableState
|
||||||
|
import androidx.compose.foundation.layout.*
|
||||||
|
import androidx.compose.material.*
|
||||||
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
|
import androidx.compose.runtime.*
|
||||||
|
import androidx.compose.runtime.saveable.rememberSaveable
|
||||||
|
import androidx.compose.ui.composed
|
||||||
|
import androidx.compose.ui.graphics.drawscope.scale
|
||||||
|
import androidx.compose.ui.graphics.lerp
|
||||||
|
import androidx.compose.ui.input.pointer.pointerInput
|
||||||
|
import androidx.compose.ui.platform.LocalDensity
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlin.math.min
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
package moe.fuqiuluo.shamrock.ui.tools
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import androidx.compose.foundation.Indication
|
||||||
|
import androidx.compose.foundation.IndicationInstance
|
||||||
|
import androidx.compose.foundation.clickable
|
||||||
|
import androidx.compose.foundation.interaction.InteractionSource
|
||||||
|
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.drawscope.ContentDrawScope
|
||||||
|
import androidx.compose.ui.semantics.Role
|
||||||
|
|
||||||
|
@SuppressLint("ComposableModifierFactory")
|
||||||
|
@Composable
|
||||||
|
fun Modifier.noRippleClickable(
|
||||||
|
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
|
||||||
|
indication: Indication? = null,
|
||||||
|
enabled: Boolean = true,
|
||||||
|
onClickLabel: String? = null,
|
||||||
|
role: Role? = null,
|
||||||
|
onClick: () -> Unit,
|
||||||
|
) = clickable(
|
||||||
|
interactionSource = interactionSource,
|
||||||
|
indication = indication,
|
||||||
|
enabled = enabled,
|
||||||
|
onClickLabel = onClickLabel,
|
||||||
|
role = role,
|
||||||
|
onClick = onClick,
|
||||||
|
)
|
||||||
|
|
||||||
|
object NoIndication : Indication {
|
||||||
|
private object NoIndicationInstance : IndicationInstance {
|
||||||
|
override fun ContentDrawScope.drawIndication() {
|
||||||
|
drawContent()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
override fun rememberUpdatedInstance(interactionSource: InteractionSource): IndicationInstance {
|
||||||
|
return NoIndicationInstance
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,209 @@
|
||||||
|
package moe.fuqiuluo.shamrock.ui.tools
|
||||||
|
|
||||||
|
import android.os.Build
|
||||||
|
import androidx.annotation.RequiresApi
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.layout.ColumnScope
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.material3.Card
|
||||||
|
import androidx.compose.material3.CardDefaults
|
||||||
|
import androidx.compose.material3.CardElevation
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.Stable
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.draw.drawBehind
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.graphics.Paint
|
||||||
|
import androidx.compose.ui.graphics.drawscope.drawIntoCanvas
|
||||||
|
import androidx.compose.ui.res.colorResource
|
||||||
|
import androidx.compose.ui.unit.Dp
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 绘制阴影范围
|
||||||
|
* [top] 顶部范围
|
||||||
|
* [start] 开始范围
|
||||||
|
* [bottom] 底部范围
|
||||||
|
* [end] 结束范围
|
||||||
|
* Create empty Shadow elevation
|
||||||
|
*/
|
||||||
|
open class ShadowElevation(
|
||||||
|
val top: Dp = 0.dp,
|
||||||
|
val start: Dp = 0.dp,
|
||||||
|
val bottom: Dp = 0.dp,
|
||||||
|
val end: Dp = 0.dp
|
||||||
|
){
|
||||||
|
companion object : ShadowElevation()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 绘制阴影内侧间距
|
||||||
|
* @param horizontal 横向
|
||||||
|
* @param vertical 纵向
|
||||||
|
* @return ShadowElevation
|
||||||
|
*/
|
||||||
|
@Stable
|
||||||
|
fun ShadowElevation.padding(
|
||||||
|
horizontal: Dp = 0.dp,
|
||||||
|
vertical: Dp = 0.dp
|
||||||
|
): ShadowElevation {
|
||||||
|
return ShadowElevation(
|
||||||
|
top = horizontal,
|
||||||
|
start = vertical,
|
||||||
|
bottom = horizontal,
|
||||||
|
end = vertical,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 绘制阴影所有范围
|
||||||
|
* @param elevation 圆角
|
||||||
|
* @return ShadowElevation
|
||||||
|
*/
|
||||||
|
fun ShadowElevation.all(
|
||||||
|
elevation: Dp = 0.dp,
|
||||||
|
): ShadowElevation {
|
||||||
|
return ShadowElevation(
|
||||||
|
top = elevation,
|
||||||
|
start = elevation,
|
||||||
|
bottom = elevation,
|
||||||
|
end = elevation,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class ShadowShape(
|
||||||
|
val topStart: Dp = 0.dp,
|
||||||
|
val bottomStart: Dp = 0.dp,
|
||||||
|
val topEnd: Dp = 0.dp,
|
||||||
|
val bottomEnd: Dp = 0.dp
|
||||||
|
)
|
||||||
|
|
||||||
|
fun ShadowShape.padding(
|
||||||
|
topAll: Dp = 0.dp,
|
||||||
|
bottomAll: Dp = 0.dp
|
||||||
|
): ShadowShape {
|
||||||
|
return ShadowShape(
|
||||||
|
topStart = topAll,
|
||||||
|
bottomStart = bottomAll,
|
||||||
|
topEnd = topAll,
|
||||||
|
bottomEnd = bottomAll,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun ShadowShape.all(
|
||||||
|
elevation: Dp = 0.dp,
|
||||||
|
): ShadowShape {
|
||||||
|
return ShadowShape(
|
||||||
|
topStart = elevation,
|
||||||
|
bottomStart = elevation,
|
||||||
|
topEnd = elevation,
|
||||||
|
bottomEnd = elevation,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 阴影Layout
|
||||||
|
* 不支持圆角,在Modifier中设置圆角会导致无作用
|
||||||
|
* 以子控件的大小为测试,请在子控件中设置padding及长宽
|
||||||
|
* @param shadowColor [Color] 绘制阴影颜色
|
||||||
|
* @param elevation [ShadowElevation] 绘制阴影范围
|
||||||
|
* @param shape [Dp] 绘制圆角
|
||||||
|
* @param offsetX [Dp] 偏移X轴
|
||||||
|
* @param offsetY [Dp] 偏移Y轴
|
||||||
|
* @param content (slot) 填充内容
|
||||||
|
* @receiver
|
||||||
|
*/
|
||||||
|
@RequiresApi(Build.VERSION_CODES.O)
|
||||||
|
@Composable
|
||||||
|
fun ShadowLayout(
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
shadowColor : Color = Color(0xffD3DBF9),
|
||||||
|
elevation: ShadowElevation = ShadowElevation(),
|
||||||
|
shape: Dp = 10.dp,
|
||||||
|
offsetX: Dp = 0.dp,
|
||||||
|
offsetY: Dp = 0.dp,
|
||||||
|
alpha: Float = 0.5f,
|
||||||
|
content: @Composable ColumnScope.() -> Unit,
|
||||||
|
) {
|
||||||
|
Card(
|
||||||
|
modifier = modifier
|
||||||
|
.padding(
|
||||||
|
top = elevation.top,
|
||||||
|
bottom = elevation.bottom,
|
||||||
|
start = elevation.start,
|
||||||
|
end = elevation.end
|
||||||
|
)
|
||||||
|
.drawColoredShadow(
|
||||||
|
shadowColor,
|
||||||
|
alpha,
|
||||||
|
borderRadius = shape,
|
||||||
|
shadowRadius = shape,
|
||||||
|
offsetX = offsetX,
|
||||||
|
offsetY = offsetY,
|
||||||
|
roundedRect = true
|
||||||
|
)
|
||||||
|
.background(Color.Transparent)
|
||||||
|
,
|
||||||
|
elevation = CardDefaults.cardElevation(
|
||||||
|
0.dp, 0.dp, 0.dp, 0.dp, 0.dp, 0.dp
|
||||||
|
),
|
||||||
|
shape = RoundedCornerShape(0.dp) ,
|
||||||
|
content = content,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 绘制基础阴影
|
||||||
|
* @param color 颜色
|
||||||
|
* @param alpha 颜色透明度
|
||||||
|
* @param borderRadius 阴影便捷圆角
|
||||||
|
* @param shadowRadius 阴影圆角
|
||||||
|
* @param offsetX 偏移X轴
|
||||||
|
* @param offsetY 偏移Y轴
|
||||||
|
* @param roundedRect 是否绘制圆角就行
|
||||||
|
*/
|
||||||
|
@RequiresApi(Build.VERSION_CODES.O)
|
||||||
|
fun Modifier.drawColoredShadow(
|
||||||
|
color: Color,
|
||||||
|
alpha: Float = 0.2f,
|
||||||
|
borderRadius: Dp = 0.dp,
|
||||||
|
shadowRadius: Dp = 0.dp,
|
||||||
|
offsetX: Dp = 0.dp,
|
||||||
|
offsetY: Dp = 0.dp,
|
||||||
|
roundedRect: Boolean = true
|
||||||
|
) = this.drawBehind {
|
||||||
|
/**将颜色转换为Argb的Int类型*/
|
||||||
|
val transparentColor = android.graphics.Color.toArgb(color.copy(alpha = .0f).value.toLong())
|
||||||
|
val shadowColor = android.graphics.Color.toArgb(color.copy(alpha = alpha).value.toLong())
|
||||||
|
/**调用Canvas绘制*/
|
||||||
|
this.drawIntoCanvas {
|
||||||
|
val paint = Paint()
|
||||||
|
paint.color = Color.Transparent
|
||||||
|
/**调用底层fragment Paint绘制*/
|
||||||
|
val frameworkPaint = paint.asFrameworkPaint()
|
||||||
|
frameworkPaint.color = transparentColor
|
||||||
|
/**绘制阴影*/
|
||||||
|
frameworkPaint.setShadowLayer(
|
||||||
|
shadowRadius.toPx(),
|
||||||
|
offsetX.toPx(),
|
||||||
|
offsetY.toPx(),
|
||||||
|
shadowColor
|
||||||
|
)
|
||||||
|
/**形状绘制*/
|
||||||
|
it.drawRoundRect(
|
||||||
|
0f,
|
||||||
|
0f,
|
||||||
|
this.size.width,
|
||||||
|
this.size.height,
|
||||||
|
if (roundedRect) this.size.height / 2 else borderRadius.toPx(),
|
||||||
|
if (roundedRect) this.size.height / 2 else borderRadius.toPx(),
|
||||||
|
paint
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,132 @@
|
||||||
|
package moe.fuqiuluo.shamrock.ui.tools
|
||||||
|
|
||||||
|
import androidx.compose.animation.animateColorAsState
|
||||||
|
import androidx.compose.animation.core.FastOutSlowInEasing
|
||||||
|
import androidx.compose.animation.core.LinearOutSlowInEasing
|
||||||
|
import androidx.compose.animation.core.animateDpAsState
|
||||||
|
import androidx.compose.animation.core.tween
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.clickable
|
||||||
|
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.defaultMinSize
|
||||||
|
import androidx.compose.foundation.layout.fillMaxHeight
|
||||||
|
import androidx.compose.foundation.layout.height
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.size
|
||||||
|
import androidx.compose.foundation.layout.width
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
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.draw.clip
|
||||||
|
import androidx.compose.ui.draw.shadow
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.layout.onGloballyPositioned
|
||||||
|
import androidx.compose.ui.platform.LocalDensity
|
||||||
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import androidx.compose.ui.unit.Dp
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun IosSwitch(
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
buttonHeight: Dp = 40.dp,
|
||||||
|
innerPadding: Dp = 3.5.dp,
|
||||||
|
shape: RoundedCornerShape = RoundedCornerShape(45.dp),
|
||||||
|
switchValue: Boolean,
|
||||||
|
positiveColor: Color = Color(0xFF35C759),
|
||||||
|
negativeColor: Color = Color(0xFFE9E9EA),
|
||||||
|
onValueChanged: (Boolean) -> Unit,
|
||||||
|
) {
|
||||||
|
var width by remember { (mutableStateOf(0.dp)) }
|
||||||
|
|
||||||
|
val interactionSource = remember {
|
||||||
|
MutableInteractionSource()
|
||||||
|
}
|
||||||
|
|
||||||
|
var switchClicked by remember {
|
||||||
|
mutableStateOf(switchValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
var padding by remember {
|
||||||
|
mutableStateOf(0.dp)
|
||||||
|
}
|
||||||
|
|
||||||
|
padding = if (!switchClicked) 0.dp else width - (width / 2)
|
||||||
|
|
||||||
|
val animateSize by animateDpAsState(
|
||||||
|
targetValue = if (!switchClicked) 0.dp else padding,
|
||||||
|
tween(
|
||||||
|
durationMillis = 300,
|
||||||
|
delayMillis = 0,
|
||||||
|
easing = LinearOutSlowInEasing
|
||||||
|
), label = "DpAnimation"
|
||||||
|
)
|
||||||
|
|
||||||
|
val animateBgColor by animateColorAsState(
|
||||||
|
targetValue = if (switchClicked) positiveColor else negativeColor,
|
||||||
|
tween(
|
||||||
|
durationMillis = 300,
|
||||||
|
delayMillis = 0,
|
||||||
|
easing = FastOutSlowInEasing
|
||||||
|
), label = "ColorAnimation"
|
||||||
|
)
|
||||||
|
|
||||||
|
val localDensity = LocalDensity.current
|
||||||
|
Box(
|
||||||
|
modifier = modifier
|
||||||
|
.defaultMinSize(
|
||||||
|
minWidth = buttonHeight * 2,
|
||||||
|
minHeight = buttonHeight
|
||||||
|
)
|
||||||
|
.onGloballyPositioned {
|
||||||
|
width = with(localDensity) {
|
||||||
|
it.size.width.toDp()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.height(buttonHeight)
|
||||||
|
.clip(shape = shape)
|
||||||
|
.background(animateBgColor)
|
||||||
|
.clickable(
|
||||||
|
interactionSource = interactionSource,
|
||||||
|
indication = null
|
||||||
|
) {
|
||||||
|
switchClicked = !switchClicked
|
||||||
|
onValueChanged(switchClicked)
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
Row {
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxHeight()
|
||||||
|
.width(animateSize)
|
||||||
|
.background(Color.Transparent)
|
||||||
|
)
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.size(buttonHeight)
|
||||||
|
.padding(innerPadding)
|
||||||
|
.shadow(elevation = 5.dp, shape)
|
||||||
|
.clip(shape = shape)
|
||||||
|
.background(Color.White)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
private fun SwitchPreView() {
|
||||||
|
IosSwitch(
|
||||||
|
switchValue = false,
|
||||||
|
buttonHeight = 22.dp,
|
||||||
|
onValueChanged = {
|
||||||
|
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
|
@ -0,0 +1,392 @@
|
||||||
|
package moe.fuqiuluo.shamrock.ui.tools
|
||||||
|
|
||||||
|
import androidx.compose.animation.animateColor
|
||||||
|
import androidx.compose.animation.core.LinearEasing
|
||||||
|
import androidx.compose.animation.core.tween
|
||||||
|
import androidx.compose.animation.core.updateTransition
|
||||||
|
import androidx.compose.foundation.Indication
|
||||||
|
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||||
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.ColumnScope
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.selection.selectable
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.material.ripple.rememberRipple
|
||||||
|
import androidx.compose.material3.LocalContentColor
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.ProvideTextStyle
|
||||||
|
import androidx.compose.material3.Typography
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.CompositionLocalProvider
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.layout.FirstBaseline
|
||||||
|
import androidx.compose.ui.layout.LastBaseline
|
||||||
|
import androidx.compose.ui.layout.Layout
|
||||||
|
import androidx.compose.ui.layout.Placeable
|
||||||
|
import androidx.compose.ui.layout.layoutId
|
||||||
|
import androidx.compose.ui.semantics.Role
|
||||||
|
import androidx.compose.ui.text.TextStyle
|
||||||
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
|
import androidx.compose.ui.unit.Density
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.unit.sp
|
||||||
|
import kotlin.math.max
|
||||||
|
|
||||||
|
private enum class ColorSchemeKeyTokens {
|
||||||
|
Background,
|
||||||
|
Error,
|
||||||
|
ErrorContainer,
|
||||||
|
InverseOnSurface,
|
||||||
|
InversePrimary,
|
||||||
|
InverseSurface,
|
||||||
|
OnBackground,
|
||||||
|
OnError,
|
||||||
|
OnErrorContainer,
|
||||||
|
OnPrimary,
|
||||||
|
OnPrimaryContainer,
|
||||||
|
OnSecondary,
|
||||||
|
OnSecondaryContainer,
|
||||||
|
OnSurface,
|
||||||
|
OnSurfaceVariant,
|
||||||
|
OnTertiary,
|
||||||
|
OnTertiaryContainer,
|
||||||
|
Outline,
|
||||||
|
OutlineVariant,
|
||||||
|
Primary,
|
||||||
|
PrimaryContainer,
|
||||||
|
Scrim,
|
||||||
|
Secondary,
|
||||||
|
SecondaryContainer,
|
||||||
|
Surface,
|
||||||
|
SurfaceTint,
|
||||||
|
SurfaceVariant,
|
||||||
|
Tertiary,
|
||||||
|
TertiaryContainer,
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum class ShapeKeyTokens {
|
||||||
|
CornerExtraLarge,
|
||||||
|
CornerExtraLargeTop,
|
||||||
|
CornerExtraSmall,
|
||||||
|
CornerExtraSmallTop,
|
||||||
|
CornerFull,
|
||||||
|
CornerLarge,
|
||||||
|
CornerLargeEnd,
|
||||||
|
CornerLargeTop,
|
||||||
|
CornerMedium,
|
||||||
|
CornerNone,
|
||||||
|
CornerSmall,
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum class TypographyKeyTokens {
|
||||||
|
BodyLarge,
|
||||||
|
BodyMedium,
|
||||||
|
BodySmall,
|
||||||
|
DisplayLarge,
|
||||||
|
DisplayMedium,
|
||||||
|
DisplaySmall,
|
||||||
|
HeadlineLarge,
|
||||||
|
HeadlineMedium,
|
||||||
|
HeadlineSmall,
|
||||||
|
LabelLarge,
|
||||||
|
LabelMedium,
|
||||||
|
LabelSmall,
|
||||||
|
TitleLarge,
|
||||||
|
TitleMedium,
|
||||||
|
TitleSmall,
|
||||||
|
}
|
||||||
|
|
||||||
|
private object ElevationTokens {
|
||||||
|
val Level0 = 0.0.dp
|
||||||
|
val Level1 = 1.0.dp
|
||||||
|
val Level2 = 3.0.dp
|
||||||
|
val Level3 = 6.0.dp
|
||||||
|
val Level4 = 8.0.dp
|
||||||
|
val Level5 = 12.0.dp
|
||||||
|
}
|
||||||
|
|
||||||
|
private object PrimaryNavigationTabTokens {
|
||||||
|
val ActiveIndicatorColor = ColorSchemeKeyTokens.Primary
|
||||||
|
val ActiveIndicatorHeight = 3.0.dp
|
||||||
|
val ActiveIndicatorShape = RoundedCornerShape(3.0.dp)
|
||||||
|
val ContainerColor = ColorSchemeKeyTokens.Surface
|
||||||
|
val ContainerElevation = ElevationTokens.Level0
|
||||||
|
val ContainerHeight = 48.0.dp
|
||||||
|
val ContainerShape = ShapeKeyTokens.CornerNone
|
||||||
|
val DividerColor = ColorSchemeKeyTokens.SurfaceVariant
|
||||||
|
val DividerHeight = 1.0.dp
|
||||||
|
val ActiveFocusIconColor = ColorSchemeKeyTokens.Primary
|
||||||
|
val ActiveHoverIconColor = ColorSchemeKeyTokens.Primary
|
||||||
|
val ActiveIconColor = ColorSchemeKeyTokens.Primary
|
||||||
|
val ActivePressedIconColor = ColorSchemeKeyTokens.Primary
|
||||||
|
val IconAndLabelTextContainerHeight = 64.0.dp
|
||||||
|
val IconSize = 24.0.dp
|
||||||
|
val InactiveFocusIconColor = ColorSchemeKeyTokens.OnSurface
|
||||||
|
val InactiveHoverIconColor = ColorSchemeKeyTokens.OnSurface
|
||||||
|
val InactiveIconColor = ColorSchemeKeyTokens.OnSurfaceVariant
|
||||||
|
val InactivePressedIconColor = ColorSchemeKeyTokens.OnSurface
|
||||||
|
val ActiveFocusLabelTextColor = ColorSchemeKeyTokens.Primary
|
||||||
|
val ActiveHoverLabelTextColor = ColorSchemeKeyTokens.Primary
|
||||||
|
val ActiveLabelTextColor = ColorSchemeKeyTokens.Primary
|
||||||
|
val ActivePressedLabelTextColor = ColorSchemeKeyTokens.Primary
|
||||||
|
val InactiveFocusLabelTextColor = ColorSchemeKeyTokens.OnSurface
|
||||||
|
val InactiveHoverLabelTextColor = ColorSchemeKeyTokens.OnSurface
|
||||||
|
val InactiveLabelTextColor = ColorSchemeKeyTokens.OnSurfaceVariant
|
||||||
|
val InactivePressedLabelTextColor = ColorSchemeKeyTokens.OnSurface
|
||||||
|
val LabelTextFont = TypographyKeyTokens.TitleSmall
|
||||||
|
}
|
||||||
|
|
||||||
|
private val HorizontalTextPadding = 16.dp
|
||||||
|
private val LargeTabHeight = 72.dp
|
||||||
|
private val SmallTabHeight = PrimaryNavigationTabTokens.ContainerHeight
|
||||||
|
private val IconDistanceFromBaseline = 20.sp
|
||||||
|
// Distance from the top of the indicator to the text baseline when there is one line of text and an
|
||||||
|
// icon
|
||||||
|
private val SingleLineTextBaselineWithIcon = 14.dp
|
||||||
|
// Distance from the top of the indicator to the last text baseline when there are two lines of text
|
||||||
|
// and an icon
|
||||||
|
private val DoubleLineTextBaselineWithIcon = 6.dp
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun TabBaselineLayout(
|
||||||
|
text: @Composable (() -> Unit)?,
|
||||||
|
icon: @Composable (() -> Unit)?
|
||||||
|
) {
|
||||||
|
Layout(
|
||||||
|
{
|
||||||
|
if (text != null) {
|
||||||
|
Box(
|
||||||
|
Modifier
|
||||||
|
.layoutId("text")
|
||||||
|
.padding(horizontal = HorizontalTextPadding)
|
||||||
|
) { text() }
|
||||||
|
}
|
||||||
|
if (icon != null) {
|
||||||
|
Box(Modifier.layoutId("icon")) { icon() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
) { measurables, constraints ->
|
||||||
|
val textPlaceable = text?.let {
|
||||||
|
measurables.first { it.layoutId == "text" }.measure(
|
||||||
|
// Measure with loose constraints for height as we don't want the text to take up more
|
||||||
|
// space than it needs
|
||||||
|
constraints.copy(minHeight = 0)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
val iconPlaceable = icon?.let {
|
||||||
|
measurables.first { it.layoutId == "icon" }.measure(constraints)
|
||||||
|
}
|
||||||
|
|
||||||
|
val tabWidth = max(textPlaceable?.width ?: 0, iconPlaceable?.width ?: 0)
|
||||||
|
|
||||||
|
val specHeight = if (textPlaceable != null && iconPlaceable != null) {
|
||||||
|
LargeTabHeight
|
||||||
|
} else {
|
||||||
|
SmallTabHeight
|
||||||
|
}.roundToPx()
|
||||||
|
|
||||||
|
val tabHeight = max(
|
||||||
|
specHeight,
|
||||||
|
(iconPlaceable?.height ?: 0) + (textPlaceable?.height ?: 0) +
|
||||||
|
IconDistanceFromBaseline.roundToPx()
|
||||||
|
)
|
||||||
|
|
||||||
|
val firstBaseline = textPlaceable?.get(FirstBaseline)
|
||||||
|
val lastBaseline = textPlaceable?.get(LastBaseline)
|
||||||
|
|
||||||
|
layout(tabWidth, tabHeight) {
|
||||||
|
when {
|
||||||
|
textPlaceable != null && iconPlaceable != null -> placeTextAndIcon(
|
||||||
|
density = this@Layout,
|
||||||
|
textPlaceable = textPlaceable,
|
||||||
|
iconPlaceable = iconPlaceable,
|
||||||
|
tabWidth = tabWidth,
|
||||||
|
tabHeight = tabHeight,
|
||||||
|
firstBaseline = firstBaseline!!,
|
||||||
|
lastBaseline = lastBaseline!!
|
||||||
|
)
|
||||||
|
textPlaceable != null -> placeTextOrIcon(textPlaceable, tabHeight)
|
||||||
|
iconPlaceable != null -> placeTextOrIcon(iconPlaceable, tabHeight)
|
||||||
|
else -> {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun Placeable.PlacementScope.placeTextOrIcon(
|
||||||
|
textOrIconPlaceable: Placeable,
|
||||||
|
tabHeight: Int
|
||||||
|
) {
|
||||||
|
val contentY = (tabHeight - textOrIconPlaceable.height) / 2
|
||||||
|
textOrIconPlaceable.placeRelative(0, contentY)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun Placeable.PlacementScope.placeTextAndIcon(
|
||||||
|
density: Density,
|
||||||
|
textPlaceable: Placeable,
|
||||||
|
iconPlaceable: Placeable,
|
||||||
|
tabWidth: Int,
|
||||||
|
tabHeight: Int,
|
||||||
|
firstBaseline: Int,
|
||||||
|
lastBaseline: Int
|
||||||
|
) {
|
||||||
|
val baselineOffset = if (firstBaseline == lastBaseline) {
|
||||||
|
SingleLineTextBaselineWithIcon
|
||||||
|
} else {
|
||||||
|
DoubleLineTextBaselineWithIcon
|
||||||
|
}
|
||||||
|
|
||||||
|
// Total offset between the last text baseline and the bottom of the Tab layout
|
||||||
|
val textOffset = with(density) {
|
||||||
|
baselineOffset.roundToPx() + PrimaryNavigationTabTokens.ActiveIndicatorHeight.roundToPx()
|
||||||
|
}
|
||||||
|
|
||||||
|
// How much space there is between the top of the icon (essentially the top of this layout)
|
||||||
|
// and the top of the text layout's bounding box (not baseline)
|
||||||
|
val iconOffset = with(density) {
|
||||||
|
iconPlaceable.height + IconDistanceFromBaseline.roundToPx() - firstBaseline
|
||||||
|
}
|
||||||
|
|
||||||
|
val textPlaceableX = (tabWidth - textPlaceable.width) / 2
|
||||||
|
val textPlaceableY = tabHeight - lastBaseline - textOffset
|
||||||
|
textPlaceable.placeRelative(textPlaceableX, textPlaceableY)
|
||||||
|
|
||||||
|
val iconPlaceableX = (tabWidth - iconPlaceable.width) / 2
|
||||||
|
val iconPlaceableY = textPlaceableY - iconOffset
|
||||||
|
iconPlaceable.placeRelative(iconPlaceableX, iconPlaceableY)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun ShamrockTab(
|
||||||
|
selected: Boolean,
|
||||||
|
onClick: () -> Unit,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
enabled: Boolean = true,
|
||||||
|
text: @Composable (() -> Unit)? = null,
|
||||||
|
icon: @Composable (() -> Unit)? = null,
|
||||||
|
selectedContentColor: Color = LocalContentColor.current,
|
||||||
|
unselectedContentColor: Color = selectedContentColor,
|
||||||
|
indication: Indication? = rememberRipple(bounded = true, color = selectedContentColor),
|
||||||
|
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }
|
||||||
|
) {
|
||||||
|
val styledText: @Composable (() -> Unit)? = text?.let {
|
||||||
|
@Composable {
|
||||||
|
val style =
|
||||||
|
MaterialTheme.typography.fromToken(PrimaryNavigationTabTokens.LabelTextFont)
|
||||||
|
.copy(textAlign = TextAlign.Center)
|
||||||
|
ProvideTextStyle(style, content = text)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ShamrockTab(
|
||||||
|
selected,
|
||||||
|
onClick,
|
||||||
|
modifier,
|
||||||
|
enabled,
|
||||||
|
selectedContentColor,
|
||||||
|
unselectedContentColor,
|
||||||
|
interactionSource,
|
||||||
|
indication
|
||||||
|
) {
|
||||||
|
TabBaselineLayout(icon = icon, text = styledText)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun ShamrockTab(
|
||||||
|
selected: Boolean,
|
||||||
|
onClick: () -> Unit,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
enabled: Boolean = true,
|
||||||
|
selectedContentColor: Color = LocalContentColor.current,
|
||||||
|
unselectedContentColor: Color = selectedContentColor,
|
||||||
|
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
|
||||||
|
indication: Indication? = rememberRipple(bounded = true, color = selectedContentColor),
|
||||||
|
content: @Composable ColumnScope.() -> Unit
|
||||||
|
) {
|
||||||
|
// The color of the Ripple should always the selected color, as we want to show the color
|
||||||
|
// before the item is considered selected, and hence before the new contentColor is
|
||||||
|
// provided by TabTransition.
|
||||||
|
|
||||||
|
TabTransition(selectedContentColor, unselectedContentColor, selected) {
|
||||||
|
Column(
|
||||||
|
modifier = modifier
|
||||||
|
.selectable(
|
||||||
|
selected = selected,
|
||||||
|
onClick = onClick,
|
||||||
|
enabled = enabled,
|
||||||
|
role = Role.Tab,
|
||||||
|
interactionSource = interactionSource,
|
||||||
|
indication = indication
|
||||||
|
)
|
||||||
|
.fillMaxWidth(),
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
|
verticalArrangement = Arrangement.Center,
|
||||||
|
content = content
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private const val TabFadeInAnimationDuration = 150
|
||||||
|
private const val TabFadeInAnimationDelay = 100
|
||||||
|
private const val TabFadeOutAnimationDuration = 100
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun TabTransition(
|
||||||
|
activeColor: Color,
|
||||||
|
inactiveColor: Color,
|
||||||
|
selected: Boolean,
|
||||||
|
content: @Composable () -> Unit
|
||||||
|
) {
|
||||||
|
val transition = updateTransition(selected, label = "")
|
||||||
|
val color by transition.animateColor(
|
||||||
|
transitionSpec = {
|
||||||
|
if (false isTransitioningTo true) {
|
||||||
|
tween(
|
||||||
|
durationMillis = TabFadeInAnimationDuration,
|
||||||
|
delayMillis = TabFadeInAnimationDelay,
|
||||||
|
easing = LinearEasing
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
tween(
|
||||||
|
durationMillis = TabFadeOutAnimationDuration,
|
||||||
|
easing = LinearEasing
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}, label = ""
|
||||||
|
) {
|
||||||
|
if (it) activeColor else inactiveColor
|
||||||
|
}
|
||||||
|
CompositionLocalProvider(
|
||||||
|
LocalContentColor provides color,
|
||||||
|
content = content
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun Typography.fromToken(value: TypographyKeyTokens): TextStyle {
|
||||||
|
return when (value) {
|
||||||
|
TypographyKeyTokens.DisplayLarge -> displayLarge
|
||||||
|
TypographyKeyTokens.DisplayMedium -> displayMedium
|
||||||
|
TypographyKeyTokens.DisplaySmall -> displaySmall
|
||||||
|
TypographyKeyTokens.HeadlineLarge -> headlineLarge
|
||||||
|
TypographyKeyTokens.HeadlineMedium -> headlineMedium
|
||||||
|
TypographyKeyTokens.HeadlineSmall -> headlineSmall
|
||||||
|
TypographyKeyTokens.TitleLarge -> titleLarge
|
||||||
|
TypographyKeyTokens.TitleMedium -> titleMedium
|
||||||
|
TypographyKeyTokens.TitleSmall -> titleSmall
|
||||||
|
TypographyKeyTokens.BodyLarge -> bodyLarge
|
||||||
|
TypographyKeyTokens.BodyMedium -> bodyMedium
|
||||||
|
TypographyKeyTokens.BodySmall -> bodySmall
|
||||||
|
TypographyKeyTokens.LabelLarge -> labelLarge
|
||||||
|
TypographyKeyTokens.LabelMedium -> labelMedium
|
||||||
|
TypographyKeyTokens.LabelSmall -> labelSmall
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
<vector android:height="24dp" android:tint="#6C6C6C"
|
||||||
|
android:viewportHeight="24" android:viewportWidth="24"
|
||||||
|
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="@android:color/white" android:pathData="M19,3H5C3.89,3 3,3.9 3,5v14c0,1.1 0.89,2 2,2h14c1.1,0 2,-0.9 2,-2V5C21,3.9 20.11,3 19,3zM19,19H5V7h14V19zM13.5,13c0,0.83 -0.67,1.5 -1.5,1.5s-1.5,-0.67 -1.5,-1.5c0,-0.83 0.67,-1.5 1.5,-1.5S13.5,12.17 13.5,13zM12,9c-2.73,0 -5.06,1.66 -6,4c0.94,2.34 3.27,4 6,4s5.06,-1.66 6,-4C17.06,10.66 14.73,9 12,9zM12,15.5c-1.38,0 -2.5,-1.12 -2.5,-2.5c0,-1.38 1.12,-2.5 2.5,-2.5c1.38,0 2.5,1.12 2.5,2.5C14.5,14.38 13.38,15.5 12,15.5z"/>
|
||||||
|
</vector>
|
After Width: | Height: | Size: 14 KiB |
|
@ -0,0 +1,170 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="108dp"
|
||||||
|
android:height="108dp"
|
||||||
|
android:viewportWidth="108"
|
||||||
|
android:viewportHeight="108">
|
||||||
|
<path
|
||||||
|
android:fillColor="#3DDC84"
|
||||||
|
android:pathData="M0,0h108v108h-108z" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M9,0L9,108"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M19,0L19,108"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M29,0L29,108"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M39,0L39,108"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M49,0L49,108"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M59,0L59,108"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M69,0L69,108"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M79,0L79,108"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M89,0L89,108"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M99,0L99,108"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M0,9L108,9"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M0,19L108,19"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M0,29L108,29"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M0,39L108,39"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M0,49L108,49"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M0,59L108,59"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M0,69L108,69"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M0,79L108,79"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M0,89L108,89"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M0,99L108,99"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M19,29L89,29"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M19,39L89,39"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M19,49L89,49"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M19,59L89,59"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M19,69L89,69"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M19,79L89,79"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M29,19L29,89"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M39,19L39,89"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M49,19L49,89"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M59,19L59,89"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M69,19L69,89"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M79,19L79,89"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
</vector>
|
|
@ -0,0 +1,30 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:aapt="http://schemas.android.com/aapt"
|
||||||
|
android:width="108dp"
|
||||||
|
android:height="108dp"
|
||||||
|
android:viewportWidth="108"
|
||||||
|
android:viewportHeight="108">
|
||||||
|
<path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
|
||||||
|
<aapt:attr name="android:fillColor">
|
||||||
|
<gradient
|
||||||
|
android:endX="85.84757"
|
||||||
|
android:endY="92.4963"
|
||||||
|
android:startX="42.9492"
|
||||||
|
android:startY="49.59793"
|
||||||
|
android:type="linear">
|
||||||
|
<item
|
||||||
|
android:color="#44000000"
|
||||||
|
android:offset="0.0" />
|
||||||
|
<item
|
||||||
|
android:color="#00000000"
|
||||||
|
android:offset="1.0" />
|
||||||
|
</gradient>
|
||||||
|
</aapt:attr>
|
||||||
|
</path>
|
||||||
|
<path
|
||||||
|
android:fillColor="#FFFFFF"
|
||||||
|
android:fillType="nonZero"
|
||||||
|
android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
|
||||||
|
android:strokeWidth="1"
|
||||||
|
android:strokeColor="#00000000" />
|
||||||
|
</vector>
|
After Width: | Height: | Size: 34 KiB |
|
@ -0,0 +1,5 @@
|
||||||
|
<vector android:height="24dp" android:tint="#6F6F6F"
|
||||||
|
android:viewportHeight="24" android:viewportWidth="24"
|
||||||
|
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="@android:color/white" android:pathData="M13,13L13,13c-0.56,0.56 -1.45,0.56 -2,0.01L11,13c-0.55,-0.55 -0.55,-1.44 0,-1.99L11,11c0.55,-0.55 1.44,-0.55 1.99,0L13,11C13.55,11.55 13.55,12.45 13,13zM12,6l2.12,2.12l2.5,-2.5l-3.2,-3.2c-0.78,-0.78 -2.05,-0.78 -2.83,0l-3.2,3.2l2.5,2.5L12,6zM6,12l2.12,-2.12l-2.5,-2.5l-3.2,3.2c-0.78,0.78 -0.78,2.05 0,2.83l3.2,3.2l2.5,-2.5L6,12zM18,12l-2.12,2.12l2.5,2.5l3.2,-3.2c0.78,-0.78 0.78,-2.05 0,-2.83l-3.2,-3.2l-2.5,2.5L18,12zM12,18l-2.12,-2.12l-2.5,2.5l3.2,3.2c0.78,0.78 2.05,0.78 2.83,0l3.2,-3.2l-2.5,-2.5L12,18z"/>
|
||||||
|
</vector>
|
|
@ -0,0 +1,5 @@
|
||||||
|
<vector android:height="24dp" android:tint="#6F6F6F"
|
||||||
|
android:viewportHeight="24" android:viewportWidth="24"
|
||||||
|
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="@android:color/white" android:pathData="M4,13h6c0.55,0 1,-0.45 1,-1L11,4c0,-0.55 -0.45,-1 -1,-1L4,3c-0.55,0 -1,0.45 -1,1v8c0,0.55 0.45,1 1,1zM4,21h6c0.55,0 1,-0.45 1,-1v-4c0,-0.55 -0.45,-1 -1,-1L4,15c-0.55,0 -1,0.45 -1,1v4c0,0.55 0.45,1 1,1zM14,21h6c0.55,0 1,-0.45 1,-1v-8c0,-0.55 -0.45,-1 -1,-1h-6c-0.55,0 -1,0.45 -1,1v8c0,0.55 0.45,1 1,1zM13,4v4c0,0.55 0.45,1 1,1h6c0.55,0 1,-0.45 1,-1L21,4c0,-0.55 -0.45,-1 -1,-1h-6c-0.55,0 -1,0.45 -1,1z"/>
|
||||||
|
</vector>
|
|
@ -0,0 +1,5 @@
|
||||||
|
<vector android:height="24dp" android:tint="#FFFFFF"
|
||||||
|
android:viewportHeight="24" android:viewportWidth="24"
|
||||||
|
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="@android:color/white" android:pathData="M9,16.2l-3.5,-3.5c-0.39,-0.39 -1.01,-0.39 -1.4,0 -0.39,0.39 -0.39,1.01 0,1.4l4.19,4.19c0.39,0.39 1.02,0.39 1.41,0L20.3,7.7c0.39,-0.39 0.39,-1.01 0,-1.4 -0.39,-0.39 -1.01,-0.39 -1.4,0L9,16.2z"/>
|
||||||
|
</vector>
|
|
@ -0,0 +1,5 @@
|
||||||
|
<vector android:height="24dp" android:tint="#6F6F6F"
|
||||||
|
android:viewportHeight="24" android:viewportWidth="24"
|
||||||
|
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="@android:color/white" android:pathData="M10,19v-5h4v5c0,0.55 0.45,1 1,1h3c0.55,0 1,-0.45 1,-1v-7h1.7c0.46,0 0.68,-0.57 0.33,-0.87L12.67,3.6c-0.38,-0.34 -0.96,-0.34 -1.34,0l-8.36,7.53c-0.34,0.3 -0.13,0.87 0.33,0.87H5v7c0,0.55 0.45,1 1,1h3c0.55,0 1,-0.45 1,-1z"/>
|
||||||
|
</vector>
|
|
@ -0,0 +1,5 @@
|
||||||
|
<vector android:height="24dp" android:tint="#6C6C6C"
|
||||||
|
android:viewportHeight="24" android:viewportWidth="24"
|
||||||
|
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="@android:color/white" android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,17c-0.55,0 -1,-0.45 -1,-1v-4c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v4c0,0.55 -0.45,1 -1,1zM13,9h-2L11,7h2v2z"/>
|
||||||
|
</vector>
|
|
@ -0,0 +1,6 @@
|
||||||
|
<vector android:height="24dp" android:tint="#6F6F6F"
|
||||||
|
android:viewportHeight="24" android:viewportWidth="24"
|
||||||
|
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="@android:color/white" android:pathData="M19,3H5C3.9,3 3,3.9 3,5v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V5C21,3.9 20.1,3 19,3zM7.68,14.98H6V9h1.71c1.28,0 1.71,1.03 1.71,1.71l0,2.56C9.42,13.95 9,14.98 7.68,14.98zM12.38,11.46v1.07h-1.18v1.39h1.93v1.07h-2.25c-0.4,0.01 -0.74,-0.31 -0.75,-0.71V9.75c-0.01,-0.4 0.31,-0.74 0.71,-0.75h2.28l0,1.07h-1.92v1.39H12.38zM16.88,14.23c-0.48,1.11 -1.33,0.89 -1.71,0L13.77,9h1.18l1.07,4.11L17.09,9h1.18L16.88,14.23z"/>
|
||||||
|
<path android:fillColor="@android:color/white" android:pathData="M7.77,10.12H7.14v3.77h0.63c0.14,0 0.28,-0.05 0.42,-0.16c0.14,-0.1 0.21,-0.26 0.21,-0.47v-2.52c0,-0.21 -0.07,-0.37 -0.21,-0.47C8.05,10.17 7.91,10.12 7.77,10.12z"/>
|
||||||
|
</vector>
|
|
@ -0,0 +1,6 @@
|
||||||
|
<vector android:height="24dp" android:tint="#6F6F6F"
|
||||||
|
android:viewportHeight="24" android:viewportWidth="24"
|
||||||
|
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="@android:color/white" android:pathData="M15.11,12.45L14,10.24l-3.11,6.21C10.73,16.79 10.38,17 10,17s-0.73,-0.21 -0.89,-0.55L7.38,13H2v5c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2v-5h-6C15.62,13 15.27,12.79 15.11,12.45z"/>
|
||||||
|
<path android:fillColor="@android:color/white" android:pathData="M20,4H4C2.9,4 2,4.9 2,6v5h6c0.38,0 0.73,0.21 0.89,0.55L10,13.76l3.11,-6.21c0.34,-0.68 1.45,-0.68 1.79,0L16.62,11H22V6C22,4.9 21.1,4 20,4z"/>
|
||||||
|
</vector>
|
|
@ -0,0 +1,5 @@
|
||||||
|
<vector android:height="24dp" android:tint="#FFFFFF"
|
||||||
|
android:viewportHeight="24" android:viewportWidth="24"
|
||||||
|
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="@android:color/white" android:pathData="M18.75,3.94L4.07,10.08c-0.83,0.35 -0.81,1.53 0.02,1.85L9.43,14c0.26,0.1 0.47,0.31 0.57,0.57l2.06,5.33c0.32,0.84 1.51,0.86 1.86,0.03l6.15,-14.67c0.33,-0.83 -0.5,-1.66 -1.32,-1.32z"/>
|
||||||
|
</vector>
|
|
@ -0,0 +1,5 @@
|
||||||
|
<vector android:height="24dp" android:tint="#FFFFFF"
|
||||||
|
android:viewportHeight="24" android:viewportWidth="24"
|
||||||
|
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="@android:color/white" android:pathData="M12,6.34l6.95,-2.58c0.8,-0.3 1.58,0.48 1.29,1.29L17.66,12L12,6.34zM21.9,19.07L4.93,2.1c-0.39,-0.39 -1.02,-0.39 -1.41,0c-0.39,0.39 -0.39,1.02 0,1.41l4.36,4.36l-4.2,1.56C3.27,9.59 3,9.97 3,10.4c0,0.42 0.26,0.8 0.65,0.96l6.42,2.57l2.57,6.42C12.8,20.74 13.18,21 13.6,21c0.43,0 0.82,-0.27 0.97,-0.67l1.56,-4.2l4.36,4.36c0.39,0.39 1.02,0.39 1.41,0C22.29,20.09 22.29,19.46 21.9,19.07z"/>
|
||||||
|
</vector>
|
|
@ -0,0 +1,5 @@
|
||||||
|
<vector android:height="24dp" android:tint="#6C6C6C"
|
||||||
|
android:viewportHeight="24" android:viewportWidth="24"
|
||||||
|
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="@android:color/white" android:pathData="M4.47,21h15.06c1.54,0 2.5,-1.67 1.73,-3L13.73,4.99c-0.77,-1.33 -2.69,-1.33 -3.46,0L2.74,18c-0.77,1.33 0.19,3 1.73,3zM12,14c-0.55,0 -1,-0.45 -1,-1v-2c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v2c0,0.55 -0.45,1 -1,1zM13,18h-2v-2h2v2z"/>
|
||||||
|
</vector>
|
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<background android:drawable="@drawable/ic_launcher_background" />
|
||||||
|
<foreground android:drawable="@drawable/ic_launcher_foreground" />
|
||||||
|
<monochrome android:drawable="@drawable/ic_launcher_foreground" />
|
||||||
|
</adaptive-icon>
|
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<background android:drawable="@drawable/ic_launcher_background" />
|
||||||
|
<foreground android:drawable="@drawable/ic_launcher_foreground" />
|
||||||
|
<monochrome android:drawable="@drawable/ic_launcher_foreground" />
|
||||||
|
</adaptive-icon>
|
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 2.8 KiB |
After Width: | Height: | Size: 982 B |
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 1.9 KiB |
After Width: | Height: | Size: 3.8 KiB |
After Width: | Height: | Size: 2.8 KiB |
After Width: | Height: | Size: 5.8 KiB |
After Width: | Height: | Size: 3.8 KiB |
After Width: | Height: | Size: 7.6 KiB |
|
@ -0,0 +1,10 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<color name="purple_200">#FFBB86FC</color>
|
||||||
|
<color name="purple_500">#FF6200EE</color>
|
||||||
|
<color name="purple_700">#FF3700B3</color>
|
||||||
|
<color name="teal_200">#FF03DAC5</color>
|
||||||
|
<color name="teal_700">#FF018786</color>
|
||||||
|
<color name="black">#FF000000</color>
|
||||||
|
<color name="white">#FFFFFFFF</color>
|
||||||
|
</resources>
|
|
@ -0,0 +1,3 @@
|
||||||
|
<resources>
|
||||||
|
<string name="app_name">Shamrock</string>
|
||||||
|
</resources>
|
|
@ -0,0 +1,5 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
|
||||||
|
<style name="Theme.Shamrock" parent="android:Theme.Material.Light.NoActionBar" />
|
||||||
|
</resources>
|
|
@ -0,0 +1,13 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?><!--
|
||||||
|
Sample backup rules file; uncomment and customize as necessary.
|
||||||
|
See https://developer.android.com/guide/topics/data/autobackup
|
||||||
|
for details.
|
||||||
|
Note: This file is ignored for devices older that API 31
|
||||||
|
See https://developer.android.com/about/versions/12/backup-restore
|
||||||
|
-->
|
||||||
|
<full-backup-content>
|
||||||
|
<!--
|
||||||
|
<include domain="sharedpref" path="."/>
|
||||||
|
<exclude domain="sharedpref" path="device.xml"/>
|
||||||
|
-->
|
||||||
|
</full-backup-content>
|
|
@ -0,0 +1,19 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?><!--
|
||||||
|
Sample data extraction rules file; uncomment and customize as necessary.
|
||||||
|
See https://developer.android.com/about/versions/12/backup-restore#xml-changes
|
||||||
|
for details.
|
||||||
|
-->
|
||||||
|
<data-extraction-rules>
|
||||||
|
<cloud-backup>
|
||||||
|
<!-- TODO: Use <include> and <exclude> to control what is backed up.
|
||||||
|
<include .../>
|
||||||
|
<exclude .../>
|
||||||
|
-->
|
||||||
|
</cloud-backup>
|
||||||
|
<!--
|
||||||
|
<device-transfer>
|
||||||
|
<include .../>
|
||||||
|
<exclude .../>
|
||||||
|
</device-transfer>
|
||||||
|
-->
|
||||||
|
</data-extraction-rules>
|
|
@ -0,0 +1,17 @@
|
||||||
|
package moe.fuqiuluo.shamrock
|
||||||
|
|
||||||
|
import org.junit.Test
|
||||||
|
|
||||||
|
import org.junit.Assert.*
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Example local unit test, which will execute on the development machine (host).
|
||||||
|
*
|
||||||
|
* See [testing documentation](http://d.android.com/tools/testing).
|
||||||
|
*/
|
||||||
|
class ExampleUnitTest {
|
||||||
|
@Test
|
||||||
|
fun addition_isCorrect() {
|
||||||
|
assertEquals(4, 2 + 2)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||||
|
plugins {
|
||||||
|
id("com.android.application") version "8.1.0" apply false
|
||||||
|
id("org.jetbrains.kotlin.android") version "1.8.10" apply false
|
||||||
|
id("org.jetbrains.kotlin.plugin.serialization") version "1.8.10" apply false
|
||||||
|
id("com.android.library") version "8.1.0" apply false
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
# Project-wide Gradle settings.
|
||||||
|
# IDE (e.g. Android Studio) users:
|
||||||
|
# Gradle settings configured through the IDE *will override*
|
||||||
|
# any settings specified in this file.
|
||||||
|
# For more details on how to configure your build environment visit
|
||||||
|
# http://www.gradle.org/docs/current/userguide/build_environment.html
|
||||||
|
# Specifies the JVM arguments used for the daemon process.
|
||||||
|
# The setting is particularly useful for tweaking memory settings.
|
||||||
|
org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
|
||||||
|
# When configured, Gradle will run in incubating parallel mode.
|
||||||
|
# This option should only be used with decoupled projects. More details, visit
|
||||||
|
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
|
||||||
|
# org.gradle.parallel=true
|
||||||
|
# AndroidX package structure to make it clearer which packages are bundled with the
|
||||||
|
# Android operating system, and which are packaged with your app's APK
|
||||||
|
# https://developer.android.com/topic/libraries/support-library/androidx-rn
|
||||||
|
android.useAndroidX=true
|
||||||
|
# Kotlin code style for this project: "official" or "obsolete":
|
||||||
|
kotlin.code.style=official
|
||||||
|
# Enables namespacing of each library's R class so that its R class includes only the
|
||||||
|
# resources declared in the library itself and none from the library's dependencies,
|
||||||
|
# thereby reducing the size of the R class for that library
|
||||||
|
android.nonTransitiveRClass=true
|
|
@ -0,0 +1,6 @@
|
||||||
|
#Thu Jul 27 20:53:51 CST 2023
|
||||||
|
distributionBase=GRADLE_USER_HOME
|
||||||
|
distributionPath=wrapper/dists
|
||||||
|
distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-bin.zip
|
||||||
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
zipStorePath=wrapper/dists
|
|
@ -0,0 +1,185 @@
|
||||||
|
#!/usr/bin/env sh
|
||||||
|
|
||||||
|
#
|
||||||
|
# Copyright 2015 the original author or authors.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
#
|
||||||
|
|
||||||
|
##############################################################################
|
||||||
|
##
|
||||||
|
## Gradle start up script for UN*X
|
||||||
|
##
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
# Attempt to set APP_HOME
|
||||||
|
# Resolve links: $0 may be a link
|
||||||
|
PRG="$0"
|
||||||
|
# Need this for relative symlinks.
|
||||||
|
while [ -h "$PRG" ] ; do
|
||||||
|
ls=`ls -ld "$PRG"`
|
||||||
|
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||||
|
if expr "$link" : '/.*' > /dev/null; then
|
||||||
|
PRG="$link"
|
||||||
|
else
|
||||||
|
PRG=`dirname "$PRG"`"/$link"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
SAVED="`pwd`"
|
||||||
|
cd "`dirname \"$PRG\"`/" >/dev/null
|
||||||
|
APP_HOME="`pwd -P`"
|
||||||
|
cd "$SAVED" >/dev/null
|
||||||
|
|
||||||
|
APP_NAME="Gradle"
|
||||||
|
APP_BASE_NAME=`basename "$0"`
|
||||||
|
|
||||||
|
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||||
|
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||||
|
|
||||||
|
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||||
|
MAX_FD="maximum"
|
||||||
|
|
||||||
|
warn () {
|
||||||
|
echo "$*"
|
||||||
|
}
|
||||||
|
|
||||||
|
die () {
|
||||||
|
echo
|
||||||
|
echo "$*"
|
||||||
|
echo
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# OS specific support (must be 'true' or 'false').
|
||||||
|
cygwin=false
|
||||||
|
msys=false
|
||||||
|
darwin=false
|
||||||
|
nonstop=false
|
||||||
|
case "`uname`" in
|
||||||
|
CYGWIN* )
|
||||||
|
cygwin=true
|
||||||
|
;;
|
||||||
|
Darwin* )
|
||||||
|
darwin=true
|
||||||
|
;;
|
||||||
|
MINGW* )
|
||||||
|
msys=true
|
||||||
|
;;
|
||||||
|
NONSTOP* )
|
||||||
|
nonstop=true
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||||
|
|
||||||
|
|
||||||
|
# Determine the Java command to use to start the JVM.
|
||||||
|
if [ -n "$JAVA_HOME" ] ; then
|
||||||
|
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||||
|
# IBM's JDK on AIX uses strange locations for the executables
|
||||||
|
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||||
|
else
|
||||||
|
JAVACMD="$JAVA_HOME/bin/java"
|
||||||
|
fi
|
||||||
|
if [ ! -x "$JAVACMD" ] ; then
|
||||||
|
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||||
|
|
||||||
|
Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
location of your Java installation."
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
JAVACMD="java"
|
||||||
|
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||||
|
|
||||||
|
Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
location of your Java installation."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Increase the maximum file descriptors if we can.
|
||||||
|
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
|
||||||
|
MAX_FD_LIMIT=`ulimit -H -n`
|
||||||
|
if [ $? -eq 0 ] ; then
|
||||||
|
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||||
|
MAX_FD="$MAX_FD_LIMIT"
|
||||||
|
fi
|
||||||
|
ulimit -n $MAX_FD
|
||||||
|
if [ $? -ne 0 ] ; then
|
||||||
|
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# For Darwin, add options to specify how the application appears in the dock
|
||||||
|
if $darwin; then
|
||||||
|
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||||
|
fi
|
||||||
|
|
||||||
|
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||||
|
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
|
||||||
|
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||||
|
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||||
|
|
||||||
|
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||||
|
|
||||||
|
# We build the pattern for arguments to be converted via cygpath
|
||||||
|
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||||
|
SEP=""
|
||||||
|
for dir in $ROOTDIRSRAW ; do
|
||||||
|
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
||||||
|
SEP="|"
|
||||||
|
done
|
||||||
|
OURCYGPATTERN="(^($ROOTDIRS))"
|
||||||
|
# Add a user-defined pattern to the cygpath arguments
|
||||||
|
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
||||||
|
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
||||||
|
fi
|
||||||
|
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||||
|
i=0
|
||||||
|
for arg in "$@" ; do
|
||||||
|
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
||||||
|
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
||||||
|
|
||||||
|
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
||||||
|
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
||||||
|
else
|
||||||
|
eval `echo args$i`="\"$arg\""
|
||||||
|
fi
|
||||||
|
i=`expr $i + 1`
|
||||||
|
done
|
||||||
|
case $i in
|
||||||
|
0) set -- ;;
|
||||||
|
1) set -- "$args0" ;;
|
||||||
|
2) set -- "$args0" "$args1" ;;
|
||||||
|
3) set -- "$args0" "$args1" "$args2" ;;
|
||||||
|
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||||
|
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||||
|
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||||
|
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||||
|
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||||
|
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Escape application args
|
||||||
|
save () {
|
||||||
|
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
||||||
|
echo " "
|
||||||
|
}
|
||||||
|
APP_ARGS=`save "$@"`
|
||||||
|
|
||||||
|
# Collect all arguments for the java command, following the shell quoting and substitution rules
|
||||||
|
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
|
||||||
|
|
||||||
|
exec "$JAVACMD" "$@"
|
|
@ -0,0 +1,89 @@
|
||||||
|
@rem
|
||||||
|
@rem Copyright 2015 the original author or authors.
|
||||||
|
@rem
|
||||||
|
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
@rem you may not use this file except in compliance with the License.
|
||||||
|
@rem You may obtain a copy of the License at
|
||||||
|
@rem
|
||||||
|
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
@rem
|
||||||
|
@rem Unless required by applicable law or agreed to in writing, software
|
||||||
|
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
@rem See the License for the specific language governing permissions and
|
||||||
|
@rem limitations under the License.
|
||||||
|
@rem
|
||||||
|
|
||||||
|
@if "%DEBUG%" == "" @echo off
|
||||||
|
@rem ##########################################################################
|
||||||
|
@rem
|
||||||
|
@rem Gradle startup script for Windows
|
||||||
|
@rem
|
||||||
|
@rem ##########################################################################
|
||||||
|
|
||||||
|
@rem Set local scope for the variables with windows NT shell
|
||||||
|
if "%OS%"=="Windows_NT" setlocal
|
||||||
|
|
||||||
|
set DIRNAME=%~dp0
|
||||||
|
if "%DIRNAME%" == "" set DIRNAME=.
|
||||||
|
set APP_BASE_NAME=%~n0
|
||||||
|
set APP_HOME=%DIRNAME%
|
||||||
|
|
||||||
|
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||||
|
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||||
|
|
||||||
|
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||||
|
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||||
|
|
||||||
|
@rem Find java.exe
|
||||||
|
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||||
|
|
||||||
|
set JAVA_EXE=java.exe
|
||||||
|
%JAVA_EXE% -version >NUL 2>&1
|
||||||
|
if "%ERRORLEVEL%" == "0" goto execute
|
||||||
|
|
||||||
|
echo.
|
||||||
|
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||||
|
echo.
|
||||||
|
echo Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
echo location of your Java installation.
|
||||||
|
|
||||||
|
goto fail
|
||||||
|
|
||||||
|
:findJavaFromJavaHome
|
||||||
|
set JAVA_HOME=%JAVA_HOME:"=%
|
||||||
|
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||||
|
|
||||||
|
if exist "%JAVA_EXE%" goto execute
|
||||||
|
|
||||||
|
echo.
|
||||||
|
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||||
|
echo.
|
||||||
|
echo Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
echo location of your Java installation.
|
||||||
|
|
||||||
|
goto fail
|
||||||
|
|
||||||
|
:execute
|
||||||
|
@rem Setup the command line
|
||||||
|
|
||||||
|
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||||
|
|
||||||
|
|
||||||
|
@rem Execute Gradle
|
||||||
|
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||||
|
|
||||||
|
:end
|
||||||
|
@rem End local scope for the variables with windows NT shell
|
||||||
|
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||||
|
|
||||||
|
:fail
|
||||||
|
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||||
|
rem the _cmd.exe /c_ return code!
|
||||||
|
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||||
|
exit /b 1
|
||||||
|
|
||||||
|
:mainEnd
|
||||||
|
if "%OS%"=="Windows_NT" endlocal
|
||||||
|
|
||||||
|
:omega
|
|
@ -0,0 +1 @@
|
||||||
|
/build
|
|
@ -0,0 +1,42 @@
|
||||||
|
plugins {
|
||||||
|
id("com.android.library")
|
||||||
|
id("org.jetbrains.kotlin.android")
|
||||||
|
}
|
||||||
|
|
||||||
|
android {
|
||||||
|
namespace = "moe.fuqiuluo.qqinterface"
|
||||||
|
compileSdk = 33
|
||||||
|
|
||||||
|
defaultConfig {
|
||||||
|
minSdk = 24
|
||||||
|
|
||||||
|
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||||
|
consumerProguardFiles("consumer-rules.pro")
|
||||||
|
}
|
||||||
|
|
||||||
|
buildTypes {
|
||||||
|
release {
|
||||||
|
isMinifyEnabled = false
|
||||||
|
proguardFiles(
|
||||||
|
getDefaultProguardFile("proguard-android-optimize.txt"),
|
||||||
|
"proguard-rules.pro"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
compileOptions {
|
||||||
|
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||||
|
targetCompatibility = JavaVersion.VERSION_1_8
|
||||||
|
}
|
||||||
|
kotlinOptions {
|
||||||
|
jvmTarget = "1.8"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation("androidx.core:core-ktx:1.9.0")
|
||||||
|
implementation("androidx.appcompat:appcompat:1.6.1")
|
||||||
|
implementation("com.google.android.material:material:1.9.0")
|
||||||
|
testImplementation("junit:junit:4.13.2")
|
||||||
|
androidTestImplementation("androidx.test.ext:junit:1.1.5")
|
||||||
|
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
# Add project specific ProGuard rules here.
|
||||||
|
# You can control the set of applied configuration files using the
|
||||||
|
# proguardFiles setting in build.gradle.
|
||||||
|
#
|
||||||
|
# For more details, see
|
||||||
|
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||||
|
|
||||||
|
# If your project uses WebView with JS, uncomment the following
|
||||||
|
# and specify the fully qualified class name to the JavaScript interface
|
||||||
|
# class:
|
||||||
|
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||||
|
# public *;
|
||||||
|
#}
|
||||||
|
|
||||||
|
# Uncomment this to preserve the line number information for
|
||||||
|
# debugging stack traces.
|
||||||
|
#-keepattributes SourceFile,LineNumberTable
|
||||||
|
|
||||||
|
# If you keep the line number information, uncomment this to
|
||||||
|
# hide the original source file name.
|
||||||
|
#-renamesourcefileattribute SourceFile
|
|
@ -0,0 +1,4 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
|
</manifest>
|
|
@ -0,0 +1,9 @@
|
||||||
|
package com.tencent.common.app;
|
||||||
|
|
||||||
|
import mqq.app.AppRuntime;
|
||||||
|
|
||||||
|
public abstract class AppInterface extends AppRuntime {
|
||||||
|
public String getCurrentNickname() {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
package com.tencent.common.app.business;
|
||||||
|
|
||||||
|
import com.tencent.common.app.AppInterface;
|
||||||
|
|
||||||
|
public abstract class BaseQQAppInterface extends AppInterface {
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
package com.tencent.common.config.pad;
|
||||||
|
|
||||||
|
public enum DeviceType {
|
||||||
|
PHONE,
|
||||||
|
TABLET,
|
||||||
|
FOLD
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
package com.tencent.image;
|
||||||
|
|
||||||
|
public class URLDrawableHandler {
|
||||||
|
}
|
|
@ -0,0 +1,76 @@
|
||||||
|
package com.tencent.mobileqq.activity.photo;
|
||||||
|
|
||||||
|
import android.os.Parcel;
|
||||||
|
import android.os.Parcelable;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
public class PhotoSendParams implements Parcelable, Serializable {
|
||||||
|
public static final Creator<PhotoSendParams> CREATOR = new Creator<PhotoSendParams>() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PhotoSendParams createFromParcel(Parcel parcel) {
|
||||||
|
return new PhotoSendParams(parcel);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PhotoSendParams[] newArray(int i) {
|
||||||
|
return new PhotoSendParams[i];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
public static final int SEND_PIC_NORMAL = 0;
|
||||||
|
public static final int SEND_PIC_QZONE = 1;
|
||||||
|
public long fileSize;
|
||||||
|
public int picType;
|
||||||
|
public String rawDownloadUrl;
|
||||||
|
public int rawHeight;
|
||||||
|
public String rawMd5;
|
||||||
|
public String rawPicPath;
|
||||||
|
public int rawWidth;
|
||||||
|
public String thumbPath;
|
||||||
|
|
||||||
|
public PhotoSendParams(String str, String str2, String str3, long j2, int i2, int i3, String str4, int i4) {
|
||||||
|
this.picType = 0;
|
||||||
|
this.thumbPath = str;
|
||||||
|
this.rawMd5 = str2;
|
||||||
|
this.rawPicPath = str3;
|
||||||
|
this.fileSize = j2;
|
||||||
|
this.rawHeight = i2;
|
||||||
|
this.rawWidth = i3;
|
||||||
|
this.rawDownloadUrl = str4;
|
||||||
|
this.picType = i4;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override // android.os.Parcelable
|
||||||
|
public int describeContents() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return "PhotoSendParams:&thumbPath:" + this.thumbPath + " &rawMd5:" + this.rawMd5 + " &rawPicPath:" + this.rawPicPath + " &rawHeight:" + this.rawHeight + " &rawWidth:" + this.rawWidth + " &rawDownloadUrl:" + this.rawDownloadUrl + " &picType:" + this.picType;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override // android.os.Parcelable
|
||||||
|
public void writeToParcel(Parcel parcel, int i2) {
|
||||||
|
parcel.writeString(this.thumbPath);
|
||||||
|
parcel.writeString(this.rawMd5);
|
||||||
|
parcel.writeString(this.rawPicPath);
|
||||||
|
parcel.writeLong(this.fileSize);
|
||||||
|
parcel.writeInt(this.rawHeight);
|
||||||
|
parcel.writeInt(this.rawWidth);
|
||||||
|
parcel.writeString(this.rawDownloadUrl);
|
||||||
|
parcel.writeInt(this.picType);
|
||||||
|
}
|
||||||
|
|
||||||
|
public PhotoSendParams(Parcel parcel) {
|
||||||
|
this.picType = 0;
|
||||||
|
this.thumbPath = parcel.readString();
|
||||||
|
this.rawMd5 = parcel.readString();
|
||||||
|
this.rawPicPath = parcel.readString();
|
||||||
|
this.fileSize = parcel.readLong();
|
||||||
|
this.rawHeight = parcel.readInt();
|
||||||
|
this.rawWidth = parcel.readInt();
|
||||||
|
this.rawDownloadUrl = parcel.readString();
|
||||||
|
this.picType = parcel.readInt();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
package com.tencent.mobileqq.app;
|
||||||
|
|
||||||
|
import com.tencent.common.app.business.BaseQQAppInterface;
|
||||||
|
|
||||||
|
public class QQAppInterface extends BaseQQAppInterface {
|
||||||
|
@Override
|
||||||
|
public String getCurrentAccountUin() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void execute(Runnable runnable) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getCurrentNickname() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void syncOnlineFriend() {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
package com.tencent.mobileqq.data;
|
||||||
|
|
||||||
|
public class MessageRecord {
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
package com.tencent.mobileqq.openapi;
|
||||||
|
|
||||||
|
import android.content.ContentProvider;
|
||||||
|
import android.content.ContentValues;
|
||||||
|
import android.database.Cursor;
|
||||||
|
import android.net.Uri;
|
||||||
|
|
||||||
|
public class OpenApiProvider extends ContentProvider {
|
||||||
|
@Override
|
||||||
|
public boolean onCreate() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Cursor query(Uri uri, String[] strings, String s, String[] strings1, String s1) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getType(Uri uri) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Uri insert(Uri uri, ContentValues contentValues) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int delete(Uri uri, String s, String[] strings) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int update(Uri uri, ContentValues contentValues, String s, String[] strings) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
package com.tencent.mobileqq.qfix;
|
||||||
|
|
||||||
|
import android.app.Application;
|
||||||
|
|
||||||
|
public class ApplicationDelegate extends Application {
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
package com.tencent.mobileqq.transfile;
|
||||||
|
|
||||||
|
import com.tencent.mobileqq.transfile.api.ITransFileController;
|
||||||
|
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
|
import mqq.app.AppRuntime;
|
||||||
|
|
||||||
|
public class BaseTransFileController implements ITransFileController {
|
||||||
|
@Override
|
||||||
|
public AtomicBoolean isWorking() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized boolean transferAsync(TransferRequest transferRequest) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate(AppRuntime appRuntime) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDestroy() {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
package com.tencent.mobileqq.transfile;
|
||||||
|
|
||||||
|
public class GroupPicUploadProcessor {
|
||||||
|
}
|
|
@ -0,0 +1,208 @@
|
||||||
|
package com.tencent.mobileqq.transfile;
|
||||||
|
|
||||||
|
import com.tencent.image.URLDrawableHandler;
|
||||||
|
import com.tencent.mobileqq.activity.photo.PhotoSendParams;
|
||||||
|
import com.tencent.mobileqq.data.MessageRecord;
|
||||||
|
|
||||||
|
import java.io.OutputStream;
|
||||||
|
|
||||||
|
public class TransferRequest {
|
||||||
|
public int chatType;
|
||||||
|
public int delayShowProgressTimeInMs;
|
||||||
|
public Object extraObject;
|
||||||
|
public boolean isShareImageByServer;
|
||||||
|
public int mBusiType;
|
||||||
|
public boolean mCanSendMsg;
|
||||||
|
public int mCommandId;
|
||||||
|
public String mDisplayOutFilePath;
|
||||||
|
//public c mDownCallBack;
|
||||||
|
public int mDownMode;
|
||||||
|
public byte[] mExtentionInfo;
|
||||||
|
public Object mExtraObj;
|
||||||
|
public long mFastForwardFileSize;
|
||||||
|
public int mFastForwardHeight;
|
||||||
|
public int mFastForwardWidth;
|
||||||
|
public int mFileType;
|
||||||
|
public long mGroupFileID;
|
||||||
|
public String mGroupFileKeyStr;
|
||||||
|
public boolean mIsPresend;
|
||||||
|
public boolean mIsPttPreSend;
|
||||||
|
public boolean mIsSecSnapChatPic;
|
||||||
|
public boolean mIsUp;
|
||||||
|
public String mLocalPath;
|
||||||
|
public String mMd5;
|
||||||
|
public long mMsgTime;
|
||||||
|
public OutputStream mOut;
|
||||||
|
public String mOutFilePath;
|
||||||
|
public String mPeerUin;
|
||||||
|
public int mPicSendSource;
|
||||||
|
public int mPttUploadPanel;
|
||||||
|
public boolean mReqVideoSubtitle;
|
||||||
|
public int mRequestDisplayLength;
|
||||||
|
public int mRequestLength;
|
||||||
|
public int mRequestOffset;
|
||||||
|
public TransferResult mResult;
|
||||||
|
public long mSecMsgId;
|
||||||
|
public String mSecondId;
|
||||||
|
public String mSelfUin;
|
||||||
|
public String mServerPath;
|
||||||
|
public int mSourceVideoCodecFormat;
|
||||||
|
public long mSubMsgId;
|
||||||
|
public int mTargetVideoCodecFormat;
|
||||||
|
public String mThumbMd5;
|
||||||
|
public String mThumbPath;
|
||||||
|
public int mUinType;
|
||||||
|
public long mUniseq;
|
||||||
|
public int multiMsgType;
|
||||||
|
public int pcmForVadNum;
|
||||||
|
public String pcmForVadPath;
|
||||||
|
public int pcmForVadPos;
|
||||||
|
public PhotoSendParams photoSendParams;
|
||||||
|
public String resIdStr;
|
||||||
|
public byte[] toSendData;
|
||||||
|
public int upMsgBusiType;
|
||||||
|
//public WXVadSeg vadSeg;
|
||||||
|
public String mRichTag = "";
|
||||||
|
public boolean isJubaoMsgType = false;
|
||||||
|
public boolean mIsSelfSend = false;
|
||||||
|
public boolean useOutputstream = true;
|
||||||
|
public boolean mSupportRangeBreakDown = false;
|
||||||
|
public int mDbRecVersion = 5;
|
||||||
|
public boolean needSendMsg = true;
|
||||||
|
public int mPrioty = 1;
|
||||||
|
public MessageRecord mRec = null;
|
||||||
|
public boolean mNeedReport = true;
|
||||||
|
public boolean mIsOnlyGetUrl = false;
|
||||||
|
public boolean mIsFastForward = false;
|
||||||
|
public boolean myPresendInvalid = false;
|
||||||
|
public boolean mPttCompressFinish = false;
|
||||||
|
public boolean bEnableEnc = false;
|
||||||
|
public boolean isQzonePic = false;
|
||||||
|
private String mKey = null;
|
||||||
|
|
||||||
|
/* compiled from: P */
|
||||||
|
/* loaded from: classes18.dex */
|
||||||
|
public static class AppInfo {
|
||||||
|
public String packName;
|
||||||
|
public String sourceIconBig;
|
||||||
|
public String sourceIconSmall;
|
||||||
|
public String sourceName;
|
||||||
|
public String sourceUrl;
|
||||||
|
public int status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* compiled from: P */
|
||||||
|
/* loaded from: classes18.dex */
|
||||||
|
public static class AppShare {
|
||||||
|
public long mAppShareID;
|
||||||
|
public String mShareUrl;
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
sb.append("mAppShareID:" + this.mAppShareID);
|
||||||
|
sb.append(",mShareUrl:" + this.mShareUrl);
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* compiled from: P */
|
||||||
|
/* loaded from: classes18.dex */
|
||||||
|
public static class PicDownExtraInfo {
|
||||||
|
public URLDrawableHandler mHandler;
|
||||||
|
public int mStartDownOffset;
|
||||||
|
public String mUrlFromMsg;
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
sb.append("mUrlFromMsg:" + this.mUrlFromMsg);
|
||||||
|
sb.append(",mStartDownOffset:" + this.mStartDownOffset);
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* compiled from: P */
|
||||||
|
/* loaded from: classes18.dex */
|
||||||
|
public static class PicUpExtraInfo {
|
||||||
|
public boolean mIsRaw;
|
||||||
|
public boolean mIsShareAppPic;
|
||||||
|
public AppShare mShareAppInfo;
|
||||||
|
public int mUinType;
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
sb.append("mUinType:" + this.mUinType);
|
||||||
|
sb.append(",mIsRaw:" + this.mIsRaw);
|
||||||
|
sb.append(",mIsShareAppPic:" + this.mIsShareAppPic);
|
||||||
|
sb.append(",mShareAppInfo:{" + this.mShareAppInfo + "}");
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* compiled from: P */
|
||||||
|
/* loaded from: classes18.dex */
|
||||||
|
public static class PttDownExtraInfo {
|
||||||
|
public int mFromType;
|
||||||
|
public int mLayer;
|
||||||
|
|
||||||
|
public PttDownExtraInfo(int i2, int i3) {
|
||||||
|
this.mFromType = i2;
|
||||||
|
this.mLayer = i3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* compiled from: P */
|
||||||
|
/* loaded from: classes18.dex */
|
||||||
|
public static class ShareExtraInfo {
|
||||||
|
public long appId;
|
||||||
|
public AppInfo appInfo;
|
||||||
|
public String audioUrl;
|
||||||
|
public boolean enableServerSendMsg;
|
||||||
|
public int forwardType;
|
||||||
|
public String imageUrl;
|
||||||
|
public int imageUrlStatus;
|
||||||
|
public String pkgName;
|
||||||
|
public int serviceType;
|
||||||
|
public int shortUrlStatus;
|
||||||
|
public String summary;
|
||||||
|
public String targetUrl;
|
||||||
|
public String title;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getKey() {
|
||||||
|
String str = this.mKey;
|
||||||
|
if (str == null) {
|
||||||
|
return this.mPeerUin + "_" + this.mFileType + "_" + this.mUniseq + "_" + this.mSubMsgId;
|
||||||
|
}
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getKeyForTransfer() {
|
||||||
|
return this.mPeerUin + this.mUniseq;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
StringBuilder sb = new StringBuilder("TransferRequest\n");
|
||||||
|
sb.append("mUniseq=" + this.mUniseq);
|
||||||
|
sb.append(",mMd5=" + this.mMd5);
|
||||||
|
sb.append(",mIsIp=" + this.mIsUp);
|
||||||
|
sb.append(",mUinType=" + this.mUinType);
|
||||||
|
sb.append(",mFileType=" + this.mFileType);
|
||||||
|
sb.append(",mSelfUin=" + this.mSelfUin);
|
||||||
|
sb.append(",mPeerUin=" + this.mPeerUin);
|
||||||
|
sb.append(",mSecondId=" + this.mSecondId);
|
||||||
|
sb.append(",mServerPath=" + this.mServerPath);
|
||||||
|
sb.append(",mLocalPath=" + this.mLocalPath);
|
||||||
|
sb.append(",mBusiType=" + this.mBusiType);
|
||||||
|
sb.append(",mGroupFileID=" + this.mGroupFileID);
|
||||||
|
sb.append(",mExtraObj={" + this.mExtraObj + "}");
|
||||||
|
StringBuilder sb2 = new StringBuilder();
|
||||||
|
sb2.append(",mPrioty=");
|
||||||
|
sb2.append(this.mPrioty);
|
||||||
|
sb.append(sb2.toString());
|
||||||
|
//sb.append(",mLogicCallBack=" + this.mUpCallBack);
|
||||||
|
sb.append(",bEnableEnc=" + this.bEnableEnc);
|
||||||
|
sb.append(",isQzonePic=" + this.isQzonePic);
|
||||||
|
sb.append(",pcmForVadPath=" + this.pcmForVadPath);
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
package com.tencent.mobileqq.transfile;
|
||||||
|
|
||||||
|
public class TransferResult {
|
||||||
|
public static final int RESULT_FAIL = -1;
|
||||||
|
public static final int RESULT_NOT_SET = -2;
|
||||||
|
public static final int RESULT_OK = 0;
|
||||||
|
public long mErrCode;
|
||||||
|
public String mErrDesc;
|
||||||
|
public TransferRequest mOrigReq;
|
||||||
|
public int mResult = -2;
|
||||||
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
package com.tencent.mobileqq.transfile.api;
|
||||||
|
|
||||||
|
import com.tencent.mobileqq.transfile.TransferRequest;
|
||||||
|
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
|
import mqq.app.api.IRuntimeService;
|
||||||
|
|
||||||
|
public interface ITransFileController extends IRuntimeService {
|
||||||
|
// void addHandle(TransProcessorHandler transProcessorHandler);
|
||||||
|
|
||||||
|
//@Deprecated
|
||||||
|
//void addProcessor(String str, IHttpCommunicatorListener iHttpCommunicatorListener);
|
||||||
|
|
||||||
|
//boolean containsProcessor(String str, long j2);
|
||||||
|
|
||||||
|
//IHttpCommunicatorListener findProcessor(String str);
|
||||||
|
|
||||||
|
//IHttpCommunicatorListener findProcessor(String str, long j2);
|
||||||
|
|
||||||
|
//TransFileControllerBusHelper getBusHelper();
|
||||||
|
|
||||||
|
//ConcurrentHashMap<String, IHttpCommunicatorListener> getProcessMap();
|
||||||
|
|
||||||
|
AtomicBoolean isWorking();
|
||||||
|
|
||||||
|
// void removeHandle(TransProcessorHandler transProcessorHandler);
|
||||||
|
|
||||||
|
// boolean removeProcessor(String str);
|
||||||
|
|
||||||
|
// void removeProcessorByPeerUin(String str, int i2);
|
||||||
|
|
||||||
|
// void stop(TransferRequest transferRequest);
|
||||||
|
|
||||||
|
boolean transferAsync(TransferRequest transferRequest);
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
package com.tencent.mobileqq.transfile.api.impl;
|
||||||
|
|
||||||
|
import com.tencent.mobileqq.transfile.BaseTransFileController;
|
||||||
|
import com.tencent.mobileqq.transfile.api.ITransFileController;
|
||||||
|
|
||||||
|
public class TransFileControllerImpl extends BaseTransFileController implements ITransFileController {
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
package com.tencent.mobileqq.transfile.protohandler;
|
||||||
|
|
||||||
|
public class GroupPicUpHandler {
|
||||||
|
}
|
|
@ -0,0 +1,60 @@
|
||||||
|
package com.tencent.qphone.base.remote;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
public class SimpleAccount {
|
||||||
|
public static final String _ISLOGINED = "_isLogined";
|
||||||
|
public static final String _LOGINPROCESS = "_loginedProcess";
|
||||||
|
public static final String _LOGINTIME = "_loginTime";
|
||||||
|
public static final String _UIN = "_uin";
|
||||||
|
|
||||||
|
public boolean containsKey(String str) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAttribute(String str, String str2) {
|
||||||
|
return str2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public HashMap<String, String> getAttributes() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLoginProcess() {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUin() {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isLogined() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String removeAttribute(String str) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAttribute(String str, String str2) {
|
||||||
|
throw new RuntimeException("key found space ");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLoginProcess(String str) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUin(String str) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toStoreString() {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
package com.tencent.qphone.base.util;
|
||||||
|
|
||||||
|
import com.tencent.mobileqq.qfix.ApplicationDelegate;
|
||||||
|
|
||||||
|
public abstract class BaseApplication extends ApplicationDelegate {
|
||||||
|
public static BaseApplication getContext() {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract int getAppId();
|
||||||
|
|
||||||
|
public abstract int getNTCoreVersion();
|
||||||
|
|
||||||
|
public abstract String getQua();
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
package com.tencent.qqnt.kernel.api;
|
||||||
|
|
||||||
|
import mqq.app.api.IRuntimeService;
|
||||||
|
|
||||||
|
public interface IKernelService extends IRuntimeService {
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
package com.tencent.qqnt.kernel.api.impl;
|
||||||
|
|
||||||
|
import com.tencent.qqnt.kernel.nativeinterface.IKernelMsgListener;
|
||||||
|
|
||||||
|
public class MsgService {
|
||||||
|
public void addMsgListener(IKernelMsgListener listener) {
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
package com.tencent.qqnt.kernel.nativeinterface;
|
||||||
|
|
||||||
|
/* loaded from: classes2.dex */
|
||||||
|
public enum ATTYPE {
|
||||||
|
UNKNOWN_AT_TYPE,
|
||||||
|
AT_EXPLICIT_USER,
|
||||||
|
AT_ROLE_GROUP,
|
||||||
|
AT_GUILD
|
||||||
|
}
|
|
@ -0,0 +1,52 @@
|
||||||
|
package com.tencent.qqnt.kernel.nativeinterface;
|
||||||
|
|
||||||
|
public final class AVRecordElement {
|
||||||
|
Integer extraType;
|
||||||
|
boolean hasRead;
|
||||||
|
int mainType;
|
||||||
|
String text;
|
||||||
|
long time;
|
||||||
|
int type;
|
||||||
|
|
||||||
|
public AVRecordElement() {
|
||||||
|
this.text = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getExtraType() {
|
||||||
|
return this.extraType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean getHasRead() {
|
||||||
|
return this.hasRead;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getMainType() {
|
||||||
|
return this.mainType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getText() {
|
||||||
|
return this.text;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getTime() {
|
||||||
|
return this.time;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getType() {
|
||||||
|
return this.type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return "AVRecordElement{type=" + this.type + ",time=" + this.time + ",text=" + this.text + ",mainType=" + this.mainType + ",hasRead=" + this.hasRead + ",extraType=" + this.extraType + ",}";
|
||||||
|
}
|
||||||
|
|
||||||
|
public AVRecordElement(int i2, long j2, String str, int i3, boolean z, Integer num) {
|
||||||
|
this.text = "";
|
||||||
|
this.type = i2;
|
||||||
|
this.time = j2;
|
||||||
|
this.text = str;
|
||||||
|
this.mainType = i3;
|
||||||
|
this.hasRead = z;
|
||||||
|
this.extraType = num;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,41 @@
|
||||||
|
package com.tencent.qqnt.kernel.nativeinterface;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
public final class AioOperateGrayTipElement implements Serializable {
|
||||||
|
String fromGrpCodeOfTmpChat;
|
||||||
|
int operateType;
|
||||||
|
String peerUid;
|
||||||
|
long serialVersionUID;
|
||||||
|
|
||||||
|
public AioOperateGrayTipElement() {
|
||||||
|
this.serialVersionUID = 1L;
|
||||||
|
this.peerUid = "";
|
||||||
|
this.fromGrpCodeOfTmpChat = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFromGrpCodeOfTmpChat() {
|
||||||
|
return this.fromGrpCodeOfTmpChat;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getOperateType() {
|
||||||
|
return this.operateType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPeerUid() {
|
||||||
|
return this.peerUid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return "AioOperateGrayTipElement{operateType=" + this.operateType + ",peerUid=" + this.peerUid + ",fromGrpCodeOfTmpChat=" + this.fromGrpCodeOfTmpChat + ",}";
|
||||||
|
}
|
||||||
|
|
||||||
|
public AioOperateGrayTipElement(int i2, String str, String str2) {
|
||||||
|
this.serialVersionUID = 1L;
|
||||||
|
this.peerUid = "";
|
||||||
|
this.fromGrpCodeOfTmpChat = "";
|
||||||
|
this.operateType = i2;
|
||||||
|
this.peerUid = str;
|
||||||
|
this.fromGrpCodeOfTmpChat = str2;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,62 @@
|
||||||
|
package com.tencent.qqnt.kernel.nativeinterface;
|
||||||
|
|
||||||
|
public final class AnonymousExtInfo {
|
||||||
|
int anonymousFlag;
|
||||||
|
byte[] anonymousId;
|
||||||
|
String anonymousNick;
|
||||||
|
long bubbleId;
|
||||||
|
long expireTime;
|
||||||
|
long headPicIndex;
|
||||||
|
String rankColor;
|
||||||
|
|
||||||
|
public AnonymousExtInfo() {
|
||||||
|
this.anonymousId = new byte[0];
|
||||||
|
this.anonymousNick = "";
|
||||||
|
this.rankColor = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getAnonymousFlag() {
|
||||||
|
return this.anonymousFlag;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getAnonymousId() {
|
||||||
|
return this.anonymousId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAnonymousNick() {
|
||||||
|
return this.anonymousNick;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getBubbleId() {
|
||||||
|
return this.bubbleId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getExpireTime() {
|
||||||
|
return this.expireTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getHeadPicIndex() {
|
||||||
|
return this.headPicIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getRankColor() {
|
||||||
|
return this.rankColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return "AnonymousExtInfo{anonymousFlag=" + this.anonymousFlag + ",anonymousId=" + this.anonymousId + ",anonymousNick=" + this.anonymousNick + ",headPicIndex=" + this.headPicIndex + ",expireTime=" + this.expireTime + ",bubbleId=" + this.bubbleId + ",rankColor=" + this.rankColor + ",}";
|
||||||
|
}
|
||||||
|
|
||||||
|
public AnonymousExtInfo(int i2, byte[] bArr, String str, long j2, long j3, long j4, String str2) {
|
||||||
|
this.anonymousId = new byte[0];
|
||||||
|
this.anonymousNick = "";
|
||||||
|
this.rankColor = "";
|
||||||
|
this.anonymousFlag = i2;
|
||||||
|
this.anonymousId = bArr;
|
||||||
|
this.anonymousNick = str;
|
||||||
|
this.headPicIndex = j2;
|
||||||
|
this.expireTime = j3;
|
||||||
|
this.bubbleId = j4;
|
||||||
|
this.rankColor = str2;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
package com.tencent.qqnt.kernel.nativeinterface;
|
||||||
|
|
||||||
|
public final class ArkElement {
|
||||||
|
String bytesData;
|
||||||
|
LinkInfo linkInfo;
|
||||||
|
Integer subElementType;
|
||||||
|
|
||||||
|
public ArkElement() {
|
||||||
|
this.bytesData = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getBytesData() {
|
||||||
|
return this.bytesData;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LinkInfo getLinkInfo() {
|
||||||
|
return this.linkInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getSubElementType() {
|
||||||
|
return this.subElementType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return "ArkElement{bytesData=" + this.bytesData + ",linkInfo=" + this.linkInfo + ",subElementType=" + this.subElementType + ",}";
|
||||||
|
}
|
||||||
|
|
||||||
|
public ArkElement(String str, LinkInfo linkInfo, Integer num) {
|
||||||
|
this.bytesData = "";
|
||||||
|
this.bytesData = str;
|
||||||
|
this.linkInfo = linkInfo;
|
||||||
|
this.subElementType = num;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
package com.tencent.qqnt.kernel.nativeinterface;
|
||||||
|
|
||||||
|
/* loaded from: classes2.dex */
|
||||||
|
public final class BasicPointInfo {
|
||||||
|
byte[] headUrl;
|
||||||
|
long readSeqNo;
|
||||||
|
long seqNo;
|
||||||
|
|
||||||
|
public BasicPointInfo() {
|
||||||
|
this.headUrl = new byte[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getHeadUrl() {
|
||||||
|
return this.headUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getReadSeqNo() {
|
||||||
|
return this.readSeqNo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getSeqNo() {
|
||||||
|
return this.seqNo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return "BasicPointInfo{headUrl=" + this.headUrl + ",seqNo=" + this.seqNo + ",readSeqNo=" + this.readSeqNo + ",}";
|
||||||
|
}
|
||||||
|
|
||||||
|
public BasicPointInfo(byte[] bArr, long j2, long j3) {
|
||||||
|
this.headUrl = new byte[0];
|
||||||
|
this.headUrl = bArr;
|
||||||
|
this.seqNo = j2;
|
||||||
|
this.readSeqNo = j3;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
package com.tencent.qqnt.kernel.nativeinterface;
|
||||||
|
|
||||||
|
/* compiled from: P */
|
||||||
|
/* loaded from: classes2.dex */
|
||||||
|
public enum BeatTypeEnum {
|
||||||
|
KRECOVERY,
|
||||||
|
KFOLDNOTSPREAD,
|
||||||
|
KFOLDCANSPREAD
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
package com.tencent.qqnt.kernel.nativeinterface;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
public final class BlockGrayTipElement implements Serializable {
|
||||||
|
boolean block;
|
||||||
|
boolean isBuddy;
|
||||||
|
String peerUid;
|
||||||
|
long serialVersionUID;
|
||||||
|
|
||||||
|
public BlockGrayTipElement() {
|
||||||
|
this.serialVersionUID = 1L;
|
||||||
|
this.peerUid = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean getBlock() {
|
||||||
|
return this.block;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean getIsBuddy() {
|
||||||
|
return this.isBuddy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPeerUid() {
|
||||||
|
return this.peerUid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return "BlockGrayTipElement{peerUid=" + this.peerUid + ",block=" + this.block + ",isBuddy=" + this.isBuddy + ",}";
|
||||||
|
}
|
||||||
|
|
||||||
|
public BlockGrayTipElement(String str, boolean z, boolean z2) {
|
||||||
|
this.serialVersionUID = 1L;
|
||||||
|
this.peerUid = "";
|
||||||
|
this.peerUid = str;
|
||||||
|
this.block = z;
|
||||||
|
this.isBuddy = z2;
|
||||||
|
}
|
||||||
|
}
|