= 0f..1f,
22 | steps: Int = 0,
23 | onValueChangeFinished: (() -> Unit)? = null,
24 | text: @Composable BoxScope.() -> Unit
25 | ) {
26 | ConstraintLayout(modifier) {
27 | val (textRef, sliderRef) = createRefs()
28 | Box(
29 | modifier = Modifier
30 | .constrainAs(textRef) {
31 | start.linkTo(parent.start)
32 | top.linkTo(parent.top)
33 | end.linkTo(parent.end)
34 | }
35 | .wrapContentHeight()
36 | ) { text() }
37 | Slider(
38 | modifier = Modifier
39 | .fillMaxWidth()
40 | .constrainAs(sliderRef) {
41 | start.linkTo(parent.start)
42 | end.linkTo(parent.end)
43 |
44 | top.linkTo(textRef.bottom, margin = (-16).dp)
45 | },
46 | value = value,
47 | onValueChange = onValueChange,
48 | enabled = enabled,
49 | valueRange = valueRange,
50 | steps = steps,
51 | onValueChangeFinished = onValueChangeFinished
52 | )
53 | }
54 | }
55 |
56 | @Preview
57 | @Composable
58 | fun PreviewSlider() {
59 | LabelSlider(value = 0f, onValueChange = {}) {
60 | Text("Hello World")
61 | }
62 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/github/jing332/frpandroid/ui/widgets/LoadingDialog.kt:
--------------------------------------------------------------------------------
1 | package com.github.jing332.text_searcher.ui.widgets
2 |
3 | import androidx.compose.animation.core.animateFloat
4 | import androidx.compose.animation.core.infiniteRepeatable
5 | import androidx.compose.animation.core.keyframes
6 | import androidx.compose.animation.core.rememberInfiniteTransition
7 | import androidx.compose.foundation.border
8 | import androidx.compose.foundation.layout.Column
9 | import androidx.compose.foundation.layout.Spacer
10 | import androidx.compose.foundation.layout.height
11 | import androidx.compose.foundation.layout.padding
12 | import androidx.compose.foundation.layout.size
13 | import androidx.compose.foundation.layout.wrapContentWidth
14 | import androidx.compose.foundation.shape.CircleShape
15 | import androidx.compose.material3.CircularProgressIndicator
16 | import androidx.compose.material3.MaterialTheme
17 | import androidx.compose.material3.Surface
18 | import androidx.compose.material3.Text
19 | import androidx.compose.runtime.Composable
20 | import androidx.compose.runtime.getValue
21 | import androidx.compose.runtime.mutableStateOf
22 | import androidx.compose.runtime.remember
23 | import androidx.compose.runtime.setValue
24 | import androidx.compose.ui.Modifier
25 | import androidx.compose.ui.draw.rotate
26 | import androidx.compose.ui.graphics.Brush
27 | import androidx.compose.ui.graphics.Color
28 | import androidx.compose.ui.tooling.preview.Preview
29 | import androidx.compose.ui.unit.Dp
30 | import androidx.compose.ui.unit.dp
31 | import androidx.compose.ui.window.Dialog
32 | import androidx.compose.ui.window.DialogProperties
33 |
34 |
35 | @Composable
36 | fun ProgressIndicatorLoading(progressIndicatorSize: Dp, progressIndicatorColor: Color) {
37 | val infiniteTransition = rememberInfiniteTransition(label = "")
38 |
39 | val angle by infiniteTransition.animateFloat(
40 | initialValue = 0f,
41 | targetValue = 360f,
42 | animationSpec = infiniteRepeatable(
43 | animation = keyframes {
44 | durationMillis = 600
45 | }
46 | ), label = ""
47 | )
48 |
49 | CircularProgressIndicator(
50 | progress = 1f,
51 | modifier = Modifier
52 | .size(progressIndicatorSize)
53 | .rotate(angle)
54 | .border(
55 | 12.dp,
56 | brush = Brush.sweepGradient(
57 | listOf(
58 | Color.Transparent,
59 | progressIndicatorColor.copy(alpha = 0.1f),
60 | progressIndicatorColor
61 | )
62 | ),
63 | shape = CircleShape
64 | ),
65 | strokeWidth = 1.dp,
66 | color = Color.Transparent
67 | )
68 | }
69 |
70 | @Composable
71 | fun LoadingDialog(onDismissRequest: () -> Unit, dismissOnBackPress: Boolean = false) {
72 | Dialog(
73 | onDismissRequest = onDismissRequest,
74 | properties = DialogProperties(dismissOnBackPress = dismissOnBackPress)
75 | ) {
76 | Surface(
77 | tonalElevation = 4.dp,
78 | shape = MaterialTheme.shapes.medium,
79 | ) {
80 | Column(modifier = Modifier.padding(horizontal = 48.dp, vertical = 12.dp).wrapContentWidth()) {
81 | ProgressIndicatorLoading(
82 | progressIndicatorSize = 64.dp,
83 | progressIndicatorColor = MaterialTheme.colorScheme.primary
84 | )
85 | Spacer(
86 | modifier = Modifier
87 | .height(16.dp)
88 | )
89 | Text(
90 | text = "加载中",
91 | )
92 | }
93 | }
94 | }
95 | }
96 |
97 | @Preview
98 | @Composable
99 | fun PreviewDialog() {
100 | var isShow by remember { mutableStateOf(true) }
101 | if (isShow)
102 | LoadingDialog(onDismissRequest = { isShow = false })
103 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/github/jing332/frpandroid/ui/widgets/Markdown.kt:
--------------------------------------------------------------------------------
1 | package com.github.jing332.frpandroid.ui.widgets
2 |
3 | import android.text.Spanned
4 | import android.text.method.LinkMovementMethod
5 | import android.view.View
6 | import android.widget.TextView
7 | import androidx.compose.material3.MaterialTheme
8 | import androidx.compose.runtime.Composable
9 | import androidx.compose.runtime.remember
10 | import androidx.compose.ui.Modifier
11 | import androidx.compose.ui.graphics.Color
12 | import androidx.compose.ui.graphics.toArgb
13 | import androidx.compose.ui.platform.LocalContext
14 | import androidx.compose.ui.viewinterop.AndroidView
15 | import io.noties.markwon.AbstractMarkwonPlugin
16 | import io.noties.markwon.LinkResolverDef
17 | import io.noties.markwon.Markwon
18 | import io.noties.markwon.MarkwonConfiguration
19 | import io.noties.markwon.MarkwonPlugin
20 | import io.noties.markwon.image.AsyncDrawableScheduler
21 | import io.noties.markwon.image.DefaultMediaDecoder
22 | import io.noties.markwon.image.ImagesPlugin
23 | import io.noties.markwon.image.network.OkHttpNetworkSchemeHandler
24 | import io.noties.markwon.image.svg.SvgMediaDecoder
25 | import io.noties.markwon.linkify.LinkifyPlugin
26 |
27 | @Composable
28 | fun Markdown(
29 | content: String,
30 | modifier: Modifier = Modifier,
31 | isSelectable: Boolean = true,
32 | textColor: Color = MaterialTheme.colorScheme.onBackground,
33 | onLinkResolve: (url: String) -> Boolean = { false },
34 | onTextViewConfiguration: (TextView) -> Unit = {},
35 | ) {
36 | val context = LocalContext.current
37 |
38 | val markwon = remember {
39 | Markwon.builder(context)
40 | .usePlugin(ImagesPlugin.create {
41 | it.addSchemeHandler(OkHttpNetworkSchemeHandler.create())
42 | it.addMediaDecoder(DefaultMediaDecoder.create())
43 | it.addMediaDecoder(SvgMediaDecoder.create())
44 | it.errorHandler { url, throwable ->
45 | throwable.printStackTrace()
46 | println(url)
47 | null
48 | }
49 | })
50 | // .usePlugin(HtmlPlugin.create())
51 | .usePlugin(object : AbstractMarkwonPlugin() {
52 | override fun configureConfiguration(builder: MarkwonConfiguration.Builder) {
53 | // builder.linkResolver { view, link ->
54 | // Log.d(TAG, "configureConfiguration: $link")
55 | // }
56 |
57 | // or subclass default instance
58 | builder.linkResolver(object : LinkResolverDef() {
59 | override fun resolve(view: View, link: String) {
60 | if (!onLinkResolve(link))
61 | super.resolve(view, link)
62 | }
63 | })
64 | }
65 | })
66 | .usePlugin(object : AbstractMarkwonPlugin(), MarkwonPlugin {
67 | override fun beforeSetText(textView: TextView, markdown: Spanned) {
68 | AsyncDrawableScheduler.unschedule(textView)
69 | }
70 |
71 | override fun afterSetText(textView: TextView) {
72 | AsyncDrawableScheduler.schedule(textView);
73 | }
74 | })
75 | .usePlugin(LinkifyPlugin.create())
76 | .build()
77 | }
78 |
79 | AndroidView(
80 | modifier = modifier,
81 | factory = {
82 | TextView(it).apply {
83 | movementMethod = LinkMovementMethod.getInstance()
84 | onTextViewConfiguration(this)
85 | }
86 | }) {
87 | it.setTextIsSelectable(isSelectable)
88 |
89 | it.setTextColor(textColor.toArgb())
90 | markwon.setMarkdown(it, content)
91 | }
92 |
93 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/github/jing332/frpandroid/ui/widgets/TextFieldDialog.kt:
--------------------------------------------------------------------------------
1 | package com.github.jing332.text_searcher.ui.widgets
2 |
3 | import androidx.compose.material3.AlertDialog
4 | import androidx.compose.material3.OutlinedTextField
5 | import androidx.compose.material3.Text
6 | import androidx.compose.material3.TextButton
7 | import androidx.compose.runtime.Composable
8 |
9 | @Composable
10 | fun TextFieldDialog(
11 | title: String,
12 | text: String,
13 | onTextChange: (String) -> Unit,
14 | onDismissRequest: () -> Unit,
15 | onConfirm: () -> Unit
16 | ) {
17 | AlertDialog(onDismissRequest = onDismissRequest,
18 | title = {
19 | Text(title)
20 | },
21 | text = {
22 | OutlinedTextField(value = text, onValueChange = onTextChange)
23 | },
24 | confirmButton = {
25 | TextButton(onClick = onConfirm) {
26 | Text("确定")
27 | }
28 | }
29 | )
30 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/github/jing332/frpandroid/ui/widgets/Widgets.kt:
--------------------------------------------------------------------------------
1 | package com.github.jing332.frpandroid.ui.widgets
2 |
3 | import android.content.BroadcastReceiver
4 | import android.content.Context
5 | import android.content.Intent
6 | import android.content.IntentFilter
7 | import androidx.compose.foundation.isSystemInDarkTheme
8 | import androidx.compose.runtime.Composable
9 | import androidx.compose.runtime.DisposableEffect
10 | import androidx.compose.runtime.SideEffect
11 | import androidx.compose.runtime.getValue
12 | import androidx.compose.runtime.rememberUpdatedState
13 | import androidx.compose.ui.graphics.Color
14 | import androidx.compose.ui.platform.LocalContext
15 | import androidx.core.content.ContextCompat
16 | import androidx.localbroadcastmanager.content.LocalBroadcastManager
17 | import com.google.accompanist.systemuicontroller.rememberSystemUiController
18 |
19 |
20 | @Composable
21 | fun TransparentSystemBars() {
22 | val systemUiController = rememberSystemUiController()
23 | val useDarkIcons = !isSystemInDarkTheme()
24 | SideEffect {
25 | systemUiController.setSystemBarsColor(
26 | color = Color.Transparent,
27 | darkIcons = useDarkIcons,
28 | isNavigationBarContrastEnforced = false,
29 | )
30 | }
31 | }
32 |
33 | @Composable
34 | fun BasicBroadcaseReceiver(
35 | intentFilter: IntentFilter,
36 | onReceive: (Intent?) -> Unit,
37 | onRegister: (BroadcastReceiver, Context) -> Unit,
38 | onUnregister: (BroadcastReceiver, Context) -> Unit
39 | ) {
40 | val context = LocalContext.current
41 | val currentReceive by rememberUpdatedState(onReceive)
42 |
43 | DisposableEffect(context, intentFilter) {
44 | val receiver = object : BroadcastReceiver() {
45 | override fun onReceive(context: Context?, intent: Intent?) {
46 | currentReceive(intent)
47 | }
48 | }
49 | onRegister(receiver, context)
50 |
51 | onDispose {
52 | onUnregister(receiver, context)
53 | }
54 | }
55 | }
56 |
57 | @Suppress("DEPRECATION")
58 | @Composable
59 | fun LocalBroadcastReceiver(intentFilter: IntentFilter, onReceive: (Intent?) -> Unit) {
60 | BasicBroadcaseReceiver(
61 | intentFilter,
62 | onReceive,
63 | { obj, context ->
64 | LocalBroadcastManager.getInstance(context).registerReceiver(obj, intentFilter)
65 | },
66 | { obj, context -> LocalBroadcastManager.getInstance(context).unregisterReceiver(obj) }
67 | )
68 | }
69 |
70 | @Composable
71 | fun SystemBroadcastReceiver(
72 | intentFilter: IntentFilter,
73 | onSystemEvent: (intent: Intent?) -> Unit
74 | ) {
75 | BasicBroadcaseReceiver(
76 | intentFilter = intentFilter, onReceive = onSystemEvent,
77 | onRegister = { obj, context ->
78 | ContextCompat.registerReceiver(
79 | context,
80 | obj,
81 | intentFilter,
82 | ContextCompat.RECEIVER_EXPORTED
83 | )
84 | },
85 | onUnregister = { obj, context -> context.unregisterReceiver(obj) }
86 | )
87 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/github/jing332/frpandroid/util/AndroidUtils.kt:
--------------------------------------------------------------------------------
1 | package com.github.jing332.frpandroid.util
2 |
3 | import android.content.BroadcastReceiver
4 | import android.content.Context
5 | import android.content.Intent
6 | import android.content.IntentFilter
7 | import android.net.Uri
8 | import android.os.Build
9 | import androidx.core.content.ContextCompat
10 |
11 | object AndroidUtils {
12 | const val ABI_ARM = "armeabi-v7a"
13 | const val ABI_ARM64 = "arm64-v8a"
14 | const val ABI_X86 = "x86"
15 | const val ABI_X86_64 = "x86_64"
16 |
17 | fun getABI(): String? {
18 | return Build.SUPPORTED_ABIS[0]
19 | }
20 |
21 | fun Context.registerGlobalReceiver(
22 | receiver: BroadcastReceiver,
23 | filter: IntentFilter,
24 | flags: Int = ContextCompat.RECEIVER_EXPORTED
25 | ) {
26 | ContextCompat.registerReceiver(this, receiver, filter, flags)
27 | }
28 |
29 | fun Context.openUri(uri: String) {
30 | val intent = Intent(Intent.ACTION_VIEW)
31 | intent.data = Uri.parse(uri)
32 | startActivity(intent)
33 | }
34 |
35 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/github/jing332/frpandroid/util/ClipBoardUtils.kt:
--------------------------------------------------------------------------------
1 | package com.github.jing332.frpandroid.util
2 |
3 | import android.content.ClipData
4 | import android.content.ClipboardManager
5 | import android.content.ClipboardManager.OnPrimaryClipChangedListener
6 | import android.content.Context
7 | import com.github.jing332.frpandroid.app
8 |
9 |
10 | /**
11 | *
12 | * author: Blankj
13 | * blog : http://blankj.com
14 | * time : 2016/09/25
15 | * desc : utils about clipboard
16 |
*
17 | */
18 | object ClipboardUtils {
19 |
20 | /**
21 | * Copy the text to clipboard.
22 | *
23 | * The label equals name of package.
24 | *
25 | * @param text The text.
26 | */
27 | fun copyText(text: CharSequence?) {
28 | val cm = app.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
29 | cm.setPrimaryClip(ClipData.newPlainText(app.getPackageName(), text))
30 | }
31 |
32 | /**
33 | * Copy the text to clipboard.
34 | *
35 | * @param label The label.
36 | * @param text The text.
37 | */
38 | fun copyText(label: CharSequence?, text: CharSequence?) {
39 | val cm = app.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
40 | cm.setPrimaryClip(ClipData.newPlainText(label, text))
41 | }
42 |
43 | /**
44 | * Clear the clipboard.
45 | */
46 | fun clear() {
47 | val cm = app.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
48 | cm.setPrimaryClip(ClipData.newPlainText(null, ""))
49 | }
50 |
51 | /**
52 | * Return the label for clipboard.
53 | *
54 | * @return the label for clipboard
55 | */
56 | fun getLabel(): CharSequence {
57 | val cm = app
58 | .getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
59 | val des = cm.primaryClipDescription ?: return ""
60 | return des.label ?: return ""
61 | }
62 |
63 | /**
64 | * Return the text for clipboard.
65 | *
66 | * @return the text for clipboard
67 | */
68 | val text: CharSequence
69 | get() {
70 | val cm =
71 | app.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
72 | val clip = cm.primaryClip
73 | if (clip != null && clip.itemCount > 0) {
74 | val text = clip.getItemAt(0).coerceToText(app)
75 | if (text != null) {
76 | return text
77 | }
78 | }
79 | return ""
80 | }
81 |
82 | /**
83 | * Add the clipboard changed listener.
84 | */
85 | fun addChangedListener(listener: OnPrimaryClipChangedListener?) {
86 | val cm = app.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
87 | cm.addPrimaryClipChangedListener(listener)
88 | }
89 |
90 | /**
91 | * Remove the clipboard changed listener.
92 | */
93 | fun removeChangedListener(listener: OnPrimaryClipChangedListener?) {
94 | val cm = app.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
95 | cm.removePrimaryClipChangedListener(listener)
96 | }
97 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/github/jing332/frpandroid/util/FileUtils.kt:
--------------------------------------------------------------------------------
1 | package com.github.jing332.frpandroid.util
2 |
3 | import java.io.File
4 | import java.io.InputStream
5 | import java.net.URLConnection
6 |
7 | object FileUtils {
8 | val File.mimeType: String?
9 | get() {
10 | val fileNameMap = URLConnection.getFileNameMap()
11 | return fileNameMap.getContentTypeFor(name)
12 | }
13 |
14 | /**
15 | * 按行读取txt
16 | */
17 | fun InputStream.readAllText(): String {
18 | this.use { ins ->
19 | ins.bufferedReader().use { reader ->
20 | val buffer = StringBuffer("")
21 | var str: String?
22 | while (reader.readLine().also { str = it } != null) {
23 | buffer.append(str)
24 | buffer.append("\n")
25 | }
26 | return buffer.toString()
27 | }
28 | }
29 | }
30 |
31 | fun copyFolder(src: File, target: File, overwrite: Boolean = true) {
32 | val folder = File(target.absolutePath + File.separator + src.name)
33 | folder.mkdirs()
34 |
35 | src.listFiles()?.forEach {
36 | if (it.isFile) {
37 | val newFile = File(folder.absolutePath + File.separator + it.name)
38 | it.copyTo(newFile, overwrite)
39 | } else if (it.isDirectory) {
40 | copyFolder(it, folder)
41 | }
42 | }
43 |
44 | }
45 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/github/jing332/frpandroid/util/NetworkUtils.kt:
--------------------------------------------------------------------------------
1 | package com.github.jing332.frpandroid.util
2 |
3 | import java.net.InetAddress
4 | import java.net.NetworkInterface
5 | import java.net.SocketException
6 | import java.util.LinkedList
7 | import java.util.Locale
8 |
9 |
10 | object NetworkUtils {
11 | fun getIPAddress(useIPv4: Boolean): String? {
12 | try {
13 | val nis = NetworkInterface.getNetworkInterfaces()
14 | val adds = LinkedList()
15 | while (nis.hasMoreElements()) {
16 | val ni = nis.nextElement()
17 | // To prevent phone of xiaomi return "10.0.2.15"
18 | if (!ni.isUp || ni.isLoopback) continue
19 | val addresses = ni.inetAddresses
20 | while (addresses.hasMoreElements()) {
21 | adds.addFirst(addresses.nextElement())
22 | }
23 | }
24 | for (add in adds) {
25 | if (!add.isLoopbackAddress) {
26 | val hostAddress = add.hostAddress ?: break
27 | val isIPv4 = hostAddress.indexOf(':') < 0
28 | if (useIPv4) {
29 | if (isIPv4) return hostAddress
30 | } else {
31 | if (!isIPv4) {
32 | val index = hostAddress.indexOf('%')
33 | return if (index < 0) hostAddress.uppercase(Locale.getDefault()) else hostAddress.substring(
34 | 0,
35 | index
36 | ).uppercase(
37 | Locale.getDefault()
38 | )
39 | }
40 | }
41 | }
42 | }
43 | } catch (e: SocketException) {
44 | e.printStackTrace()
45 | }
46 | return ""
47 | }
48 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/github/jing332/frpandroid/util/StringUtils.kt:
--------------------------------------------------------------------------------
1 | package com.github.jing332.frpandroid.util
2 |
3 | object StringUtils {
4 | fun String.removeAnsiCodes(): String {
5 | val ansiRegex = Regex("\\x1B\\[[0-9;]*[m|K]")
6 | return this.replace(ansiRegex, "")
7 | }
8 |
9 | private fun paramsParseInternal(params: String): HashMap {
10 | val parameters: HashMap = hashMapOf()
11 | if (params.isBlank()) return parameters
12 |
13 | for (param in params.split("&")) {
14 | val entry = param.split("=".toRegex()).dropLastWhile { it.isEmpty() }
15 | if (entry.size > 1) {
16 | parameters[entry[0]] = entry[1]
17 | } else {
18 | parameters[entry[0]] = ""
19 | }
20 | }
21 | return parameters
22 | }
23 |
24 | fun String.paramsParse() = paramsParseInternal(this)
25 |
26 | fun String.toNumberInt(): Int {
27 | return this.replace(Regex("[^0-9]"), "").toIntOrNull() ?: 0
28 | }
29 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/github/jing332/frpandroid/util/ThrottleUtil.kt:
--------------------------------------------------------------------------------
1 | package com.github.jing332.frpandroid.util
2 |
3 | import kotlinx.coroutines.*
4 |
5 | @OptIn(DelicateCoroutinesApi::class)
6 | class ThrottleUtil(private val scope: CoroutineScope = GlobalScope, val time: Long = 100L) {
7 | private var job: Job? = null
8 |
9 | fun runAction(
10 | dispatcher: CoroutineDispatcher = Dispatchers.Main,
11 | action: suspend () -> Unit,
12 | ) {
13 | job?.cancel()
14 | job = null
15 | job = scope.launch(dispatcher) {
16 | delay(time)
17 | action.invoke()
18 | }
19 | }
20 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/github/jing332/frpandroid/util/ToastUtils.kt:
--------------------------------------------------------------------------------
1 | package com.github.jing332.frpandroid.util
2 |
3 | import android.content.Context
4 | import android.widget.Toast
5 | import androidx.annotation.StringRes
6 | import com.drake.net.utils.runMain
7 |
8 | object ToastUtils {
9 | fun Context.toast(@StringRes strId: String) {
10 | runMain {
11 | Toast.makeText(this, strId, Toast.LENGTH_SHORT).show()
12 | }
13 | }
14 |
15 | fun Context.toast(@StringRes strId: Int, vararg args: Any) {
16 | runMain {
17 | Toast.makeText(
18 | this,
19 | getString(strId, *args),
20 | Toast.LENGTH_SHORT
21 | ).show()
22 | }
23 | }
24 |
25 | fun Context.longToast(str: String) {
26 | runMain {
27 | Toast.makeText(this, str, Toast.LENGTH_LONG).show()
28 | }
29 | }
30 |
31 | fun Context.longToast(@StringRes strId: Int) {
32 | runMain {
33 | Toast.makeText(this, strId, Toast.LENGTH_LONG).show()
34 | }
35 | }
36 |
37 | fun Context.longToast(@StringRes strId: Int, vararg args: Any) {
38 | runMain {
39 | Toast.makeText(
40 | this,
41 | getString(strId, *args),
42 | Toast.LENGTH_LONG
43 | ).show()
44 | }
45 | }
46 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable-anydpi-v24/ic_notification_frpc.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
12 |
13 |
15 |
17 |
19 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-anydpi-v24/ic_notification_frps.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
12 |
13 |
15 |
17 |
19 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_notification_frpc.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jing332/FrpAndroid/d69fc5e4f893eef152340aabe0db06db13dc5df0/app/src/main/res/drawable-hdpi/ic_notification_frpc.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_notification_frps.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jing332/FrpAndroid/d69fc5e4f893eef152340aabe0db06db13dc5df0/app/src/main/res/drawable-hdpi/ic_notification_frps.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_notification_frpc.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jing332/FrpAndroid/d69fc5e4f893eef152340aabe0db06db13dc5df0/app/src/main/res/drawable-mdpi/ic_notification_frpc.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_notification_frps.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jing332/FrpAndroid/d69fc5e4f893eef152340aabe0db06db13dc5df0/app/src/main/res/drawable-mdpi/ic_notification_frps.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_notification_frpc.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jing332/FrpAndroid/d69fc5e4f893eef152340aabe0db06db13dc5df0/app/src/main/res/drawable-xhdpi/ic_notification_frpc.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_notification_frps.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jing332/FrpAndroid/d69fc5e4f893eef152340aabe0db06db13dc5df0/app/src/main/res/drawable-xhdpi/ic_notification_frps.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_notification_frpc.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jing332/FrpAndroid/d69fc5e4f893eef152340aabe0db06db13dc5df0/app/src/main/res/drawable-xxhdpi/ic_notification_frpc.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_notification_frps.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jing332/FrpAndroid/d69fc5e4f893eef152340aabe0db06db13dc5df0/app/src/main/res/drawable-xxhdpi/ic_notification_frps.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/baseline_trending_up_24.xml:
--------------------------------------------------------------------------------
1 |
8 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/client.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/edit.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
12 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_app_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
11 |
12 |
14 |
16 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_frpc.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
12 |
13 |
15 |
17 |
19 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_frps.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
12 |
13 |
15 |
17 |
19 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/server.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_app_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_app_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_app_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jing332/FrpAndroid/d69fc5e4f893eef152340aabe0db06db13dc5df0/app/src/main/res/mipmap-hdpi/ic_app_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_app_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jing332/FrpAndroid/d69fc5e4f893eef152340aabe0db06db13dc5df0/app/src/main/res/mipmap-hdpi/ic_app_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_app_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jing332/FrpAndroid/d69fc5e4f893eef152340aabe0db06db13dc5df0/app/src/main/res/mipmap-mdpi/ic_app_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_app_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jing332/FrpAndroid/d69fc5e4f893eef152340aabe0db06db13dc5df0/app/src/main/res/mipmap-mdpi/ic_app_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_app_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jing332/FrpAndroid/d69fc5e4f893eef152340aabe0db06db13dc5df0/app/src/main/res/mipmap-xhdpi/ic_app_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_app_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jing332/FrpAndroid/d69fc5e4f893eef152340aabe0db06db13dc5df0/app/src/main/res/mipmap-xhdpi/ic_app_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_app_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jing332/FrpAndroid/d69fc5e4f893eef152340aabe0db06db13dc5df0/app/src/main/res/mipmap-xxhdpi/ic_app_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_app_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jing332/FrpAndroid/d69fc5e4f893eef152340aabe0db06db13dc5df0/app/src/main/res/mipmap-xxhdpi/ic_app_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_app_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jing332/FrpAndroid/d69fc5e4f893eef152340aabe0db06db13dc5df0/app/src/main/res/mipmap-xxxhdpi/ic_app_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_app_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jing332/FrpAndroid/d69fc5e4f893eef152340aabe0db06db13dc5df0/app/src/main/res/mipmap-xxxhdpi/ic_app_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/values/ic_app_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FFFFFF
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FFFFFF
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | FrpAndroid
4 |
5 | 开源许可
6 | 返回
7 | 未选择文件
8 | ❌ 错误
9 | 确定
10 | 描述
11 | 日志
12 | AList服务器
13 | 添加桌面快捷方式
14 | 关闭
15 | 复制地址
16 | AList运行中
17 | 取消
18 | admin 密码已设为:\n %1$s
19 | admin 密码
20 | 关闭失败:%1$s
21 | 已复制地址
22 | ⚠️启动服务器才可设置admin密码
23 | AList配置
24 | 设置
25 | 密码
26 | 启动中
27 | 关闭中
28 | FRPC开关
29 | FRPS开关
30 | 更多选项
31 | 关于
32 | 监听地址
33 | 编辑 %1$s
34 | 请至少启用一个服务器!
35 | AList提供者
36 | account
37 | 路径已复制
38 | 检查更新
39 | FRP服务
40 | FRPS
41 | FRPC
42 | ⚠️ FRP错误 (%1$d),请查看日志
43 | 配置
44 | 启动
45 | 帮助文档
46 | FRP在线文档
47 | 添加配置
48 | 搜索过滤
49 | 保存
50 | 编辑配置
51 | 警告
52 | 已存在相同的配置项,是否覆盖?
53 | 推荐使用MT管理器进行编辑
54 |
55 |
--------------------------------------------------------------------------------
/app/src/main/res/values/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/backup_rules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/data_extraction_rules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/file_path_data.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/file_paths.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/network_security_config.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | ext {
3 | kotlin_version = '1.9.0'
4 | agp_version = '8.2.0-alpha16'
5 | room_version = '2.5.2'
6 | ksp_version = '1.9.0-1.0.13'
7 | about_lib_version = "10.8.3"
8 | }
9 | }
10 |
11 | plugins {
12 | id 'com.android.application' version "$agp_version" apply false
13 | id 'com.android.library' version "$agp_version" apply false
14 | id 'org.jetbrains.kotlin.android' version "$kotlin_version" apply false
15 | id 'org.jetbrains.kotlin.plugin.serialization' version "$kotlin_version"
16 | id("com.google.devtools.ksp") version "$ksp_version" apply false
17 | id("com.mikepenz.aboutlibraries.plugin") version "$about_lib_version" apply false
18 | }
19 |
20 | task clean(type: Delete) {
21 | delete rootProject.buildDir
22 | }
--------------------------------------------------------------------------------
/frp/install_all_win.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | function build() {
4 | export CC="E:\Android_NDK\android-ndk-r25c\toolchains\llvm\prebuilt\windows-x86_64\bin\\$1-linux-android21-clang.cmd"
5 | ./install_frp.sh $2 $3 $4
6 | }
7 |
8 | build aarch64 frpc arm64 arm64-v8a
9 | build aarch64 frps arm64 arm64-v8a
--------------------------------------------------------------------------------
/frp/install_frp.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | export frp_dir=$PWD
4 | function build() {
5 | echo "Building $1 $2 $3 ${PWD}"
6 |
7 | export CGO_ENABLED=1
8 | export GOOS=android
9 | export GOARCH="$2"
10 |
11 | FN="lib$1.so"
12 | rm -f ${FN}
13 | go build -ldflags "-s -w" -o ${FN}
14 |
15 | mkdir -p ${frp_dir}/../app/libs/$3
16 | cp -f ${FN} ${frp_dir}/../app/libs/$3
17 | }
18 |
19 | cp -f ./frp-*/conf/* ../app/src/main/assets/defaultData
20 |
21 | cd ./frp-*/cmd/$1
22 | build $1 $2 $3
23 |
24 | # function build_all() {
25 | # rm -f $1
26 | # build $1 "arm" "armeabi-v7a"
27 | # build $1 "arm64" "arm64-v8a"
28 | # build $1 "386" "x86"
29 | # build $1 "amd64" "x86_64"
30 | # }
31 |
32 | # cd frp-*/cmd
33 | # cd ./frpc
34 | # build_all frpc
35 |
36 | # cd ./frps
37 | # build_all frps
38 |
--------------------------------------------------------------------------------
/frp/install_src.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | TAG_NAME=$(curl -s https://api.github.com/repos/fatedier/frp/releases/latest | grep -o '"tag_name": ".*"' | cut -d'"' -f4)
4 |
5 | URL="https://github.com/fatedier/frp/archive/refs/tags/${TAG_NAME}.tar.gz"
6 | echo "Downloading frpc sources ${TAG_NAME} from ${URL}"
7 |
8 | curl -L -o "src.tgz" $URL
9 | rm -rf frp-*
10 | tar -xzvf src.tgz
11 | rm -f src.tgz
--------------------------------------------------------------------------------
/frp/update_docs_md.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | function doc {
4 | curl -L -o $PWD/../app/src/main/assets/docs/$1/$2 $3
5 | }
6 |
7 | doc zh server-configures.md https://raw.githubusercontent.com/gofrp/frp-doc/master/content/zh-cn/docs/Reference/server-configures.md
8 | #doc en server-configures.md https://raw.githubusercontent.com/gofrp/frp-doc/master/content/en/docs/Reference/server-configures.md
9 |
10 | doc zh client-configures.md https://raw.githubusercontent.com/gofrp/frp-doc/master/content/zh-cn/docs/Reference/client-configures.md
11 | #doc en client-configures.md https://raw.githubusercontent.com/gofrp/frp-doc/master/content/en/docs/Reference/client-configures.md
12 |
13 | doc zh proxy.md https://github.com/gofrp/frp-doc/raw/master/content/zh-cn/docs/Reference/proxy.md
14 |
15 | doc zh visitor.md https://github.com/gofrp/frp-doc/raw/master/content/zh-cn/docs/Reference/visitor.md
--------------------------------------------------------------------------------
/frp_version:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 -XX:+UseParallelGC
2 | android.useAndroidX=true
3 | android.enableJetifier = true
4 | android.nonTransitiveRClass=true
5 | android.nonFinalResIds=false
6 | android.enableR8.fullMode=false
7 | android.injected.testOnly=false
8 |
9 | org.gradle.parallel=true
10 | # Use this flag sparingly, in case some of the plugins are not fully compatible
11 | #org.gradle.unsafe.configuration-cache=true
12 | #org.gradle.unsafe.configuration-cache-problems=warn
13 |
14 | kotlin.code.style=official
15 | kotlin.incremental=true
16 | kotlin.incremental.java=true
17 | kotlin.incremental.js=true
18 | #kotlin.caching.enabled=true
19 | kotlin.parallel.tasks.in.project=true
20 |
21 |
22 | #kapt.incremental.apt=true
23 | #kapt.include.compile.classpath=false
24 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jing332/FrpAndroid/d69fc5e4f893eef152340aabe0db06db13dc5df0/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Sat Aug 12 16:22:48 CST 2023
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-bin.zip
5 | networkTimeout=10000
6 | zipStoreBase=GRADLE_USER_HOME
7 | zipStorePath=wrapper/dists
8 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%"=="" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%"=="" set DIRNAME=.
29 | @rem This is normally unused
30 | set APP_BASE_NAME=%~n0
31 | set APP_HOME=%DIRNAME%
32 |
33 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
34 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
35 |
36 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
37 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
38 |
39 | @rem Find java.exe
40 | if defined JAVA_HOME goto findJavaFromJavaHome
41 |
42 | set JAVA_EXE=java.exe
43 | %JAVA_EXE% -version >NUL 2>&1
44 | if %ERRORLEVEL% equ 0 goto execute
45 |
46 | echo.
47 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
48 | echo.
49 | echo Please set the JAVA_HOME variable in your environment to match the
50 | echo location of your Java installation.
51 |
52 | goto fail
53 |
54 | :findJavaFromJavaHome
55 | set JAVA_HOME=%JAVA_HOME:"=%
56 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
57 |
58 | if exist "%JAVA_EXE%" goto execute
59 |
60 | echo.
61 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
62 | echo.
63 | echo Please set the JAVA_HOME variable in your environment to match the
64 | echo location of your Java installation.
65 |
66 | goto fail
67 |
68 | :execute
69 | @rem Setup the command line
70 |
71 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
72 |
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if %ERRORLEVEL% equ 0 goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | set EXIT_CODE=%ERRORLEVEL%
85 | if %EXIT_CODE% equ 0 set EXIT_CODE=1
86 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
87 | exit /b %EXIT_CODE%
88 |
89 | :mainEnd
90 | if "%OS%"=="Windows_NT" endlocal
91 |
92 | :omega
93 |
--------------------------------------------------------------------------------
/images/1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jing332/FrpAndroid/d69fc5e4f893eef152340aabe0db06db13dc5df0/images/1.jpg
--------------------------------------------------------------------------------
/images/2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jing332/FrpAndroid/d69fc5e4f893eef152340aabe0db06db13dc5df0/images/2.jpg
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | pluginManagement {
2 | repositories {
3 | gradlePluginPortal()
4 | google()
5 | mavenCentral()
6 | }
7 | }
8 | dependencyResolutionManagement {
9 | repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
10 | repositories {
11 | google()
12 | mavenCentral()
13 | maven { url 'https://jitpack.io' }
14 | }
15 | }
16 | rootProject.name = "FrpAndroid"
17 | include ':app'
18 |
--------------------------------------------------------------------------------