add components

This commit is contained in:
2023-12-24 21:54:27 +03:00
parent d1de9be97f
commit 34ce33f4a3
30 changed files with 604 additions and 150 deletions
+2 -2
View File
@@ -77,7 +77,7 @@ android {
compose = true
}
composeOptions {
kotlinCompilerExtensionVersion = "1.5.1"
kotlinCompilerExtensionVersion = "1.5.7"
}
packaging {
resources {
@@ -104,7 +104,7 @@ dependencies {
androidTestImplementation(libs.ui.test.junit4)
debugImplementation(libs.ui.tooling)
debugImplementation(libs.ui.test.manifest)
implementation(project(mapOf("path" to ":devmenu")))
implementation ("commons-codec:commons-codec:1.15")
+4 -3
View File
@@ -1,7 +1,9 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application>
<activity android:name="com.ea.ironmonkey.devmenu.MainActivity"
<application android:name="com.megboyzz.devmenu.App">
<activity
android:name="com.megboyzz.devmenu.MainActivity"
android:theme="@android:style/Theme.Material.Light.NoActionBar"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@@ -9,5 +11,4 @@
</intent-filter>
</activity>
</application>
</manifest>
@@ -179,7 +179,7 @@ class GameActivity : ComponentActivity(), DrawFrameListener {
// Calculate screen-related score
val screenScore =
sqrt((screenWidth * screenHeight).toDouble()) * 0.0010000000474974513 * 0.5
sqrt((screenWidth * screenHeight).toDouble()) * 0.001 * 0.5
// Log CPU information
try {
Binary file not shown.
+7 -4
View File
@@ -1,7 +1,9 @@
plugins {
alias(libs.plugins.androidLibrary)
alias(libs.plugins.kotlinAndroid)
alias(libs.plugins.ksp)
kotlin("kapt")
//alias(libs.plugins.ksp)
}
android {
@@ -38,13 +40,14 @@ android {
compose = true
}
composeOptions {
kotlinCompilerExtensionVersion = "1.5.1"
kotlinCompilerExtensionVersion = "1.5.7"
}
packaging {
resources {
excludes += "/META-INF/{AL2.0,LGPL2.1}"
}
}
}
dependencies {
@@ -69,7 +72,7 @@ dependencies {
debugImplementation(libs.ui.test.manifest)
implementation(libs.dagger)
ksp(libs.dagger.compiler)
kapt(libs.dagger.compiler)
implementation(libs.room)
ksp(libs.room.compiler)
kapt(libs.room.compiler)
}
@@ -1,7 +1,8 @@
package com.megboyzz.devmenu.domain.usecases.files
import java.io.File
import javax.inject.Inject
class RemoveFileUseCase {
class RemoveFileUseCase @Inject constructor() {
operator fun invoke(file: File): Boolean = file.delete()
}
@@ -1,8 +1,9 @@
package com.megboyzz.devmenu.domain.usecases.files
import java.io.File
import javax.inject.Inject
class RenameFileUseCase {
class RenameFileUseCase @Inject constructor() {
operator fun invoke(file: File, newName: String) =
if(file.exists())
file.renameTo(File(file.parent, newName))
+2 -4
View File
@@ -1,12 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application>
<application android:name=".App">
<activity
android:name=".MainActivity"
android:exported="true"
android:label="@string/title_activity_main"
android:theme="@style/Theme.DevMenu" />
android:exported="true"/>
</application>
</manifest>
@@ -0,0 +1,35 @@
package com.megboyzz.devmenu
import android.app.Application
import com.megboyzz.devmenu.di.components.DaggerFilesUseCaseComponent
import com.megboyzz.devmenu.di.components.DaggerHideFilesUseCaseComponent
import com.megboyzz.devmenu.di.components.DaggerReplacementUseCaseComponent
import com.megboyzz.devmenu.di.components.DaggerSettingsUseCaseComponent
import com.megboyzz.devmenu.di.components.DaggerTrackingHandlerUseCaseComponent
import com.megboyzz.devmenu.di.components.FilesUseCaseComponent
import com.megboyzz.devmenu.di.components.HideFilesUseCaseComponent
import com.megboyzz.devmenu.di.components.ReplacementUseCaseComponent
import com.megboyzz.devmenu.di.components.SettingsUseCaseComponent
import com.megboyzz.devmenu.di.components.TrackingHandlerUseCaseComponent
import kotlinx.coroutines.coroutineScope
import kotlin.concurrent.thread
class App: Application() {
lateinit var filesUseCaseComponent: FilesUseCaseComponent
lateinit var hideFilesUseCaseComponent: HideFilesUseCaseComponent
lateinit var replacementUseCaseComponent: ReplacementUseCaseComponent
lateinit var settingsUseCaseComponent: SettingsUseCaseComponent
lateinit var trackingHandlerUseCaseComponent: TrackingHandlerUseCaseComponent
override fun onCreate() {
super.onCreate()
filesUseCaseComponent = DaggerFilesUseCaseComponent.builder().context(this).build()
hideFilesUseCaseComponent = DaggerHideFilesUseCaseComponent.builder().context(this).build()
replacementUseCaseComponent = DaggerReplacementUseCaseComponent.builder().context(this).build()
settingsUseCaseComponent = DaggerSettingsUseCaseComponent.builder().context(this).build()
trackingHandlerUseCaseComponent = DaggerTrackingHandlerUseCaseComponent.builder().context(this).build()
}
}
@@ -1,16 +1,42 @@
package com.megboyzz.devmenu
import android.content.Intent
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import com.megboyzz.devmenu.di.components.AppComponent
import dagger.internal.DaggerGenerated
import com.megboyzz.devmenu.ui.components.MainScaffold
class MainActivity : ComponentActivity() {
private fun runGame(){
val gameActivityClass = classLoader.loadClass("com.ea.ironmonkey.GameActivity")
val intent = Intent(this, gameActivityClass)
startActivity(intent)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val isDevMenuEnabled = (application as App)
.trackingHandlerUseCaseComponent
.isDevMenuEnabledUseCase()
if(!isDevMenuEnabled){
runGame()
return
}
setContent {
MainScaffold(
onSettingsClick = { /*TODO*/ },
onSearchValueChanged = {},
onFloatingButtonClick = ::runGame
) {
setContent {}
}
}
}
}
@@ -1,50 +0,0 @@
package com.megboyzz.devmenu.di.components
import android.content.Context
import com.megboyzz.devmenu.db.entites.Replacement
import com.megboyzz.devmenu.di.components.subcomponents.FilesUseCaseComponent
import com.megboyzz.devmenu.di.components.subcomponents.HideFilesUseCaseComponent
import com.megboyzz.devmenu.di.components.subcomponents.ReplacementUseCaseComponent
import com.megboyzz.devmenu.di.components.subcomponents.SettingsUseCaseComponent
import com.megboyzz.devmenu.di.components.subcomponents.TrackingHandlerUseCaseComponent
import com.megboyzz.devmenu.di.modules.DatabaseModule
import com.megboyzz.devmenu.di.modules.RepositoryModule
import com.megboyzz.devmenu.di.modules.SubcomponentsModule
import com.megboyzz.devmenu.domain.usecases.files.GetFilePropsUseCase
import dagger.BindsInstance
import dagger.Component
import dagger.Subcomponent
import javax.inject.Singleton
@Component(
modules = [
SubcomponentsModule::class,
DatabaseModule::class,
RepositoryModule::class
]
)
@Singleton
interface AppComponent {
val filesUseCaseComponent: FilesUseCaseComponent.Builder
val hideFilesUseCaseComponent: HideFilesUseCaseComponent.Builder
val replacementUseCaseComponent: ReplacementUseCaseComponent.Builder
val settingsUseCaseComponent: SettingsUseCaseComponent.Builder
val trackingHandlerUseCaseComponent: TrackingHandlerUseCaseComponent.Builder
@Component.Builder
interface Builder{
@BindsInstance
fun context(context: Context): Builder
fun build(): AppComponent
}
}
@@ -1,7 +1,8 @@
package com.megboyzz.devmenu.di.components.subcomponents
package com.megboyzz.devmenu.di.components
import android.content.Context
import com.megboyzz.devmenu.di.components.AppComponent
import com.megboyzz.devmenu.di.modules.DatabaseModule
import com.megboyzz.devmenu.di.modules.RepositoryModule
import com.megboyzz.devmenu.domain.usecases.files.GetExternalFilesUseCase
import com.megboyzz.devmenu.domain.usecases.files.GetFilePropsUseCase
import com.megboyzz.devmenu.domain.usecases.files.GetInternalFilesUseCase
@@ -9,9 +10,15 @@ import com.megboyzz.devmenu.domain.usecases.files.RemoveFileUseCase
import com.megboyzz.devmenu.domain.usecases.files.RenameFileUseCase
import dagger.BindsInstance
import dagger.Component
import dagger.Subcomponent
import javax.inject.Singleton
@Subcomponent
@Component(
modules = [
DatabaseModule::class,
RepositoryModule::class
]
)
@Singleton
interface FilesUseCaseComponent {
val getExternalFilesUseCase: GetExternalFilesUseCase
@@ -26,7 +33,10 @@ interface FilesUseCaseComponent {
@Component.Builder
interface Builder{
fun build(): AppComponent
@BindsInstance
fun context(context: Context): Builder
fun build(): FilesUseCaseComponent
}
}
@@ -1,14 +1,23 @@
package com.megboyzz.devmenu.di.components.subcomponents
package com.megboyzz.devmenu.di.components
import com.megboyzz.devmenu.di.components.AppComponent
import android.content.Context
import com.megboyzz.devmenu.di.modules.DatabaseModule
import com.megboyzz.devmenu.di.modules.RepositoryModule
import com.megboyzz.devmenu.domain.usecases.hidefiles.GetAllHidedFilesUseCase
import com.megboyzz.devmenu.domain.usecases.hidefiles.HideFileUseCase
import com.megboyzz.devmenu.domain.usecases.hidefiles.UnHideAllUseCase
import com.megboyzz.devmenu.domain.usecases.hidefiles.UnHideFileUseCase
import dagger.BindsInstance
import dagger.Component
import dagger.Subcomponent
import javax.inject.Singleton
@Subcomponent
@Component(
modules = [
DatabaseModule::class,
RepositoryModule::class
]
)
@Singleton
interface HideFilesUseCaseComponent {
val getAllHidedFilesUseCase: GetAllHidedFilesUseCase
@@ -21,7 +30,11 @@ interface HideFilesUseCaseComponent {
@Component.Builder
interface Builder{
fun build(): AppComponent
@BindsInstance
fun context(context: Context): Builder
fun build(): HideFilesUseCaseComponent
}
}
@@ -1,14 +1,23 @@
package com.megboyzz.devmenu.di.components.subcomponents
package com.megboyzz.devmenu.di.components
import com.megboyzz.devmenu.di.components.AppComponent
import android.content.Context
import com.megboyzz.devmenu.di.modules.DatabaseModule
import com.megboyzz.devmenu.di.modules.RepositoryModule
import com.megboyzz.devmenu.domain.usecases.replacement.GetAllReplacedFilesUseCase
import com.megboyzz.devmenu.domain.usecases.replacement.RecoverAllReplacementsUseCase
import com.megboyzz.devmenu.domain.usecases.replacement.RecoverReplacementUseCase
import com.megboyzz.devmenu.domain.usecases.replacement.ReplaceFileUseCase
import dagger.BindsInstance
import dagger.Component
import dagger.Subcomponent
import javax.inject.Singleton
@Subcomponent
@Component(
modules = [
DatabaseModule::class,
RepositoryModule::class
]
)
@Singleton
interface ReplacementUseCaseComponent {
val getAllReplacedFilesUseCase: GetAllReplacedFilesUseCase
@@ -21,7 +30,10 @@ interface ReplacementUseCaseComponent {
@Component.Builder
interface Builder{
fun build(): AppComponent
@BindsInstance
fun context(context: Context): Builder
fun build(): ReplacementUseCaseComponent
}
}
@@ -1,14 +1,23 @@
package com.megboyzz.devmenu.di.components.subcomponents
package com.megboyzz.devmenu.di.components
import com.megboyzz.devmenu.di.components.AppComponent
import android.content.Context
import com.megboyzz.devmenu.di.modules.DatabaseModule
import com.megboyzz.devmenu.di.modules.RepositoryModule
import com.megboyzz.devmenu.domain.usecases.settings.RemoveGameDataUseCase
import com.megboyzz.devmenu.domain.usecases.settings.SetGameLangUseCase
import com.megboyzz.devmenu.domain.usecases.settings.SetTrackingSaveFileUseCase
import com.megboyzz.devmenu.domain.usecases.settings.TurnOffDevMenuUseCase
import dagger.BindsInstance
import dagger.Component
import dagger.Subcomponent
import javax.inject.Singleton
@Subcomponent
@Component(
modules = [
DatabaseModule::class,
RepositoryModule::class
]
)
@Singleton
interface SettingsUseCaseComponent {
val removeGameDataUseCase: RemoveGameDataUseCase
@@ -21,7 +30,10 @@ interface SettingsUseCaseComponent {
@Component.Builder
interface Builder{
fun build(): AppComponent
@BindsInstance
fun context(context: Context): Builder
fun build(): SettingsUseCaseComponent
}
}
@@ -1,13 +1,22 @@
package com.megboyzz.devmenu.di.components.subcomponents
package com.megboyzz.devmenu.di.components
import com.megboyzz.devmenu.di.components.AppComponent
import android.content.Context
import com.megboyzz.devmenu.di.modules.DatabaseModule
import com.megboyzz.devmenu.di.modules.RepositoryModule
import com.megboyzz.devmenu.domain.usecases.IsDevMenuEnabledUseCase
import com.megboyzz.devmenu.domain.usecases.StartTrackingUseCase
import com.megboyzz.devmenu.domain.usecases.StopTrackingUseCase
import dagger.BindsInstance
import dagger.Component
import dagger.Subcomponent
import javax.inject.Singleton
@Subcomponent
@Component(
modules = [
DatabaseModule::class,
RepositoryModule::class
]
)
@Singleton
interface TrackingHandlerUseCaseComponent {
val isDevMenuEnabledUseCase: IsDevMenuEnabledUseCase
@@ -18,7 +27,10 @@ interface TrackingHandlerUseCaseComponent {
@Component.Builder
interface Builder{
fun build(): AppComponent
@BindsInstance
fun context(context: Context): Builder
fun build(): TrackingHandlerUseCaseComponent
}
}
@@ -1,19 +0,0 @@
package com.megboyzz.devmenu.di.modules
import com.megboyzz.devmenu.di.components.subcomponents.FilesUseCaseComponent
import com.megboyzz.devmenu.di.components.subcomponents.HideFilesUseCaseComponent
import com.megboyzz.devmenu.di.components.subcomponents.ReplacementUseCaseComponent
import com.megboyzz.devmenu.di.components.subcomponents.SettingsUseCaseComponent
import com.megboyzz.devmenu.di.components.subcomponents.TrackingHandlerUseCaseComponent
import dagger.Module
@Module(
subcomponents = [
FilesUseCaseComponent::class,
HideFilesUseCaseComponent::class,
ReplacementUseCaseComponent::class,
SettingsUseCaseComponent::class,
TrackingHandlerUseCaseComponent::class
]
)
object SubcomponentsModule
@@ -12,6 +12,8 @@ import androidx.compose.ui.unit.Dp
@Composable
fun Int.asPainter() = painterResource(this)
@Composable
fun Int.asString() = stringResource(this)
@@ -20,3 +22,23 @@ fun SpacerWidth(width: Dp) = Spacer(Modifier.width(width))
@Composable
fun SpacerHeight(height: Dp) = Spacer(Modifier.height(height))
/**
* Возвращает лямбду того типа которая требуется в Composable контексте<br>
* например есть функция
*
* fun example(
* a: @Composable () -> SomeType
* )
*
* Чтобы предать туда параметр нужно обернуть это в скобки<br>
*
* example(a = { SomeType() })
*
* а можно не создавать еще один уровень вложения и использовать asComposableLambda
*
* example(a = SomeType().asComposableLambda)
*/
val <T> T.asComposableLambda: @Composable () -> T
get() = { this }
@@ -0,0 +1,171 @@
package com.megboyzz.devmenu.ui.components
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.BoxScope
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.KeyboardArrowRight
import androidx.compose.material.icons.outlined.Star
import androidx.compose.material3.Divider
import androidx.compose.material3.Icon
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
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.graphics.painter.Painter
import androidx.compose.ui.graphics.vector.rememberVectorPainter
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.megboyzz.devmenu.R
import com.megboyzz.devmenu.ui.asPainter
@Composable
fun ClickableMenuPosition(
name: String,
icon: Painter,
onClick: () -> Unit
) {
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceBetween,
modifier = Modifier
.clickableWithRipple(onClick = onClick)
.fillMaxWidth()
) {
CoreMenuPosition(name = name, icon = icon)
Icon(Icons.Default.KeyboardArrowRight, null)
}
}
@Composable
fun CoreMenuPosition(
name: String,
icon: Painter
) {
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(16.dp),
) {
Image(
painter = icon,
contentDescription = null,
Modifier.size(24.dp)
)
Text(text = name)
}
}
@Composable
fun FsElementInContextMenu(
name: String,
type: ElementType,
) {
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(12.dp)
) {
val modifier = Modifier.size(32.dp).shadow(elevation = 6.dp)
when(type){
ElementType.isHidden -> { Image(painter = R.drawable.icon_hidden_file.asPainter(), contentDescription = null, modifier) }
ElementType.isFile -> { Image(painter = R.drawable.icon_file.asPainter(), contentDescription = null, modifier) }
ElementType.isDir -> { Image(painter = R.drawable.icon_folder.asPainter(), contentDescription = null, modifier) }
ElementType.isReplaced -> { Image(painter = R.drawable.icon_replaced_file.asPainter(), contentDescription = null, modifier) }
}
Text(
text = name
)
}
}
@Composable
fun FileContextMenu(
name: String,
type: ElementType,
) {
CoreFileContextMenu {
Column(
verticalArrangement = Arrangement.spacedBy(20.dp)
) {
FsElementInContextMenu(name = name, type = type)
Divider()
ClickableMenuPosition(
name = "Заменить",
icon = rememberVectorPainter(image = Icons.Outlined.Star)
) {
}
ClickableMenuPosition(
name = "Заменить",
icon = rememberVectorPainter(image = Icons.Outlined.Star)
) {
}
ClickableMenuPosition(
name = "Заменить",
icon = rememberVectorPainter(image = Icons.Outlined.Star)
) {
}
ClickableMenuPosition(
name = "Заменить",
icon = rememberVectorPainter(image = Icons.Outlined.Star)
) {
}
}
}
}
@Composable
fun CoreFileContextMenu(
content: @Composable BoxScope.() -> Unit
) {
Box(
modifier = Modifier
.wrapContentHeight()
.fillMaxWidth()
//TODO отвязать от цвета
.background(Color.White)
.clip(RoundedCornerShape(10.dp)),
contentAlignment = Alignment.TopCenter
){
Box(
modifier = Modifier.padding(
horizontal = 32.dp,
vertical = 24.dp
),
content = content
)
}
}
@Preview
@Composable
fun ClicablePreview() {
FileContextMenu(
name = "my_file.txt",
type = ElementType.isFile
)
}
@@ -0,0 +1,82 @@
package com.megboyzz.devmenu.ui.components
import android.widget.Toast
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.combinedClickable
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.fillMaxSize
import androidx.compose.material.ripple.rememberRipple
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.platform.LocalContext
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.megboyzz.devmenu.R
import com.megboyzz.devmenu.ui.asPainter
import com.megboyzz.devmenu.ui.theme.DevMenuTheme
enum class ElementType {
isHidden,
isReplaced,
isFile,
isDir
}
@Composable
fun FsElement(
name: String,
type: ElementType,
onClick: () -> Unit,
onLongPressClick: () -> Unit
) {
Column(
verticalArrangement = Arrangement.spacedBy(10.dp),
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier.clickableWithRipple(
onClick = onClick,
onLongClick = onLongPressClick
)
) {
when(type){
ElementType.isHidden -> { Image(painter = R.drawable.icon_hidden_file.asPainter(), contentDescription = null) }
ElementType.isFile -> { Image(painter = R.drawable.icon_file.asPainter(), contentDescription = null) }
ElementType.isDir -> { Image(painter = R.drawable.icon_folder.asPainter(), contentDescription = null) }
ElementType.isReplaced -> { Image(painter = R.drawable.icon_replaced_file.asPainter(), contentDescription = null) }
}
Text(
text = name
)
}
}
@Preview
@Composable
fun FileIcon() {
val context = LocalContext.current
Box(
modifier = Modifier
.fillMaxSize()
.background(Color.White)
) {
FsElement(
name = "my_file.txt",
type = ElementType.isReplaced,
onLongPressClick = {Toast.makeText(context, "long!", Toast.LENGTH_SHORT).show()},
onClick = {Toast.makeText(context, "one!", Toast.LENGTH_SHORT).show()}
)
}
}
@@ -1,22 +1,27 @@
package com.megboyzz.devmenu.ui.components
import android.util.Log
import android.widget.Toast
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.core.tween
import androidx.compose.animation.slideInVertically
import androidx.compose.animation.slideOutVertically
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.BasicTextField
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.PlayArrow
import androidx.compose.material.icons.outlined.Search
import androidx.compose.material.icons.outlined.Settings
import androidx.compose.material3.Divider
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.FloatingActionButton
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.Scaffold
@@ -33,22 +38,45 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.megboyzz.devmenu.ui.asComposableLambda
import com.megboyzz.devmenu.ui.theme.DevMenuTheme
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun MainScaffold() {
fun MainScaffold(
onSettingsClick: () -> Unit,
onSearchValueChanged: (String) -> Unit,
onFloatingButtonClick: () -> Unit,
content: @Composable (PaddingValues) -> Unit
) {
var searchValue by remember { mutableStateOf("") }
Scaffold(
topBar = {
TopAppBar(
title = { Text("") },
TopBar(
searchValue = searchValue,
onSearchValueChanged = {
searchValue = it
onSearchValueChanged(it)
},
onSettingsClick = onSettingsClick
)
},
floatingActionButton = {
FloatingActionButton(
onClick = onFloatingButtonClick,
shape = CircleShape,
content = {Icon(imageVector = Icons.Default.PlayArrow, contentDescription = null)}
)
},
content = content
)
}
) {
it.calculateBottomPadding()
}
}
@OptIn(ExperimentalMaterial3Api::class)
@@ -59,19 +87,26 @@ fun TopBar(
onSettingsClick: () -> Unit
) {
var text by remember { mutableStateOf("") }
var isSearching by remember { mutableStateOf(false) }
val context = LocalContext.current
TopAppBar(
title = {
Box {
if(isSearching) {
AnimatedVisibility(
visible = isSearching,
enter = slideInVertically(animationSpec = tween(durationMillis = 200)) {
-it / 3
},
exit = slideOutVertically(animationSpec = tween(durationMillis = 200)) {
-it / 3
}
) {
SearchFileTextField(
value = text,
onValueChange = { text = it }
value = searchValue,
onValueChange = onSearchValueChanged
)
} else Text("NFSMW DevMenu")
}
if(!isSearching) Text("NFSMW DevMenu")
}
},
@@ -111,13 +146,15 @@ fun SearchButton(
@Preview
@Composable
fun TopBarPrev() {
fun ScaffoldPreview() {
DevMenuTheme {
TopBar(
searchValue = "А как какать",
MainScaffold(
onSettingsClick = { /*TODO*/ },
onSearchValueChanged = {},
onSettingsClick = {}
)
onFloatingButtonClick = { /*TODO*/ }
) {
}
}
}
@@ -137,13 +174,16 @@ fun SearchFileTextField(
Modifier
.fillMaxWidth()
.background(Color.White, RoundedCornerShape(percent = 30))
.border(1.dp, Color.Black, RoundedCornerShape(percent = 30))
.padding(start = 12.dp),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
Box(Modifier.padding(vertical = 4.dp)) {
innerTextField()
}
}
}
},
)
@@ -0,0 +1,25 @@
package com.megboyzz.devmenu.ui.components
import android.annotation.SuppressLint
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.combinedClickable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.material.ripple.rememberRipple
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
@SuppressLint("ModifierFactoryUnreferencedReceiver")
@OptIn(ExperimentalFoundationApi::class)
@Composable
fun Modifier.clickableWithRipple(
onClick: () -> Unit,
onLongClick: () -> Unit = {}
): Modifier {
return Modifier.combinedClickable(
interactionSource = remember { MutableInteractionSource() },
indication = rememberRipple(),
onClick = onClick,
onLongClick = onLongClick
)
}
+9
View File
@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="30dp"
android:height="3dp"
android:viewportWidth="30"
android:viewportHeight="3">
<path
android:pathData="M1.5,0L28.5,0A1.5,1.5 0,0 1,30 1.5L30,1.5A1.5,1.5 0,0 1,28.5 3L1.5,3A1.5,1.5 0,0 1,0 1.5L0,1.5A1.5,1.5 0,0 1,1.5 0z"
android:fillColor="#C9C9C9"/>
</vector>
@@ -0,0 +1,12 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="55dp"
android:height="54dp"
android:viewportWidth="55"
android:viewportHeight="54">
<path
android:pathData="M10,0L44.857,0A10,10 0,0 1,54.857 10L54.857,43.053A10,10 0,0 1,44.857 53.053L10,53.053A10,10 0,0 1,0 43.053L0,10A10,10 0,0 1,10 0z"
android:fillColor="#36A0EA"/>
<path
android:pathData="M31.629,23.289C30.292,23.289 29.01,22.824 28.065,21.995C27.12,21.166 26.589,20.041 26.589,18.868V12.974H19.869C18.978,12.974 18.123,13.284 17.493,13.837C16.863,14.39 16.509,15.139 16.509,15.921V35.079C16.509,35.861 16.863,36.61 17.493,37.163C18.123,37.716 18.978,38.026 19.869,38.026H34.989C35.88,38.026 36.734,37.716 37.364,37.163C37.995,36.61 38.349,35.861 38.349,35.079V23.289H31.629ZM28.269,18.868C28.269,19.65 28.623,20.4 29.253,20.952C29.883,21.505 30.737,21.816 31.629,21.816H37.66L28.269,13.578V18.868ZM19.869,11.5H28.269L40.029,21.816V35.079C40.029,36.251 39.498,37.376 38.552,38.205C37.607,39.034 36.325,39.5 34.989,39.5H19.869C18.532,39.5 17.25,39.034 16.305,38.205C15.36,37.376 14.829,36.251 14.829,35.079V15.921C14.829,14.748 15.36,13.624 16.305,12.795C17.25,11.966 18.532,11.5 19.869,11.5Z"
android:fillColor="#ffffff"/>
</vector>
@@ -0,0 +1,12 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="55dp"
android:height="54dp"
android:viewportWidth="55"
android:viewportHeight="54">
<path
android:pathData="M10,0L44.857,0A10,10 0,0 1,54.857 10L54.857,43.053A10,10 0,0 1,44.857 53.053L10,53.053A10,10 0,0 1,0 43.053L0,10A10,10 0,0 1,10 0z"
android:fillColor="#36A0EA"/>
<path
android:pathData="M17.165,14.092H23.481L28.218,19.066H37.692C38.948,19.066 40.153,19.59 41.041,20.522C41.93,21.455 42.429,22.72 42.429,24.039V33.987C42.429,35.306 41.93,36.571 41.041,37.504C40.153,38.437 38.948,38.96 37.692,38.96H17.165C15.909,38.96 14.704,38.437 13.816,37.504C12.928,36.571 12.429,35.306 12.429,33.987V19.066C12.429,17.747 12.928,16.482 13.816,15.549C14.704,14.616 15.909,14.092 17.165,14.092ZM17.165,15.75C16.328,15.75 15.525,16.099 14.932,16.721C14.34,17.343 14.007,18.186 14.007,19.066V33.987C14.007,34.866 14.34,35.71 14.932,36.332C15.525,36.953 16.328,37.303 17.165,37.303H37.692C38.529,37.303 39.333,36.953 39.925,36.332C40.517,35.71 40.85,34.866 40.85,33.987V24.039C40.85,23.16 40.517,22.317 39.925,21.695C39.333,21.073 38.529,20.724 37.692,20.724H27.571L22.834,15.75H17.165Z"
android:fillColor="#ffffff"/>
</vector>
@@ -0,0 +1,19 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="55dp"
android:height="54dp"
android:viewportWidth="55"
android:viewportHeight="54">
<path
android:pathData="M10,0L44.857,0A10,10 0,0 1,54.857 10L54.857,43.053A10,10 0,0 1,44.857 53.053L10,53.053A10,10 0,0 1,0 43.053L0,10A10,10 0,0 1,10 0z"
android:fillColor="#36A0EA"/>
<path
android:pathData="M31.629,23.289C30.292,23.289 29.01,22.824 28.065,21.995C27.12,21.166 26.589,20.041 26.589,18.868V12.974H19.869C18.978,12.974 18.123,13.284 17.493,13.837C16.863,14.39 16.509,15.139 16.509,15.921V35.079C16.509,35.861 16.863,36.61 17.493,37.163C18.123,37.716 18.978,38.026 19.869,38.026H34.989C35.88,38.026 36.734,37.716 37.364,37.163C37.995,36.61 38.349,35.861 38.349,35.079V23.289H31.629ZM28.269,18.868C28.269,19.65 28.623,20.4 29.253,20.952C29.883,21.505 30.737,21.816 31.629,21.816H37.66L28.269,13.578V18.868ZM19.869,11.5H28.269L40.029,21.816V35.079C40.029,36.251 39.498,37.376 38.552,38.205C37.607,39.034 36.325,39.5 34.989,39.5H19.869C18.532,39.5 17.25,39.034 16.305,38.205C15.36,37.376 14.829,36.251 14.829,35.079V15.921C14.829,14.748 15.36,13.624 16.305,12.795C17.25,11.966 18.532,11.5 19.869,11.5Z"
android:fillColor="#ffffff"/>
<group>
<clip-path
android:pathData="M21.429,23h12v12h-12z"/>
<path
android:pathData="M29.479,29.65L28.754,28.925C28.829,28.533 28.716,28.167 28.416,27.825C28.116,27.483 27.729,27.35 27.254,27.425L26.529,26.7C26.67,26.633 26.814,26.583 26.96,26.55C27.106,26.517 27.262,26.5 27.429,26.5C28.054,26.5 28.585,26.719 29.022,27.156C29.46,27.594 29.679,28.125 29.679,28.75C29.679,28.917 29.662,29.073 29.629,29.219C29.595,29.365 29.545,29.508 29.479,29.65ZM31.079,31.225L30.354,30.525C30.67,30.283 30.951,30.019 31.197,29.731C31.443,29.444 31.654,29.117 31.829,28.75C31.412,27.908 30.814,27.24 30.035,26.744C29.256,26.248 28.387,26 27.429,26C27.187,26 26.949,26.017 26.716,26.05C26.483,26.083 26.254,26.133 26.029,26.2L25.254,25.425C25.595,25.283 25.945,25.177 26.304,25.106C26.662,25.035 27.037,25 27.429,25C28.687,25 29.808,25.348 30.791,26.044C31.774,26.74 32.487,27.642 32.929,28.75C32.737,29.242 32.485,29.698 32.172,30.119C31.86,30.54 31.495,30.908 31.079,31.225ZM31.329,34.3L29.229,32.225C28.937,32.317 28.643,32.385 28.347,32.431C28.052,32.477 27.745,32.5 27.429,32.5C26.17,32.5 25.049,32.152 24.066,31.456C23.083,30.76 22.37,29.858 21.929,28.75C22.104,28.308 22.324,27.898 22.591,27.519C22.858,27.14 23.162,26.8 23.504,26.5L22.129,25.1L22.829,24.4L32.029,33.6L31.329,34.3ZM24.204,27.2C23.962,27.417 23.741,27.654 23.541,27.913C23.341,28.171 23.17,28.45 23.029,28.75C23.445,29.592 24.043,30.26 24.822,30.756C25.601,31.252 26.47,31.5 27.429,31.5C27.595,31.5 27.758,31.49 27.916,31.469C28.074,31.448 28.237,31.425 28.404,31.4L27.954,30.925C27.862,30.95 27.774,30.969 27.691,30.981C27.608,30.994 27.52,31 27.429,31C26.804,31 26.272,30.781 25.835,30.344C25.397,29.906 25.179,29.375 25.179,28.75C25.179,28.658 25.185,28.571 25.197,28.487C25.21,28.404 25.229,28.317 25.254,28.225L24.204,27.2Z"
android:fillColor="#ffffff"/>
</group>
</vector>
@@ -0,0 +1,15 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="55dp"
android:height="54dp"
android:viewportWidth="55"
android:viewportHeight="54">
<path
android:pathData="M10,0L44.857,0A10,10 0,0 1,54.857 10L54.857,43.053A10,10 0,0 1,44.857 53.053L10,53.053A10,10 0,0 1,0 43.053L0,10A10,10 0,0 1,10 0z"
android:fillColor="#36A0EA"/>
<path
android:pathData="M31.629,23.289C30.292,23.289 29.01,22.824 28.065,21.995C27.12,21.166 26.589,20.041 26.589,18.868V12.974H19.869C18.978,12.974 18.123,13.284 17.493,13.837C16.863,14.39 16.509,15.139 16.509,15.921V35.079C16.509,35.861 16.863,36.61 17.493,37.163C18.123,37.716 18.978,38.026 19.869,38.026H34.989C35.88,38.026 36.734,37.716 37.364,37.163C37.995,36.61 38.349,35.861 38.349,35.079V23.289H31.629ZM28.269,18.868C28.269,19.65 28.623,20.4 29.253,20.952C29.883,21.505 30.737,21.816 31.629,21.816H37.66L28.269,13.578V18.868ZM19.869,11.5H28.269L40.029,21.816V35.079C40.029,36.251 39.498,37.376 38.552,38.205C37.607,39.034 36.325,39.5 34.989,39.5H19.869C18.532,39.5 17.25,39.034 16.305,38.205C15.36,37.376 14.829,36.251 14.829,35.079V15.921C14.829,14.748 15.36,13.624 16.305,12.795C17.25,11.966 18.532,11.5 19.869,11.5Z"
android:fillColor="#ffffff"/>
<path
android:pathData="M25.09,32.409L27.428,31.009L29.765,32.425L29.147,29.775L31.204,27.998L28.491,27.759L27.428,25.266L26.365,27.744L23.652,27.982L25.709,29.766L25.09,32.409ZM27.428,31.84L24.749,33.45C24.681,33.486 24.612,33.503 24.542,33.5C24.472,33.496 24.408,33.475 24.351,33.435C24.294,33.394 24.25,33.342 24.222,33.276C24.193,33.211 24.189,33.138 24.21,33.057L24.915,30.026L22.558,27.979C22.494,27.926 22.454,27.865 22.439,27.796C22.423,27.727 22.426,27.659 22.447,27.592C22.463,27.528 22.5,27.475 22.555,27.432C22.61,27.388 22.678,27.363 22.759,27.357L25.877,27.083L27.09,24.216C27.124,24.146 27.172,24.092 27.234,24.055C27.295,24.018 27.36,24 27.428,24C27.496,24 27.56,24.018 27.622,24.055C27.684,24.092 27.732,24.146 27.766,24.216L28.979,27.083L32.097,27.357C32.178,27.363 32.246,27.388 32.301,27.432C32.356,27.475 32.394,27.528 32.415,27.592C32.432,27.659 32.433,27.727 32.417,27.796C32.402,27.865 32.362,27.926 32.298,27.979L29.941,30.026L30.652,33.057C30.669,33.138 30.663,33.211 30.634,33.276C30.605,33.342 30.563,33.394 30.505,33.435C30.448,33.475 30.384,33.496 30.314,33.5C30.244,33.503 30.175,33.486 30.107,33.45L27.428,31.84Z"
android:fillColor="#ffffff"/>
</vector>
-3
View File
@@ -1,3 +0,0 @@
<resources>
<string name="title_activity_main">MainActivity</string>
</resources>
-5
View File
@@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="Theme.DevMenu" parent="android:Theme.Material.Light.NoActionBar" />
</resources>
+4 -4
View File
@@ -1,16 +1,16 @@
[versions]
agp = "8.1.2"
junit-junit = "4.13.2"
kotlin = "1.9.0"
kotlin = "1.9.21"
core-ktx = "1.12.0"
junit = "4.14"
androidx-test-ext-junit = "1.1.5"
espresso-core = "3.5.1"
lifecycle-runtime-ktx = "2.6.2"
activity-compose = "1.7.2"
compose-bom = "2023.08.00"
activity-compose = "1.8.2"
compose-bom = "2023.10.01"
appcompat = "1.6.1"
material = "1.10.0"
material = "1.11.0"
org-jetbrains-kotlin-jvm = "1.9.0"
ksp = "1.9.21-1.0.15"
dagger = "2.46.1"