2 |

3 |
ANeko Reborn
4 |
ANeko Reborn is a modern version of the classic ANeko app.
5 |
It features a cute cat animation that follows your finger on the Android screen, inspired by apps like nekoDA, xneko, oneko, and more.
6 |
This version is built for modern Android devices with better performance and compatibility.
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
Download
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 | ---
32 |
33 | ## Features
34 |
35 | * The cat follows your finger around the screen
36 | * Updated user interface with Material You styling
37 | * Compatible with Android 14 and newer
38 | * Handles overlay permissions automatically
39 | * Smoother animations and improved performance
40 | * Supports custom cat skins
41 |
42 | ---
43 |
44 | ## Community
45 |
46 | Join our community on Telegram:
47 | [](https://t.me/aneko_community)
48 |
49 | ## Build Instructions
50 |
51 | ### Requirements
52 |
53 | * [Android Studio](https://developer.android.com/studio)
54 | * Java 11 or higher
55 |
56 | ### Steps
57 |
58 | 1. Clone the repository:
59 | ```bash
60 | git clone https://github.com/pass-with-high-score/ANeko.git
61 | cd ANeko
62 | ```
63 | 2. Open the project in Android Studio
64 |
65 | 3. Sync Gradle and run the app on a device or emulator
66 |
67 | ---
68 |
69 | ## Creating Custom Skins
70 |
71 | ANeko supports two skin types:
72 |
73 | ### App-based Skins (version <= 1.2.3)
74 |
75 | * Create a new module with your assets and logic
76 | * Refer to
77 | the [skin documentation](http://www.tamanegi.org/prog/android-apps/aneko-skin.html#create-skin)
78 |
79 | ### File-based Skins (version >= 1.3.0) Recommended
80 |
81 | * Manually place skin files in the correct directory
82 | * More detailed instructions will be provided soon
83 |
84 | ---
85 |
86 | ## Roadmap
87 | You can see it here: [Link](https://github.com/pass-with-high-score/ANeko/discussions/35#discussion-8397935)
88 |
89 | ## License
90 |
91 | This project is licensed under the **GNU Lesser General Public License v2.1**.
92 | You are free to use, modify, and distribute it, but you must include proper credits and the
93 | license.
94 | See the full [LICENSE](LICENSE) file for details.
95 |
96 | ---
97 |
98 | ## Credits
99 |
100 | * Original ANeko by [Tamanegi](https://github.com/lllllT)
101 | * Fork maintained by [choiman1559](https://github.com/choiman1559/ANeko)
102 | * Updated and improved by [Nguyen Quang Minh](https://github.com/nqmgaming)
103 |
104 | ---
105 |
106 | ## Contributing
107 |
108 | Pull requests and issue reports are welcome.
109 | Help us improve ANeko Reborn!
110 |
111 | ### Help us translate ANeko
112 |
113 | Want to see ANeko in your language?
114 | Join our translation project here: [https://poeditor.com/join/project/zX7Nu44XDh](https://poeditor.com/join/project/zX7Nu44XDh)
115 |
116 | ---
117 |
118 | ## Star History
119 | Thanks
120 |
121 |
122 | [](https://www.star-history.com/#pass-with-high-score/ANeko&Date)
123 |
--------------------------------------------------------------------------------
/app/src/main/java/org/nqmgaming/aneko/presentation/home/component/SelectLanguageDialog.kt:
--------------------------------------------------------------------------------
1 | package org.nqmgaming.aneko.presentation.home.component
2 |
3 | import androidx.compose.foundation.layout.Column
4 | import androidx.compose.foundation.layout.Row
5 | import androidx.compose.foundation.layout.Spacer
6 | import androidx.compose.foundation.layout.fillMaxWidth
7 | import androidx.compose.foundation.layout.padding
8 | import androidx.compose.foundation.layout.width
9 | import androidx.compose.foundation.selection.selectable
10 | import androidx.compose.material3.AlertDialog
11 | import androidx.compose.material3.MaterialTheme
12 | import androidx.compose.material3.RadioButton
13 | import androidx.compose.material3.Text
14 | import androidx.compose.material3.TextButton
15 | import androidx.compose.runtime.Composable
16 | import androidx.compose.runtime.mutableStateOf
17 | import androidx.compose.runtime.remember
18 | import androidx.compose.ui.Alignment
19 | import androidx.compose.ui.Modifier
20 | import androidx.compose.ui.platform.LocalContext
21 | import androidx.compose.ui.platform.LocalResources
22 | import androidx.compose.ui.res.stringResource
23 | import androidx.compose.ui.unit.dp
24 | import org.nqmgaming.aneko.R
25 | import org.nqmgaming.aneko.data.Language
26 | import org.nqmgaming.aneko.util.extension.changeLanguage
27 | import org.nqmgaming.aneko.util.extension.getLanguageCode
28 |
29 | @Composable
30 | fun SelectLanguageDialog(
31 | onDismiss: () -> Unit,
32 | ) {
33 | val context = LocalContext.current
34 | val codes = LocalResources.current.getStringArray(R.array.language_codes)
35 | val names = LocalResources.current.getStringArray(R.array.language_names)
36 | val languages = codes.zip(names) { code, name -> Language(code, name) }
37 |
38 | val currentLanguage = remember {
39 | mutableStateOf(context.getLanguageCode())
40 | }
41 |
42 | AlertDialog(
43 | containerColor = MaterialTheme.colorScheme.surface,
44 | onDismissRequest = onDismiss,
45 | title = {
46 | Column {
47 | Text(
48 | text = stringResource(R.string.choose_language_title),
49 | style = MaterialTheme.typography.headlineSmall
50 | )
51 | TextButton(
52 | onClick = onDismiss
53 | ) {
54 | Text(stringResource(R.string.contribute_to_translation))
55 | }
56 | }
57 |
58 | },
59 | text = {
60 | Column(
61 | modifier = Modifier.fillMaxWidth()
62 | ) {
63 | languages.forEach { language ->
64 | Row(
65 | modifier = Modifier
66 | .fillMaxWidth()
67 | .selectable(
68 | selected = (language.code == currentLanguage.value),
69 | onClick = {
70 | currentLanguage.value = language.code
71 | }
72 | )
73 | .padding(vertical = 8.dp),
74 | verticalAlignment = Alignment.CenterVertically
75 | ) {
76 | RadioButton(
77 | selected = (language.code == currentLanguage.value),
78 | onClick = {
79 | currentLanguage.value = language.code
80 | }
81 | )
82 | Spacer(modifier = Modifier.width(8.dp))
83 | Text(
84 | text = language.displayName,
85 | style = MaterialTheme.typography.bodyLarge
86 | )
87 | }
88 | }
89 | }
90 | },
91 | confirmButton = {
92 | TextButton(
93 | onClick = {
94 | context.changeLanguage(currentLanguage.value)
95 | onDismiss()
96 | }
97 | ) {
98 | Text("Ok")
99 | }
100 | },
101 | dismissButton = {
102 | TextButton(
103 | onClick = onDismiss
104 | ) {
105 | Text(stringResource(R.string.cancel))
106 | }
107 | }
108 | )
109 | }
--------------------------------------------------------------------------------
/app/src/main/java/org/nqmgaming/aneko/presentation/home/component/PowerToggleButton.kt:
--------------------------------------------------------------------------------
1 | package org.nqmgaming.aneko.presentation.home.component
2 |
3 | import android.content.Intent
4 | import android.provider.Settings
5 | import androidx.compose.foundation.background
6 | import androidx.compose.foundation.clickable
7 | import androidx.compose.foundation.layout.Box
8 | import androidx.compose.foundation.layout.size
9 | import androidx.compose.foundation.shape.CircleShape
10 | import androidx.compose.material.icons.Icons
11 | import androidx.compose.material.icons.filled.PowerSettingsNew
12 | import androidx.compose.material3.AlertDialog
13 | import androidx.compose.material3.Icon
14 | import androidx.compose.material3.MaterialTheme
15 | import androidx.compose.material3.Text
16 | import androidx.compose.material3.TextButton
17 | import androidx.compose.runtime.Composable
18 | import androidx.compose.runtime.getValue
19 | import androidx.compose.runtime.mutableStateOf
20 | import androidx.compose.runtime.remember
21 | import androidx.compose.runtime.setValue
22 | import androidx.compose.ui.Alignment
23 | import androidx.compose.ui.Modifier
24 | import androidx.compose.ui.draw.clip
25 | import androidx.compose.ui.graphics.vector.ImageVector
26 | import androidx.compose.ui.platform.LocalContext
27 | import androidx.compose.ui.res.stringResource
28 | import androidx.compose.ui.unit.dp
29 | import androidx.core.net.toUri
30 | import org.nqmgaming.aneko.R
31 |
32 | @Composable
33 | fun PowerToggleButton(
34 | isEnabled: Boolean,
35 | onChangeEnable: (Boolean) -> Unit
36 | ) {
37 | val context = LocalContext.current
38 | val backgroundColor =
39 | if (isEnabled) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.surface
40 | val iconColor =
41 | if (isEnabled) MaterialTheme.colorScheme.onPrimary else MaterialTheme.colorScheme.onSurface
42 | val icon: ImageVector = Icons.Filled.PowerSettingsNew
43 |
44 | var showPermissionDialog by remember { mutableStateOf(false) }
45 |
46 | if (showPermissionDialog) {
47 | AlertDialog(
48 | containerColor = MaterialTheme.colorScheme.surface,
49 | onDismissRequest = { showPermissionDialog = false },
50 | title = { Text(text = stringResource(R.string.overlay_permission_title)) },
51 | text = {
52 | Text(
53 | stringResource(R.string.overlay_permission_description)
54 | )
55 | },
56 | confirmButton = {
57 | TextButton(onClick = {
58 | showPermissionDialog = false
59 | val intent = Intent(
60 | Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
61 | "package:${context.packageName}".toUri()
62 | )
63 | context.startActivity(intent)
64 | }) {
65 | Text(stringResource(R.string.allow_button))
66 | }
67 | },
68 | dismissButton = {
69 | TextButton(onClick = { showPermissionDialog = false }) {
70 | Text(stringResource(R.string.cancel_button))
71 | }
72 | }
73 | )
74 | }
75 |
76 | Box(
77 | modifier = Modifier
78 | .size(110.dp)
79 | .clip(CircleShape)
80 | .background(MaterialTheme.colorScheme.onSurface.copy(alpha = 0.2f)),
81 | contentAlignment = Alignment.Center
82 | ) {
83 | Box(
84 | modifier = Modifier
85 | .size(100.dp)
86 | .align(Alignment.Center)
87 | .clip(CircleShape)
88 | .background(backgroundColor)
89 | .clickable {
90 | if (!Settings.canDrawOverlays(context)) {
91 | showPermissionDialog = true
92 | } else {
93 | onChangeEnable(!isEnabled)
94 | }
95 | },
96 | contentAlignment = Alignment.Center
97 | ) {
98 | Icon(
99 | imageVector = icon,
100 | contentDescription = if (isEnabled) stringResource(R.string.power_on) else stringResource(
101 | R.string.power_off
102 | ),
103 | tint = iconColor,
104 | modifier = Modifier.size(40.dp)
105 | )
106 | }
107 | }
108 |
109 | }
110 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_anim_search_close.xml:
--------------------------------------------------------------------------------
1 |